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 inline bool readfont(const font_glyph_data
& glyph
, uint32_t xp1
, uint32_t yp1
)
31 if(xp1
< 1 || xp1
> glyph
.width
|| yp1
< 1 || yp1
> glyph
.height
)
35 size_t ge
= yp1
* glyph
.stride
+ (xp1
/ 32);
36 size_t gb
= 31 - xp1
% 32;
37 return ((glyph
.glyph
[ge
] >> gb
) & 1);
40 template<bool T
> void _render(const font_glyph_data
& glyph
, framebuffer
<T
>& fb
, int32_t x
, int32_t y
,
41 premultiplied_color fg
, premultiplied_color bg
, premultiplied_color hl
)
43 uint32_t xdc
, xoff
, xsize
;
44 uint32_t ydc
, yoff
, ysize
;
46 bound(x
- 1, glyph
.width
+ 2, fb
.get_width(), xdc
, xoff
, xsize
);
47 bound(y
- 1, glyph
.height
+ 2, fb
.get_height(), ydc
, yoff
, ysize
);
50 for(unsigned i
= 0; i
< ysize
; i
++) {
51 auto p
= fb
.rowptr(i
+ ydc
) + xdc
;
52 for(unsigned j
= 0; j
< xsize
; j
++) {
54 in_halo
|= readfont(glyph
, j
+ xoff
- 1, i
+ yoff
- 1);
55 in_halo
|= readfont(glyph
, j
+ xoff
, i
+ yoff
- 1);
56 in_halo
|= readfont(glyph
, j
+ xoff
+ 1, i
+ yoff
- 1);
57 in_halo
|= readfont(glyph
, j
+ xoff
- 1, i
+ yoff
);
58 in_halo
|= readfont(glyph
, j
+ xoff
+ 1, i
+ yoff
);
59 in_halo
|= readfont(glyph
, j
+ xoff
- 1, i
+ yoff
+ 1);
60 in_halo
|= readfont(glyph
, j
+ xoff
, i
+ yoff
+ 1);
61 in_halo
|= readfont(glyph
, j
+ xoff
+ 1, i
+ yoff
+ 1);
62 if(readfont(glyph
, j
+ xoff
, i
+ yoff
))
72 bound(x
, glyph
.width
, fb
.get_width(), xdc
, xoff
, xsize
);
73 bound(y
, glyph
.height
, fb
.get_height(), ydc
, yoff
, ysize
);
76 for(unsigned i
= 0; i
< ysize
; i
++) {
77 auto p
= fb
.rowptr(i
+ ydc
) + xdc
;
78 for(unsigned j
= 0; j
< xsize
; j
++) {
79 size_t ge
= (i
+ yoff
) * glyph
.stride
+ ((j
+ xoff
) / 32);
80 size_t gb
= 31 - (j
+ xoff
) % 32;
81 if((glyph
.glyph
[ge
] >> gb
) & 1)
91 font_glyph_data::font_glyph_data()
93 stride
= width
= height
= 0;
96 font_glyph_data::font_glyph_data(std::istream
& s
)
100 bool upside_down
= true;
104 throw std::runtime_error("Can't read glyph bitmap header");
105 if(read16ule(header
+ 0) != 0x4D42)
106 throw std::runtime_error("Bad glyph BMP magic");
107 if(read16ule(header
+ 14) != 12) {
111 s
.read(header
+ 26, 14);
113 throw std::runtime_error("Can't read glyph bitmap header");
116 uint32_t startoff
= read32ule(header
+ 10);
118 width
= read16ule(header
+ 18);
119 height
= read16ule(header
+ 20);
120 if(read16ule(header
+ 22) != 1)
121 throw std::runtime_error("Bad glyph BMP planecount");
122 if(read16ule(header
+ 24) != 1)
123 throw std::runtime_error("Bad glyph BMP bitdepth");
125 throw std::runtime_error("Glyph BMP data can't overlap header");
127 long _width
= read32sle(header
+ 18);
128 long _height
= read32sle(header
+ 22);
130 throw std::runtime_error("Bad glyph BMP size");
134 height
= (_height
>= 0) ? height
: -height
;
136 if(read16ule(header
+ 26) != 1)
137 throw std::runtime_error("Bad glyph BMP planecount");
138 if(read16ule(header
+ 28) != 1)
139 throw std::runtime_error("Bad glyph BMP bitdepth");
140 if(read32ule(header
+ 30) != 0)
141 throw std::runtime_error("Bad glyph BMP compression method");
143 throw std::runtime_error("Glyph BMP data can't overlap header");
145 //Discard data until start of bitmap.
146 while(rcount
< startoff
) {
149 throw std::runtime_error("EOF while skipping to BMP data");
152 stride
= (width
+ 31) / 32;
153 glyph
.resize(stride
* height
);
154 memset(&glyph
[0], 0, sizeof(uint32_t) * glyph
.size());
155 size_t toskip
= (4 - ((width
+ 7) / 8) % 4) % 4;
156 for(size_t i
= 0; i
< height
; i
++) {
157 size_t y
= upside_down
? (height
- i
- 1) : i
;
158 size_t bpos
= y
* stride
* 32;
159 for(size_t j
= 0; j
< width
; j
+= 8) {
160 size_t e
= (bpos
+ j
) / 32;
161 size_t b
= (bpos
+ j
) % 32;
164 throw std::runtime_error("EOF while reading BMP data");
165 glyph
[e
] |= ((uint32_t)c
<< (24 - b
));
167 for(size_t j
= 0; j
< toskip
; j
++) {
170 throw std::runtime_error("EOF while reading BMP data");
175 void font_glyph_data::render(framebuffer
<false>& fb
, int32_t x
, int32_t y
, premultiplied_color fg
,
176 premultiplied_color bg
, premultiplied_color hl
) const
178 _render(*this, fb
, x
, y
, fg
, bg
, hl
);
181 void font_glyph_data::render(framebuffer
<true>& fb
, int32_t x
, int32_t y
, premultiplied_color fg
,
182 premultiplied_color bg
, premultiplied_color hl
) const
184 _render(*this, fb
, x
, y
, fg
, bg
, hl
);
188 custom_font::custom_font()
193 custom_font::custom_font(const std::string
& file
)
195 std::istream
* toclose
= NULL
;
199 for(auto member
: r
) {
200 //Parse the key out of filename.
202 std::string tname
= member
;
206 } else if(regex_match("[0-9]+(-[0-9]+)*", tname
))
208 extract_token(tname
, tmp
, "-");
209 key
.append(1, parse_value
<uint32_t>(tmp
));
216 std::istream
& s
= r
[member
];
219 add(key
, font_glyph_data(s
));
220 } catch(std::bad_alloc
& e
) {
222 } catch(std::exception
& e
) {
223 throw std::runtime_error(tname
+ std::string(": ") + e
.what());
228 } catch(std::bad_alloc
& e
) {
232 } catch(std::exception
& e
) {
235 throw std::runtime_error(std::string("Error reading font: ") + e
.what());
239 std::ostream
& operator<<(std::ostream
& os
, const std::u32string
& lkey
)
242 return (os
<< "bad");
243 for(size_t i
= 0; i
< lkey
.length(); i
++) {
246 os
<< static_cast<uint32_t>(lkey
[i
]);
251 void custom_font::add(const std::u32string
& key
, const font_glyph_data
& glyph
) throw(std::bad_alloc
)
254 if(glyph
.height
> rowadvance
)
255 rowadvance
= glyph
.height
;
258 std::u32string
custom_font::best_ligature_match(const std::u32string
& codepoints
, size_t start
) const
259 throw(std::bad_alloc
)
262 if(start
>= codepoints
.length())
264 std::u32string best
= tmp
;
265 for(size_t i
= 1; i
<= codepoints
.size() - start
; i
++) {
266 tmp
.append(1, codepoints
[start
+ i
- 1]);
267 std::u32string lkey
= tmp
;
268 if(glyphs
.count(lkey
))
270 auto j
= glyphs
.lower_bound(lkey
);
271 //If lower_bound is greater than equivalent length of string, there can be no better match.
272 if(j
== glyphs
.end())
274 const std::u32string
& tmp2
= j
->first
;
275 bool best_found
= false;
276 for(size_t k
= 0; k
< tmp2
.length() && start
+ k
< codepoints
.length(); k
++)
277 if(tmp2
[k
] > codepoints
[start
+ k
]) {
280 } else if(tmp2
[k
] < codepoints
[start
+ k
])
288 const font_glyph_data
& custom_font::lookup_glyph(const std::u32string
& key
) const throw()
290 static font_glyph_data empty_glyph
;
291 auto i
= glyphs
.find(key
);
292 return (i
== glyphs
.end()) ? empty_glyph
: i
->second
;