1 #include "framebuffer-font2.hpp"
3 #include "serialization.hpp"
14 inline bool readfont(const font2::glyph
& fglyph
, uint32_t xp1
, uint32_t yp1
)
16 if(xp1
< 1 || xp1
> fglyph
.width
|| yp1
< 1 || yp1
> fglyph
.height
)
20 size_t ge
= yp1
* fglyph
.stride
+ (xp1
/ 32);
21 size_t gb
= 31 - xp1
% 32;
22 return ((fglyph
.fglyph
[ge
] >> gb
) & 1);
25 template<bool T
> void _render(const font2::glyph
& fglyph
, fb
<T
>& fb
, int32_t x
, int32_t y
,
26 color fg
, color bg
, color hl
)
33 range bX
= (range::make_w(fb
.get_width()) - _x
) & range::make_w(fglyph
.width
+ 2);
34 range bY
= (range::make_w(fb
.get_height()) - _y
) & range::make_w(fglyph
.height
+ 2);
35 for(unsigned i
= bY
.low(); i
< bY
.high(); i
++) {
36 auto p
= fb
.rowptr(i
+ _y
) + (_x
+ bX
.low());
37 for(unsigned j
= bX
.low(); j
< bX
.high(); j
++) {
39 in_halo
|= readfont(fglyph
, j
- 1, i
- 1);
40 in_halo
|= readfont(fglyph
, j
, i
- 1);
41 in_halo
|= readfont(fglyph
, j
+ 1, i
- 1);
42 in_halo
|= readfont(fglyph
, j
- 1, i
);
43 in_halo
|= readfont(fglyph
, j
+ 1, i
);
44 in_halo
|= readfont(fglyph
, j
- 1, i
+ 1);
45 in_halo
|= readfont(fglyph
, j
, i
+ 1);
46 in_halo
|= readfont(fglyph
, j
+ 1, i
+ 1);
47 if(readfont(fglyph
, j
, i
))
57 range bX
= (range::make_w(fb
.get_width()) - _x
) & range::make_w(fglyph
.width
);
58 range bY
= (range::make_w(fb
.get_height()) - _y
) & range::make_w(fglyph
.height
);
59 for(unsigned i
= bY
.low(); i
< bY
.high(); i
++) {
60 auto p
= fb
.rowptr(i
+ _y
) + (_x
+ bX
.low());
61 for(unsigned j
= bX
.low(); j
< bX
.high(); j
++) {
62 size_t ge
= i
* fglyph
.stride
+ (j
/ 32);
63 size_t gb
= 31 - j
% 32;
64 if((fglyph
.fglyph
[ge
] >> gb
) & 1)
76 stride
= width
= height
= 0;
79 font2::glyph::glyph(std::istream
& s
)
83 bool upside_down
= true;
87 throw std::runtime_error("Can't read glyph bitmap header");
88 if(serialization::u16l(header
+ 0) != 0x4D42)
89 throw std::runtime_error("Bad glyph BMP magic");
90 if(serialization::u16l(header
+ 14) != 12) {
94 s
.read(header
+ 26, 14);
96 throw std::runtime_error("Can't read glyph bitmap header");
99 uint32_t startoff
= serialization::u32l(header
+ 10);
101 width
= serialization::u16l(header
+ 18);
102 height
= serialization::u16l(header
+ 20);
103 if(serialization::u16l(header
+ 22) != 1)
104 throw std::runtime_error("Bad glyph BMP planecount");
105 if(serialization::u16l(header
+ 24) != 1)
106 throw std::runtime_error("Bad glyph BMP bitdepth");
108 throw std::runtime_error("Glyph BMP data can't overlap header");
110 long _width
= serialization::s32l(header
+ 18);
111 long _height
= serialization::s32l(header
+ 22);
113 throw std::runtime_error("Bad glyph BMP size");
117 height
= (_height
>= 0) ? height
: -height
;
119 if(serialization::u16l(header
+ 26) != 1)
120 throw std::runtime_error("Bad glyph BMP planecount");
121 if(serialization::u16l(header
+ 28) != 1)
122 throw std::runtime_error("Bad glyph BMP bitdepth");
123 if(serialization::u32l(header
+ 30) != 0)
124 throw std::runtime_error("Bad glyph BMP compression method");
126 throw std::runtime_error("Glyph BMP data can't overlap header");
128 //Discard data until start of bitmap.
129 while(rcount
< startoff
) {
132 throw std::runtime_error("EOF while skipping to BMP data");
135 stride
= (width
+ 31) / 32;
136 fglyph
.resize(stride
* height
);
137 memset(&fglyph
[0], 0, sizeof(uint32_t) * fglyph
.size());
138 size_t toskip
= (4 - ((width
+ 7) / 8) % 4) % 4;
139 for(size_t i
= 0; i
< height
; i
++) {
140 size_t y
= upside_down
? (height
- i
- 1) : i
;
141 size_t bpos
= y
* stride
* 32;
142 for(size_t j
= 0; j
< width
; j
+= 8) {
143 size_t e
= (bpos
+ j
) / 32;
144 size_t b
= (bpos
+ j
) % 32;
147 throw std::runtime_error("EOF while reading BMP data");
148 fglyph
[e
] |= ((uint32_t)c
<< (24 - b
));
150 for(size_t j
= 0; j
< toskip
; j
++) {
153 throw std::runtime_error("EOF while reading BMP data");
158 void font2::glyph::dump(std::ostream
& s
) const
160 static uint8_t hdr
[32] = {
161 0x42, 0x4d, 0x38, 0, 0, 0, 0, 0, 0, 0, 0x20, 0, 0, 0, 0x0c, 0,
162 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 1, 0, 1, 0, 0, 0, 0, 0xff, 0xff, 0xff
164 serialization::u16l(hdr
+ 18, width
);
165 serialization::u16l(hdr
+ 20, height
);
166 s
.write((char*)hdr
, 32);
167 uint32_t rowsize
= (width
+ 7) / 8;
168 rowsize
= (rowsize
+ 3) & (~3);
169 uint8_t buf
[rowsize
];
170 memset(buf
, 0, rowsize
);
171 for(size_t i
= 0; i
< height
; i
++) {
172 size_t y
= height
- i
- 1;
173 size_t bpos
= y
* stride
* 32;
174 for(size_t j
= 0; j
< width
; j
+= 8) {
175 size_t e
= (bpos
+ j
) / 32;
176 size_t b
= (bpos
+ j
) % 32;
177 buf
[j
>> 3] = fglyph
[e
] >> (24 - b
);
179 s
.write((char*)&buf
[0], rowsize
);
183 void font2::glyph::render(fb
<false>& fb
, int32_t x
, int32_t y
, color fg
,
184 color bg
, color hl
) const
186 _render(*this, fb
, x
, y
, fg
, bg
, hl
);
189 void font2::glyph::render(fb
<true>& fb
, int32_t x
, int32_t y
, color fg
,
190 color bg
, color hl
) const
192 _render(*this, fb
, x
, y
, fg
, bg
, hl
);
195 void font2::glyph::render(uint8_t* buf
, size_t _stride
, uint32_t u
, uint32_t v
, uint32_t w
, uint32_t h
) const
197 //Clip the bounding box to valid range.
198 u
= std::min(u
, (uint32_t)width
);
199 v
= std::min(v
, (uint32_t)height
);
200 w
= std::min(w
, (uint32_t)width
);
201 h
= std::min(h
, (uint32_t)height
);
202 if(u
+ w
> width
) w
= width
- u
;
203 if(v
+ h
> height
) h
= height
- v
;
205 //Do the actual render.
206 size_t ge
= v
* stride
;
207 for(unsigned j
= 0; j
< h
; j
++) {
208 for(unsigned i
= 0; i
< w
; i
++) {
210 size_t gb
= 31 - (dx
& 31);
211 buf
[i
] = (fglyph
[ge
+ (dx
>> 5)] >> gb
) & 1;
223 font2::font2(const std::string
& file
)
225 std::istream
* toclose
= NULL
;
229 for(auto member
: r
) {
230 //Parse the key out of filename.
232 std::string tname
= member
;
236 } else if(regex_match("[0-9]+(-[0-9]+)*", tname
))
237 for(auto& tmp
: token_iterator
<char>::foreach(tname
, {"-"}))
238 key
.append(1, parse_value
<uint32_t>(tmp
));
244 std::istream
& s
= r
[member
];
248 } catch(std::bad_alloc
& e
) {
250 } catch(std::exception
& e
) {
251 throw std::runtime_error(tname
+ std::string(": ") + e
.what());
256 } catch(std::bad_alloc
& e
) {
260 } catch(std::exception
& e
) {
263 throw std::runtime_error(std::string("Error reading font: ") + e
.what());
267 font2::font2(struct font
& bfont
)
269 auto s
= bfont
.get_glyphs_set();
271 for(auto i
= s
.begin();;i
++) {
272 const font::glyph
& j
= (i
!= s
.end()) ? bfont
.get_glyph(*i
) : bfont
.get_bad_glyph();
274 k
.width
= j
.get_width();
275 k
.height
= j
.get_height();
278 for(size_t y
= 0; y
< k
.height
; y
++) {
279 for(size_t x
= 0; x
< k
.width
; x
++) {
280 if(j
.read_pixel(x
, y
))
281 k
.fglyph
[y
] |= 1UL << (31 - x
);
284 rowadvance
= std::max((size_t)rowadvance
, (size_t)j
.get_height());
285 std::u32string key
= (i
!= s
.end()) ? std::u32string(1, *i
) : std::u32string();
287 if(i
== s
.end()) break;
291 std::ostream
& operator<<(std::ostream
& os
, const std::u32string
& lkey
)
294 return (os
<< "bad");
295 for(size_t i
= 0; i
< lkey
.length(); i
++) {
298 os
<< static_cast<uint32_t>(lkey
[i
]);
303 void font2::add(const std::u32string
& key
, const glyph
& fglyph
)
305 glyphs
[key
] = fglyph
;
306 if(fglyph
.height
> rowadvance
)
307 rowadvance
= fglyph
.height
;
310 std::u32string
font2::best_ligature_match(const std::u32string
& codepoints
, size_t start
) const
313 if(start
>= codepoints
.length())
315 std::u32string best
= tmp
;
316 for(size_t i
= 1; i
<= codepoints
.size() - start
; i
++) {
317 tmp
.append(1, codepoints
[start
+ i
- 1]);
318 std::u32string lkey
= tmp
;
319 if(glyphs
.count(lkey
))
321 auto j
= glyphs
.lower_bound(lkey
);
322 //If lower_bound is greater than equivalent length of string, there can be no better match.
323 if(j
== glyphs
.end())
325 const std::u32string
& tmp2
= j
->first
;
326 bool best_found
= false;
327 for(size_t k
= 0; k
< tmp2
.length() && start
+ k
< codepoints
.length(); k
++)
328 if(tmp2
[k
] > codepoints
[start
+ k
]) {
331 } else if(tmp2
[k
] < codepoints
[start
+ k
])
339 const font2::glyph
& font2::lookup_glyph(const std::u32string
& key
) const throw()
341 static glyph empty_glyph
;
342 auto i
= glyphs
.find(key
);
343 return (i
== glyphs
.end()) ? empty_glyph
: i
->second
;
346 std::pair
<uint32_t, uint32_t> font2::get_metrics(const std::u32string
& str
, uint32_t xalign
) const
350 for_each_glyph(str
, xalign
, [&w
, &h
](uint32_t x
, uint32_t y
, const glyph
& g
) {
351 w
= std::max(w
, x
+ (uint32_t)g
.width
);
352 h
= std::max(h
, y
+ (uint32_t)g
.height
);
354 return std::make_pair(w
, h
);
357 void font2::for_each_glyph(const std::u32string
& str
, uint32_t xalign
, std::function
<void(uint32_t x
, uint32_t y
,
358 const glyph
& g
)> cb
) const
363 for(size_t i
= 0; i
< str
.size();) {
364 uint32_t cp
= str
[i
];
365 std::u32string k
= best_ligature_match(str
, i
);
366 const glyph
& g
= lookup_glyph(k
);
372 drawx
= (((drawx
+ xalign
) + 64) >> 6 << 6) - xalign
;
373 } else if(cp
== 10) {
375 drawy
+= get_rowadvance();
383 void font2::dump(const std::string
& file
) const
385 zip::writer
w(file
, 9);
386 for(auto& i
: glyphs
) {
387 std::string key
= "";
391 std::ostringstream x
;
392 auto len
= i
.first
.length();
394 for(unsigned j
= 0; j
< len
; j
++) {
401 std::ostream
& s
= w
.create_file(key
);