1 #include "customfont.hpp"
2 #include "serialization.hpp"
9 void bound(int32_t c
, uint32_t odim
, uint32_t dim
, uint32_t& dc
, uint32_t& off
, uint32_t& size
)
11 if(c
>= (int32_t)dim
|| c
+ odim
<= 0) {
29 template<bool T
> void _render(const font_glyph_data
& glyph
, framebuffer
<T
>& fb
, int32_t x
, int32_t y
,
30 premultiplied_color fg
, premultiplied_color bg
)
32 uint32_t xdc
, xoff
, xsize
;
33 uint32_t ydc
, yoff
, ysize
;
34 bound(x
, glyph
.width
, fb
.get_width(), xdc
, xoff
, xsize
);
35 bound(y
, glyph
.height
, fb
.get_height(), ydc
, yoff
, ysize
);
38 for(unsigned i
= 0; i
< ysize
; i
++) {
39 auto p
= fb
.rowptr(i
+ ydc
);
40 for(unsigned j
= 0; j
< xsize
; j
++) {
41 size_t ge
= (i
+ yoff
) * glyph
.stride
+ ((j
+ xoff
) / 32);
42 size_t gb
= 31 - (j
+ xoff
) % 32;
43 if((glyph
.glyph
[ge
] >> gb
) & 1)
52 font_glyph_data::font_glyph_data()
54 stride
= width
= height
= 0;
57 font_glyph_data::font_glyph_data(std::istream
& s
)
61 bool upside_down
= true;
65 throw std::runtime_error("Can't read glyph bitmap header");
66 if(read16ule(header
+ 0) != 0x4D42)
67 throw std::runtime_error("Bad glyph BMP magic");
68 if(read16ule(header
+ 14) != 12) {
72 s
.read(header
+ 26, 14);
74 throw std::runtime_error("Can't read glyph bitmap header");
77 uint32_t startoff
= read32ule(header
+ 10);
79 width
= read16ule(header
+ 18);
80 height
= read16ule(header
+ 20);
81 if(read16ule(header
+ 22) != 1)
82 throw std::runtime_error("Bad glyph BMP planecount");
83 if(read16ule(header
+ 24) != 1)
84 throw std::runtime_error("Bad glyph BMP bitdepth");
86 throw std::runtime_error("Glyph BMP data can't overlap header");
88 long _width
= read32sle(header
+ 18);
89 long _height
= read32sle(header
+ 22);
91 throw std::runtime_error("Bad glyph BMP size");
95 height
= (_height
>= 0) ? height
: -height
;
97 if(read16ule(header
+ 26) != 1)
98 throw std::runtime_error("Bad glyph BMP planecount");
99 if(read16ule(header
+ 28) != 1)
100 throw std::runtime_error("Bad glyph BMP bitdepth");
101 if(read32ule(header
+ 30) != 0)
102 throw std::runtime_error("Bad glyph BMP compression method");
104 throw std::runtime_error("Glyph BMP data can't overlap header");
106 //Discard data until start of bitmap.
107 while(rcount
< startoff
) {
110 throw std::runtime_error("EOF while skipping to BMP data");
113 stride
= (width
+ 31) / 32;
114 glyph
.resize(stride
* height
);
115 memset(&glyph
[0], 0, sizeof(uint32_t) * glyph
.size());
116 size_t toskip
= (4 - ((width
+ 7) / 8) % 4) % 4;
117 for(size_t i
= 0; i
< height
; i
++) {
118 size_t y
= upside_down
? (height
- i
- 1) : i
;
119 size_t bpos
= y
* stride
* 32;
120 for(size_t j
= 0; j
< width
; j
+= 8) {
121 size_t e
= (bpos
+ j
) / 32;
122 size_t b
= (bpos
+ j
) % 32;
125 throw std::runtime_error("EOF while reading BMP data");
126 glyph
[e
] |= ((uint32_t)c
<< (24 - b
));
128 for(size_t j
= 0; j
< toskip
; j
++) {
131 throw std::runtime_error("EOF while reading BMP data");
136 void font_glyph_data::render(framebuffer
<false>& fb
, int32_t x
, int32_t y
, premultiplied_color fg
,
137 premultiplied_color bg
) const
139 _render(*this, fb
, x
, y
, fg
, bg
);
142 void font_glyph_data::render(framebuffer
<true>& fb
, int32_t x
, int32_t y
, premultiplied_color fg
,
143 premultiplied_color bg
) const
145 _render(*this, fb
, x
, y
, fg
, bg
);
149 custom_font::custom_font()
154 custom_font::custom_font(const std::string
& file
)
156 std::istream
* toclose
= NULL
;
160 for(auto member
: r
) {
161 //Parse the key out of filename.
163 std::string tname
= member
;
167 } else if(regex_match("[0-9]+(-[0-9]+)*", tname
))
169 extract_token(tname
, tmp
, "-");
170 key
.append(1, parse_value
<uint32_t>(tmp
));
177 std::istream
& s
= r
[member
];
180 add(key
, font_glyph_data(s
));
181 } catch(std::bad_alloc
& e
) {
183 } catch(std::exception
& e
) {
184 throw std::runtime_error(tname
+ std::string(": ") + e
.what());
189 } catch(std::bad_alloc
& e
) {
193 } catch(std::exception
& e
) {
196 throw std::runtime_error(std::string("Error reading font: ") + e
.what());
200 std::ostream
& operator<<(std::ostream
& os
, const std::u32string
& lkey
)
203 return (os
<< "bad");
204 for(size_t i
= 0; i
< lkey
.length(); i
++) {
207 os
<< static_cast<uint32_t>(lkey
[i
]);
212 void custom_font::add(const std::u32string
& key
, const font_glyph_data
& glyph
) throw(std::bad_alloc
)
215 if(glyph
.height
> rowadvance
)
216 rowadvance
= glyph
.height
;
219 std::u32string
custom_font::best_ligature_match(const std::u32string
& codepoints
, size_t start
) const
220 throw(std::bad_alloc
)
223 if(start
>= codepoints
.length())
225 std::u32string best
= tmp
;
226 for(size_t i
= 1; i
<= codepoints
.size() - start
; i
++) {
227 tmp
.append(1, codepoints
[start
+ i
- 1]);
228 std::u32string lkey
= tmp
;
229 if(glyphs
.count(lkey
))
231 auto j
= glyphs
.lower_bound(lkey
);
232 //If lower_bound is greater than equivalent length of string, there can be no better match.
233 if(j
== glyphs
.end())
235 const std::u32string
& tmp2
= j
->first
;
236 bool best_found
= false;
237 for(size_t k
= 0; k
< tmp2
.length() && start
+ k
< codepoints
.length(); k
++)
238 if(tmp2
[k
] > codepoints
[start
+ k
]) {
241 } else if(tmp2
[k
] < codepoints
[start
+ k
])
249 const font_glyph_data
& custom_font::lookup_glyph(const std::u32string
& key
) const throw()
251 static font_glyph_data empty_glyph
;
252 auto i
= glyphs
.find(key
);
253 return (i
== glyphs
.end()) ? empty_glyph
: i
->second
;