mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 15:57:45 +00:00
LibTTF: Initial work on parsing and rasterizing composite glyphs.
This doesn't handle every case yet.
This commit is contained in:
parent
bd354bc2ae
commit
1e1d2cdedf
4 changed files with 328 additions and 220 deletions
|
@ -38,6 +38,15 @@ public:
|
|||
: m_values { 1, 0, 0, 1, 0, 0 }
|
||||
{
|
||||
}
|
||||
AffineTransform(float a, float b, float c, float d, float e, float f)
|
||||
{
|
||||
m_values[0] = a;
|
||||
m_values[1] = b;
|
||||
m_values[2] = c;
|
||||
m_values[3] = d;
|
||||
m_values[4] = e;
|
||||
m_values[5] = f;
|
||||
}
|
||||
|
||||
AffineTransform(float a, float b, float c, float d, float e, float f)
|
||||
: m_values { a, b, c, d, e, f }
|
||||
|
@ -72,6 +81,8 @@ public:
|
|||
AffineTransform& rotate_radians(float);
|
||||
AffineTransform& multiply(const AffineTransform&);
|
||||
|
||||
AffineTransform operator*(const AffineTransform&) const;
|
||||
|
||||
private:
|
||||
float m_values[6] { 0 };
|
||||
};
|
||||
|
|
|
@ -49,6 +49,11 @@ i16 be_i16(const u8* ptr)
|
|||
return (((i16) ptr[0]) << 8) | ((i16) ptr[1]);
|
||||
}
|
||||
|
||||
float be_fword(const u8* ptr)
|
||||
{
|
||||
return (float) be_i16(ptr) / (float) (1 << 14);
|
||||
}
|
||||
|
||||
u32 tag_from_str(const char *str)
|
||||
{
|
||||
return be_u32((const u8*) str);
|
||||
|
@ -122,6 +127,27 @@ u16 Font::Hhea::number_of_h_metrics() const
|
|||
return be_u16(m_slice.offset_pointer((u32) Offsets::NumberOfHMetrics));
|
||||
}
|
||||
|
||||
Font::GlyphHorizontalMetrics Font::Hmtx::get_glyph_horizontal_metrics(u32 glyph_id) const
|
||||
{
|
||||
ASSERT(glyph_id < m_num_glyphs);
|
||||
if (glyph_id < m_number_of_h_metrics) {
|
||||
auto offset = glyph_id * (u32) Sizes::LongHorMetric;
|
||||
u16 advance_width = be_u16(m_slice.offset_pointer(offset));
|
||||
i16 left_side_bearing = be_i16(m_slice.offset_pointer(offset + 2));
|
||||
return GlyphHorizontalMetrics {
|
||||
.advance_width = advance_width,
|
||||
.left_side_bearing = left_side_bearing,
|
||||
};
|
||||
}
|
||||
auto offset = m_number_of_h_metrics * (u32) Sizes::LongHorMetric + (glyph_id - m_number_of_h_metrics) * (u32) Sizes::LeftSideBearing;
|
||||
u16 advance_width = be_u16(m_slice.offset_pointer((m_number_of_h_metrics - 1) * (u32) Sizes::LongHorMetric));
|
||||
i16 left_side_bearing = be_i16(m_slice.offset_pointer(offset));
|
||||
return GlyphHorizontalMetrics {
|
||||
.advance_width = advance_width,
|
||||
.left_side_bearing = left_side_bearing,
|
||||
};
|
||||
}
|
||||
|
||||
u16 Font::Maxp::num_glyphs() const
|
||||
{
|
||||
return be_u16(m_slice.offset_pointer((u32) Offsets::NumGlyphs));
|
||||
|
@ -287,7 +313,13 @@ RefPtr<Gfx::Bitmap> Font::raster_glyph(u32 glyph_id, float x_scale, float y_scal
|
|||
}
|
||||
auto glyph_offset = m_loca.get_glyph_offset(glyph_id);
|
||||
auto glyph = m_glyf.glyph(glyph_offset);
|
||||
return glyph.raster(x_scale, y_scale);
|
||||
return glyph.raster(x_scale, y_scale, [&](u16 glyph_id) {
|
||||
if (glyph_id >= m_maxp.num_glyphs()) {
|
||||
glyph_id = 0;
|
||||
}
|
||||
auto glyph_offset = m_loca.get_glyph_offset(glyph_id);
|
||||
return m_glyf.glyph(glyph_offset);
|
||||
});
|
||||
}
|
||||
|
||||
int ScaledFont::width(const StringView& string) const
|
||||
|
|
|
@ -27,12 +27,15 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/ByteBuffer.h>
|
||||
#include <AK/FixedArray.h>
|
||||
#include <AK/Noncopyable.h>
|
||||
#include <AK/Optional.h>
|
||||
#include <AK/RefCounted.h>
|
||||
#include <AK/StringView.h>
|
||||
#include <LibGfx/AffineTransform.h>
|
||||
#include <LibGfx/Bitmap.h>
|
||||
#include <LibGfx/Size.h>
|
||||
#include <math.h>
|
||||
|
||||
#define POINTS_PER_INCH 72.0f
|
||||
#define DEFAULT_DPI 96
|
||||
|
@ -64,7 +67,7 @@ class Font : public RefCounted<Font> {
|
|||
AK_MAKE_NONCOPYABLE(Font);
|
||||
|
||||
public:
|
||||
static RefPtr<Font> load_from_file(const StringView& path, unsigned index);
|
||||
static RefPtr<Font> load_from_file(const StringView& path, unsigned index = 0);
|
||||
|
||||
private:
|
||||
enum class Offsets {
|
||||
|
@ -84,6 +87,19 @@ private:
|
|||
RefPtr<Gfx::Bitmap> raster_glyph(u32 glyph_id, float x_scale, float y_scale) const;
|
||||
u32 glyph_count() const { return m_maxp.num_glyphs(); }
|
||||
|
||||
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;
|
||||
FixedArray<float> m_data;
|
||||
};
|
||||
|
||||
enum class IndexToLocFormat {
|
||||
Offset16,
|
||||
Offset32,
|
||||
|
@ -327,54 +343,87 @@ private:
|
|||
public:
|
||||
class Glyph {
|
||||
public:
|
||||
static Glyph simple(const ByteBuffer& slice, u16 num_contours, i16 xmin, i16 ymin, i16 xmax, i16 ymax);
|
||||
static Glyph composite(const ByteBuffer& slice); // FIXME: This is currently just a dummy. Need to add support for composite glyphs.
|
||||
RefPtr<Gfx::Bitmap> raster(float x_scale, float y_scale) const;
|
||||
int ascender() const
|
||||
Glyph(const ByteBuffer& slice, i16 xmin, i16 ymin, i16 xmax, i16 ymax, i16 num_contours = -1)
|
||||
: m_xmin(xmin)
|
||||
, m_ymin(ymin)
|
||||
, m_xmax(xmax)
|
||||
, m_ymax(ymax)
|
||||
, m_num_contours(num_contours)
|
||||
, m_slice(move(slice))
|
||||
{
|
||||
if (m_type == Type::Simple) {
|
||||
return m_meta.simple.ymax;
|
||||
if (m_num_contours >= 0) {
|
||||
m_type = Type::Simple;
|
||||
}
|
||||
// FIXME: Support composite outlines.
|
||||
TODO();
|
||||
}
|
||||
int descender() const
|
||||
template <typename GlyphCb>
|
||||
RefPtr<Gfx::Bitmap> raster(float x_scale, float y_scale, GlyphCb glyph_callback) const
|
||||
{
|
||||
if (m_type == Type::Simple) {
|
||||
return m_meta.simple.ymin;
|
||||
switch (m_type) {
|
||||
case Type::Simple:
|
||||
return raster_simple(x_scale, y_scale);
|
||||
case Type::Composite:
|
||||
return raster_composite(x_scale, y_scale, glyph_callback);
|
||||
}
|
||||
// FIXME: Support composite outlines.
|
||||
TODO();
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
int ascender() const { return m_ymax; }
|
||||
int descender() const { return m_ymin; }
|
||||
|
||||
private:
|
||||
enum class Type {
|
||||
Simple,
|
||||
Composite,
|
||||
};
|
||||
struct Simple {
|
||||
u16 num_contours;
|
||||
i16 xmin;
|
||||
i16 ymin;
|
||||
i16 xmax;
|
||||
i16 ymax;
|
||||
};
|
||||
struct Composite {
|
||||
|
||||
class ComponentIterator {
|
||||
public:
|
||||
struct Item {
|
||||
u16 glyph_id;
|
||||
Gfx::AffineTransform affine;
|
||||
};
|
||||
|
||||
Glyph(const ByteBuffer& slice, Type type)
|
||||
: m_type(type)
|
||||
, m_slice(move(slice))
|
||||
ComponentIterator(const ByteBuffer& slice)
|
||||
: m_slice(slice)
|
||||
{
|
||||
}
|
||||
RefPtr<Gfx::Bitmap> raster_simple(float x_scale, float y_scale) const;
|
||||
Optional<Item> next();
|
||||
|
||||
Type m_type;
|
||||
private:
|
||||
ByteBuffer m_slice;
|
||||
bool m_has_more { true };
|
||||
u32 m_offset { 0 };
|
||||
};
|
||||
|
||||
void raster_inner(Rasterizer&, Gfx::AffineTransform&) const;
|
||||
RefPtr<Gfx::Bitmap> raster_simple(float x_scale, float y_scale) const;
|
||||
template <typename GlyphCb>
|
||||
RefPtr<Gfx::Bitmap> raster_composite(float x_scale, float y_scale, GlyphCb glyph_callback) const
|
||||
{
|
||||
u32 width = (u32) (ceil((m_xmax - m_xmin) * x_scale)) + 1;
|
||||
u32 height = (u32) (ceil((m_ymax - m_ymin) * y_scale)) + 1;
|
||||
Rasterizer rasterizer(Gfx::IntSize(width, height));
|
||||
auto affine = Gfx::AffineTransform().scale(x_scale, -y_scale).translate(-m_xmin, -m_ymax);
|
||||
ComponentIterator component_iterator(m_slice);
|
||||
while (true) {
|
||||
auto opt_item = component_iterator.next();
|
||||
if (!opt_item.has_value()) {
|
||||
break;
|
||||
}
|
||||
auto item = opt_item.value();
|
||||
auto affine_here = affine * item.affine;
|
||||
auto glyph = glyph_callback(item.glyph_id);
|
||||
glyph.raster_inner(rasterizer, affine_here);
|
||||
}
|
||||
return rasterizer.accumulate();
|
||||
}
|
||||
|
||||
Type m_type { Type::Composite };
|
||||
i16 m_xmin;
|
||||
i16 m_ymin;
|
||||
i16 m_xmax;
|
||||
i16 m_ymax;
|
||||
i16 m_num_contours { -1 };
|
||||
ByteBuffer m_slice;
|
||||
union {
|
||||
Simple simple;
|
||||
Composite composite;
|
||||
} m_meta;
|
||||
};
|
||||
|
||||
Glyf() {}
|
||||
|
|
|
@ -25,16 +25,15 @@
|
|||
*/
|
||||
|
||||
#include "Font.h"
|
||||
#include <AK/FixedArray.h>
|
||||
#include <LibGfx/FloatPoint.h>
|
||||
#include <LibGfx/Path.h>
|
||||
#include <math.h>
|
||||
|
||||
namespace TTF {
|
||||
|
||||
extern u16 be_u16(const u8* ptr);
|
||||
extern u32 be_u32(const u8* ptr);
|
||||
extern i16 be_i16(const u8* ptr);
|
||||
extern float be_fword(const u8* ptr);
|
||||
|
||||
enum class SimpleGlyfFlags {
|
||||
// From spec.
|
||||
|
@ -55,6 +54,21 @@ enum class SimpleGlyfFlags {
|
|||
YPositiveShortVector = 0x24,
|
||||
};
|
||||
|
||||
enum class CompositeGlyfFlags {
|
||||
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 PointIterator {
|
||||
public:
|
||||
struct Item {
|
||||
|
@ -62,16 +76,13 @@ public:
|
|||
Gfx::FloatPoint point;
|
||||
};
|
||||
|
||||
PointIterator(const ByteBuffer& slice, u16 num_points, u32 flags_offset, u32 x_offset, u32 y_offset, float x_translate, float y_translate, float x_scale, float y_scale)
|
||||
PointIterator(const ByteBuffer& 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_x_translate(x_translate)
|
||||
, m_y_translate(y_translate)
|
||||
, m_x_scale(x_scale)
|
||||
, m_y_scale(y_scale)
|
||||
, m_affine(affine)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -119,11 +130,8 @@ public:
|
|||
m_points_remaining--;
|
||||
Item ret = {
|
||||
.on_curve = (m_flag & (u8) SimpleGlyfFlags::OnCurve) != 0,
|
||||
.point = m_last_point,
|
||||
.point = m_affine.map(m_last_point),
|
||||
};
|
||||
ret.point.move_by(m_x_translate, m_y_translate);
|
||||
ret.point.set_x(ret.point.x() * m_x_scale);
|
||||
ret.point.set_y(ret.point.y() * m_y_scale);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -136,15 +144,71 @@ private:
|
|||
u32 m_flags_offset;
|
||||
u32 m_x_offset;
|
||||
u32 m_y_offset;
|
||||
float m_x_translate;
|
||||
float m_y_translate;
|
||||
float m_x_scale;
|
||||
float m_y_scale;
|
||||
Gfx::AffineTransform m_affine;
|
||||
};
|
||||
|
||||
class Rasterizer {
|
||||
public:
|
||||
Rasterizer(Gfx::Size size)
|
||||
Optional<Font::Glyf::Glyph::ComponentIterator::Item> Font::Glyf::Glyph::ComponentIterator::next() {
|
||||
if (!m_has_more) {
|
||||
return {};
|
||||
}
|
||||
u16 flags = be_u16(m_slice.offset_pointer(m_offset));
|
||||
m_offset += 2;
|
||||
u16 glyph_id = be_u16(m_slice.offset_pointer(m_offset));
|
||||
m_offset += 2;
|
||||
i16 arg1 = 0, arg2 = 0;
|
||||
if (flags & (u16) CompositeGlyfFlags::Arg1AndArg2AreWords) {
|
||||
arg1 = be_i16(m_slice.offset_pointer(m_offset));
|
||||
m_offset += 2;
|
||||
arg2 = be_i16(m_slice.offset_pointer(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) CompositeGlyfFlags::WeHaveATwoByTwo) {
|
||||
a = be_fword(m_slice.offset_pointer(m_offset));
|
||||
m_offset += 2;
|
||||
b = be_fword(m_slice.offset_pointer(m_offset));
|
||||
m_offset += 2;
|
||||
c = be_fword(m_slice.offset_pointer(m_offset));
|
||||
m_offset += 2;
|
||||
d = be_fword(m_slice.offset_pointer(m_offset));
|
||||
m_offset += 2;
|
||||
} else if (flags & (u16) CompositeGlyfFlags::WeHaveAnXAndYScale) {
|
||||
a = be_fword(m_slice.offset_pointer(m_offset));
|
||||
m_offset += 2;
|
||||
d = be_fword(m_slice.offset_pointer(m_offset));
|
||||
m_offset += 2;
|
||||
} else if (flags & (u16) CompositeGlyfFlags::WeHaveAScale) {
|
||||
a = be_fword(m_slice.offset_pointer(m_offset));
|
||||
m_offset += 2;
|
||||
d = a;
|
||||
}
|
||||
// FIXME: Handle UseMyMetrics, ScaledComponentOffset, UnscaledComponentOffset, non-ArgsAreXYValues
|
||||
if (flags & (u16) CompositeGlyfFlags::ArgsAreXYValues) {
|
||||
e = arg1;
|
||||
f = arg2;
|
||||
} else {
|
||||
TODO();
|
||||
}
|
||||
if (flags & (u16) CompositeGlyfFlags::UseMyMetrics) {
|
||||
TODO();
|
||||
}
|
||||
if (flags & (u16) CompositeGlyfFlags::ScaledComponentOffset) {
|
||||
TODO();
|
||||
}
|
||||
if (flags & (u16) CompositeGlyfFlags::UnscaledComponentOffset) {
|
||||
TODO();
|
||||
}
|
||||
m_has_more = (flags & (u16) CompositeGlyfFlags::MoreComponents);
|
||||
return Item {
|
||||
.glyph_id = glyph_id,
|
||||
.affine = Gfx::AffineTransform(a, b, c, d, e, f),
|
||||
};
|
||||
}
|
||||
|
||||
Font::Rasterizer::Rasterizer(Gfx::IntSize size)
|
||||
: m_size(size)
|
||||
, m_data(m_size.width() * m_size.height())
|
||||
{
|
||||
|
@ -153,16 +217,14 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
RefPtr<Gfx::Bitmap> draw_path(Gfx::Path& path)
|
||||
void Font::Rasterizer::draw_path(Gfx::Path& path)
|
||||
{
|
||||
for (auto& line : path.split_lines()) {
|
||||
draw_line(line.from, line.to);
|
||||
}
|
||||
return accumulate();
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<Gfx::Bitmap> accumulate()
|
||||
RefPtr<Gfx::Bitmap> Font::Rasterizer::accumulate()
|
||||
{
|
||||
auto bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::RGBA32, m_size);
|
||||
Color base_color = Color::from_rgb(0xffffff);
|
||||
|
@ -184,10 +246,18 @@ private:
|
|||
return bitmap;
|
||||
}
|
||||
|
||||
void draw_line(Gfx::FloatPoint p0, Gfx::FloatPoint p1)
|
||||
void Font::Rasterizer::draw_line(Gfx::FloatPoint p0, Gfx::FloatPoint p1)
|
||||
{
|
||||
// FIXME: Shift x and y according to dy/dx
|
||||
if (p0.x() < 0.0) { p0.set_x(roundf(p0.x())); }
|
||||
if (p0.y() < 0.0) { p0.set_y(roundf(p0.y())); }
|
||||
if (p1.x() < 0.0) { p1.set_x(roundf(p1.x())); }
|
||||
if (p1.y() < 0.0) { p1.set_y(roundf(p1.y())); }
|
||||
|
||||
dbg() << "m_size: " << m_size << " | p0: (" << p0.x() << ", " << p0.y() << ") | p1: (" << p1.x() << ", " << p1.y() << ")";
|
||||
ASSERT(p0.x() >= 0.0 && p0.y() >= 0.0 && p0.x() <= m_size.width() && p0.y() <= m_size.height());
|
||||
ASSERT(p1.x() >= 0.0 && p1.y() >= 0.0 && 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;
|
||||
|
@ -249,31 +319,6 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
Gfx::Size m_size;
|
||||
FixedArray<float> m_data;
|
||||
};
|
||||
|
||||
Font::GlyphHorizontalMetrics Font::Hmtx::get_glyph_horizontal_metrics(u32 glyph_id) const
|
||||
{
|
||||
ASSERT(glyph_id < m_num_glyphs);
|
||||
if (glyph_id < m_number_of_h_metrics) {
|
||||
auto offset = glyph_id * (u32) Sizes::LongHorMetric;
|
||||
u16 advance_width = be_u16(m_slice.offset_pointer(offset));
|
||||
i16 left_side_bearing = be_i16(m_slice.offset_pointer(offset + 2));
|
||||
return GlyphHorizontalMetrics {
|
||||
.advance_width = advance_width,
|
||||
.left_side_bearing = left_side_bearing,
|
||||
};
|
||||
}
|
||||
auto offset = m_number_of_h_metrics * (u32) Sizes::LongHorMetric + (glyph_id - m_number_of_h_metrics) * (u32) Sizes::LeftSideBearing;
|
||||
u16 advance_width = be_u16(m_slice.offset_pointer((m_number_of_h_metrics - 1) * (u32) Sizes::LongHorMetric));
|
||||
i16 left_side_bearing = be_i16(m_slice.offset_pointer(offset));
|
||||
return GlyphHorizontalMetrics {
|
||||
.advance_width = advance_width,
|
||||
.left_side_bearing = left_side_bearing,
|
||||
};
|
||||
}
|
||||
|
||||
u32 Font::Loca::get_glyph_offset(u32 glyph_id) const
|
||||
{
|
||||
ASSERT(glyph_id < m_num_glyphs);
|
||||
|
@ -287,39 +332,6 @@ u32 Font::Loca::get_glyph_offset(u32 glyph_id) const
|
|||
}
|
||||
}
|
||||
|
||||
Font::Glyf::Glyph Font::Glyf::Glyph::simple(const ByteBuffer& slice, u16 num_contours, i16 xmin, i16 ymin, i16 xmax, i16 ymax)
|
||||
{
|
||||
auto ret = Glyph(slice, Type::Simple);
|
||||
ret.m_meta.simple = Simple {
|
||||
.num_contours = num_contours,
|
||||
.xmin = xmin,
|
||||
.ymin = ymin,
|
||||
.xmax = xmax,
|
||||
.ymax = ymax,
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
// FIXME: This is currently just a dummy. Need to add support for composite glyphs.
|
||||
Font::Glyf::Glyph Font::Glyf::Glyph::composite(const ByteBuffer& slice)
|
||||
{
|
||||
auto ret = Glyph(slice, Type::Composite);
|
||||
ret.m_meta.composite = Composite();
|
||||
return ret;
|
||||
}
|
||||
|
||||
RefPtr<Gfx::Bitmap> Font::Glyf::Glyph::raster(float x_scale, float y_scale) const
|
||||
{
|
||||
switch (m_type) {
|
||||
case Type::Simple:
|
||||
return raster_simple(x_scale, y_scale);
|
||||
case Type::Composite:
|
||||
// FIXME: Add support for composite glyphs
|
||||
TODO();
|
||||
}
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
static void get_ttglyph_offsets(const ByteBuffer& slice, u32 num_points, u32 flags_offset, u32 *x_offset, u32 *y_offset)
|
||||
{
|
||||
u32 flags_size = 0;
|
||||
|
@ -351,25 +363,22 @@ static void get_ttglyph_offsets(const ByteBuffer& slice, u32 num_points, u32 fla
|
|||
*y_offset = *x_offset + x_size;
|
||||
}
|
||||
|
||||
RefPtr<Gfx::Bitmap> Font::Glyf::Glyph::raster_simple(float x_scale, float y_scale) const
|
||||
void Font::Glyf::Glyph::raster_inner(Rasterizer& rasterizer, Gfx::AffineTransform& affine) const
|
||||
{
|
||||
auto simple = m_meta.simple;
|
||||
// Get offets for flags, x, and y.
|
||||
u16 num_points = be_u16(m_slice.offset_pointer((simple.num_contours - 1) * 2)) + 1;
|
||||
u16 num_instructions = be_u16(m_slice.offset_pointer(simple.num_contours * 2));
|
||||
u32 flags_offset = simple.num_contours * 2 + 2 + num_instructions;
|
||||
u16 num_points = be_u16(m_slice.offset_pointer((m_num_contours - 1) * 2)) + 1;
|
||||
u16 num_instructions = be_u16(m_slice.offset_pointer(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.
|
||||
u32 width = (u32) (ceil((simple.xmax - simple.xmin) * x_scale)) + 1;
|
||||
u32 height = (u32) (ceil((simple.ymax - simple.ymin) * y_scale)) + 1;
|
||||
Gfx::Path path;
|
||||
PointIterator point_iterator(m_slice, num_points, flags_offset, x_offset, y_offset, -simple.xmin, -simple.ymax, x_scale, -y_scale);
|
||||
PointIterator point_iterator(m_slice, num_points, flags_offset, x_offset, y_offset, affine);
|
||||
|
||||
int last_contour_end = -1;
|
||||
u32 contour_index = 0;
|
||||
i32 contour_index = 0;
|
||||
u32 contour_size = 0;
|
||||
Optional<Gfx::FloatPoint> contour_start = {};
|
||||
Optional<Gfx::FloatPoint> last_offcurve_point = {};
|
||||
|
@ -377,7 +386,7 @@ RefPtr<Gfx::Bitmap> Font::Glyf::Glyph::raster_simple(float x_scale, float y_scal
|
|||
// Render glyph
|
||||
while (true) {
|
||||
if (!contour_start.has_value()) {
|
||||
if (contour_index >= simple.num_contours) {
|
||||
if (contour_index >= m_num_contours) {
|
||||
break;
|
||||
}
|
||||
int current_contour_end = be_u16(m_slice.offset_pointer(contour_index++ * 2));
|
||||
|
@ -449,7 +458,17 @@ RefPtr<Gfx::Bitmap> Font::Glyf::Glyph::raster_simple(float x_scale, float y_scal
|
|||
}
|
||||
}
|
||||
|
||||
return Rasterizer(Gfx::Size(width, height)).draw_path(path);
|
||||
rasterizer.draw_path(path);
|
||||
}
|
||||
|
||||
RefPtr<Gfx::Bitmap> Font::Glyf::Glyph::raster_simple(float x_scale, float y_scale) const
|
||||
{
|
||||
u32 width = (u32) (ceil((m_xmax - m_xmin) * x_scale)) + 2;
|
||||
u32 height = (u32) (ceil((m_ymax - m_ymin) * y_scale)) + 2;
|
||||
Rasterizer rasterizer(Gfx::IntSize(width, height));
|
||||
auto affine = Gfx::AffineTransform().scale(x_scale, -y_scale).translate(-m_xmin, -m_ymax);
|
||||
raster_inner(rasterizer, affine);
|
||||
return rasterizer.accumulate();
|
||||
}
|
||||
|
||||
Font::Glyf::Glyph Font::Glyf::glyph(u32 offset) const
|
||||
|
@ -461,10 +480,7 @@ Font::Glyf::Glyph Font::Glyf::glyph(u32 offset) const
|
|||
i16 xmax = be_i16(m_slice.offset_pointer(offset + (u32) Offsets::XMax));
|
||||
i16 ymax = be_i16(m_slice.offset_pointer(offset + (u32) Offsets::YMax));
|
||||
auto slice = ByteBuffer::wrap(m_slice.offset_pointer(offset + (u32) Sizes::GlyphHeader), m_slice.size() - offset - (u32) Sizes::GlyphHeader);
|
||||
if (num_contours < 0) {
|
||||
return Glyph::composite(slice);
|
||||
}
|
||||
return Glyph::simple(slice, num_contours, xmin, ymin, xmax, ymax);
|
||||
return Glyph(slice, xmin, ymin, xmax, ymax, num_contours);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue