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

LibAccelGfx+LibWeb: Move glyph atlas into a singleton class

This is going to allow us reuse glyph texture across painters and page
repaints.
This commit is contained in:
Aliaksandr Kalenik 2023-11-26 15:22:06 +01:00 committed by Andreas Kling
parent 4b23046a22
commit 28723d8be1
6 changed files with 157 additions and 105 deletions

View file

@ -5,10 +5,8 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/QuickSort.h>
#include <LibAccelGfx/GL.h>
#include <LibAccelGfx/Painter.h>
#include <LibGfx/Color.h>
#include <LibGfx/ImmutableBitmap.h>
#include <LibGfx/Painter.h>
@ -145,23 +143,12 @@ OwnPtr<Painter> Painter::create()
return make<Painter>(context);
}
OwnPtr<Painter> Painter::create_with_glyphs_texture_from_painter(Painter const& painter)
{
auto& context = Context::the();
auto glyphs_texture_painter = make<Painter>(context);
glyphs_texture_painter->m_glyphs_texture = painter.m_glyphs_texture;
glyphs_texture_painter->m_glyphs_texture_size = painter.m_glyphs_texture_size;
glyphs_texture_painter->m_glyphs_texture_map = painter.m_glyphs_texture_map;
return glyphs_texture_painter;
}
Painter::Painter(Context& context)
: m_context(context)
, m_rectangle_program(Program::create(Program::Name::RectangleProgram, vertex_shader_source, solid_color_fragment_shader_source))
, m_rounded_rectangle_program(Program::create(Program::Name::RoundedRectangleProgram, vertex_shader_source, rect_with_rounded_corners_fragment_shader_source))
, m_blit_program(Program::create(Program::Name::BlitProgram, blit_vertex_shader_source, blit_fragment_shader_source))
, m_linear_gradient_program(Program::create(Program::Name::LinearGradientProgram, linear_gradient_vertex_shader_source, linear_gradient_fragment_shader_source))
, m_glyphs_texture(GL::create_texture())
{
m_state_stack.empend(State());
}
@ -365,62 +352,6 @@ void Painter::draw_scaled_bitmap(Gfx::FloatRect const& dst_rect, Gfx::Bitmap con
GL::delete_texture(texture);
}
void Painter::prepare_glyph_texture(HashMap<Gfx::Font const*, HashTable<u32>> const& unique_glyphs)
{
HashMap<GlyphsTextureKey, NonnullRefPtr<Gfx::Bitmap>> glyph_bitmaps;
for (auto const& [font, code_points] : unique_glyphs) {
for (auto const& code_point : code_points) {
auto glyph = font->glyph(code_point);
if (glyph.bitmap()) {
auto atlas_key = GlyphsTextureKey { font, code_point };
glyph_bitmaps.set(atlas_key, *glyph.bitmap());
}
}
}
if (glyph_bitmaps.is_empty())
return;
Vector<GlyphsTextureKey> glyphs_sorted_by_height;
glyphs_sorted_by_height.ensure_capacity(glyph_bitmaps.size());
for (auto const& [atlas_key, bitmap] : glyph_bitmaps) {
glyphs_sorted_by_height.append(atlas_key);
}
quick_sort(glyphs_sorted_by_height, [&](auto const& a, auto const& b) {
auto const& bitmap_a = *glyph_bitmaps.get(a);
auto const& bitmap_b = *glyph_bitmaps.get(b);
return bitmap_a->height() > bitmap_b->height();
});
int current_x = 0;
int current_y = 0;
int row_height = 0;
int texture_width = 512;
int padding = 1;
for (auto const& glyphs_texture_key : glyphs_sorted_by_height) {
auto const& bitmap = *glyph_bitmaps.get(glyphs_texture_key);
if (current_x + bitmap->width() > texture_width) {
current_x = 0;
current_y += row_height + padding;
row_height = 0;
}
m_glyphs_texture_map.set(glyphs_texture_key, { current_x, current_y, bitmap->width(), bitmap->height() });
current_x += bitmap->width() + padding;
row_height = max(row_height, bitmap->height());
}
auto glyphs_texture_bitmap = MUST(Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, { texture_width, current_y + row_height }));
auto glyphs_texure_painter = Gfx::Painter(*glyphs_texture_bitmap);
for (auto const& [glyphs_texture_key, glyph_bitmap] : glyph_bitmaps) {
auto rect = m_glyphs_texture_map.get(glyphs_texture_key).value();
glyphs_texure_painter.blit({ rect.x(), rect.y() }, glyph_bitmap, glyph_bitmap->rect());
}
m_glyphs_texture_size = glyphs_texture_bitmap->size();
GL::upload_texture_data(m_glyphs_texture, *glyphs_texture_bitmap);
}
void Painter::draw_glyph_run(Vector<Gfx::DrawGlyphOrEmoji> const& glyph_run, Color const& color)
{
bind_target_canvas();
@ -428,20 +359,22 @@ void Painter::draw_glyph_run(Vector<Gfx::DrawGlyphOrEmoji> const& glyph_run, Col
Vector<GLfloat> vertices;
vertices.ensure_capacity(glyph_run.size() * 24);
for (auto& glyph_or_emoji : glyph_run) {
auto const& glyph_atlas = GlyphAtlas::the();
for (auto const& glyph_or_emoji : glyph_run) {
if (glyph_or_emoji.has<Gfx::DrawGlyph>()) {
auto& glyph = glyph_or_emoji.get<Gfx::DrawGlyph>();
auto const& glyph = glyph_or_emoji.get<Gfx::DrawGlyph>();
auto const* font = glyph.font;
auto code_point = glyph.code_point;
auto point = glyph.position;
auto maybe_texture_rect = m_glyphs_texture_map.get(GlyphsTextureKey { font, code_point });
auto maybe_texture_rect = glyph_atlas.get_glyph_rect(font, code_point);
if (!maybe_texture_rect.has_value()) {
continue;
}
auto texture_rect = to_texture_space(maybe_texture_rect.value().to_type<float>(), m_glyphs_texture_size);
auto texture_rect = to_texture_space(maybe_texture_rect.value().to_type<float>(), *glyph_atlas.texture().size);
auto glyph_position = point + Gfx::FloatPoint(font->glyph_left_bearing(code_point), 0);
auto glyph_size = maybe_texture_rect->size().to_type<float>();
@ -497,7 +430,7 @@ void Painter::draw_glyph_run(Vector<Gfx::DrawGlyphOrEmoji> const& glyph_run, Col
m_blit_program.use();
GL::bind_texture(m_glyphs_texture);
GL::bind_texture(glyph_atlas.texture());
GL::set_texture_scale_mode(GL::ScalingMode::Nearest);
auto position_attribute = m_blit_program.get_attribute_location("aVertexPosition");