1 #include "framebuffer-font2.hpp"
2 #include "serialization.hpp"
11 void bound(int32_t c
, uint32_t odim
, uint32_t dim
, uint32_t& dc
, uint32_t& off
, uint32_t& size
)
13 if(c
>= (int32_t)dim
|| c
+ odim
<= 0) {
31 inline bool readfont(const font2::glyph
& fglyph
, uint32_t xp1
, uint32_t yp1
)
33 if(xp1
< 1 || xp1
> fglyph
.width
|| yp1
< 1 || yp1
> fglyph
.height
)
37 size_t ge
= yp1
* fglyph
.stride
+ (xp1
/ 32);
38 size_t gb
= 31 - xp1
% 32;
39 return ((fglyph
.fglyph
[ge
] >> gb
) & 1);
42 template<bool T
> void _render(const font2::glyph
& fglyph
, fb
<T
>& fb
, int32_t x
, int32_t y
,
43 color fg
, color bg
, color hl
)
45 uint32_t xdc
, xoff
, xsize
;
46 uint32_t ydc
, yoff
, ysize
;
48 bound(x
- 1, fglyph
.width
+ 2, fb
.get_width(), xdc
, xoff
, xsize
);
49 bound(y
- 1, fglyph
.height
+ 2, fb
.get_height(), ydc
, yoff
, ysize
);
52 for(unsigned i
= 0; i
< ysize
; i
++) {
53 auto p
= fb
.rowptr(i
+ ydc
) + xdc
;
54 for(unsigned j
= 0; j
< xsize
; j
++) {
56 in_halo
|= readfont(fglyph
, j
+ xoff
- 1, i
+ yoff
- 1);
57 in_halo
|= readfont(fglyph
, j
+ xoff
, i
+ yoff
- 1);
58 in_halo
|= readfont(fglyph
, j
+ xoff
+ 1, i
+ yoff
- 1);
59 in_halo
|= readfont(fglyph
, j
+ xoff
- 1, i
+ yoff
);
60 in_halo
|= readfont(fglyph
, j
+ xoff
+ 1, i
+ yoff
);
61 in_halo
|= readfont(fglyph
, j
+ xoff
- 1, i
+ yoff
+ 1);
62 in_halo
|= readfont(fglyph
, j
+ xoff
, i
+ yoff
+ 1);
63 in_halo
|= readfont(fglyph
, j
+ xoff
+ 1, i
+ yoff
+ 1);
64 if(readfont(fglyph
, j
+ xoff
, i
+ yoff
))
74 bound(x
, fglyph
.width
, fb
.get_width(), xdc
, xoff
, xsize
);
75 bound(y
, fglyph
.height
, fb
.get_height(), ydc
, yoff
, ysize
);
78 for(unsigned i
= 0; i
< ysize
; i
++) {
79 auto p
= fb
.rowptr(i
+ ydc
) + xdc
;
80 for(unsigned j
= 0; j
< xsize
; j
++) {
81 size_t ge
= (i
+ yoff
) * fglyph
.stride
+ ((j
+ xoff
) / 32);
82 size_t gb
= 31 - (j
+ xoff
) % 32;
83 if((fglyph
.fglyph
[ge
] >> gb
) & 1)
95 stride
= width
= height
= 0;
98 font2::glyph::glyph(std::istream
& s
)
102 bool upside_down
= true;
106 throw std::runtime_error("Can't read glyph bitmap header");
107 if(serialization::u16l(header
+ 0) != 0x4D42)
108 throw std::runtime_error("Bad glyph BMP magic");
109 if(serialization::u16l(header
+ 14) != 12) {
113 s
.read(header
+ 26, 14);
115 throw std::runtime_error("Can't read glyph bitmap header");
118 uint32_t startoff
= serialization::u32l(header
+ 10);
120 width
= serialization::u16l(header
+ 18);
121 height
= serialization::u16l(header
+ 20);
122 if(serialization::u16l(header
+ 22) != 1)
123 throw std::runtime_error("Bad glyph BMP planecount");
124 if(serialization::u16l(header
+ 24) != 1)
125 throw std::runtime_error("Bad glyph BMP bitdepth");
127 throw std::runtime_error("Glyph BMP data can't overlap header");
129 long _width
= serialization::s32l(header
+ 18);
130 long _height
= serialization::s32l(header
+ 22);
132 throw std::runtime_error("Bad glyph BMP size");
136 height
= (_height
>= 0) ? height
: -height
;
138 if(serialization::u16l(header
+ 26) != 1)
139 throw std::runtime_error("Bad glyph BMP planecount");
140 if(serialization::u16l(header
+ 28) != 1)
141 throw std::runtime_error("Bad glyph BMP bitdepth");
142 if(serialization::u32l(header
+ 30) != 0)
143 throw std::runtime_error("Bad glyph BMP compression method");
145 throw std::runtime_error("Glyph BMP data can't overlap header");
147 //Discard data until start of bitmap.
148 while(rcount
< startoff
) {
151 throw std::runtime_error("EOF while skipping to BMP data");
154 stride
= (width
+ 31) / 32;
155 fglyph
.resize(stride
* height
);
156 memset(&fglyph
[0], 0, sizeof(uint32_t) * fglyph
.size());
157 size_t toskip
= (4 - ((width
+ 7) / 8) % 4) % 4;
158 for(size_t i
= 0; i
< height
; i
++) {
159 size_t y
= upside_down
? (height
- i
- 1) : i
;
160 size_t bpos
= y
* stride
* 32;
161 for(size_t j
= 0; j
< width
; j
+= 8) {
162 size_t e
= (bpos
+ j
) / 32;
163 size_t b
= (bpos
+ j
) % 32;
166 throw std::runtime_error("EOF while reading BMP data");
167 fglyph
[e
] |= ((uint32_t)c
<< (24 - b
));
169 for(size_t j
= 0; j
< toskip
; j
++) {
172 throw std::runtime_error("EOF while reading BMP data");
177 void font2::glyph::render(fb
<false>& fb
, int32_t x
, int32_t y
, color fg
,
178 color bg
, color hl
) const
180 _render(*this, fb
, x
, y
, fg
, bg
, hl
);
183 void font2::glyph::render(fb
<true>& fb
, int32_t x
, int32_t y
, color fg
,
184 color bg
, color hl
) const
186 _render(*this, fb
, x
, y
, fg
, bg
, hl
);
195 font2::font2(const std::string
& file
)
197 std::istream
* toclose
= NULL
;
201 for(auto member
: r
) {
202 //Parse the key out of filename.
204 std::string tname
= member
;
208 } else if(regex_match("[0-9]+(-[0-9]+)*", tname
))
209 for(auto& tmp
: token_iterator_foreach(tname
, {"-"}))
210 key
.append(1, parse_value
<uint32_t>(tmp
));
216 std::istream
& s
= r
[member
];
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 font2::font2(struct font
& bfont
)
241 auto s
= bfont
.get_glyphs_set();
242 for(auto i
= s
.begin();;i
++) {
243 const font::glyph
& j
= (i
!= s
.end()) ? bfont
.get_glyph(*i
) : bfont
.get_bad_glyph();
245 k
.width
= j
.wide
? 16 : 8;
249 for(size_t y
= 0; y
< 16; y
++) {
251 uint32_t r
= j
.data
[y
/ (j
.wide
? 2 : 4)];
253 r
>>= 16 - ((y
& 1) << 4);
255 r
>>= 24 - ((y
& 3) << 3);
256 for(size_t x
= 0; x
< k
.width
; x
++) {
257 uint32_t b
= (j
.wide
? 15 : 7) - x
;
258 if(((r
>> b
) & 1) != 0)
259 k
.fglyph
[y
] |= 1UL << (31 - x
);
262 std::u32string key
= (i
!= s
.end()) ? std::u32string(1, *i
) : std::u32string();
264 if(i
== s
.end()) break;
269 std::ostream
& operator<<(std::ostream
& os
, const std::u32string
& lkey
)
272 return (os
<< "bad");
273 for(size_t i
= 0; i
< lkey
.length(); i
++) {
276 os
<< static_cast<uint32_t>(lkey
[i
]);
281 void font2::add(const std::u32string
& key
, const glyph
& fglyph
) throw(std::bad_alloc
)
283 glyphs
[key
] = fglyph
;
284 if(fglyph
.height
> rowadvance
)
285 rowadvance
= fglyph
.height
;
288 std::u32string
font2::best_ligature_match(const std::u32string
& codepoints
, size_t start
) const
289 throw(std::bad_alloc
)
292 if(start
>= codepoints
.length())
294 std::u32string best
= tmp
;
295 for(size_t i
= 1; i
<= codepoints
.size() - start
; i
++) {
296 tmp
.append(1, codepoints
[start
+ i
- 1]);
297 std::u32string lkey
= tmp
;
298 if(glyphs
.count(lkey
))
300 auto j
= glyphs
.lower_bound(lkey
);
301 //If lower_bound is greater than equivalent length of string, there can be no better match.
302 if(j
== glyphs
.end())
304 const std::u32string
& tmp2
= j
->first
;
305 bool best_found
= false;
306 for(size_t k
= 0; k
< tmp2
.length() && start
+ k
< codepoints
.length(); k
++)
307 if(tmp2
[k
] > codepoints
[start
+ k
]) {
310 } else if(tmp2
[k
] < codepoints
[start
+ k
])
318 const font2::glyph
& font2::lookup_glyph(const std::u32string
& key
) const throw()
320 static glyph empty_glyph
;
321 auto i
= glyphs
.find(key
);
322 return (i
== glyphs
.end()) ? empty_glyph
: i
->second
;