1 #include "framebuffer-font2.hpp"
3 #include "serialization.hpp"
12 inline bool readfont(const font2::glyph
& fglyph
, uint32_t xp1
, uint32_t yp1
)
14 if(xp1
< 1 || xp1
> fglyph
.width
|| yp1
< 1 || yp1
> fglyph
.height
)
18 size_t ge
= yp1
* fglyph
.stride
+ (xp1
/ 32);
19 size_t gb
= 31 - xp1
% 32;
20 return ((fglyph
.fglyph
[ge
] >> gb
) & 1);
23 template<bool T
> void _render(const font2::glyph
& fglyph
, fb
<T
>& fb
, int32_t x
, int32_t y
,
24 color fg
, color bg
, color hl
)
31 range bX
= (range::make_w(fb
.get_width()) - _x
) & range::make_w(fglyph
.width
+ 2);
32 range bY
= (range::make_w(fb
.get_height()) - _y
) & range::make_w(fglyph
.height
+ 2);
33 for(unsigned i
= bY
.low(); i
< bY
.high(); i
++) {
34 auto p
= fb
.rowptr(i
+ _y
) + (_x
+ bX
.low());
35 for(unsigned j
= bX
.low(); j
< bX
.high(); j
++) {
37 in_halo
|= readfont(fglyph
, j
- 1, i
- 1);
38 in_halo
|= readfont(fglyph
, j
, i
- 1);
39 in_halo
|= readfont(fglyph
, j
+ 1, i
- 1);
40 in_halo
|= readfont(fglyph
, j
- 1, i
);
41 in_halo
|= readfont(fglyph
, j
+ 1, i
);
42 in_halo
|= readfont(fglyph
, j
- 1, i
+ 1);
43 in_halo
|= readfont(fglyph
, j
, i
+ 1);
44 in_halo
|= readfont(fglyph
, j
+ 1, i
+ 1);
45 if(readfont(fglyph
, j
, i
))
55 range bX
= (range::make_w(fb
.get_width()) - _x
) & range::make_w(fglyph
.width
);
56 range bY
= (range::make_w(fb
.get_height()) - _y
) & range::make_w(fglyph
.height
);
57 for(unsigned i
= bY
.low(); i
< bY
.high(); i
++) {
58 auto p
= fb
.rowptr(i
+ _y
) + (_x
+ bX
.low());
59 for(unsigned j
= bX
.low(); j
< bX
.high(); j
++) {
60 size_t ge
= i
* fglyph
.stride
+ (j
/ 32);
61 size_t gb
= 31 - j
% 32;
62 if((fglyph
.fglyph
[ge
] >> gb
) & 1)
74 stride
= width
= height
= 0;
77 font2::glyph::glyph(std::istream
& s
)
81 bool upside_down
= true;
85 throw std::runtime_error("Can't read glyph bitmap header");
86 if(serialization::u16l(header
+ 0) != 0x4D42)
87 throw std::runtime_error("Bad glyph BMP magic");
88 if(serialization::u16l(header
+ 14) != 12) {
92 s
.read(header
+ 26, 14);
94 throw std::runtime_error("Can't read glyph bitmap header");
97 uint32_t startoff
= serialization::u32l(header
+ 10);
99 width
= serialization::u16l(header
+ 18);
100 height
= serialization::u16l(header
+ 20);
101 if(serialization::u16l(header
+ 22) != 1)
102 throw std::runtime_error("Bad glyph BMP planecount");
103 if(serialization::u16l(header
+ 24) != 1)
104 throw std::runtime_error("Bad glyph BMP bitdepth");
106 throw std::runtime_error("Glyph BMP data can't overlap header");
108 long _width
= serialization::s32l(header
+ 18);
109 long _height
= serialization::s32l(header
+ 22);
111 throw std::runtime_error("Bad glyph BMP size");
115 height
= (_height
>= 0) ? height
: -height
;
117 if(serialization::u16l(header
+ 26) != 1)
118 throw std::runtime_error("Bad glyph BMP planecount");
119 if(serialization::u16l(header
+ 28) != 1)
120 throw std::runtime_error("Bad glyph BMP bitdepth");
121 if(serialization::u32l(header
+ 30) != 0)
122 throw std::runtime_error("Bad glyph BMP compression method");
124 throw std::runtime_error("Glyph BMP data can't overlap header");
126 //Discard data until start of bitmap.
127 while(rcount
< startoff
) {
130 throw std::runtime_error("EOF while skipping to BMP data");
133 stride
= (width
+ 31) / 32;
134 fglyph
.resize(stride
* height
);
135 memset(&fglyph
[0], 0, sizeof(uint32_t) * fglyph
.size());
136 size_t toskip
= (4 - ((width
+ 7) / 8) % 4) % 4;
137 for(size_t i
= 0; i
< height
; i
++) {
138 size_t y
= upside_down
? (height
- i
- 1) : i
;
139 size_t bpos
= y
* stride
* 32;
140 for(size_t j
= 0; j
< width
; j
+= 8) {
141 size_t e
= (bpos
+ j
) / 32;
142 size_t b
= (bpos
+ j
) % 32;
145 throw std::runtime_error("EOF while reading BMP data");
146 fglyph
[e
] |= ((uint32_t)c
<< (24 - b
));
148 for(size_t j
= 0; j
< toskip
; j
++) {
151 throw std::runtime_error("EOF while reading BMP data");
156 void font2::glyph::render(fb
<false>& fb
, int32_t x
, int32_t y
, color fg
,
157 color bg
, color hl
) const
159 _render(*this, fb
, x
, y
, fg
, bg
, hl
);
162 void font2::glyph::render(fb
<true>& fb
, int32_t x
, int32_t y
, color fg
,
163 color bg
, color hl
) const
165 _render(*this, fb
, x
, y
, fg
, bg
, hl
);
168 void font2::glyph::render(uint8_t* buf
, size_t _stride
, uint32_t u
, uint32_t v
, uint32_t w
, uint32_t h
) const
170 //Clip the bounding box to valid range.
171 u
= std::min(u
, (uint32_t)width
);
172 v
= std::min(v
, (uint32_t)height
);
173 w
= std::min(w
, (uint32_t)width
);
174 h
= std::min(h
, (uint32_t)height
);
175 if(u
+ w
> width
) w
= width
- u
;
176 if(v
+ h
> height
) h
= height
- v
;
178 //Do the actual render.
179 size_t ge
= v
* stride
;
180 for(unsigned j
= 0; j
< h
; j
++) {
183 for(unsigned i
= 0; i
< w
; i
++) {
185 size_t gb
= 31 - (dx
& 31);
186 buf
[i
] = (fglyph
[ge
+ (dx
>> 5)] >> gb
) & 1;
198 font2::font2(const std::string
& file
)
200 std::istream
* toclose
= NULL
;
204 for(auto member
: r
) {
205 //Parse the key out of filename.
207 std::string tname
= member
;
211 } else if(regex_match("[0-9]+(-[0-9]+)*", tname
))
212 for(auto& tmp
: token_iterator
<char>::foreach(tname
, {"-"}))
213 key
.append(1, parse_value
<uint32_t>(tmp
));
219 std::istream
& s
= r
[member
];
223 } catch(std::bad_alloc
& e
) {
225 } catch(std::exception
& e
) {
226 throw std::runtime_error(tname
+ std::string(": ") + e
.what());
231 } catch(std::bad_alloc
& e
) {
235 } catch(std::exception
& e
) {
238 throw std::runtime_error(std::string("Error reading font: ") + e
.what());
242 font2::font2(struct font
& bfont
)
244 auto s
= bfont
.get_glyphs_set();
245 for(auto i
= s
.begin();;i
++) {
246 const font::glyph
& j
= (i
!= s
.end()) ? bfont
.get_glyph(*i
) : bfont
.get_bad_glyph();
248 k
.width
= j
.wide
? 16 : 8;
252 for(size_t y
= 0; y
< 16; y
++) {
254 uint32_t r
= j
.data
[y
/ (j
.wide
? 2 : 4)];
256 r
>>= 16 - ((y
& 1) << 4);
258 r
>>= 24 - ((y
& 3) << 3);
259 for(size_t x
= 0; x
< k
.width
; x
++) {
260 uint32_t b
= (j
.wide
? 15 : 7) - x
;
261 if(((r
>> b
) & 1) != 0)
262 k
.fglyph
[y
] |= 1UL << (31 - x
);
265 std::u32string key
= (i
!= s
.end()) ? std::u32string(1, *i
) : std::u32string();
267 if(i
== s
.end()) break;
272 std::ostream
& operator<<(std::ostream
& os
, const std::u32string
& lkey
)
275 return (os
<< "bad");
276 for(size_t i
= 0; i
< lkey
.length(); i
++) {
279 os
<< static_cast<uint32_t>(lkey
[i
]);
284 void font2::add(const std::u32string
& key
, const glyph
& fglyph
) throw(std::bad_alloc
)
286 glyphs
[key
] = fglyph
;
287 if(fglyph
.height
> rowadvance
)
288 rowadvance
= fglyph
.height
;
291 std::u32string
font2::best_ligature_match(const std::u32string
& codepoints
, size_t start
) const
292 throw(std::bad_alloc
)
295 if(start
>= codepoints
.length())
297 std::u32string best
= tmp
;
298 for(size_t i
= 1; i
<= codepoints
.size() - start
; i
++) {
299 tmp
.append(1, codepoints
[start
+ i
- 1]);
300 std::u32string lkey
= tmp
;
301 if(glyphs
.count(lkey
))
303 auto j
= glyphs
.lower_bound(lkey
);
304 //If lower_bound is greater than equivalent length of string, there can be no better match.
305 if(j
== glyphs
.end())
307 const std::u32string
& tmp2
= j
->first
;
308 bool best_found
= false;
309 for(size_t k
= 0; k
< tmp2
.length() && start
+ k
< codepoints
.length(); k
++)
310 if(tmp2
[k
] > codepoints
[start
+ k
]) {
313 } else if(tmp2
[k
] < codepoints
[start
+ k
])
321 const font2::glyph
& font2::lookup_glyph(const std::u32string
& key
) const throw()
323 static glyph empty_glyph
;
324 auto i
= glyphs
.find(key
);
325 return (i
== glyphs
.end()) ? empty_glyph
: i
->second
;
328 std::pair
<uint32_t, uint32_t> font2::get_metrics(const std::u32string
& str
, uint32_t xalign
) const
332 for_each_glyph(str
, xalign
, [&w
, &h
](uint32_t x
, uint32_t y
, const glyph
& g
) {
333 w
= std::max(w
, x
+ (uint32_t)g
.width
);
334 h
= std::max(h
, y
+ (uint32_t)g
.height
);
336 return std::make_pair(w
, h
);
339 void font2::for_each_glyph(const std::u32string
& str
, uint32_t xalign
, std::function
<void(uint32_t x
, uint32_t y
,
340 const glyph
& g
)> cb
) const
345 for(size_t i
= 0; i
< str
.size();) {
346 uint32_t cp
= str
[i
];
347 std::u32string k
= best_ligature_match(str
, i
);
348 const glyph
& g
= lookup_glyph(k
);
354 drawx
= (((drawx
+ xalign
) + 64) >> 6 << 6) - xalign
;
355 } else if(cp
== 10) {
357 drawy
+= get_rowadvance();