summaryrefslogtreecommitdiff
path: root/Userland
diff options
context:
space:
mode:
authorJulian Offenhäuser <offenhaeuser@protonmail.com>2022-11-17 23:14:24 +0100
committerAndreas Kling <kling@serenityos.org>2022-11-19 11:04:34 +0100
commit0b6299849e5fabb59c3f60ac9a3ce96b86b52bb2 (patch)
tree8d40d46bd38429a75dd53ad0b3ec50834360afcc /Userland
parentd444724d240efd71ee8a5038280536e979606b81 (diff)
downloadserenity-0b6299849e5fabb59c3f60ac9a3ce96b86b52bb2.zip
LibGfx: Move TTF::Rasterizer to its own files
The custom TTF path rasterizer is actually generic enough for it to be used for other fonts. To make this more clear, it now lives on its own in the "Font" directory.
Diffstat (limited to 'Userland')
-rw-r--r--Userland/Libraries/LibGfx/CMakeLists.txt1
-rw-r--r--Userland/Libraries/LibGfx/Font/PathRasterizer.cpp144
-rw-r--r--Userland/Libraries/LibGfx/Font/PathRasterizer.h28
-rw-r--r--Userland/Libraries/LibGfx/Font/TrueType/Glyf.cpp137
-rw-r--r--Userland/Libraries/LibGfx/Font/TrueType/Glyf.h20
5 files changed, 179 insertions, 151 deletions
diff --git a/Userland/Libraries/LibGfx/CMakeLists.txt b/Userland/Libraries/LibGfx/CMakeLists.txt
index c8051ec574..0738d9e3e7 100644
--- a/Userland/Libraries/LibGfx/CMakeLists.txt
+++ b/Userland/Libraries/LibGfx/CMakeLists.txt
@@ -17,6 +17,7 @@ set(SOURCES
Font/BitmapFont.cpp
Font/Emoji.cpp
Font/FontDatabase.cpp
+ Font/PathRasterizer.cpp
Font/ScaledFont.cpp
Font/TrueType/Cmap.cpp
Font/TrueType/Font.cpp
diff --git a/Userland/Libraries/LibGfx/Font/PathRasterizer.cpp b/Userland/Libraries/LibGfx/Font/PathRasterizer.cpp
new file mode 100644
index 0000000000..dbf0d4b0e0
--- /dev/null
+++ b/Userland/Libraries/LibGfx/Font/PathRasterizer.cpp
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2020, Srimanta Barua <srimanta.barua1@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <LibGfx/Font/PathRasterizer.h>
+
+namespace Gfx {
+
+PathRasterizer::PathRasterizer(Gfx::IntSize size)
+ : m_size(size)
+{
+ m_data.resize(m_size.width() * m_size.height());
+ for (int i = 0; i < m_size.width() * m_size.height(); i++) {
+ m_data[i] = 0.0f;
+ }
+}
+
+void PathRasterizer::draw_path(Gfx::Path& path)
+{
+ for (auto& line : path.split_lines()) {
+ draw_line(line.from, line.to);
+ }
+}
+
+RefPtr<Gfx::Bitmap> PathRasterizer::accumulate()
+{
+ auto bitmap_or_error = Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRA8888, m_size);
+ if (bitmap_or_error.is_error())
+ return {};
+ auto bitmap = bitmap_or_error.release_value_but_fixme_should_propagate_errors();
+ Color base_color = Color::from_rgb(0xffffff);
+ for (int y = 0; y < m_size.height(); y++) {
+ float accumulator = 0.0;
+ for (int x = 0; x < m_size.width(); x++) {
+ accumulator += m_data[y * m_size.width() + x];
+ float value = accumulator;
+ if (value < 0.0f) {
+ value = -value;
+ }
+ if (value > 1.0f) {
+ value = 1.0;
+ }
+ u8 alpha = value * 255.0f;
+ bitmap->set_pixel(x, y, base_color.with_alpha(alpha));
+ }
+ }
+ return bitmap;
+}
+
+void PathRasterizer::draw_line(Gfx::FloatPoint p0, Gfx::FloatPoint p1)
+{
+ // FIXME: Shift x and y according to dy/dx
+ if (p0.x() < 0.0f) {
+ p0.set_x(roundf(p0.x()));
+ }
+ if (p0.y() < 0.0f) {
+ p0.set_y(roundf(p0.y()));
+ }
+ if (p1.x() < 0.0f) {
+ p1.set_x(roundf(p1.x()));
+ }
+ if (p1.y() < 0.0f) {
+ p1.set_y(roundf(p1.y()));
+ }
+
+ if (!(p0.x() >= 0.0f && p0.y() >= 0.0f && p0.x() <= m_size.width() && p0.y() <= m_size.height())) {
+ dbgln("!P0({},{})", p0.x(), p0.y());
+ return;
+ }
+
+ if (!(p1.x() >= 0.0f && p1.y() >= 0.0f && p1.x() <= m_size.width() && p1.y() <= m_size.height())) {
+ dbgln("!P1({},{})", p1.x(), p1.y());
+ return;
+ }
+
+ VERIFY(p0.x() >= 0.0f && p0.y() >= 0.0f && p0.x() <= m_size.width() && p0.y() <= m_size.height());
+ VERIFY(p1.x() >= 0.0f && p1.y() >= 0.0f && p1.x() <= m_size.width() && p1.y() <= m_size.height());
+
+ // If we're on the same Y, there's no need to draw
+ if (p0.y() == p1.y()) {
+ return;
+ }
+
+ float direction = -1.0;
+ if (p1.y() < p0.y()) {
+ direction = 1.0;
+ auto tmp = p0;
+ p0 = p1;
+ p1 = tmp;
+ }
+
+ float dxdy = (p1.x() - p0.x()) / (p1.y() - p0.y());
+ u32 y0 = floorf(p0.y());
+ u32 y1 = ceilf(p1.y());
+ float x_cur = p0.x();
+
+ for (u32 y = y0; y < y1; y++) {
+ u32 line_offset = m_size.width() * y;
+
+ float dy = min(y + 1.0f, p1.y()) - max((float)y, p0.y());
+ float directed_dy = dy * direction;
+ float x_next = x_cur + dy * dxdy;
+ if (x_next < 0.0f) {
+ x_next = 0.0f;
+ }
+ float x0 = x_cur;
+ float x1 = x_next;
+ if (x1 < x0) {
+ x1 = x_cur;
+ x0 = x_next;
+ }
+ float x0_floor = floorf(x0);
+ float x1_ceil = ceilf(x1);
+ u32 x0i = x0_floor;
+
+ if (x1_ceil <= x0_floor + 1.0f) {
+ // If x0 and x1 are within the same pixel, then area to the right is (1 - (mid(x0, x1) - x0_floor)) * dy
+ float area = ((x0 + x1) * 0.5f) - x0_floor;
+ m_data[line_offset + x0i] += directed_dy * (1.0f - area);
+ m_data[line_offset + x0i + 1] += directed_dy * area;
+ } else {
+ float dydx = 1.0f / dxdy;
+ if (dydx < 0)
+ dydx = -dydx;
+
+ float x0_right = 1.0f - (x0 - x0_floor);
+ u32 x1_floor_i = floorf(x1);
+ float area_upto_here = 0.5f * x0_right * x0_right * dydx;
+ m_data[line_offset + x0i] += direction * area_upto_here;
+ for (u32 x = x0i + 1; x < x1_floor_i; x++) {
+ m_data[line_offset + x] += direction * dydx;
+ area_upto_here += dydx;
+ }
+ float remaining_area = (dy - area_upto_here);
+ m_data[line_offset + x1_floor_i] += direction * remaining_area;
+ }
+
+ x_cur = x_next;
+ }
+}
+
+}
diff --git a/Userland/Libraries/LibGfx/Font/PathRasterizer.h b/Userland/Libraries/LibGfx/Font/PathRasterizer.h
new file mode 100644
index 0000000000..90020da3ef
--- /dev/null
+++ b/Userland/Libraries/LibGfx/Font/PathRasterizer.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2020, Srimanta Barua <srimanta.barua1@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/Vector.h>
+#include <LibGfx/Bitmap.h>
+#include <LibGfx/Path.h>
+
+namespace Gfx {
+
+class PathRasterizer {
+public:
+ PathRasterizer(Gfx::IntSize);
+ void draw_path(Gfx::Path&);
+ RefPtr<Gfx::Bitmap> accumulate();
+
+private:
+ void draw_line(Gfx::FloatPoint, Gfx::FloatPoint);
+
+ Gfx::IntSize m_size;
+ Vector<float> m_data;
+};
+
+}
diff --git a/Userland/Libraries/LibGfx/Font/TrueType/Glyf.cpp b/Userland/Libraries/LibGfx/Font/TrueType/Glyf.cpp
index 1b25f9c644..a2aae72b4d 100644
--- a/Userland/Libraries/LibGfx/Font/TrueType/Glyf.cpp
+++ b/Userland/Libraries/LibGfx/Font/TrueType/Glyf.cpp
@@ -189,139 +189,6 @@ Optional<Glyf::Glyph::ComponentIterator::Item> Glyf::Glyph::ComponentIterator::n
};
}
-Rasterizer::Rasterizer(Gfx::IntSize size)
- : m_size(size)
-{
- m_data.resize(m_size.width() * m_size.height());
- for (int i = 0; i < m_size.width() * m_size.height(); i++) {
- m_data[i] = 0.0f;
- }
-}
-
-void Rasterizer::draw_path(Gfx::Path& path)
-{
- for (auto& line : path.split_lines()) {
- draw_line(line.from, line.to);
- }
-}
-
-RefPtr<Gfx::Bitmap> Rasterizer::accumulate()
-{
- auto bitmap_or_error = Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRA8888, m_size);
- if (bitmap_or_error.is_error())
- return {};
- auto bitmap = bitmap_or_error.release_value_but_fixme_should_propagate_errors();
- Color base_color = Color::from_rgb(0xffffff);
- for (int y = 0; y < m_size.height(); y++) {
- float accumulator = 0.0;
- for (int x = 0; x < m_size.width(); x++) {
- accumulator += m_data[y * m_size.width() + x];
- float value = accumulator;
- if (value < 0.0f) {
- value = -value;
- }
- if (value > 1.0f) {
- value = 1.0;
- }
- u8 alpha = value * 255.0f;
- bitmap->set_pixel(x, y, base_color.with_alpha(alpha));
- }
- }
- return bitmap;
-}
-
-void Rasterizer::draw_line(Gfx::FloatPoint p0, Gfx::FloatPoint p1)
-{
- // FIXME: Shift x and y according to dy/dx
- if (p0.x() < 0.0f) {
- p0.set_x(roundf(p0.x()));
- }
- if (p0.y() < 0.0f) {
- p0.set_y(roundf(p0.y()));
- }
- if (p1.x() < 0.0f) {
- p1.set_x(roundf(p1.x()));
- }
- if (p1.y() < 0.0f) {
- p1.set_y(roundf(p1.y()));
- }
-
- if (!(p0.x() >= 0.0f && p0.y() >= 0.0f && p0.x() <= m_size.width() && p0.y() <= m_size.height())) {
- dbgln("!P0({},{})", p0.x(), p0.y());
- return;
- }
-
- if (!(p1.x() >= 0.0f && p1.y() >= 0.0f && p1.x() <= m_size.width() && p1.y() <= m_size.height())) {
- dbgln("!P1({},{})", p1.x(), p1.y());
- return;
- }
-
- VERIFY(p0.x() >= 0.0f && p0.y() >= 0.0f && p0.x() <= m_size.width() && p0.y() <= m_size.height());
- VERIFY(p1.x() >= 0.0f && p1.y() >= 0.0f && p1.x() <= m_size.width() && p1.y() <= m_size.height());
-
- // If we're on the same Y, there's no need to draw
- if (p0.y() == p1.y()) {
- return;
- }
-
- float direction = -1.0;
- if (p1.y() < p0.y()) {
- direction = 1.0;
- auto tmp = p0;
- p0 = p1;
- p1 = tmp;
- }
-
- float dxdy = (p1.x() - p0.x()) / (p1.y() - p0.y());
- u32 y0 = floorf(p0.y());
- u32 y1 = ceilf(p1.y());
- float x_cur = p0.x();
-
- for (u32 y = y0; y < y1; y++) {
- u32 line_offset = m_size.width() * y;
-
- float dy = min(y + 1.0f, p1.y()) - max((float)y, p0.y());
- float directed_dy = dy * direction;
- float x_next = x_cur + dy * dxdy;
- if (x_next < 0.0f) {
- x_next = 0.0f;
- }
- float x0 = x_cur;
- float x1 = x_next;
- if (x1 < x0) {
- x1 = x_cur;
- x0 = x_next;
- }
- float x0_floor = floorf(x0);
- float x1_ceil = ceilf(x1);
- u32 x0i = x0_floor;
-
- if (x1_ceil <= x0_floor + 1.0f) {
- // If x0 and x1 are within the same pixel, then area to the right is (1 - (mid(x0, x1) - x0_floor)) * dy
- float area = ((x0 + x1) * 0.5f) - x0_floor;
- m_data[line_offset + x0i] += directed_dy * (1.0f - area);
- m_data[line_offset + x0i + 1] += directed_dy * area;
- } else {
- float dydx = 1.0f / dxdy;
- if (dydx < 0)
- dydx = -dydx;
-
- float x0_right = 1.0f - (x0 - x0_floor);
- u32 x1_floor_i = floorf(x1);
- float area_upto_here = 0.5f * x0_right * x0_right * dydx;
- m_data[line_offset + x0i] += direction * area_upto_here;
- for (u32 x = x0i + 1; x < x1_floor_i; x++) {
- m_data[line_offset + x] += direction * dydx;
- area_upto_here += dydx;
- }
- float remaining_area = (dy - area_upto_here);
- m_data[line_offset + x1_floor_i] += direction * remaining_area;
- }
-
- x_cur = x_next;
- }
-}
-
Optional<Loca> Loca::from_slice(ReadonlyBytes slice, u32 num_glyphs, IndexToLocFormat index_to_loc_format)
{
switch (index_to_loc_format) {
@@ -383,7 +250,7 @@ static void get_ttglyph_offsets(ReadonlyBytes slice, u32 num_points, u32 flags_o
*y_offset = *x_offset + x_size;
}
-void Glyf::Glyph::rasterize_impl(Rasterizer& rasterizer, Gfx::AffineTransform const& transform) const
+void Glyf::Glyph::rasterize_impl(Gfx::PathRasterizer& rasterizer, Gfx::AffineTransform const& transform) const
{
// Get offset for flags, x, and y.
u16 num_points = be_u16(m_slice.offset_pointer((m_num_contours - 1) * 2)) + 1;
@@ -483,7 +350,7 @@ RefPtr<Gfx::Bitmap> Glyf::Glyph::rasterize_simple(i16 font_ascender, i16 font_de
{
u32 width = (u32)(ceilf((m_xmax - m_xmin) * x_scale)) + 2;
u32 height = (u32)(ceilf((font_ascender - font_descender) * y_scale)) + 2;
- Rasterizer rasterizer(Gfx::IntSize(width, height));
+ Gfx::PathRasterizer rasterizer(Gfx::IntSize(width, height));
auto affine = Gfx::AffineTransform().scale(x_scale, -y_scale).translate(-m_xmin, -font_ascender);
rasterize_impl(rasterizer, affine);
return rasterizer.accumulate();
diff --git a/Userland/Libraries/LibGfx/Font/TrueType/Glyf.h b/Userland/Libraries/LibGfx/Font/TrueType/Glyf.h
index 04cf16fa19..228e9f73f2 100644
--- a/Userland/Libraries/LibGfx/Font/TrueType/Glyf.h
+++ b/Userland/Libraries/LibGfx/Font/TrueType/Glyf.h
@@ -10,24 +10,12 @@
#include <AK/Vector.h>
#include <LibGfx/AffineTransform.h>
#include <LibGfx/Bitmap.h>
+#include <LibGfx/Font/PathRasterizer.h>
#include <LibGfx/Font/TrueType/Tables.h>
#include <math.h>
namespace TTF {
-class Rasterizer {
-public:
- Rasterizer(Gfx::IntSize);
- void draw_path(Gfx::Path&);
- RefPtr<Gfx::Bitmap> accumulate();
-
-private:
- void draw_line(Gfx::FloatPoint, Gfx::FloatPoint);
-
- Gfx::IntSize m_size;
- Vector<float> m_data;
-};
-
class Loca {
public:
static Optional<Loca> from_slice(ReadonlyBytes, u32 num_glyphs, IndexToLocFormat);
@@ -101,11 +89,11 @@ public:
u32 m_offset { 0 };
};
- void rasterize_impl(Rasterizer&, Gfx::AffineTransform const&) const;
+ void rasterize_impl(Gfx::PathRasterizer&, Gfx::AffineTransform const&) const;
RefPtr<Gfx::Bitmap> rasterize_simple(i16 ascender, i16 descender, float x_scale, float y_scale) const;
template<typename GlyphCb>
- void rasterize_composite_loop(Rasterizer& rasterizer, Gfx::AffineTransform const& transform, GlyphCb glyph_callback) const
+ void rasterize_composite_loop(Gfx::PathRasterizer& rasterizer, Gfx::AffineTransform const& transform, GlyphCb glyph_callback) const
{
ComponentIterator component_iterator(m_slice);
@@ -132,7 +120,7 @@ public:
{
u32 width = (u32)(ceilf((m_xmax - m_xmin) * x_scale)) + 1;
u32 height = (u32)(ceilf((font_ascender - font_descender) * y_scale)) + 1;
- Rasterizer rasterizer(Gfx::IntSize(width, height));
+ Gfx::PathRasterizer rasterizer(Gfx::IntSize(width, height));
auto affine = Gfx::AffineTransform().scale(x_scale, -y_scale).translate(-m_xmin, -font_ascender);
rasterize_composite_loop(rasterizer, affine, glyph_callback);