1 // Copyright 2013 Google Inc. All Rights Reserved.
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 // Font management utilities
23 #include "./store_bytes.h"
24 #include "./table_tags.h"
28 Font::Table
* Font::FindTable(uint32_t tag
) {
29 std::map
<uint32_t, Font::Table
>::iterator it
= tables
.find(tag
);
30 return it
== tables
.end() ? 0 : &it
->second
;
33 const Font::Table
* Font::FindTable(uint32_t tag
) const {
34 std::map
<uint32_t, Font::Table
>::const_iterator it
= tables
.find(tag
);
35 return it
== tables
.end() ? 0 : &it
->second
;
38 bool ReadFont(const uint8_t* data
, size_t len
, Font
* font
) {
39 Buffer
file(data
, len
);
41 // We don't care about the search_range, entry_selector and range_shift
42 // fields, they will always be computed upon writing the font.
43 if (!file
.ReadU32(&font
->flavor
) ||
44 !file
.ReadU16(&font
->num_tables
) ||
46 return FONT_COMPRESSION_FAILURE();
49 std::map
<uint32_t, uint32_t> intervals
;
50 for (uint16_t i
= 0; i
< font
->num_tables
; ++i
) {
52 if (!file
.ReadU32(&table
.tag
) ||
53 !file
.ReadU32(&table
.checksum
) ||
54 !file
.ReadU32(&table
.offset
) ||
55 !file
.ReadU32(&table
.length
)) {
56 return FONT_COMPRESSION_FAILURE();
58 if ((table
.offset
& 3) != 0 ||
60 len
- table
.length
< table
.offset
) {
61 return FONT_COMPRESSION_FAILURE();
63 intervals
[table
.offset
] = table
.length
;
64 table
.data
= data
+ table
.offset
;
65 if (font
->tables
.find(table
.tag
) != font
->tables
.end()) {
66 return FONT_COMPRESSION_FAILURE();
68 font
->tables
[table
.tag
] = table
;
71 // Check that tables are non-overlapping.
72 uint32_t last_offset
= 12UL + 16UL * font
->num_tables
;
73 for (const auto& i
: intervals
) {
74 if (i
.first
< last_offset
|| i
.first
+ i
.second
< i
.first
) {
75 return FONT_COMPRESSION_FAILURE();
77 last_offset
= i
.first
+ i
.second
;
82 size_t FontFileSize(const Font
& font
) {
83 size_t max_offset
= 12ULL + 16ULL * font
.num_tables
;
84 for (const auto& i
: font
.tables
) {
85 const Font::Table
& table
= i
.second
;
86 size_t padding_size
= (4 - (table
.length
& 3)) & 3;
87 size_t end_offset
= (padding_size
+ table
.offset
) + table
.length
;
88 max_offset
= std::max(max_offset
, end_offset
);
93 bool WriteFont(const Font
& font
, uint8_t* dst
, size_t dst_size
) {
94 if (dst_size
< 12ULL + 16ULL * font
.num_tables
) {
95 return FONT_COMPRESSION_FAILURE();
98 StoreU32(font
.flavor
, &offset
, dst
);
99 Store16(font
.num_tables
, &offset
, dst
);
100 uint16_t max_pow2
= font
.num_tables
? Log2Floor(font
.num_tables
) : 0;
101 uint16_t search_range
= max_pow2
? 1 << (max_pow2
+ 4) : 0;
102 uint16_t range_shift
= (font
.num_tables
<< 4) - search_range
;
103 Store16(search_range
, &offset
, dst
);
104 Store16(max_pow2
, &offset
, dst
);
105 Store16(range_shift
, &offset
, dst
);
106 for (const auto& i
: font
.tables
) {
107 const Font::Table
& table
= i
.second
;
108 StoreU32(table
.tag
, &offset
, dst
);
109 StoreU32(table
.checksum
, &offset
, dst
);
110 StoreU32(table
.offset
, &offset
, dst
);
111 StoreU32(table
.length
, &offset
, dst
);
112 if (table
.offset
+ table
.length
< table
.offset
||
113 dst_size
< table
.offset
+ table
.length
) {
114 return FONT_COMPRESSION_FAILURE();
116 memcpy(dst
+ table
.offset
, table
.data
, table
.length
);
117 size_t padding_size
= (4 - (table
.length
& 3)) & 3;
118 if (table
.offset
+ table
.length
+ padding_size
< padding_size
||
119 dst_size
< table
.offset
+ table
.length
+ padding_size
) {
120 return FONT_COMPRESSION_FAILURE();
122 memset(dst
+ table
.offset
+ table
.length
, 0, padding_size
);
127 int NumGlyphs(const Font
& font
) {
128 const Font::Table
* head_table
= font
.FindTable(kHeadTableTag
);
129 const Font::Table
* loca_table
= font
.FindTable(kLocaTableTag
);
130 if (head_table
== NULL
|| loca_table
== NULL
|| head_table
->length
< 52) {
133 int index_fmt
= IndexFormat(font
);
134 int num_glyphs
= (loca_table
->length
/ (index_fmt
== 0 ? 2 : 4)) - 1;
138 int IndexFormat(const Font
& font
) {
139 const Font::Table
* head_table
= font
.FindTable(kHeadTableTag
);
140 if (head_table
== NULL
) {
143 return head_table
->data
[51];
146 bool GetGlyphData(const Font
& font
, int glyph_index
,
147 const uint8_t** glyph_data
, size_t* glyph_size
) {
148 if (glyph_index
< 0) {
149 return FONT_COMPRESSION_FAILURE();
151 const Font::Table
* head_table
= font
.FindTable(kHeadTableTag
);
152 const Font::Table
* loca_table
= font
.FindTable(kLocaTableTag
);
153 const Font::Table
* glyf_table
= font
.FindTable(kGlyfTableTag
);
154 if (head_table
== NULL
|| loca_table
== NULL
|| glyf_table
== NULL
||
155 head_table
->length
< 52) {
156 return FONT_COMPRESSION_FAILURE();
159 int index_fmt
= IndexFormat(font
);
161 Buffer
loca_buf(loca_table
->data
, loca_table
->length
);
162 if (index_fmt
== 0) {
163 uint16_t offset1
, offset2
;
164 if (!loca_buf
.Skip(2 * glyph_index
) ||
165 !loca_buf
.ReadU16(&offset1
) ||
166 !loca_buf
.ReadU16(&offset2
) ||
168 2 * offset2
> glyf_table
->length
) {
169 return FONT_COMPRESSION_FAILURE();
171 *glyph_data
= glyf_table
->data
+ 2 * offset1
;
172 *glyph_size
= 2 * (offset2
- offset1
);
174 uint32_t offset1
, offset2
;
175 if (!loca_buf
.Skip(4 * glyph_index
) ||
176 !loca_buf
.ReadU32(&offset1
) ||
177 !loca_buf
.ReadU32(&offset2
) ||
179 offset2
> glyf_table
->length
) {
180 return FONT_COMPRESSION_FAILURE();
182 *glyph_data
= glyf_table
->data
+ offset1
;
183 *glyph_size
= offset2
- offset1
;
188 bool RemoveDigitalSignature(Font
* font
) {
189 std::map
<uint32_t, Font::Table
>::iterator it
=
190 font
->tables
.find(kDsigTableTag
);
191 if (it
!= font
->tables
.end()) {
192 font
->tables
.erase(it
);
193 font
->num_tables
= font
->tables
.size();