Skip to content

Commit be15868

Browse files
SrimantaBaruaawesomekling
authored andcommitted
LibGfx: Started working on TTF font parser.
I'm planning to make this a minimal-allocation TTF parser. This will speed up start-up time for applications, but have some overhead for rasterizing glyphs. Which should be okay, since rasterized glyph bitmaps should be cached anyway. This commit just adds the loading of the HEAD table.
1 parent 6cec7a2 commit be15868

File tree

3 files changed

+247
-0
lines changed

3 files changed

+247
-0
lines changed

Libraries/LibGfx/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ set(SOURCES
3030
SystemTheme.cpp
3131
Triangle.cpp
3232
WindowTheme.cpp
33+
TTFont.cpp
3334
)
3435

3536
serenity_lib(LibGfx gfx)

Libraries/LibGfx/TTFont.cpp

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
/*
2+
* Copyright (c) 2020, Srimanta Barua <srimanta.barua1@gmail.com>
3+
* All rights reserved.
4+
*
5+
* Redistribution and use in source and binary forms, with or without
6+
* modification, are permitted provided that the following conditions are met:
7+
*
8+
* 1. Redistributions of source code must retain the above copyright notice, this
9+
* list of conditions and the following disclaimer.
10+
*
11+
* 2. Redistributions in binary form must reproduce the above copyright notice,
12+
* this list of conditions and the following disclaimer in the documentation
13+
* and/or other materials provided with the distribution.
14+
*
15+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25+
*/
26+
27+
#include "TTFont.h"
28+
#include <AK/LogStream.h>
29+
#include <bits/stdint.h>
30+
#include <LibCore/File.h>
31+
32+
namespace Gfx {
33+
34+
static u16 be_u16(const u8* ptr)
35+
{
36+
return (((u16) ptr[0]) << 8) | ((u16) ptr[1]);
37+
}
38+
39+
static u32 be_u32(const u8* ptr)
40+
{
41+
return (((u32) ptr[0]) << 24) | (((u32) ptr[1]) << 16) | (((u32) ptr[2]) << 8) | ((u32) ptr[3]);
42+
}
43+
44+
static i16 be_i16(const u8* ptr)
45+
{
46+
return (((i16) ptr[0]) << 8) | ((i16) ptr[1]);
47+
}
48+
49+
static u32 tag_from_str(const char *str)
50+
{
51+
return be_u32((const u8*) str);
52+
}
53+
54+
u16 TTFHead::units_per_em() const
55+
{
56+
return be_u16(m_slice.offset_pointer(18));
57+
}
58+
59+
i16 TTFHead::xmin() const
60+
{
61+
return be_i16(m_slice.offset_pointer(36));
62+
}
63+
64+
i16 TTFHead::ymin() const
65+
{
66+
return be_i16(m_slice.offset_pointer(38));
67+
}
68+
69+
i16 TTFHead::xmax() const
70+
{
71+
return be_i16(m_slice.offset_pointer(40));
72+
}
73+
74+
i16 TTFHead::ymax() const
75+
{
76+
return be_i16(m_slice.offset_pointer(42));
77+
}
78+
79+
u16 TTFHead::lowest_recommended_ppem() const
80+
{
81+
return be_u16(m_slice.offset_pointer(46));
82+
}
83+
84+
Result<TTFIndexToLocFormat, i16> TTFHead::index_to_loc_format() const
85+
{
86+
i16 raw = be_i16(m_slice.offset_pointer(50));
87+
switch (raw) {
88+
case 0:
89+
return TTFIndexToLocFormat::Offset16;
90+
case 1:
91+
return TTFIndexToLocFormat::Offset32;
92+
default:
93+
return raw;
94+
}
95+
}
96+
97+
OwnPtr<TTFont> TTFont::load_from_file(const StringView& path, unsigned index)
98+
{
99+
dbg() << "path: " << path << " | index: " << index;
100+
auto file_or_error = Core::File::open(String(path), Core::IODevice::ReadOnly);
101+
if (file_or_error.is_error()) {
102+
dbg() << "Could not open file: " << file_or_error.error();
103+
return nullptr;
104+
}
105+
auto file = file_or_error.value();
106+
if (!file->open(Core::IODevice::ReadOnly)) {
107+
dbg() << "Could not open file";
108+
return nullptr;
109+
}
110+
auto buffer = file->read_all();
111+
if (buffer.size() < 4) {
112+
dbg() << "Font file too small";
113+
return nullptr;
114+
}
115+
u32 tag = be_u32(buffer.data());
116+
if (tag == tag_from_str("ttcf")) {
117+
// It's a font collection
118+
if (buffer.size() < 12 + 4 * (index + 1)) {
119+
dbg() << "Font file too small";
120+
return nullptr;
121+
}
122+
u32 offset = be_u32(buffer.offset_pointer(12 + 4 * index));
123+
return OwnPtr(new TTFont(move(buffer), offset));
124+
} else if (tag == tag_from_str("OTTO")) {
125+
dbg() << "CFF fonts not supported yet";
126+
return nullptr;
127+
} else if (tag != 0x00010000) {
128+
dbg() << "Not a valid TTF font";
129+
return nullptr;
130+
} else {
131+
return OwnPtr(new TTFont(move(buffer), 0));
132+
}
133+
}
134+
135+
TTFont::TTFont(AK::ByteBuffer&& buffer, u32 offset)
136+
: m_buffer(move(buffer))
137+
{
138+
ASSERT(m_buffer.size() >= offset + 12);
139+
bool head_has_been_initialized = false;
140+
141+
//auto sfnt_version = be_u32(data + offset);
142+
auto num_tables = be_u16(m_buffer.offset_pointer(offset + 4));
143+
ASSERT(m_buffer.size() >= offset + 12 + num_tables * 16);
144+
145+
for (auto i = 0; i < num_tables; i++) {
146+
u32 record_offset = offset + 12 + i * 16;
147+
u32 tag = be_u32(m_buffer.offset_pointer(record_offset));
148+
u32 table_offset = be_u32(m_buffer.offset_pointer(record_offset + 8));
149+
u32 table_length = be_u32(m_buffer.offset_pointer(record_offset + 12));
150+
ASSERT(m_buffer.size() >= table_offset + table_length);
151+
152+
// Get the tables we need
153+
if (tag == tag_from_str("head")) {
154+
auto buffer = ByteBuffer::wrap(m_buffer.offset_pointer(table_offset), table_length);
155+
m_head = TTFHead(move(buffer));
156+
head_has_been_initialized = true;
157+
}
158+
}
159+
160+
// Check that we've got everything we need
161+
ASSERT(head_has_been_initialized);
162+
}
163+
}

Libraries/LibGfx/TTFont.h

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
* Copyright (c) 2020, Srimanta Barua <srimanta.barua1@gmail.com>
3+
* All rights reserved.
4+
*
5+
* Redistribution and use in source and binary forms, with or without
6+
* modification, are permitted provided that the following conditions are met:
7+
*
8+
* 1. Redistributions of source code must retain the above copyright notice, this
9+
* list of conditions and the following disclaimer.
10+
*
11+
* 2. Redistributions in binary form must reproduce the above copyright notice,
12+
* this list of conditions and the following disclaimer in the documentation
13+
* and/or other materials provided with the distribution.
14+
*
15+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25+
*/
26+
27+
#pragma once
28+
29+
#include <AK/ByteBuffer.h>
30+
#include <AK/OwnPtr.h>
31+
#include <AK/Result.h>
32+
#include <AK/StringView.h>
33+
34+
namespace Gfx {
35+
36+
class TTFont;
37+
38+
enum class TTFIndexToLocFormat {
39+
Offset16,
40+
Offset32,
41+
};
42+
43+
class TTFHead {
44+
private:
45+
TTFHead() {}
46+
TTFHead(ByteBuffer&& slice)
47+
: m_slice(move(slice))
48+
{
49+
ASSERT(m_slice.size() >= 54);
50+
dbg() << "HEAD:"
51+
<< "\n units_per_em: " << units_per_em()
52+
<< "\n xmin: " << xmin()
53+
<< "\n ymin: " << ymin()
54+
<< "\n xmax: " << xmax()
55+
<< "\n ymax: " << ymax()
56+
<< "\n lowest_recommended_ppem: " << lowest_recommended_ppem();
57+
}
58+
u16 units_per_em() const;
59+
i16 xmin() const;
60+
i16 ymin() const;
61+
i16 xmax() const;
62+
i16 ymax() const;
63+
u16 lowest_recommended_ppem() const;
64+
Result<TTFIndexToLocFormat, i16> index_to_loc_format() const;
65+
66+
ByteBuffer m_slice;
67+
bool m_is_init;
68+
69+
friend TTFont;
70+
};
71+
72+
class TTFont {
73+
public:
74+
static OwnPtr<TTFont> load_from_file(const StringView& path, unsigned index);
75+
76+
private:
77+
TTFont(AK::ByteBuffer&& buffer, u32 offset);
78+
79+
AK::ByteBuffer m_buffer;
80+
TTFHead m_head;
81+
};
82+
83+
}

0 commit comments

Comments
 (0)