1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-24 14:27:35 +00:00

LibGfx: Avoid rounding/truncating glyph positions till blitting

This keeps some overloads that accept ints to avoid adding calls to
.to_type<float>() all over the place.
This commit is contained in:
MacDue 2023-01-01 19:42:00 +01:00 committed by Andreas Kling
parent 68f678f566
commit a1726b1ba5
14 changed files with 172 additions and 106 deletions

View file

@ -170,7 +170,7 @@ private:
if (m_show_percent) {
auto volume_text = m_audio_muted ? "mute" : DeprecatedString::formatted("{}%", m_audio_volume);
painter.draw_text({ 16, 3, 24, 16 }, volume_text, Gfx::FontDatabase::default_fixed_width_font(), Gfx::TextAlignment::TopLeft, palette().window_text());
painter.draw_text(Gfx::IntRect { 16, 3, 24, 16 }, volume_text, Gfx::FontDatabase::default_fixed_width_font(), Gfx::TextAlignment::TopLeft, palette().window_text());
}
}

View file

@ -217,7 +217,7 @@ void ImageEditor::paint_event(GUI::PaintEvent& event)
int const editor_x = content_to_frame_position({ x, 0 }).x();
painter.draw_line({ editor_x, 0 }, { editor_x, m_ruler_thickness }, ruler_fg_color);
painter.draw_text({ { editor_x + 2, 0 }, { m_ruler_thickness, m_ruler_thickness - 2 } }, DeprecatedString::formatted("{}", x), painter.font(), Gfx::TextAlignment::CenterLeft, ruler_text_color);
painter.draw_text(Gfx::IntRect { { editor_x + 2, 0 }, { m_ruler_thickness, m_ruler_thickness - 2 } }, DeprecatedString::formatted("{}", x), painter.font(), Gfx::TextAlignment::CenterLeft, ruler_text_color);
}
// Vertical ruler
@ -234,7 +234,7 @@ void ImageEditor::paint_event(GUI::PaintEvent& event)
int const editor_y = content_to_frame_position({ 0, y }).y();
painter.draw_line({ 0, editor_y }, { m_ruler_thickness, editor_y }, ruler_fg_color);
painter.draw_text({ { 0, editor_y - m_ruler_thickness }, { m_ruler_thickness, m_ruler_thickness } }, DeprecatedString::formatted("{}", y), painter.font(), Gfx::TextAlignment::BottomRight, ruler_text_color);
painter.draw_text(Gfx::IntRect { { 0, editor_y - m_ruler_thickness }, { m_ruler_thickness, m_ruler_thickness } }, DeprecatedString::formatted("{}", y), painter.font(), Gfx::TextAlignment::BottomRight, ruler_text_color);
}
// Mouse position indicator

View file

@ -142,7 +142,7 @@ void TextTool::on_second_paint(Layer const* layer, GUI::PaintEvent& event)
auto text_bitmap = text_bitmap_result.release_value();
auto text_painter = GUI::Painter(text_bitmap);
text_painter.set_font(*m_selected_font);
text_painter.draw_text({ 0, 0, text_width, text_height }, typed_text, Gfx::TextAlignment::TopLeft, m_text_color);
text_painter.draw_text(Gfx::IntRect { 0, 0, text_width, text_height }, typed_text, Gfx::TextAlignment::TopLeft, m_text_color);
m_text_editor->update();

View file

@ -32,7 +32,7 @@ NetworkStatisticsWidget::NetworkStatisticsWidget()
m_network_link_down_bitmap = Gfx::Bitmap::try_create(m_network_connected_bitmap->format(), m_network_connected_bitmap->size()).release_value_but_fixme_should_propagate_errors();
{
Gfx::Painter painter(*m_network_link_down_bitmap);
painter.blit_filtered({}, *m_network_connected_bitmap, m_network_connected_bitmap->rect(), [](Color color) {
painter.blit_filtered(Gfx::IntPoint {}, *m_network_connected_bitmap, m_network_connected_bitmap->rect(), [](Color color) {
return color.to_grayscale();
});
}

View file

@ -109,7 +109,7 @@ void WelcomeWidget::paint_event(GUI::PaintEvent& event)
painter.add_clip_rect(event.rect());
static auto font = Gfx::BitmapFont::load_from_file("/res/fonts/MarietaRegular24.font"sv);
painter.draw_text({ 12, 4, 1, 30 }, "Welcome to "sv, *font, Gfx::TextAlignment::CenterLeft, palette().base_text());
painter.draw_text({ 12 + static_cast<int>(ceilf(font->width("Welcome to "sv))), 4, 1, 30 }, "Serenity"sv, font->bold_variant(), Gfx::TextAlignment::CenterLeft, palette().base_text());
painter.draw_text({ 12 + static_cast<int>(ceilf(font->width("Welcome to "sv))) + static_cast<int>(ceilf(font->bold_variant().width("Serenity"sv))), 4, 1, 30 }, "OS"sv, font->bold_variant(), Gfx::TextAlignment::CenterLeft, palette().base() == palette().window() ? palette().base_text() : palette().base());
painter.draw_text(Gfx::IntRect { 12, 4, 1, 30 }, "Welcome to "sv, *font, Gfx::TextAlignment::CenterLeft, palette().base_text());
painter.draw_text(Gfx::IntRect { 12 + static_cast<int>(ceilf(font->width("Welcome to "sv))), 4, 1, 30 }, "Serenity"sv, font->bold_variant(), Gfx::TextAlignment::CenterLeft, palette().base_text());
painter.draw_text(Gfx::IntRect { 12 + static_cast<int>(ceilf(font->width("Welcome to "sv))) + static_cast<int>(ceilf(font->bold_variant().width("Serenity"sv))), 4, 1, 30 }, "OS"sv, font->bold_variant(), Gfx::TextAlignment::CenterLeft, palette().base() == palette().window() ? palette().base_text() : palette().base());
}

View file

@ -135,26 +135,26 @@ void Canvas::draw()
painter.draw_rect({ 20, 260, 480, 320 }, Color::DarkGray);
painter.draw_rect({ 520, 260, 240, 80 }, Color::DarkGray);
painter.draw_text({ 520, 260, 240, 80 }, "CenterLeft"sv, Gfx::TextAlignment::CenterLeft, Color::White);
painter.draw_text({ 520, 260, 240, 80 }, "Center"sv, Gfx::TextAlignment::Center, Color::White);
painter.draw_text({ 520, 260, 240, 80 }, "CenterRight"sv, Gfx::TextAlignment::CenterRight, Color::White);
painter.draw_text({ 520, 260, 240, 80 }, "TopLeft"sv, Gfx::TextAlignment::TopLeft, Color::White);
painter.draw_text({ 520, 260, 240, 80 }, "TopRight"sv, Gfx::TextAlignment::TopRight, Color::White);
painter.draw_text({ 520, 260, 240, 80 }, "BottomLeft"sv, Gfx::TextAlignment::BottomLeft, Color::White);
painter.draw_text({ 520, 260, 240, 80 }, "BottomRight"sv, Gfx::TextAlignment::BottomRight, Color::White);
painter.draw_text(Gfx::IntRect { 520, 260, 240, 80 }, "CenterLeft"sv, Gfx::TextAlignment::CenterLeft, Color::White);
painter.draw_text(Gfx::IntRect { 520, 260, 240, 80 }, "Center"sv, Gfx::TextAlignment::Center, Color::White);
painter.draw_text(Gfx::IntRect { 520, 260, 240, 80 }, "CenterRight"sv, Gfx::TextAlignment::CenterRight, Color::White);
painter.draw_text(Gfx::IntRect { 520, 260, 240, 80 }, "TopLeft"sv, Gfx::TextAlignment::TopLeft, Color::White);
painter.draw_text(Gfx::IntRect { 520, 260, 240, 80 }, "TopRight"sv, Gfx::TextAlignment::TopRight, Color::White);
painter.draw_text(Gfx::IntRect { 520, 260, 240, 80 }, "BottomLeft"sv, Gfx::TextAlignment::BottomLeft, Color::White);
painter.draw_text(Gfx::IntRect { 520, 260, 240, 80 }, "BottomRight"sv, Gfx::TextAlignment::BottomRight, Color::White);
painter.draw_rect({ 520, 360, 240, 30 }, Color::DarkGray);
painter.draw_text({ 520, 360, 240, 30 }, "Emojis! 🙂😂🐞🦄"sv, Gfx::TextAlignment::Center, Color::White);
painter.draw_text(Gfx::IntRect { 520, 360, 240, 30 }, "Emojis! 🙂😂🐞🦄"sv, Gfx::TextAlignment::Center, Color::White);
painter.draw_rect({ 520, 410, 240, 80 }, Color::DarkGray);
painter.draw_text({ 520, 415, 240, 20 }, "Normal text"sv, Gfx::FontDatabase::default_font(), Gfx::TextAlignment::CenterLeft, Color::Red);
painter.draw_text({ 520, 430, 240, 20 }, "Bold text"sv, Gfx::FontDatabase::default_font().bold_variant(), Gfx::TextAlignment::CenterLeft, Color::Green);
painter.draw_text({ 520, 450, 240, 20 }, "Normal text (fixed width)"sv, Gfx::FontDatabase::default_fixed_width_font(), Gfx::TextAlignment::CenterLeft, Color::Blue);
painter.draw_text({ 520, 465, 240, 20 }, "Bold text (fixed width)"sv, Gfx::FontDatabase::default_fixed_width_font().bold_variant(), Gfx::TextAlignment::CenterLeft, Color::Yellow);
painter.draw_text(Gfx::IntRect { 520, 415, 240, 20 }, "Normal text"sv, Gfx::FontDatabase::default_font(), Gfx::TextAlignment::CenterLeft, Color::Red);
painter.draw_text(Gfx::IntRect { 520, 430, 240, 20 }, "Bold text"sv, Gfx::FontDatabase::default_font().bold_variant(), Gfx::TextAlignment::CenterLeft, Color::Green);
painter.draw_text(Gfx::IntRect { 520, 450, 240, 20 }, "Normal text (fixed width)"sv, Gfx::FontDatabase::default_fixed_width_font(), Gfx::TextAlignment::CenterLeft, Color::Blue);
painter.draw_text(Gfx::IntRect { 520, 465, 240, 20 }, "Bold text (fixed width)"sv, Gfx::FontDatabase::default_fixed_width_font().bold_variant(), Gfx::TextAlignment::CenterLeft, Color::Yellow);
auto font = Gfx::BitmapFont::load_from_file("/res/fonts/PebbletonBold14.font"sv);
painter.draw_rect({ 520, 510, 240, 30 }, Color::DarkGray);
painter.draw_text({ 520, 510, 240, 30 }, "Hello friends! :^)"sv, *font, Gfx::TextAlignment::Center, Color::White);
painter.draw_text(Gfx::IntRect { 520, 510, 240, 30 }, "Hello friends! :^)"sv, *font, Gfx::TextAlignment::Center, Color::White);
painter.fill_rect({ 520, 560, 10, 20 }, Color::White);
painter.fill_rect({ 530, 560, 10, 20 }, Color::WarmGray);

View file

@ -207,7 +207,7 @@ void CardPainter::paint_inverted_card(Gfx::Bitmap& bitmap, Gfx::Bitmap const& so
{
Gfx::Painter painter { bitmap };
painter.clear_rect(bitmap.rect(), Gfx::Color::Transparent);
painter.blit_filtered({ 0, 0 }, source_to_invert, source_to_invert.rect(), [&](Color color) {
painter.blit_filtered(Gfx::IntPoint {}, source_to_invert, source_to_invert.rect(), [&](Color color) {
return color.inverted();
});
}

View file

@ -727,10 +727,10 @@ void AbstractView::draw_item_text(Gfx::Painter& painter, ModelIndex const& index
// Highlight the text background first
auto background_searching_length = searching_length;
painter.draw_text([&](Gfx::IntRect const& rect, Utf8CodePointIterator&) {
painter.draw_text([&](Gfx::FloatRect const& rect, Utf8CodePointIterator&) {
if (background_searching_length > 0) {
background_searching_length--;
painter.fill_rect(rect.inflated(0, 2), palette().highlight_searching());
painter.fill_rect(rect.to_type<int>().inflated(0, 2), palette().highlight_searching());
}
},
text_rect, item_text, font, alignment, elision);
@ -739,7 +739,7 @@ void AbstractView::draw_item_text(Gfx::Painter& painter, ModelIndex const& index
auto text_searching_length = searching_length;
auto highlight_text_color = palette().highlight_searching_text();
searching_length = searching_text.length();
painter.draw_text([&](Gfx::IntRect const& rect, Utf8CodePointIterator& it) {
painter.draw_text([&](auto const& rect, Utf8CodePointIterator& it) {
if (text_searching_length > 0) {
text_searching_length--;
painter.draw_glyph_or_emoji(rect.location(), it, font, highlight_text_color);

View file

@ -117,7 +117,7 @@ void Label::size_to_fit()
int Label::text_calculated_preferred_height() const
{
return Gfx::TextLayout(&font(), Utf8View { m_text }, text_rect()).bounding_rect(Gfx::TextWrapping::Wrap, Gfx::Painter::LINE_SPACING).height();
return int(AK::ceil(Gfx::TextLayout(&font(), Utf8View { m_text }, text_rect().to_type<float>()).bounding_rect(Gfx::TextWrapping::Wrap, Gfx::Painter::LINE_SPACING).height()));
}
Optional<UISize> Label::calculated_preferred_size() const

View file

@ -1375,20 +1375,20 @@ void Painter::draw_scaled_bitmap(IntRect const& a_dst_rect, Gfx::Bitmap const& s
}
}
FLATTEN void Painter::draw_glyph(IntPoint point, u32 code_point, Color color)
FLATTEN void Painter::draw_glyph(FloatPoint point, u32 code_point, Color color)
{
draw_glyph(point, code_point, font(), color);
}
FLATTEN void Painter::draw_glyph(IntPoint point, u32 code_point, Font const& font, Color color)
FLATTEN void Painter::draw_glyph(FloatPoint point, u32 code_point, Font const& font, Color color)
{
auto glyph = font.glyph(code_point);
auto top_left = point + IntPoint(glyph.left_bearing(), 0);
if (glyph.is_glyph_bitmap()) {
draw_bitmap(top_left, glyph.glyph_bitmap(), color);
draw_bitmap(top_left.to_type<int>(), glyph.glyph_bitmap(), color);
} else {
blit_filtered(top_left, *glyph.bitmap(), glyph.bitmap()->rect(), [color](Color pixel) -> Color {
blit_filtered(top_left.to_type<int>(), *glyph.bitmap(), glyph.bitmap()->rect(), [color](Color pixel) -> Color {
return pixel.multiply(color);
});
}
@ -1405,7 +1405,7 @@ void Painter::draw_emoji(IntPoint point, Gfx::Bitmap const& emoji, Font const& f
draw_scaled_bitmap(dst_rect, emoji, emoji.rect());
}
void Painter::draw_glyph_or_emoji(IntPoint point, u32 code_point, Font const& font, Color color)
void Painter::draw_glyph_or_emoji(FloatPoint point, u32 code_point, Font const& font, Color color)
{
StringBuilder builder;
builder.append_code_point(code_point);
@ -1413,7 +1413,7 @@ void Painter::draw_glyph_or_emoji(IntPoint point, u32 code_point, Font const& fo
return draw_glyph_or_emoji(point, it, font, color);
}
void Painter::draw_glyph_or_emoji(IntPoint point, Utf8CodePointIterator& it, Font const& font, Color color)
void Painter::draw_glyph_or_emoji(FloatPoint point, Utf8CodePointIterator& it, Font const& font, Color color)
{
// FIXME: These should live somewhere else.
constexpr u32 text_variation_selector = 0xFE0E;
@ -1454,7 +1454,7 @@ void Painter::draw_glyph_or_emoji(IntPoint point, Utf8CodePointIterator& it, Fon
// If we didn't find a text glyph, or have an emoji variation selector or regional indicator, try to draw an emoji glyph.
if (auto const* emoji = Emoji::emoji_for_code_point_iterator(it)) {
draw_emoji(point, *emoji, font);
draw_emoji(point.to_type<int>(), *emoji, font);
return;
}
@ -1469,8 +1469,28 @@ void Painter::draw_glyph_or_emoji(IntPoint point, Utf8CodePointIterator& it, Fon
draw_glyph(point, 0xFFFD, font, color);
}
void Painter::draw_glyph(IntPoint point, u32 code_point, Color color)
{
draw_glyph(point.to_type<float>(), code_point, font(), color);
}
void Painter::draw_glyph(IntPoint point, u32 code_point, Font const& font, Color color)
{
draw_glyph(point.to_type<float>(), code_point, font, color);
}
void Painter::draw_glyph_or_emoji(IntPoint point, u32 code_point, Font const& font, Color color)
{
draw_glyph_or_emoji(point.to_type<float>(), code_point, font, color);
}
void Painter::draw_glyph_or_emoji(IntPoint point, Utf8CodePointIterator& it, Font const& font, Color color)
{
draw_glyph_or_emoji(point.to_type<float>(), it, font, color);
}
template<typename DrawGlyphFunction>
void draw_text_line(IntRect const& a_rect, Utf8View const& text, Font const& font, TextAlignment alignment, TextDirection direction, DrawGlyphFunction draw_glyph)
void draw_text_line(FloatRect const& a_rect, Utf8View const& text, Font const& font, TextAlignment alignment, TextDirection direction, DrawGlyphFunction draw_glyph)
{
auto rect = a_rect;
@ -1498,12 +1518,12 @@ void draw_text_line(IntRect const& a_rect, Utf8View const& text, Font const& fon
}
if (is_vertically_centered_text_alignment(alignment)) {
int distance_from_baseline_to_bottom = (font.pixel_size() - 1) - font.baseline();
auto distance_from_baseline_to_bottom = (font.pixel_size() - 1) - font.baseline();
rect.translate_by(0, distance_from_baseline_to_bottom / 2);
}
auto point = rect.location();
int space_width = font.glyph_width(' ') + font.glyph_spacing();
auto space_width = font.glyph_width(' ') + font.glyph_spacing();
if (direction == TextDirection::RTL) {
point.translate_by(rect.width(), 0); // Start drawing from the end
@ -1519,11 +1539,11 @@ void draw_text_line(IntRect const& a_rect, Utf8View const& text, Font const& fon
continue;
}
int kerning = round_to<int>(font.glyphs_horizontal_kerning(last_code_point, code_point));
if (kerning != 0.f)
auto kerning = font.glyphs_horizontal_kerning(last_code_point, code_point);
if (kerning != 0.0f)
point.translate_by(direction == TextDirection::LTR ? kerning : -kerning, 0);
IntSize glyph_size(font.glyph_or_emoji_width(code_point) + font.glyph_spacing(), font.pixel_size());
FloatSize glyph_size(font.glyph_or_emoji_width(code_point) + font.glyph_spacing(), font.pixel_size());
if (direction == TextDirection::RTL)
point.translate_by(-glyph_size.width(), 0); // If we are drawing right to left, we have to move backwards before drawing the glyph
draw_glyph({ point, glyph_size }, it);
@ -1698,14 +1718,14 @@ bool Painter::text_contains_bidirectional_text(Utf8View const& text, TextDirecti
}
template<typename DrawGlyphFunction>
void Painter::do_draw_text(IntRect const& rect, Utf8View const& text, Font const& font, TextAlignment alignment, TextElision elision, TextWrapping wrapping, DrawGlyphFunction draw_glyph)
void Painter::do_draw_text(FloatRect const& rect, Utf8View const& text, Font const& font, TextAlignment alignment, TextElision elision, TextWrapping wrapping, DrawGlyphFunction draw_glyph)
{
if (draw_text_get_length(text) == 0)
return;
TextLayout layout(&font, text, rect);
int line_height = font.pixel_size() + LINE_SPACING;
auto line_height = font.pixel_size() + LINE_SPACING;
auto lines = layout.lines(elision, wrapping, LINE_SPACING);
auto bounding_rect = layout.bounding_rect(wrapping, LINE_SPACING);
@ -1722,10 +1742,10 @@ void Painter::do_draw_text(IntRect const& rect, Utf8View const& text, Font const
bounding_rect.set_location({ (rect.right() + 1) - bounding_rect.width(), rect.y() });
break;
case TextAlignment::CenterLeft:
bounding_rect.set_location({ rect.x(), rect.center().y() - (bounding_rect.height() / 2) });
bounding_rect.set_location({ rect.x(), rect.center().y() - int(bounding_rect.height() / 2) });
break;
case TextAlignment::CenterRight:
bounding_rect.set_location({ (rect.right() + 1) - bounding_rect.width(), rect.center().y() - (bounding_rect.height() / 2) });
bounding_rect.set_location({ (rect.right() + 1) - bounding_rect.width(), rect.center().y() - int(bounding_rect.height() / 2) });
break;
case TextAlignment::Center:
bounding_rect.center_within(rect);
@ -1749,7 +1769,7 @@ void Painter::do_draw_text(IntRect const& rect, Utf8View const& text, Font const
for (size_t i = 0; i < lines.size(); ++i) {
auto line = Utf8View { lines[i] };
IntRect line_rect { bounding_rect.x(), bounding_rect.y() + static_cast<int>(i) * line_height, bounding_rect.width(), line_height };
FloatRect line_rect { bounding_rect.x(), bounding_rect.y() + i * line_height, bounding_rect.width(), line_height };
line_rect.intersect(rect);
TextDirection line_direction = get_text_direction(line);
@ -1779,67 +1799,102 @@ void Painter::do_draw_text(IntRect const& rect, Utf8View const& text, Font const
}
}
void Painter::draw_text(IntRect const& rect, StringView text, TextAlignment alignment, Color color, TextElision elision, TextWrapping wrapping)
void Painter::draw_text(FloatRect const& rect, StringView text, TextAlignment alignment, Color color, TextElision elision, TextWrapping wrapping)
{
draw_text(rect, text, font(), alignment, color, elision, wrapping);
}
void Painter::draw_text(FloatRect const& rect, Utf32View const& text, TextAlignment alignment, Color color, TextElision elision, TextWrapping wrapping)
{
draw_text(rect, text, font(), alignment, color, elision, wrapping);
}
void Painter::draw_text(FloatRect const& rect, StringView raw_text, Font const& font, TextAlignment alignment, Color color, TextElision elision, TextWrapping wrapping)
{
Utf8View text { raw_text };
do_draw_text(rect, text, font, alignment, elision, wrapping, [&](FloatRect const& r, Utf8CodePointIterator& it) {
draw_glyph_or_emoji(r.location(), it, font, color);
});
}
void Painter::draw_text(FloatRect const& rect, Utf32View const& raw_text, Font const& font, TextAlignment alignment, Color color, TextElision elision, TextWrapping wrapping)
{
// FIXME: UTF-32 should eventually be completely removed, but for the time
// being some places might depend on it, so we do some internal conversion.
StringBuilder builder;
builder.append(raw_text);
auto text = Utf8View { builder.string_view() };
do_draw_text(rect, text, font, alignment, elision, wrapping, [&](FloatRect const& r, Utf8CodePointIterator& it) {
draw_glyph_or_emoji(r.location(), it, font, color);
});
}
void Painter::draw_text(Function<void(FloatRect const&, Utf8CodePointIterator&)> draw_one_glyph, FloatRect const& rect, Utf8View const& text, Font const& font, TextAlignment alignment, TextElision elision, TextWrapping wrapping)
{
VERIFY(scale() == 1); // FIXME: Add scaling support.
do_draw_text(rect, text, font, alignment, elision, wrapping, [&](FloatRect const& r, Utf8CodePointIterator& it) {
draw_one_glyph(r, it);
});
}
void Painter::draw_text(Function<void(FloatRect const&, Utf8CodePointIterator&)> draw_one_glyph, FloatRect const& rect, StringView raw_text, Font const& font, TextAlignment alignment, TextElision elision, TextWrapping wrapping)
{
VERIFY(scale() == 1); // FIXME: Add scaling support.
Utf8View text { raw_text };
do_draw_text(rect, text, font, alignment, elision, wrapping, [&](FloatRect const& r, Utf8CodePointIterator& it) {
draw_one_glyph(r, it);
});
}
void Painter::draw_text(Function<void(FloatRect const&, Utf8CodePointIterator&)> draw_one_glyph, FloatRect const& rect, Utf32View const& raw_text, Font const& font, TextAlignment alignment, TextElision elision, TextWrapping wrapping)
{
VERIFY(scale() == 1); // FIXME: Add scaling support.
// FIXME: UTF-32 should eventually be completely removed, but for the time
// being some places might depend on it, so we do some internal conversion.
StringBuilder builder;
builder.append(raw_text);
auto text = Utf8View { builder.string_view() };
do_draw_text(rect, text, font, alignment, elision, wrapping, [&](FloatRect const& r, Utf8CodePointIterator& it) {
draw_one_glyph(r, it);
});
}
void Painter::draw_text(IntRect const& rect, StringView text, TextAlignment alignment, Color color, TextElision elision, TextWrapping wrapping)
{
draw_text(rect.to_type<float>(), text, font(), alignment, color, elision, wrapping);
}
void Painter::draw_text(IntRect const& rect, Utf32View const& text, TextAlignment alignment, Color color, TextElision elision, TextWrapping wrapping)
{
draw_text(rect, text, font(), alignment, color, elision, wrapping);
draw_text(rect.to_type<float>(), text, font(), alignment, color, elision, wrapping);
}
void Painter::draw_text(IntRect const& rect, StringView raw_text, Font const& font, TextAlignment alignment, Color color, TextElision elision, TextWrapping wrapping)
{
Utf8View text { raw_text };
do_draw_text(rect, text, font, alignment, elision, wrapping, [&](IntRect const& r, Utf8CodePointIterator& it) {
draw_glyph_or_emoji(r.location(), it, font, color);
});
draw_text(rect.to_type<float>(), raw_text, font, alignment, color, elision, wrapping);
}
void Painter::draw_text(IntRect const& rect, Utf32View const& raw_text, Font const& font, TextAlignment alignment, Color color, TextElision elision, TextWrapping wrapping)
{
// FIXME: UTF-32 should eventually be completely removed, but for the time
// being some places might depend on it, so we do some internal conversion.
StringBuilder builder;
builder.append(raw_text);
auto text = Utf8View { builder.string_view() };
do_draw_text(rect, text, font, alignment, elision, wrapping, [&](IntRect const& r, Utf8CodePointIterator& it) {
draw_glyph_or_emoji(r.location(), it, font, color);
});
return draw_text(rect.to_type<float>(), raw_text, font, alignment, color, elision, wrapping);
}
void Painter::draw_text(Function<void(IntRect const&, Utf8CodePointIterator&)> draw_one_glyph, IntRect const& rect, Utf8View const& text, Font const& font, TextAlignment alignment, TextElision elision, TextWrapping wrapping)
void Painter::draw_text(Function<void(FloatRect const&, Utf8CodePointIterator&)> draw_one_glyph, IntRect const& rect, Utf8View const& text, Font const& font, TextAlignment alignment, TextElision elision, TextWrapping wrapping)
{
VERIFY(scale() == 1); // FIXME: Add scaling support.
do_draw_text(rect, text, font, alignment, elision, wrapping, [&](IntRect const& r, Utf8CodePointIterator& it) {
draw_one_glyph(r, it);
});
return draw_text(move(draw_one_glyph), rect.to_type<float>(), text, font, alignment, elision, wrapping);
}
void Painter::draw_text(Function<void(IntRect const&, Utf8CodePointIterator&)> draw_one_glyph, IntRect const& rect, StringView raw_text, Font const& font, TextAlignment alignment, TextElision elision, TextWrapping wrapping)
void Painter::draw_text(Function<void(FloatRect const&, Utf8CodePointIterator&)> draw_one_glyph, IntRect const& rect, StringView raw_text, Font const& font, TextAlignment alignment, TextElision elision, TextWrapping wrapping)
{
VERIFY(scale() == 1); // FIXME: Add scaling support.
Utf8View text { raw_text };
do_draw_text(rect, text, font, alignment, elision, wrapping, [&](IntRect const& r, Utf8CodePointIterator& it) {
draw_one_glyph(r, it);
});
return draw_text(move(draw_one_glyph), rect.to_type<float>(), raw_text, font, alignment, elision, wrapping);
}
void Painter::draw_text(Function<void(IntRect const&, Utf8CodePointIterator&)> draw_one_glyph, IntRect const& rect, Utf32View const& raw_text, Font const& font, TextAlignment alignment, TextElision elision, TextWrapping wrapping)
void Painter::draw_text(Function<void(FloatRect const&, Utf8CodePointIterator&)> draw_one_glyph, IntRect const& rect, Utf32View const& raw_text, Font const& font, TextAlignment alignment, TextElision elision, TextWrapping wrapping)
{
VERIFY(scale() == 1); // FIXME: Add scaling support.
// FIXME: UTF-32 should eventually be completely removed, but for the time
// being some places might depend on it, so we do some internal conversion.
StringBuilder builder;
builder.append(raw_text);
auto text = Utf8View { builder.string_view() };
do_draw_text(rect, text, font, alignment, elision, wrapping, [&](IntRect const& r, Utf8CodePointIterator& it) {
draw_one_glyph(r, it);
});
return draw_text(move(draw_one_glyph), rect.to_type<float>(), raw_text, font, alignment, elision, wrapping);
}
void Painter::set_pixel(IntPoint p, Color color, bool blend)
@ -2481,7 +2536,7 @@ void Painter::draw_text_run(FloatPoint baseline_start, Utf8View const& string, F
{
auto pixel_metrics = font.pixel_metrics();
float x = baseline_start.x();
int y = baseline_start.y() - pixel_metrics.ascent;
float y = baseline_start.y() - pixel_metrics.ascent;
float space_width = font.glyph_or_emoji_width(' ');
u32 last_code_point = 0;
@ -2496,7 +2551,7 @@ void Painter::draw_text_run(FloatPoint baseline_start, Utf8View const& string, F
// FIXME: this is probably not the real space taken for complex emojis
x += font.glyphs_horizontal_kerning(last_code_point, code_point);
draw_glyph_or_emoji({ static_cast<int>(x), y }, code_point_iterator, font, color);
draw_glyph_or_emoji(FloatPoint { x, y }, code_point_iterator, font, color);
x += font.glyph_or_emoji_width(code_point) + font.glyph_spacing();
last_code_point = code_point;
}

View file

@ -81,19 +81,30 @@ public:
void blit_offset(IntPoint, Gfx::Bitmap const&, IntRect const& src_rect, IntPoint);
void blit_disabled(IntPoint, Gfx::Bitmap const&, IntRect const&, Palette const&);
void blit_tiled(IntRect const&, Gfx::Bitmap const&, IntRect const& src_rect);
void draw_text(FloatRect const&, StringView, Font const&, TextAlignment = TextAlignment::TopLeft, Color = Color::Black, TextElision = TextElision::None, TextWrapping = TextWrapping::DontWrap);
void draw_text(FloatRect const&, StringView, TextAlignment = TextAlignment::TopLeft, Color = Color::Black, TextElision = TextElision::None, TextWrapping = TextWrapping::DontWrap);
void draw_text(FloatRect const&, Utf32View const&, Font const&, TextAlignment = TextAlignment::TopLeft, Color = Color::Black, TextElision = TextElision::None, TextWrapping = TextWrapping::DontWrap);
void draw_text(FloatRect const&, Utf32View const&, TextAlignment = TextAlignment::TopLeft, Color = Color::Black, TextElision = TextElision::None, TextWrapping = TextWrapping::DontWrap);
void draw_text(Function<void(FloatRect const&, Utf8CodePointIterator&)>, FloatRect const&, StringView, Font const&, TextAlignment = TextAlignment::TopLeft, TextElision = TextElision::None, TextWrapping = TextWrapping::DontWrap);
void draw_text(Function<void(FloatRect const&, Utf8CodePointIterator&)>, FloatRect const&, Utf8View const&, Font const&, TextAlignment = TextAlignment::TopLeft, TextElision = TextElision::None, TextWrapping = TextWrapping::DontWrap);
void draw_text(Function<void(FloatRect const&, Utf8CodePointIterator&)>, FloatRect const&, Utf32View const&, Font const&, TextAlignment = TextAlignment::TopLeft, TextElision = TextElision::None, TextWrapping = TextWrapping::DontWrap);
void draw_text(IntRect const&, StringView, Font const&, TextAlignment = TextAlignment::TopLeft, Color = Color::Black, TextElision = TextElision::None, TextWrapping = TextWrapping::DontWrap);
void draw_text(IntRect const&, StringView, TextAlignment = TextAlignment::TopLeft, Color = Color::Black, TextElision = TextElision::None, TextWrapping = TextWrapping::DontWrap);
void draw_text(IntRect const&, Utf32View const&, Font const&, TextAlignment = TextAlignment::TopLeft, Color = Color::Black, TextElision = TextElision::None, TextWrapping = TextWrapping::DontWrap);
void draw_text(IntRect const&, Utf32View const&, TextAlignment = TextAlignment::TopLeft, Color = Color::Black, TextElision = TextElision::None, TextWrapping = TextWrapping::DontWrap);
void draw_text(Function<void(IntRect const&, Utf8CodePointIterator&)>, IntRect const&, StringView, Font const&, TextAlignment = TextAlignment::TopLeft, TextElision = TextElision::None, TextWrapping = TextWrapping::DontWrap);
void draw_text(Function<void(IntRect const&, Utf8CodePointIterator&)>, IntRect const&, Utf8View const&, Font const&, TextAlignment = TextAlignment::TopLeft, TextElision = TextElision::None, TextWrapping = TextWrapping::DontWrap);
void draw_text(Function<void(IntRect const&, Utf8CodePointIterator&)>, IntRect const&, Utf32View const&, Font const&, TextAlignment = TextAlignment::TopLeft, TextElision = TextElision::None, TextWrapping = TextWrapping::DontWrap);
void draw_text(Function<void(FloatRect const&, Utf8CodePointIterator&)>, IntRect const&, StringView, Font const&, TextAlignment = TextAlignment::TopLeft, TextElision = TextElision::None, TextWrapping = TextWrapping::DontWrap);
void draw_text(Function<void(FloatRect const&, Utf8CodePointIterator&)>, IntRect const&, Utf8View const&, Font const&, TextAlignment = TextAlignment::TopLeft, TextElision = TextElision::None, TextWrapping = TextWrapping::DontWrap);
void draw_text(Function<void(FloatRect const&, Utf8CodePointIterator&)>, IntRect const&, Utf32View const&, Font const&, TextAlignment = TextAlignment::TopLeft, TextElision = TextElision::None, TextWrapping = TextWrapping::DontWrap);
void draw_ui_text(Gfx::IntRect const&, StringView, Gfx::Font const&, TextAlignment, Gfx::Color);
void draw_glyph(IntPoint, u32, Color);
void draw_glyph(IntPoint, u32, Font const&, Color);
void draw_emoji(IntPoint, Gfx::Bitmap const&, Font const&);
void draw_glyph_or_emoji(IntPoint, u32, Font const&, Color);
void draw_glyph_or_emoji(IntPoint, Utf8CodePointIterator&, Font const&, Color);
void draw_glyph(FloatPoint, u32, Color);
void draw_glyph(FloatPoint, u32, Font const&, Color);
void draw_glyph_or_emoji(FloatPoint, u32, Font const&, Color);
void draw_glyph_or_emoji(FloatPoint, Utf8CodePointIterator&, Font const&, Color);
void draw_circle_arc_intersecting(IntRect const&, IntPoint, int radius, Color, int thickness);
// Streamlined text drawing routine that does no wrapping/elision/alignment.
@ -214,7 +225,7 @@ private:
Vector<DirectionalRun> split_text_into_directional_runs(Utf8View const&, TextDirection initial_direction);
bool text_contains_bidirectional_text(Utf8View const&, TextDirection);
template<typename DrawGlyphFunction>
void do_draw_text(IntRect const&, Utf8View const& text, Font const&, TextAlignment, TextElision, TextWrapping, DrawGlyphFunction);
void do_draw_text(FloatRect const&, Utf8View const& text, Font const&, TextAlignment, TextElision, TextWrapping, DrawGlyphFunction);
};
class PainterStateSaver {

View file

@ -20,15 +20,15 @@ struct Block {
Utf8View characters;
};
IntRect TextLayout::bounding_rect(TextWrapping wrapping, int line_spacing) const
FloatRect TextLayout::bounding_rect(TextWrapping wrapping, int line_spacing) const
{
auto lines = wrap_lines(TextElision::None, wrapping, line_spacing, FitWithinRect::No);
if (!lines.size()) {
return {};
}
IntRect bounding_rect = {
0, 0, 0, static_cast<int>((lines.size() * (m_font->pixel_size() + line_spacing)) - line_spacing)
FloatRect bounding_rect = {
0, 0, 0, (lines.size() * (m_font->pixel_size() + line_spacing)) - line_spacing
};
for (auto& line : lines) {
@ -119,7 +119,7 @@ Vector<DeprecatedString, 32> TextLayout::wrap_lines(TextElision elision, TextWra
Vector<DeprecatedString> lines;
StringBuilder builder;
size_t line_width = 0;
float line_width = 0;
size_t current_block = 0;
bool did_not_finish = false;
for (Block& block : blocks) {
@ -139,14 +139,14 @@ Vector<DeprecatedString, 32> TextLayout::wrap_lines(TextElision elision, TextWra
}
case BlockType::Whitespace:
case BlockType::Word: {
size_t block_width = font().width(block.characters);
float block_width = font().width(block.characters);
// FIXME: This should look at the specific advance amount of the
// last character, but we don't support that yet.
if (current_block != blocks.size() - 1) {
block_width += font().glyph_spacing();
}
if (wrapping == TextWrapping::Wrap && line_width + block_width > static_cast<unsigned>(m_rect.width())) {
if (wrapping == TextWrapping::Wrap && line_width + block_width > m_rect.width()) {
lines.append(builder.to_deprecated_string());
builder.clear();
line_width = 0;
@ -185,10 +185,10 @@ blocks_processed:
DeprecatedString TextLayout::elide_text_from_right(Utf8View text, bool force_elision) const
{
size_t text_width = m_font->width(text);
float text_width = m_font->width(text);
if (force_elision || text_width > static_cast<unsigned>(m_rect.width())) {
size_t ellipsis_width = m_font->width("..."sv);
size_t current_width = ellipsis_width;
float ellipsis_width = m_font->width("..."sv);
float current_width = ellipsis_width;
size_t glyph_spacing = m_font->glyph_spacing();
// FIXME: This code will break when the font has glyphs with advance
@ -198,11 +198,11 @@ DeprecatedString TextLayout::elide_text_from_right(Utf8View text, bool force_eli
size_t offset = 0;
for (auto it = text.begin(); !it.done(); ++it) {
auto code_point = *it;
int glyph_width = m_font->glyph_or_emoji_width(code_point);
auto glyph_width = m_font->glyph_or_emoji_width(code_point);
// NOTE: Glyph spacing should not be added after the last glyph on the line,
// but since we are here because the last glyph does not actually fit on the line,
// we don't have to worry about spacing.
int width_with_this_glyph_included = current_width + glyph_width + glyph_spacing;
auto width_with_this_glyph_included = current_width + glyph_width + glyph_spacing;
if (width_with_this_glyph_included > m_rect.width())
break;
current_width += glyph_width + glyph_spacing;

View file

@ -44,7 +44,7 @@ enum class FitWithinRect {
// b) Taking the Lines from TextLayout and painting each glyph.
class TextLayout {
public:
TextLayout(Gfx::Font const* font, Utf8View const& text, IntRect const& rect)
TextLayout(Gfx::Font const* font, Utf8View const& text, FloatRect const& rect)
: m_font(font)
, m_text(text)
, m_rect(rect)
@ -57,15 +57,15 @@ public:
Utf8View const& text() const { return m_text; }
void set_text(Utf8View const& text) { m_text = text; }
IntRect const& rect() const { return m_rect; }
void set_rect(IntRect const& rect) { m_rect = rect; }
FloatRect const& rect() const { return m_rect; }
void set_rect(FloatRect const& rect) { m_rect = rect; }
Vector<DeprecatedString, 32> lines(TextElision elision, TextWrapping wrapping, int line_spacing) const
{
return wrap_lines(elision, wrapping, line_spacing, FitWithinRect::Yes);
}
IntRect bounding_rect(TextWrapping wrapping, int line_spacing) const;
FloatRect bounding_rect(TextWrapping wrapping, int line_spacing) const;
private:
Vector<DeprecatedString, 32> wrap_lines(TextElision, TextWrapping, int line_spacing, FitWithinRect) const;
@ -73,7 +73,7 @@ private:
Font const* m_font;
Utf8View m_text;
IntRect m_rect;
FloatRect m_rect;
};
}

View file

@ -213,7 +213,7 @@ Gfx::Font const& ScreenNumberOverlay::font()
void ScreenNumberOverlay::render_overlay_bitmap(Gfx::Painter& painter)
{
painter.draw_text({ {}, rect().size() }, DeprecatedString::formatted("{}", m_screen.index() + 1), font(), Gfx::TextAlignment::Center, Color::White);
painter.draw_text(Gfx::IntRect { {}, rect().size() }, DeprecatedString::formatted("{}", m_screen.index() + 1), font(), Gfx::TextAlignment::Center, Color::White);
}
Gfx::IntRect ScreenNumberOverlay::calculate_content_rect_for_screen(Screen& screen)
@ -264,7 +264,7 @@ void WindowGeometryOverlay::update_rect()
void WindowGeometryOverlay::render_overlay_bitmap(Gfx::Painter& painter)
{
painter.draw_text({ {}, rect().size() }, m_label, WindowManager::the().font(), Gfx::TextAlignment::Center, Color::White);
painter.draw_text(Gfx::IntRect { {}, rect().size() }, m_label, WindowManager::the().font(), Gfx::TextAlignment::Center, Color::White);
}
void WindowGeometryOverlay::window_rect_changed()