1
0
mirror of https://github.com/SerenityOS/serenity synced 2024-07-09 14:30:46 +00:00

LibPDF: Index Type1 glyphs by name, not char code

Storing glyphs indexed by char code in a Type1 Font Program binds a Font
Program instance to the particular Encoding that was used at Font
Program construction time. This makes it difficult to reuse Font Program
instances against different Encodings, which would be otherwise
possible.

This commit changes how we store the glyphs on Type1 Font Programs.
Instead of storing them on a map indexed by char code, the map is now
indexed by glyph name. In turn, when rendering a glyph we use the
Encoding object to turn the char code into a glyph name, which in turn
is used to index into the map of glyphs.

This is the first step towards reusability of Type1 Font Programs. It
also unlocks the ability to render glyphs that are described via the
"seac" command (standard encoding accented character), which requires
accessing the base and accent glyphs by name.
This commit is contained in:
Rodrigo Tobar 2023-02-05 14:04:48 +08:00 committed by Andreas Kling
parent f99c9dc11a
commit c084943457
5 changed files with 25 additions and 27 deletions

View File

@ -108,29 +108,27 @@ PDFErrorOr<NonnullRefPtr<CFF>> CFF::create(ReadonlyBytes const& cff_bytes, RefPt
glyph.width += float(nominalWidthX);
}
for (size_t i = 0; i < glyphs.size(); i++) {
if (i == 0) {
TRY(cff->add_glyph(0, move(glyphs[0])));
continue;
}
auto const& name = charset[i - 1];
TRY(cff->add_glyph(name, move(glyphs[i])));
}
// Encoding given or read
if (encoding) {
for (size_t i = 0; i < glyphs.size(); i++) {
if (i == 0) {
TRY(cff->add_glyph(0, move(glyphs[0])));
continue;
}
auto const& name = charset[i - 1];
u16 code = encoding->get_char_code(name);
TRY(cff->add_glyph(code, move(glyphs[i])));
}
cff->set_encoding(move(encoding));
} else {
auto encoding = Encoding::create();
for (size_t i = 0; i < glyphs.size(); i++) {
if (i == 0) {
TRY(cff->add_glyph(0, move(glyphs[0])));
encoding->set(0, ".notdef");
continue;
}
auto code = encoding_codes[i - 1];
auto char_name = charset[i - 1];
TRY(cff->add_glyph(code, move(glyphs[i])));
encoding->set(code, char_name);
}
cff->set_encoding(move(encoding));

View File

@ -92,9 +92,8 @@ PDFErrorOr<void> PS1FontProgram::parse_encrypted_portion(ByteBuffer const& buffe
auto line = TRY(decrypt(reader.bytes().slice(reader.offset(), encrypted_size), m_encryption_key, m_lenIV));
reader.move_by(encrypted_size);
auto glyph_name = word.substring_view(1);
auto char_code = encoding()->get_char_code(glyph_name);
GlyphParserState state;
TRY(add_glyph(char_code, TRY(parse_glyph(line, subroutines, state, false))));
TRY(add_glyph(glyph_name, TRY(parse_glyph(line, subroutines, state, false))));
}
}
}

View File

@ -86,7 +86,8 @@ void Type1Font::draw_glyph(Gfx::Painter& painter, Gfx::FloatPoint point, float w
return;
}
auto translation = m_data.font_program->glyph_translation(char_code, width);
auto char_name = m_data.encoding->get_name(char_code);
auto translation = m_data.font_program->glyph_translation(char_name, width);
point = point.translated(translation);
auto glyph_position = Gfx::GlyphRasterPosition::get_nearest_fit_for(point);
@ -97,7 +98,7 @@ void Type1Font::draw_glyph(Gfx::Painter& painter, Gfx::FloatPoint point, float w
if (maybe_bitmap.has_value()) {
bitmap = maybe_bitmap.value();
} else {
bitmap = m_data.font_program->rasterize_glyph(char_code, width, glyph_position.subpixel_offset);
bitmap = m_data.font_program->rasterize_glyph(char_name, width, glyph_position.subpixel_offset);
m_glyph_cache.set(index, bitmap);
}

View File

@ -52,9 +52,9 @@ enum ExtendedCommand {
Flex1,
};
RefPtr<Gfx::Bitmap> Type1FontProgram::rasterize_glyph(u32 char_code, float width, Gfx::GlyphSubpixelOffset subpixel_offset)
RefPtr<Gfx::Bitmap> Type1FontProgram::rasterize_glyph(DeprecatedFlyString const& char_name, float width, Gfx::GlyphSubpixelOffset subpixel_offset)
{
auto path = build_char(char_code, width, subpixel_offset);
auto path = build_char(char_name, width, subpixel_offset);
auto bounding_box = path.bounding_box().size();
u32 w = (u32)ceilf(bounding_box.width()) + 2;
@ -65,9 +65,9 @@ RefPtr<Gfx::Bitmap> Type1FontProgram::rasterize_glyph(u32 char_code, float width
return rasterizer.accumulate();
}
Gfx::Path Type1FontProgram::build_char(u32 char_code, float width, Gfx::GlyphSubpixelOffset subpixel_offset)
Gfx::Path Type1FontProgram::build_char(DeprecatedFlyString const& char_name, float width, Gfx::GlyphSubpixelOffset subpixel_offset)
{
auto maybe_glyph = m_glyph_map.get(char_code);
auto maybe_glyph = m_glyph_map.get(char_name);
if (!maybe_glyph.has_value())
return {};
@ -84,9 +84,9 @@ Gfx::Path Type1FontProgram::build_char(u32 char_code, float width, Gfx::GlyphSub
return glyph.path.copy_transformed(transform);
}
Gfx::FloatPoint Type1FontProgram::glyph_translation(u32 char_code, float width) const
Gfx::FloatPoint Type1FontProgram::glyph_translation(DeprecatedFlyString const& char_name, float width) const
{
auto maybe_glyph = m_glyph_map.get(char_code);
auto maybe_glyph = m_glyph_map.get(char_name);
if (!maybe_glyph.has_value())
return {};

View File

@ -20,8 +20,8 @@ class Encoding;
class Type1FontProgram : public RefCounted<Type1FontProgram> {
public:
RefPtr<Gfx::Bitmap> rasterize_glyph(u32 char_code, float width, Gfx::GlyphSubpixelOffset subpixel_offset);
Gfx::FloatPoint glyph_translation(u32 char_code, float width) const;
RefPtr<Gfx::Bitmap> rasterize_glyph(DeprecatedFlyString const& char_name, float width, Gfx::GlyphSubpixelOffset subpixel_offset);
Gfx::FloatPoint glyph_translation(DeprecatedFlyString const& char_name, float width) const;
RefPtr<Encoding> encoding() const { return m_encoding; }
protected:
@ -68,18 +68,18 @@ protected:
m_font_matrix = move(font_matrix);
}
PDFErrorOr<void> add_glyph(u16 char_code, Glyph&& glyph)
PDFErrorOr<void> add_glyph(DeprecatedFlyString name, Glyph&& glyph)
{
TRY(m_glyph_map.try_set(char_code, glyph));
TRY(m_glyph_map.try_set(move(name), move(glyph)));
return {};
}
private:
HashMap<u16, Glyph> m_glyph_map;
HashMap<DeprecatedFlyString, Glyph> m_glyph_map;
Gfx::AffineTransform m_font_matrix;
RefPtr<Encoding> m_encoding;
Gfx::Path build_char(u32 char_code, float width, Gfx::GlyphSubpixelOffset subpixel_offset);
Gfx::Path build_char(DeprecatedFlyString const& char_name, float width, Gfx::GlyphSubpixelOffset subpixel_offset);
Gfx::AffineTransform glyph_transform_to_device_space(Glyph const& glyph, float width) const;
};