summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibTTF/Glyf.h
blob: 0497bc72905d94439cde105c3f309b2a259a330b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/*
 * Copyright (c) 2020, Srimanta Barua <srimanta.barua1@gmail.com>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#pragma once

#include <AK/Span.h>
#include <AK/Vector.h>
#include <LibGfx/AffineTransform.h>
#include <LibGfx/Bitmap.h>
#include <LibTTF/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(const ReadonlyBytes&, u32 num_glyphs, IndexToLocFormat);
    u32 get_glyph_offset(u32 glyph_id) const;

private:
    Loca(const ReadonlyBytes& slice, u32 num_glyphs, IndexToLocFormat index_to_loc_format)
        : m_slice(slice)
        , m_num_glyphs(num_glyphs)
        , m_index_to_loc_format(index_to_loc_format)
    {
    }

    ReadonlyBytes m_slice;
    u32 m_num_glyphs { 0 };
    IndexToLocFormat m_index_to_loc_format;
};

class Glyf {
public:
    class Glyph {
    public:
        Glyph(const ReadonlyBytes& 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(slice)
        {
            if (m_num_contours >= 0) {
                m_type = Type::Simple;
            }
        }
        template<typename GlyphCb>
        RefPtr<Gfx::Bitmap> raster(float x_scale, float y_scale, GlyphCb glyph_callback) const
        {
            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);
            }
            VERIFY_NOT_REACHED();
        }
        int ascender() const { return m_ymax; }
        int descender() const { return m_ymin; }

    private:
        enum class Type {
            Simple,
            Composite,
        };

        class ComponentIterator {
        public:
            struct Item {
                u16 glyph_id;
                Gfx::AffineTransform affine;
            };

            ComponentIterator(const ReadonlyBytes& slice)
                : m_slice(slice)
            {
            }
            Optional<Item> next();

        private:
            ReadonlyBytes 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.multiply(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 { 0 };
        i16 m_ymin { 0 };
        i16 m_xmax { 0 };
        i16 m_ymax { 0 };
        i16 m_num_contours { -1 };
        ReadonlyBytes m_slice;
    };

    Glyf(const ReadonlyBytes& slice)
        : m_slice(slice)
    {
    }
    Glyph glyph(u32 offset) const;

private:
    enum class Offsets {
        XMin = 2,
        YMin = 4,
        XMax = 6,
        YMax = 8,
    };
    enum class Sizes {
        GlyphHeader = 10,
    };

    ReadonlyBytes m_slice;
};

}