diff --git a/Meta/Lagom/CMakeLists.txt b/Meta/Lagom/CMakeLists.txt index 0a8c78a8ba9..2919155ddda 100644 --- a/Meta/Lagom/CMakeLists.txt +++ b/Meta/Lagom/CMakeLists.txt @@ -456,7 +456,6 @@ if (ENABLE_GUI_TARGETS) lagom_utility(animation SOURCES ../../Userland/Utilities/animation.cpp LIBS LibGfx LibMain) lagom_utility(icc SOURCES ../../Userland/Utilities/icc.cpp LIBS LibGfx LibMain LibURL) lagom_utility(image SOURCES ../../Userland/Utilities/image.cpp LIBS LibGfx LibMain) - lagom_utility(ttfdisasm SOURCES ../../Userland/Utilities/ttfdisasm.cpp LIBS LibGfx LibMain) endif() lagom_utility(js SOURCES ../../Userland/Utilities/js.cpp LIBS LibCrypto LibJS LibLine LibUnicode LibMain LibTextCodec Threads::Threads) diff --git a/Userland/Libraries/LibGfx/DeprecatedPath.cpp b/Userland/Libraries/LibGfx/DeprecatedPath.cpp index a0e3f80e2b2..8a88d349c00 100644 --- a/Userland/Libraries/LibGfx/DeprecatedPath.cpp +++ b/Userland/Libraries/LibGfx/DeprecatedPath.cpp @@ -158,85 +158,6 @@ void DeprecatedPath::elliptical_arc_to(FloatPoint point, FloatSize radii, float theta_delta); } -void DeprecatedPath::text(Utf8View text, Font const& font) -{ - if (!is(font)) { - // FIXME: This API only accepts Gfx::Font for ease of use. - dbgln("Cannot path-ify bitmap fonts!"); - return; - } - - auto& scaled_font = static_cast(font); - for_each_glyph_position( - last_point(), text, scaled_font, [&](DrawGlyphOrEmoji const& glyph_or_emoji) { - if (glyph_or_emoji.has()) { - auto& glyph = glyph_or_emoji.get(); - move_to(glyph.position); - scaled_font.append_glyph_path_to(*this, glyph.glyph_id); - } - }, - IncludeLeftBearing::Yes); -} - -DeprecatedPath DeprecatedPath::place_text_along(Utf8View text, Font const& font) const -{ - if (!is(font)) { - // FIXME: This API only accepts Gfx::Font for ease of use. - dbgln("Cannot path-ify bitmap fonts!"); - return {}; - } - - auto lines = split_lines(); - auto next_point_for_offset = [&, line_index = 0U, distance_along_path = 0.0f, last_line_length = 0.0f](float offset) mutable -> Optional { - while (line_index < lines.size() && offset > distance_along_path) { - last_line_length = lines[line_index++].length(); - distance_along_path += last_line_length; - } - if (offset > distance_along_path) - return {}; - if (last_line_length > 1) { - // If the last line segment was fairly long, compute the point in the line. - float p = (last_line_length + offset - distance_along_path) / last_line_length; - auto current_line = lines[line_index - 1]; - return current_line.a() + (current_line.b() - current_line.a()).scaled(p); - } - if (line_index >= lines.size()) - return {}; - return lines[line_index].a(); - }; - - auto& scaled_font = static_cast(font); - Gfx::DeprecatedPath result_path; - Gfx::for_each_glyph_position( - {}, text, font, [&](Gfx::DrawGlyphOrEmoji glyph_or_emoji) { - auto* glyph = glyph_or_emoji.get_pointer(); - if (!glyph) - return; - auto offset = glyph->position.x(); - auto width = scaled_font.glyph_metrics(glyph->glyph_id).advance_width; - auto start = next_point_for_offset(offset); - if (!start.has_value()) - return; - auto end = next_point_for_offset(offset + width); - if (!end.has_value()) - return; - // Find the angle between the start and end points on the path. - auto delta = *end - *start; - auto angle = AK::atan2(delta.y(), delta.x()); - Gfx::DeprecatedPath glyph_path; - // Rotate the glyph then move it to start point. - scaled_font.append_glyph_path_to(glyph_path, glyph->glyph_id); - auto transform = Gfx::AffineTransform {} - .translate(*start) - .multiply(Gfx::AffineTransform {}.rotate_radians(angle)) - .multiply(Gfx::AffineTransform {}.translate({ 0, -scaled_font.pixel_metrics().ascent })); - glyph_path = glyph_path.copy_transformed(transform); - result_path.append_path(glyph_path); - }, - Gfx::IncludeLeftBearing::Yes); - return result_path; -} - void DeprecatedPath::close() { // If there's no `moveto` starting this subpath assume the start is (0, 0). diff --git a/Userland/Libraries/LibGfx/DeprecatedPath.h b/Userland/Libraries/LibGfx/DeprecatedPath.h index d12caebefc9..ba8e46e1b52 100644 --- a/Userland/Libraries/LibGfx/DeprecatedPath.h +++ b/Userland/Libraries/LibGfx/DeprecatedPath.h @@ -183,8 +183,6 @@ public: elliptical_arc_to(point, { radius, radius }, 0, large_arc, sweep); } - void text(Utf8View, Font const&); - FloatPoint last_point() { if (!m_points.is_empty()) @@ -196,9 +194,6 @@ public: void close_all_subpaths(); DeprecatedPath stroke_to_fill(float thickness) const; - - DeprecatedPath place_text_along(Utf8View text, Font const&) const; - DeprecatedPath copy_transformed(AffineTransform const&) const; ReadonlySpan split_lines() const diff --git a/Userland/Libraries/LibGfx/Font/Font.h b/Userland/Libraries/LibGfx/Font/Font.h index d0a50a9b07b..a0416efccef 100644 --- a/Userland/Libraries/LibGfx/Font/Font.h +++ b/Userland/Libraries/LibGfx/Font/Font.h @@ -75,7 +75,6 @@ public: virtual u16 weight() const = 0; virtual bool contains_glyph(u32 code_point) const = 0; - virtual bool append_glyph_path_to(Gfx::DeprecatedPath&, u32 glyph_id) const = 0; virtual u32 glyph_id_for_code_point(u32 code_point) const = 0; virtual float glyph_left_bearing(u32 code_point) const = 0; virtual float glyph_width(u32 code_point) const = 0; @@ -97,8 +96,6 @@ public: Font const& bold_variant() const; hb_font_t* harfbuzz_font() const; - virtual bool has_color_bitmaps() const = 0; - virtual Typeface const& typeface() const = 0; private: diff --git a/Userland/Libraries/LibGfx/Font/OpenType/Glyf.cpp b/Userland/Libraries/LibGfx/Font/OpenType/Glyf.cpp index 272573f799b..4954dac63f3 100644 --- a/Userland/Libraries/LibGfx/Font/OpenType/Glyf.cpp +++ b/Userland/Libraries/LibGfx/Font/OpenType/Glyf.cpp @@ -4,9 +4,6 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include -#include -#include #include #include @@ -14,167 +11,6 @@ namespace OpenType { extern u16 be_u16(u8 const* ptr); extern u32 be_u32(u8 const* ptr); -extern i16 be_i16(u8 const* ptr); -extern float be_fword(u8 const* ptr); - -enum class SimpleGlyfFlags { - // From spec. - OnCurve = 0x01, - XShortVector = 0x02, - YShortVector = 0x04, - RepeatFlag = 0x08, - XIsSameOrPositiveXShortVector = 0x10, - YIsSameOrPositiveYShortVector = 0x20, - // Combinations - XMask = 0x12, - YMask = 0x24, - XLongVector = 0x00, - YLongVector = 0x00, - XNegativeShortVector = 0x02, - YNegativeShortVector = 0x04, - XPositiveShortVector = 0x12, - YPositiveShortVector = 0x24, -}; - -class PointIterator { -public: - struct Item { - bool on_curve; - Gfx::FloatPoint point; - }; - - PointIterator(ReadonlyBytes slice, u16 num_points, u32 flags_offset, u32 x_offset, u32 y_offset, Gfx::AffineTransform affine) - : m_slice(slice) - , m_points_remaining(num_points) - , m_flags_offset(flags_offset) - , m_x_offset(x_offset) - , m_y_offset(y_offset) - , m_affine(affine) - { - } - - Optional next() - { - if (m_points_remaining == 0) { - return {}; - } - if (m_flags_remaining > 0) { - m_flags_remaining--; - } else { - m_flag = m_slice[m_flags_offset++]; - if (m_flag & (u8)SimpleGlyfFlags::RepeatFlag) { - m_flags_remaining = m_slice[m_flags_offset++]; - } - } - switch (m_flag & (u8)SimpleGlyfFlags::XMask) { - case (u8)SimpleGlyfFlags::XLongVector: - m_last_point.set_x(m_last_point.x() + be_i16(m_slice.offset(m_x_offset))); - m_x_offset += 2; - break; - case (u8)SimpleGlyfFlags::XNegativeShortVector: - m_last_point.set_x(m_last_point.x() - m_slice[m_x_offset++]); - break; - case (u8)SimpleGlyfFlags::XPositiveShortVector: - m_last_point.set_x(m_last_point.x() + m_slice[m_x_offset++]); - break; - default: - break; - } - switch (m_flag & (u8)SimpleGlyfFlags::YMask) { - case (u8)SimpleGlyfFlags::YLongVector: - m_last_point.set_y(m_last_point.y() + be_i16(m_slice.offset(m_y_offset))); - m_y_offset += 2; - break; - case (u8)SimpleGlyfFlags::YNegativeShortVector: - m_last_point.set_y(m_last_point.y() - m_slice[m_y_offset++]); - break; - case (u8)SimpleGlyfFlags::YPositiveShortVector: - m_last_point.set_y(m_last_point.y() + m_slice[m_y_offset++]); - break; - default: - break; - } - m_points_remaining--; - Item ret = { - .on_curve = (m_flag & (u8)SimpleGlyfFlags::OnCurve) != 0, - .point = m_affine.map(m_last_point), - }; - return ret; - } - -private: - ReadonlyBytes m_slice; - u16 m_points_remaining; - u8 m_flag { 0 }; - Gfx::FloatPoint m_last_point = { 0.0f, 0.0f }; - u32 m_flags_remaining = { 0 }; - u32 m_flags_offset; - u32 m_x_offset; - u32 m_y_offset; - Gfx::AffineTransform m_affine; -}; - -Optional Glyf::Glyph::ComponentIterator::next() -{ - if (!m_has_more) { - return {}; - } - u16 flags = be_u16(m_slice.offset(m_offset)); - m_offset += 2; - u16 glyph_id = be_u16(m_slice.offset(m_offset)); - m_offset += 2; - i16 arg1 = 0, arg2 = 0; - if (flags & (u16)CompositeFlags::Arg1AndArg2AreWords) { - arg1 = be_i16(m_slice.offset(m_offset)); - m_offset += 2; - arg2 = be_i16(m_slice.offset(m_offset)); - m_offset += 2; - } else { - arg1 = (i8)m_slice[m_offset++]; - arg2 = (i8)m_slice[m_offset++]; - } - float a = 1.0, b = 0.0, c = 0.0, d = 1.0, e = 0.0, f = 0.0; - if (flags & (u16)CompositeFlags::WeHaveATwoByTwo) { - a = be_fword(m_slice.offset(m_offset)); - m_offset += 2; - b = be_fword(m_slice.offset(m_offset)); - m_offset += 2; - c = be_fword(m_slice.offset(m_offset)); - m_offset += 2; - d = be_fword(m_slice.offset(m_offset)); - m_offset += 2; - } else if (flags & (u16)CompositeFlags::WeHaveAnXAndYScale) { - a = be_fword(m_slice.offset(m_offset)); - m_offset += 2; - d = be_fword(m_slice.offset(m_offset)); - m_offset += 2; - } else if (flags & (u16)CompositeFlags::WeHaveAScale) { - a = be_fword(m_slice.offset(m_offset)); - m_offset += 2; - d = a; - } - // FIXME: Handle UseMyMetrics, ScaledComponentOffset, UnscaledComponentOffset, non-ArgsAreXYValues - if (flags & (u16)CompositeFlags::ArgsAreXYValues) { - e = arg1; - f = arg2; - } else { - // FIXME: Implement this. There's no TODO() here since many fonts work just fine without this. - } - if (flags & (u16)CompositeFlags::UseMyMetrics) { - // FIXME: Implement this. There's no TODO() here since many fonts work just fine without this. - } - if (flags & (u16)CompositeFlags::ScaledComponentOffset) { - // FIXME: Implement this. There's no TODO() here since many fonts work just fine without this. - } - if (flags & (u16)CompositeFlags::UnscaledComponentOffset) { - // FIXME: Implement this. There's no TODO() here since many fonts work just fine without this. - } - m_has_more = (flags & (u16)CompositeFlags::MoreComponents); - return Item { - .glyph_id = glyph_id, - .affine = Gfx::AffineTransform(a, b, c, d, e, f), - }; -} ErrorOr Loca::from_slice(ReadonlyBytes slice, u32 num_glyphs, IndexToLocFormat index_to_loc_format) { @@ -205,121 +41,6 @@ u32 Loca::get_glyph_offset(u32 glyph_id) const } } -static void get_ttglyph_offsets(ReadonlyBytes slice, u32 num_points, u32 flags_offset, u32* x_offset, u32* y_offset) -{ - u32 flags_size = 0; - u32 x_size = 0; - u32 repeat_count; - while (num_points > 0) { - u8 flag = slice[flags_offset + flags_size]; - if (flag & (u8)SimpleGlyfFlags::RepeatFlag) { - flags_size++; - repeat_count = slice[flags_offset + flags_size] + 1; - } else { - repeat_count = 1; - } - flags_size++; - switch (flag & (u8)SimpleGlyfFlags::XMask) { - case (u8)SimpleGlyfFlags::XLongVector: - x_size += repeat_count * 2; - break; - case (u8)SimpleGlyfFlags::XNegativeShortVector: - case (u8)SimpleGlyfFlags::XPositiveShortVector: - x_size += repeat_count; - break; - default: - break; - } - num_points -= repeat_count; - } - *x_offset = flags_offset + flags_size; - *y_offset = *x_offset + x_size; -} - -ReadonlyBytes Glyf::Glyph::program() const -{ - if (m_num_contours == 0) - return {}; - - auto instructions_start = m_num_contours * 2; - u16 num_instructions = be_u16(m_slice.offset(instructions_start)); - return m_slice.slice(instructions_start + 2, num_instructions); -} - -void Glyf::Glyph::append_path_impl(Gfx::DeprecatedPath& path, Gfx::AffineTransform const& transform) const -{ - if (m_num_contours == 0) - return; - - // Get offset for flags, x, and y. - u16 num_points = be_u16(m_slice.offset((m_num_contours - 1) * 2)) + 1; - u16 num_instructions = be_u16(m_slice.offset(m_num_contours * 2)); - u32 flags_offset = m_num_contours * 2 + 2 + num_instructions; - u32 x_offset = 0; - u32 y_offset = 0; - get_ttglyph_offsets(m_slice, num_points, flags_offset, &x_offset, &y_offset); - - // Prepare to render glyph. - PointIterator point_iterator(m_slice, num_points, flags_offset, x_offset, y_offset, transform); - - u32 current_point_index = 0; - for (u16 contour_index = 0; contour_index < m_num_contours; contour_index++) { - u32 current_contour_last_point_index = be_u16(m_slice.offset(contour_index * 2)); - - Vector points; - while (current_point_index <= current_contour_last_point_index) { - points.append(*point_iterator.next()); - current_point_index++; - } - - if (points.is_empty()) - continue; - - auto current = points.last(); - auto next = points.first(); - - if (current.on_curve) { - path.move_to(current.point); - } else if (next.on_curve) { - path.move_to(next.point); - } else { - auto implied_point = (current.point + next.point) * 0.5f; - path.move_to(implied_point); - } - - for (size_t i = 0; i < points.size(); i++) { - current = next; - next = points[(i + 1) % points.size()]; - if (current.on_curve) { - path.line_to(current.point); - } else if (next.on_curve) { - path.quadratic_bezier_curve_to(current.point, next.point); - } else { - auto implied_point = (current.point + next.point) * 0.5f; - path.quadratic_bezier_curve_to(current.point, implied_point); - } - } - } -} - -bool Glyf::Glyph::append_simple_path(Gfx::DeprecatedPath& path, i16 font_ascender, i16 font_descender, float x_scale, float y_scale) const -{ - if (m_xmin > m_xmax) [[unlikely]] { - dbgln("OpenType: Glyph has invalid xMin ({}) > xMax ({})", m_xmin, m_xmax); - return false; - } - if (font_descender > font_ascender) [[unlikely]] { - dbgln("OpenType: Glyph has invalid ascender ({}) > descender ({})", font_ascender, font_descender); - return false; - } - auto affine = Gfx::AffineTransform() - .translate(path.last_point()) - .scale(x_scale, -y_scale) - .translate(-m_xmin, -font_ascender); - append_path_impl(path, affine); - return true; -} - Optional Glyf::glyph(u32 offset) const { if (offset + sizeof(GlyphHeader) > m_slice.size()) diff --git a/Userland/Libraries/LibGfx/Font/OpenType/Glyf.h b/Userland/Libraries/LibGfx/Font/OpenType/Glyf.h index 7347e3f1c2e..6bccd2ab40d 100644 --- a/Userland/Libraries/LibGfx/Font/OpenType/Glyf.h +++ b/Userland/Libraries/LibGfx/Font/OpenType/Glyf.h @@ -9,9 +9,6 @@ #include #include #include -#include -#include -#include #include #include #include @@ -43,21 +40,6 @@ private: // glyf: Glyph Data class Glyf { public: - enum class CompositeFlags { - Arg1AndArg2AreWords = 0x0001, - ArgsAreXYValues = 0x0002, - RoundXYToGrid = 0x0004, - WeHaveAScale = 0x0008, - MoreComponents = 0x0020, - WeHaveAnXAndYScale = 0x0040, - WeHaveATwoByTwo = 0x0080, - WeHaveInstructions = 0x0100, - UseMyMetrics = 0x0200, - OverlapCompound = 0x0400, // Not relevant - can overlap without this set - ScaledComponentOffset = 0x0800, - UnscaledComponentOffset = 0x1000, - }; - class Glyph { public: Glyph(ReadonlyBytes slice, i16 xmin, i16 ymin, i16 xmax, i16 ymax, i16 num_contours = -1) @@ -73,90 +55,18 @@ public: } } - template - bool append_path(Gfx::DeprecatedPath& path, i16 font_ascender, i16 font_descender, float x_scale, float y_scale, GlyphCb glyph_callback) const - { - switch (m_type) { - case Type::Simple: - return append_simple_path(path, font_ascender, font_descender, x_scale, y_scale); - case Type::Composite: - return append_composite_path(path, font_ascender, x_scale, y_scale, glyph_callback); - } - VERIFY_NOT_REACHED(); - } - i16 xmax() const { return m_xmax; } i16 xmin() const { return m_xmin; } int ascender() const { return m_ymax; } int descender() const { return m_ymin; } - ReadonlyBytes program() const; - private: enum class Type { Simple, Composite, }; - class ComponentIterator { - public: - struct Item { - u16 glyph_id; - Gfx::AffineTransform affine; - }; - - ComponentIterator(ReadonlyBytes slice) - : m_slice(slice) - { - } - Optional next(); - - private: - ReadonlyBytes m_slice; - bool m_has_more { true }; - u32 m_offset { 0 }; - }; - - void append_path_impl(Gfx::DeprecatedPath&, Gfx::AffineTransform const&) const; - bool append_simple_path(Gfx::DeprecatedPath&, i16 ascender, i16 descender, float x_scale, float y_scale) const; - - template - void resolve_composite_path_loop(Gfx::DeprecatedPath& path, Gfx::AffineTransform const& transform, GlyphCb glyph_callback) const - { - ComponentIterator component_iterator(m_slice); - - while (true) { - auto opt_item = component_iterator.next(); - if (!opt_item.has_value()) { - break; - } - auto item = opt_item.value(); - Gfx::AffineTransform affine_here { transform }; - affine_here.multiply(item.affine); - auto glyph = glyph_callback(item.glyph_id); - if (!glyph.has_value()) - continue; - - if (glyph->m_type == Type::Simple) { - glyph->append_path_impl(path, affine_here); - } else { - glyph->resolve_composite_path_loop(path, transform, glyph_callback); - } - } - } - - template - bool append_composite_path(Gfx::DeprecatedPath& path, i16 font_ascender, float x_scale, float y_scale, GlyphCb glyph_callback) const - { - auto affine = Gfx::AffineTransform() - .translate(path.last_point()) - .scale(x_scale, -y_scale) - .translate(-m_xmin, -font_ascender); - resolve_composite_path_loop(path, affine, glyph_callback); - return true; - } - Type m_type { Type::Composite }; i16 m_xmin { 0 }; i16 m_ymin { 0 }; diff --git a/Userland/Libraries/LibGfx/Font/OpenType/Tables.cpp b/Userland/Libraries/LibGfx/Font/OpenType/Tables.cpp index fdabe633183..dc8b0b0bf73 100644 --- a/Userland/Libraries/LibGfx/Font/OpenType/Tables.cpp +++ b/Userland/Libraries/LibGfx/Font/OpenType/Tables.cpp @@ -443,85 +443,6 @@ Optional OS2::x_height() const [](auto*) { return Optional(); }); } -ErrorOr CBLC::from_slice(ReadonlyBytes slice) -{ - if (slice.size() < sizeof(CblcHeader)) - return Error::from_string_literal("CBLC table too small"); - auto const& header = *bit_cast(slice.data()); - - size_t num_sizes = header.num_sizes; - Checked size_used_by_bitmap_sizes = num_sizes; - size_used_by_bitmap_sizes *= sizeof(BitmapSize); - if (size_used_by_bitmap_sizes.has_overflow()) - return Error::from_string_literal("Integer overflow in CBLC table"); - - Checked total_size = sizeof(CblcHeader); - total_size += size_used_by_bitmap_sizes; - if (total_size.has_overflow()) - return Error::from_string_literal("Integer overflow in CBLC table"); - - if (slice.size() < total_size) - return Error::from_string_literal("CBLC table too small"); - - ReadonlySpan bitmap_sizes { bit_cast(slice.data() + sizeof(CblcHeader)), num_sizes }; - - return CBLC { slice, header, bitmap_sizes }; -} - -Optional CBLC::bitmap_size_for_glyph_id(u32 glyph_id) const -{ - for (auto const& bitmap_size : m_bitmap_sizes) { - if (glyph_id >= bitmap_size.start_glyph_index && glyph_id <= bitmap_size.end_glyph_index) { - return bitmap_size; - } - } - return {}; -} - -Optional CBLC::index_subtable_for_glyph_id(u32 glyph_id, u16& first_glyph_index, u16& last_glyph_index) const -{ - auto maybe_bitmap_size = bitmap_size_for_glyph_id(glyph_id); - if (!maybe_bitmap_size.has_value()) { - return {}; - } - auto const& bitmap_size = maybe_bitmap_size.value(); - - Checked required_size = static_cast(bitmap_size.index_subtable_array_offset); - required_size += bitmap_size.index_tables_size; - - if (m_slice.size() < required_size) { - dbgln("CBLC index subtable array goes out of bounds"); - return {}; - } - - auto index_subtables_slice = m_slice.slice(bitmap_size.index_subtable_array_offset, bitmap_size.index_tables_size); - ReadonlySpan index_subtable_arrays { - bit_cast(index_subtables_slice.data()), bitmap_size.number_of_index_subtables - }; - - EBLC::IndexSubTableArray const* index_subtable_array = nullptr; - for (auto const& array : index_subtable_arrays) { - if (glyph_id >= array.first_glyph_index && glyph_id <= array.last_glyph_index) - index_subtable_array = &array; - } - if (!index_subtable_array) { - return {}; - } - - auto index_subtable_slice = m_slice.slice(bitmap_size.index_subtable_array_offset + index_subtable_array->additional_offset_to_index_subtable); - first_glyph_index = index_subtable_array->first_glyph_index; - last_glyph_index = index_subtable_array->last_glyph_index; - return *bit_cast(index_subtable_slice.data()); -} - -ErrorOr CBDT::from_slice(ReadonlyBytes slice) -{ - if (slice.size() < sizeof(CbdtHeader)) - return Error::from_string_literal("CBDT table too small"); - auto const& header = *bit_cast(slice.data()); - return CBDT { slice, header }; -} - ErrorOr GPOS::from_slice(ReadonlyBytes slice) { FixedMemoryStream stream { slice }; diff --git a/Userland/Libraries/LibGfx/Font/OpenType/Tables.h b/Userland/Libraries/LibGfx/Font/OpenType/Tables.h index e1edfc2f6c5..f7262c2c87e 100644 --- a/Userland/Libraries/LibGfx/Font/OpenType/Tables.h +++ b/Userland/Libraries/LibGfx/Font/OpenType/Tables.h @@ -192,36 +192,6 @@ struct GlyphHorizontalMetrics { i16 left_side_bearing; }; -// https://learn.microsoft.com/en-us/typography/opentype/spec/fpgm -// fpgm: Font Program -struct Fpgm { -public: - explicit Fpgm(ReadonlyBytes slice) - : m_slice(slice) - { - } - - ReadonlyBytes program_data() const { return m_slice; } - -private: - ReadonlyBytes m_slice; -}; - -// https://learn.microsoft.com/en-us/typography/opentype/spec/prep -// prep: Control Value Program -struct Prep { -public: - explicit Prep(ReadonlyBytes slice) - : m_slice(slice) - { - } - - ReadonlyBytes program_data() const { return m_slice; } - -private: - ReadonlyBytes m_slice; -}; - // https://learn.microsoft.com/en-us/typography/opentype/spec/hmtx // hmtx: Horizontal Metrics Table class Hmtx { @@ -455,150 +425,6 @@ private: Vector const m_subtables; }; -// https://learn.microsoft.com/en-us/typography/opentype/spec/eblc -// EBLC — Embedded Bitmap Location Table -class EBLC { -public: - // https://learn.microsoft.com/en-us/typography/opentype/spec/eblc#sbitlinemetrics-record - struct [[gnu::packed]] SbitLineMetrics { - Int8 ascender {}; - Int8 descender {}; - Uint8 width_max {}; - Int8 caret_slope_numerator {}; - Int8 caret_slope_denominator {}; - Int8 caret_offset {}; - Int8 min_origin_sb {}; - Int8 min_advance_sb {}; - Int8 max_before_bl {}; - Int8 min_after_bl {}; - Int8 pad1 {}; - Int8 pad2 {}; - }; - static_assert(AssertSize()); - - // https://learn.microsoft.com/en-us/typography/opentype/spec/eblc#indexsubtablearray - struct [[gnu::packed]] IndexSubTableArray { - Uint16 first_glyph_index; - Uint16 last_glyph_index; - Offset32 additional_offset_to_index_subtable; - }; - static_assert(AssertSize()); - - // https://learn.microsoft.com/en-us/typography/opentype/spec/eblc#indexsubheader - struct [[gnu::packed]] IndexSubHeader { - Uint16 index_format; - Uint16 image_format; - Offset32 image_data_offset; - }; - static_assert(AssertSize()); - - // https://learn.microsoft.com/en-us/typography/opentype/spec/eblc#indexsubtable1-variable-metrics-glyphs-with-4-byte-offsets - // IndexSubTable1: variable-metrics glyphs with 4-byte offsets - struct [[gnu::packed]] IndexSubTable1 { - IndexSubHeader header; - Offset32 sbit_offsets[]; - }; - static_assert(AssertSize()); -}; - -// https://learn.microsoft.com/en-us/typography/opentype/spec/cblc -// CBLC — Color Bitmap Location Table -class CBLC { -public: - // https://learn.microsoft.com/en-us/typography/opentype/spec/cblc#bitmapsize-record - struct [[gnu::packed]] BitmapSize { - Offset32 index_subtable_array_offset; - Uint32 index_tables_size; - Uint32 number_of_index_subtables; - Uint32 color_ref; - EBLC::SbitLineMetrics hori; - EBLC::SbitLineMetrics vert; - Uint16 start_glyph_index; - Uint16 end_glyph_index; - Uint8 ppem_x {}; - Uint8 ppem_y {}; - Uint8 bit_depth {}; - Int8 flags {}; - }; - static_assert(AssertSize()); - - // https://learn.microsoft.com/en-us/typography/opentype/spec/cblc#cblcheader - struct [[gnu::packed]] CblcHeader { - Uint16 major_version; - Uint16 minor_version; - Uint32 num_sizes; - // Stored in a separate span: - // BitmapSize bitmap_sizes[]; - }; - static_assert(AssertSize()); - - static ErrorOr from_slice(ReadonlyBytes); - Optional bitmap_size_for_glyph_id(u32 glyph_id) const; - Optional index_subtable_for_glyph_id(u32 glyph_id, u16& first_glyph_index, u16& last_glyph_index) const; - -private: - explicit CBLC(ReadonlyBytes slice, CblcHeader const& header, ReadonlySpan bitmap_sizes) - : m_slice(slice) - , m_header(header) - , m_bitmap_sizes(bitmap_sizes) - { - } - - ReadonlyBytes m_slice; - CblcHeader const& m_header; - ReadonlySpan m_bitmap_sizes; -}; - -// https://learn.microsoft.com/en-us/typography/opentype/spec/ebdt -// EBDT — Embedded Bitmap Data Table -class EBDT { -public: - // https://learn.microsoft.com/en-us/typography/opentype/spec/ebdt#smallglyphmetrics - struct [[gnu::packed]] SmallGlyphMetrics { - Uint8 height {}; - Uint8 width {}; - Int8 bearing_x {}; - Int8 bearing_y {}; - Uint8 advance {}; - }; - static_assert(AssertSize()); -}; - -// https://learn.microsoft.com/en-us/typography/opentype/spec/cbdt -// CBDT — Color Bitmap Data Table -class CBDT { -public: - // https://learn.microsoft.com/en-us/typography/opentype/spec/cbdt#table-structure - struct [[gnu::packed]] CbdtHeader { - Uint16 major_version; - Uint16 minor_version; - }; - static_assert(AssertSize()); - - // https://learn.microsoft.com/en-us/typography/opentype/spec/cbdt#format-17-small-metrics-png-image-data - struct [[gnu::packed]] Format17 { - EBDT::SmallGlyphMetrics glyph_metrics; - Uint32 data_len; - Uint8 data[]; - }; - static_assert(AssertSize()); - - static ErrorOr from_slice(ReadonlyBytes); - ReadonlyBytes bytes() const { return m_slice; } - - CbdtHeader const& header() const { return m_header; } - -private: - explicit CBDT(ReadonlyBytes slice, CbdtHeader const& header) - : m_slice(slice) - , m_header(header) - { - } - - ReadonlyBytes m_slice; - CbdtHeader const& m_header; -}; - // https://learn.microsoft.com/en-us/typography/opentype/spec/chapter2#feature-list-table struct [[gnu::packed]] FeatureRecord { Tag feature_tag; diff --git a/Userland/Libraries/LibGfx/Font/OpenType/Typeface.cpp b/Userland/Libraries/LibGfx/Font/OpenType/Typeface.cpp index a68b1100a38..2ea33160dea 100644 --- a/Userland/Libraries/LibGfx/Font/OpenType/Typeface.cpp +++ b/Userland/Libraries/LibGfx/Font/OpenType/Typeface.cpp @@ -128,7 +128,6 @@ namespace OpenType { u16 be_u16(u8 const*); u32 be_u32(u8 const*); i16 be_i16(u8 const*); -float be_fword(u8 const*); u16 be_u16(u8 const* ptr) { @@ -145,11 +144,6 @@ i16 be_i16(u8 const* ptr) return (((i16)ptr[0]) << 8) | ((i16)ptr[1]); } -float be_fword(u8 const* ptr) -{ - return (float)be_i16(ptr) / (float)(1 << 14); -} - ErrorOr> Typeface::try_load_from_resource(Core::Resource const& resource, unsigned index) { auto font_data = Gfx::FontData::create_from_resource(resource); @@ -229,11 +223,7 @@ ErrorOr> Typeface::try_load_from_offset(ReadonlyBytes bu Optional opt_glyf_slice = {}; Optional opt_os2_slice = {}; Optional opt_kern_slice = {}; - Optional opt_fpgm_slice = {}; - Optional opt_prep_slice = {}; - Optional cblc; - Optional cbdt; Optional gpos; TRY(for_each_table_record(buffer, offset, [&](Tag table_tag, ReadonlyBytes tag_buffer) -> ErrorOr { @@ -258,14 +248,6 @@ ErrorOr> Typeface::try_load_from_offset(ReadonlyBytes bu opt_os2_slice = tag_buffer; } else if (table_tag == Tag("kern")) { opt_kern_slice = tag_buffer; - } else if (table_tag == Tag("fpgm")) { - opt_fpgm_slice = tag_buffer; - } else if (table_tag == Tag("prep")) { - opt_prep_slice = tag_buffer; - } else if (table_tag == Tag("CBLC")) { - cblc = TRY(CBLC::from_slice(tag_buffer)); - } else if (table_tag == Tag("CBDT")) { - cbdt = TRY(CBDT::from_slice(tag_buffer)); } else if (table_tag == Tag("GPOS")) { gpos = TRY(GPOS::from_slice(tag_buffer)); } @@ -329,14 +311,6 @@ ErrorOr> Typeface::try_load_from_offset(ReadonlyBytes bu if (opt_kern_slice.has_value()) kern = TRY(Kern::from_slice(opt_kern_slice.value())); - Optional fpgm; - if (opt_fpgm_slice.has_value()) - fpgm = Fpgm(opt_fpgm_slice.value()); - - Optional prep; - if (opt_prep_slice.has_value()) - prep = Prep(opt_prep_slice.value()); - return adopt_ref(*new Typeface( move(head), move(name), @@ -348,10 +322,6 @@ ErrorOr> Typeface::try_load_from_offset(ReadonlyBytes bu move(glyf), move(os2), move(kern), - move(fpgm), - move(prep), - move(cblc), - move(cbdt), move(gpos), buffer.slice(offset), options.index)); @@ -387,46 +357,8 @@ Gfx::ScaledFontMetrics Typeface::metrics([[maybe_unused]] float x_scale, float y }; } -Typeface::EmbeddedBitmapData Typeface::embedded_bitmap_data_for_glyph(u32 glyph_id) const +float Typeface::glyph_advance(u32 glyph_id, float x_scale, float, float, float) const { - if (!has_color_bitmaps()) - return Empty {}; - - u16 first_glyph_index {}; - u16 last_glyph_index {}; - auto maybe_index_subtable = m_cblc->index_subtable_for_glyph_id(glyph_id, first_glyph_index, last_glyph_index); - if (!maybe_index_subtable.has_value()) - return Empty {}; - - auto const& index_subtable = maybe_index_subtable.value(); - auto const& bitmap_size = m_cblc->bitmap_size_for_glyph_id(glyph_id).value(); - - if (index_subtable.index_format == 1) { - auto const& index_subtable1 = *bit_cast(&index_subtable); - size_t size_of_array = (last_glyph_index - first_glyph_index + 1) + 1; - auto sbit_offsets = ReadonlySpan { index_subtable1.sbit_offsets, size_of_array }; - auto sbit_offset = sbit_offsets[glyph_id - first_glyph_index]; - size_t glyph_data_offset = sbit_offset + index_subtable.image_data_offset; - - if (index_subtable.image_format == 17) { - return EmbeddedBitmapWithFormat17 { - .bitmap_size = bitmap_size, - .format17 = *bit_cast(m_cbdt->bytes().slice(glyph_data_offset, size_of_array).data()), - }; - } - dbgln("FIXME: Implement OpenType embedded bitmap image format {}", index_subtable.image_format); - } else { - dbgln("FIXME: Implement OpenType embedded bitmap index format {}", index_subtable.index_format); - } - - return Empty {}; -} - -float Typeface::glyph_advance(u32 glyph_id, float x_scale, float y_scale, float point_width, float point_height) const -{ - if (has_color_bitmaps()) - return glyph_metrics(glyph_id, x_scale, y_scale, point_width, point_height).advance_width; - if (!m_hmtx.has_value()) return 0; @@ -437,33 +369,8 @@ float Typeface::glyph_advance(u32 glyph_id, float x_scale, float y_scale, float return static_cast(horizontal_metrics.advance_width) * x_scale; } -Gfx::ScaledGlyphMetrics Typeface::glyph_metrics(u32 glyph_id, float x_scale, float y_scale, float point_width, float point_height) const +Gfx::ScaledGlyphMetrics Typeface::glyph_metrics(u32 glyph_id, float x_scale, float y_scale, float, float) const { - auto embedded_bitmap_metrics = embedded_bitmap_data_for_glyph(glyph_id).visit( - [&](EmbeddedBitmapWithFormat17 const& data) -> Optional { - // FIXME: This is a pretty ugly hack to work out new scale factors based on the relationship between - // the pixels-per-em values and the font point size. It appears that bitmaps are not in the same - // coordinate space as the head table's "units per em" value. - // There's definitely some cleaner way to do this. - float x_scale = (point_width * DEFAULT_DPI) / (POINTS_PER_INCH * data.bitmap_size.ppem_x); - float y_scale = (point_height * DEFAULT_DPI) / (POINTS_PER_INCH * data.bitmap_size.ppem_y); - - return Gfx::ScaledGlyphMetrics { - .ascender = static_cast(data.bitmap_size.hori.ascender) * y_scale, - .descender = static_cast(data.bitmap_size.hori.descender) * y_scale, - .advance_width = static_cast(data.format17.glyph_metrics.advance) * x_scale, - .left_side_bearing = static_cast(data.format17.glyph_metrics.bearing_x) * x_scale, - }; - }, - [&](Empty) -> Optional { - // Unsupported format or no embedded bitmap for this glyph ID. - return {}; - }); - - if (embedded_bitmap_metrics.has_value()) { - return embedded_bitmap_metrics.release_value(); - } - if (!m_loca.has_value() || !m_glyf.has_value() || !m_hmtx.has_value()) { return Gfx::ScaledGlyphMetrics {}; } @@ -511,61 +418,6 @@ float Typeface::glyphs_horizontal_kerning(u32 left_glyph_id, u32 right_glyph_id, return 0.0f; } -Typeface::AscenderAndDescender Typeface::resolve_ascender_and_descender() const -{ - i16 ascender = 0; - i16 descender = 0; - - if (m_os2.has_value() && m_os2->use_typographic_metrics()) { - ascender = m_os2->typographic_ascender(); - descender = m_os2->typographic_descender(); - } else { - ascender = m_hhea.ascender(); - descender = m_hhea.descender(); - } - return { ascender, descender }; -} - -Optional Typeface::extract_and_append_glyph_path_to(Gfx::DeprecatedPath& path, u32 glyph_id, i16 ascender, i16 descender, float x_scale, float y_scale) const -{ - if (!m_loca.has_value() || !m_glyf.has_value()) { - return {}; - } - - if (glyph_id >= glyph_count()) { - glyph_id = 0; - } - - auto glyph_offset0 = m_loca->get_glyph_offset(glyph_id); - auto glyph_offset1 = m_loca->get_glyph_offset(glyph_id + 1); - - // If a glyph has no outline, then loca[n] = loca [n+1]. - if (glyph_offset0 == glyph_offset1) - return {}; - - auto glyph = m_glyf->glyph(glyph_offset0); - if (!glyph.has_value()) - return {}; - - bool success = glyph->append_path(path, ascender, descender, x_scale, y_scale, [&](u16 glyph_id) { - if (glyph_id >= glyph_count()) { - glyph_id = 0; - } - auto glyph_offset = m_loca->get_glyph_offset(glyph_id); - return m_glyf->glyph(glyph_offset); - }); - - if (success) - return glyph; - return {}; -} - -bool Typeface::append_glyph_path_to(Gfx::DeprecatedPath& path, u32 glyph_id, float x_scale, float y_scale) const -{ - auto ascender_and_descender = resolve_ascender_and_descender(); - return extract_and_append_glyph_path_to(path, glyph_id, ascender_and_descender.ascender, ascender_and_descender.descender, x_scale, y_scale).has_value(); -} - u32 Typeface::glyph_count() const { return m_maxp.num_glyphs(); @@ -652,40 +504,6 @@ u8 Typeface::slope() const return *m_slope; } -bool Typeface::is_fixed_width() const -{ - // FIXME: Read this information from the font file itself. - // FIXME: Although, it appears some application do similar hacks - return glyph_metrics(glyph_id_for_code_point('.'), 1, 1, 1, 1).advance_width == glyph_metrics(glyph_id_for_code_point('X'), 1, 1, 1, 1).advance_width; -} - -Optional Typeface::font_program() const -{ - if (m_fpgm.has_value()) - return m_fpgm->program_data(); - return {}; -} - -Optional Typeface::control_value_program() const -{ - if (m_prep.has_value()) - return m_prep->program_data(); - return {}; -} - -Optional Typeface::glyph_program(u32 glyph_id) const -{ - if (!m_loca.has_value() || !m_glyf.has_value()) { - return {}; - } - - auto glyph_offset = m_loca->get_glyph_offset(glyph_id); - auto glyph = m_glyf->glyph(glyph_offset); - if (!glyph.has_value()) - return {}; - return glyph->program(); -} - u32 Typeface::glyph_id_for_code_point(u32 code_point) const { return glyph_page(code_point / GlyphPage::glyphs_per_page).glyph_ids[code_point % GlyphPage::glyphs_per_page]; @@ -719,28 +537,5 @@ void Typeface::populate_glyph_page(GlyphPage& glyph_page, size_t page_index) con glyph_page.glyph_ids[i] = m_cmap->glyph_id_for_code_point(code_point); } } -bool Typeface::has_color_bitmaps() const -{ - return m_cblc.has_value() && m_cbdt.has_value(); -} - -RefPtr Typeface::color_bitmap(u32 glyph_id) const -{ - return embedded_bitmap_data_for_glyph(glyph_id).visit( - [&](EmbeddedBitmapWithFormat17 const& data) -> RefPtr { - auto data_slice = ReadonlyBytes { data.format17.data, static_cast(data.format17.data_len) }; - auto decoder = Gfx::PNGImageDecoderPlugin::create(data_slice).release_value_but_fixme_should_propagate_errors(); - auto frame = decoder->frame(0); - if (frame.is_error()) { - dbgln("PNG decode failed"); - return nullptr; - } - return frame.value().image; - }, - [&](Empty) -> RefPtr { - // Unsupported format or no image for this glyph ID. - return nullptr; - }); -} } diff --git a/Userland/Libraries/LibGfx/Font/OpenType/Typeface.h b/Userland/Libraries/LibGfx/Font/OpenType/Typeface.h index 5523218fbbe..5857f473400 100644 --- a/Userland/Libraries/LibGfx/Font/OpenType/Typeface.h +++ b/Userland/Libraries/LibGfx/Font/OpenType/Typeface.h @@ -58,7 +58,6 @@ public: virtual Gfx::ScaledGlyphMetrics glyph_metrics(u32 glyph_id, float x_scale, float y_scale, float point_width, float point_height) const override; virtual float glyph_advance(u32 glyph_id, float x_scale, float y_scale, float point_width, float point_height) const override; virtual float glyphs_horizontal_kerning(u32 left_glyph_id, u32 right_glyph_id, float x_scale) const override; - virtual bool append_glyph_path_to(Gfx::DeprecatedPath&, u32 glyph_id, float x_scale, float y_scale) const override; virtual u32 glyph_count() const override; virtual u16 units_per_em() const override; virtual u32 glyph_id_for_code_point(u32 code_point) const override; @@ -67,12 +66,6 @@ public: virtual u16 weight() const override; virtual u16 width() const override; virtual u8 slope() const override; - virtual bool is_fixed_width() const override; - virtual bool has_color_bitmaps() const override; - - Optional font_program() const; - Optional control_value_program() const; - Optional glyph_program(u32 glyph_id) const; // https://learn.microsoft.com/en-us/typography/opentype/spec/otff // "OpenType fonts that contain TrueType outlines should use the value of 0x00010000 for the sfntVersion. @@ -92,26 +85,6 @@ protected: virtual unsigned ttc_index() const override { return m_ttc_index; } private: - struct AscenderAndDescender { - i16 ascender; - i16 descender; - }; - - AscenderAndDescender resolve_ascender_and_descender() const; - - Optional extract_and_append_glyph_path_to(Gfx::DeprecatedPath&, u32 glyph_id, i16 ascender, i16 descender, float x_scale, float y_scale) const; - - RefPtr color_bitmap(u32 glyph_id) const; - - struct EmbeddedBitmapWithFormat17 { - CBLC::BitmapSize const& bitmap_size; - CBDT::Format17 const& format17; - }; - - using EmbeddedBitmapData = Variant; - - EmbeddedBitmapData embedded_bitmap_data_for_glyph(u32 glyph_id) const; - static ErrorOr> try_load_from_offset(ReadonlyBytes, u32 offset, Options options); Typeface( @@ -125,10 +98,6 @@ private: Optional&& glyf, Optional os2, Optional&& kern, - Optional fpgm, - Optional prep, - Optional cblc, - Optional cbdt, Optional gpos, ReadonlyBytes buffer, unsigned ttc_index) @@ -144,10 +113,6 @@ private: , m_cmap(move(cmap)) , m_os2(move(os2)) , m_kern(move(kern)) - , m_fpgm(move(fpgm)) - , m_prep(move(prep)) - , m_cblc(move(cblc)) - , m_cbdt(move(cbdt)) , m_gpos(move(gpos)) { } @@ -167,10 +132,6 @@ private: NonnullOwnPtr m_cmap; Optional m_os2; Optional m_kern; - Optional m_fpgm; - Optional m_prep; - Optional m_cblc; - Optional m_cbdt; Optional m_gpos; // This cache stores information per code point. diff --git a/Userland/Libraries/LibGfx/Font/ScaledFont.cpp b/Userland/Libraries/LibGfx/Font/ScaledFont.cpp index afa3c6cfaaa..48a5e47375b 100644 --- a/Userland/Libraries/LibGfx/Font/ScaledFont.cpp +++ b/Userland/Libraries/LibGfx/Font/ScaledFont.cpp @@ -63,11 +63,6 @@ ALWAYS_INLINE float ScaledFont::unicode_view_width(T const& view) const return longest_width; } -bool ScaledFont::append_glyph_path_to(Gfx::DeprecatedPath& path, u32 glyph_id) const -{ - return m_typeface->append_glyph_path_to(path, glyph_id, m_x_scale, m_y_scale); -} - float ScaledFont::glyph_left_bearing(u32 code_point) const { auto id = glyph_id_for_code_point(code_point); @@ -83,10 +78,8 @@ float ScaledFont::glyph_width(u32 code_point) const template static float glyph_or_emoji_width_impl(ScaledFont const& font, CodePointIterator& it) { - if (!font.has_color_bitmaps()) { - if (auto const* emoji = Emoji::emoji_for_code_point_iterator(it)) - return font.pixel_size() * emoji->width() / emoji->height(); - } + if (auto const* emoji = Emoji::emoji_for_code_point_iterator(it)) + return font.pixel_size() * emoji->width() / emoji->height(); return font.glyph_width(*it); } diff --git a/Userland/Libraries/LibGfx/Font/ScaledFont.h b/Userland/Libraries/LibGfx/Font/ScaledFont.h index 83157242280..a9e011bba06 100644 --- a/Userland/Libraries/LibGfx/Font/ScaledFont.h +++ b/Userland/Libraries/LibGfx/Font/ScaledFont.h @@ -35,7 +35,6 @@ public: virtual float glyph_or_emoji_width(Utf8CodePointIterator&) const override; virtual float glyphs_horizontal_kerning(u32 left_code_point, u32 right_code_point) const override; virtual u32 glyph_id_for_code_point(u32 code_point) const override { return m_typeface->glyph_id_for_code_point(code_point); } - virtual bool append_glyph_path_to(Gfx::DeprecatedPath&, u32 glyph_id) const override; virtual float preferred_line_height() const override { return metrics().height() + metrics().line_gap; } virtual int x_height() const override { return m_point_height; } // FIXME: Read from font virtual u8 baseline() const override { return m_point_height; } // FIXME: Read from font @@ -47,8 +46,6 @@ public: virtual NonnullRefPtr scaled_with_size(float point_size) const; virtual NonnullRefPtr with_size(float point_size) const override; - virtual bool has_color_bitmaps() const override { return m_typeface->has_color_bitmaps(); } - virtual Typeface const& typeface() const override { return m_typeface; } SkFont skia_font(float scale) const; diff --git a/Userland/Libraries/LibGfx/Font/Typeface.h b/Userland/Libraries/LibGfx/Font/Typeface.h index 95f2e2332c1..18d50cf5939 100644 --- a/Userland/Libraries/LibGfx/Font/Typeface.h +++ b/Userland/Libraries/LibGfx/Font/Typeface.h @@ -51,7 +51,6 @@ public: virtual ScaledGlyphMetrics glyph_metrics(u32 glyph_id, float x_scale, float y_scale, float point_width, float point_height) const = 0; virtual float glyph_advance(u32 glyph_id, float x_scale, float y_scale, float point_width, float point_height) const = 0; virtual float glyphs_horizontal_kerning(u32 left_glyph_id, u32 right_glyph_id, float x_scale) const = 0; - virtual bool append_glyph_path_to(Gfx::DeprecatedPath&, u32 glyph_id, float x_scale, float y_scale) const = 0; virtual u32 glyph_count() const = 0; virtual u16 units_per_em() const = 0; @@ -61,8 +60,6 @@ public: virtual u16 weight() const = 0; virtual u16 width() const = 0; virtual u8 slope() const = 0; - virtual bool is_fixed_width() const = 0; - virtual bool has_color_bitmaps() const = 0; [[nodiscard]] NonnullRefPtr scaled_font(float point_size) const; diff --git a/Userland/Libraries/LibGfx/TextLayout.cpp b/Userland/Libraries/LibGfx/TextLayout.cpp index 4894a0d5be0..afa68e77fa4 100644 --- a/Userland/Libraries/LibGfx/TextLayout.cpp +++ b/Userland/Libraries/LibGfx/TextLayout.cpp @@ -14,33 +14,8 @@ namespace Gfx { -static DrawGlyphOrEmoji construct_glyph_or_emoji(size_t index, FloatPoint const& position, Gfx::Font const& font, Span glyph_info, Span input_glyph_info) +static DrawGlyphOrEmoji construct_glyph_or_emoji(size_t index, FloatPoint const& position, Gfx::Font const&, Span glyph_info, Span) { - if (font.has_color_bitmaps()) { - auto cluster_start = glyph_info[index].cluster; - auto cluster_end = [&]() -> u32 { - if (index + 1 < glyph_info.size()) - return glyph_info[index + 1].cluster; - return input_glyph_info.last().cluster + 1; - }(); - - Vector cluster; - for (size_t j = 0; j < input_glyph_info.size(); ++j) { - auto const& glyph = input_glyph_info[j]; - if (glyph.cluster >= cluster_end) - break; - if (glyph.cluster >= cluster_start) - cluster.append(glyph.codepoint); - } - - if (auto const* emoji = Emoji::emoji_for_code_points(cluster)) { - return DrawEmoji { - .position = position, - .emoji = emoji, - }; - } - } - return DrawGlyph { .position = position, .glyph_id = glyph_info[index].codepoint, diff --git a/Userland/Utilities/ttfdisasm.cpp b/Userland/Utilities/ttfdisasm.cpp deleted file mode 100644 index 0c638643389..00000000000 --- a/Userland/Utilities/ttfdisasm.cpp +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (c) 2023, MacDue - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include - -using namespace OpenType::Hinting; - -#define YELLOW "\e[33m" -#define CYAN "\e[36m" -#define PURPLE "\e[95m" -#define GREEN "\e[92m" -#define RESET "\e[0m" -#define GRAY "\e[90m" - -struct InstructionPrinter : InstructionHandler { - InstructionPrinter(bool enable_highlighting) - : m_enable_highlighting(enable_highlighting) - { - } - - void before_operation(InstructionStream& stream, Opcode opcode) override - { - if (opcode == Opcode::FDEF && stream.current_position() > 1 && m_indent_level == 1) - outln(); - switch (opcode) { - case Opcode::EIF: - case Opcode::ELSE: - case Opcode::ENDF: - m_indent_level--; - break; - default: - break; - } - auto digits = int(AK::log10(float(stream.length()))) + 1; - if (m_enable_highlighting) - out(GRAY); - out("{:0{}}:", stream.current_position() - 1, digits); - if (m_enable_highlighting) - out(RESET); - out("{:{}}", ""sv, m_indent_level * 2); - } - - void after_operation(InstructionStream&, Opcode opcode) override - { - switch (opcode) { - case Opcode::IF: - case Opcode::ELSE: - case Opcode::IDEF: - case Opcode::FDEF: - m_indent_level++; - break; - default: - break; - } - } - - void print_number(u16 value) - { - if (m_enable_highlighting) - return out(GREEN " {}" RESET, value); - return out(" {}", value); - } - - void print_bytes(ReadonlyBytes bytes, bool first = true) - { - for (auto value : bytes) { - if (!first) - out(","); - print_number(value); - first = false; - } - } - - void print_words(ReadonlyBytes bytes, bool first = true) - { - for (size_t i = 0; i < bytes.size(); i += 2) { - if (!first) - out(","); - print_number(bytes[i] << 8 | bytes[i + 1]); - first = false; - } - } - - void default_handler(Context context) override - { - auto instruction = context.instruction(); - auto name = opcode_mnemonic(instruction.opcode()); - if (m_enable_highlighting) - out(YELLOW); - out(name); - if (m_enable_highlighting) - out(CYAN); - out("["); - if (m_enable_highlighting) - out(PURPLE); - if (instruction.flag_bits() > 0) - out("{:0{}b}", to_underlying(instruction.opcode()) & ((1 << instruction.flag_bits()) - 1), instruction.flag_bits()); - if (m_enable_highlighting) - out(CYAN); - out("]"); - if (m_enable_highlighting) - out(RESET); - switch (instruction.opcode()) { - case Opcode::NPUSHB... Opcode::NPUSHB_MAX: - print_number(instruction.values().size()); - print_bytes(instruction.values(), false); - break; - case Opcode::NPUSHW... Opcode::NPUSHW_MAX: - print_number(instruction.values().size() / 2); - print_words(instruction.values(), false); - break; - case Opcode::PUSHB... Opcode::PUSHB_MAX: - print_bytes(instruction.values()); - break; - case Opcode::PUSHW... Opcode::PUSHW_MAX: - print_words(instruction.values()); - break; - default: - break; - } - outln(); - } - -private: - bool m_enable_highlighting; - u32 m_indent_level { 1 }; -}; - -static bool s_disassembly_attempted = false; - -static void print_disassembly(StringView name, Optional program, bool enable_highlighting, u32 code_point = 0) -{ - s_disassembly_attempted = true; - if (!program.has_value()) { - out(name, code_point); - outln(": not found"); - return; - } - out(name, code_point); - outln(": ({} bytes)\n", program->size()); - InstructionPrinter printer { enable_highlighting }; - InstructionStream stream { printer, *program }; - while (!stream.at_end()) - stream.process_next_instruction(); -} - -ErrorOr serenity_main(Main::Arguments arguments) -{ - Core::ArgsParser args_parser; - - StringView font_path; - bool no_color = false; - bool dump_font_program = false; - bool dump_prep_program = false; - StringView text; - args_parser.add_positional_argument(font_path, "Path to font", "FILE"); - args_parser.add_option(dump_font_program, "Disassemble font program (fpgm table)", "disasm-fpgm", 'f'); - args_parser.add_option(dump_prep_program, "Disassemble CVT program (prep table)", "disasm-prep", 'p'); - args_parser.add_option(text, "Disassemble glyph programs", "disasm-glyphs", 'g', "text"); - args_parser.add_option(no_color, "Disable syntax highlighting", "no-color", 'n'); - args_parser.parse(arguments); - - auto resource = TRY(Core::Resource::load_from_filesystem(font_path)); - auto font = TRY(OpenType::Typeface::try_load_from_resource(resource)); - - if (dump_font_program) - print_disassembly("Font program"sv, font->font_program(), !no_color); - if (dump_prep_program) { - if (dump_font_program) - outln(); - print_disassembly("CVT program"sv, font->control_value_program(), !no_color); - } - if (!text.is_empty()) { - Utf8View utf8_view { text }; - bool first = !(dump_font_program || dump_prep_program); - for (u32 code_point : utf8_view) { - if (!first) - outln(); - auto glyph_id = font->glyph_id_for_code_point(code_point); - print_disassembly("Glyph program for codepoint {}"sv, font->glyph_program(glyph_id), !no_color, code_point); - first = false; - } - } - - if (!s_disassembly_attempted) { - args_parser.print_usage(stderr, arguments.strings[0]); - return 1; - } - return 0; -}