mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-28 01:28:53 +00:00
15c8cac78b
Clang really doesn't like char subscripts. I can't say I blame it. Fix the warning by an explicit cast to unsigned. include/nitpicker_gfx/tff_font.h:230:53: error: array subscript is of type 'char' [-Werror,-Wchar-subscripts] Tff::Vertical_metrics const m = _vertical_metrics['m']; ^~~~ Issue #4421
243 lines
5.8 KiB
C++
243 lines
5.8 KiB
C++
/*
|
|
* \brief Implementation of 'Text_painter::Font' using a trivial font format
|
|
* \author Norman Feske
|
|
* \date 2018-03-12
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2018 Genode Labs GmbH
|
|
*
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
* under the terms of the GNU Affero General Public License version 3.
|
|
*/
|
|
|
|
#ifndef _INCLUDE__NITPICKER_GFX__TFF_FONT_H_
|
|
#define _INCLUDE__NITPICKER_GFX__TFF_FONT_H_
|
|
|
|
#include <base/allocator.h>
|
|
#include <nitpicker_gfx/text_painter.h>
|
|
|
|
class Tff_font : public Text_painter::Font
|
|
{
|
|
public:
|
|
|
|
struct Glyph_buffer
|
|
{
|
|
char * const ptr;
|
|
Genode::size_t const size;
|
|
};
|
|
|
|
template <unsigned SIZE>
|
|
struct Static_glyph_buffer : Glyph_buffer
|
|
{
|
|
char _data[SIZE];
|
|
Static_glyph_buffer() : Glyph_buffer({_data, sizeof(_data)}) { }
|
|
};
|
|
|
|
struct Allocated_glyph_buffer : Tff_font::Glyph_buffer
|
|
{
|
|
Genode::Allocator &_alloc;
|
|
|
|
Allocated_glyph_buffer(void const *tff, Genode::Allocator &alloc)
|
|
:
|
|
Tff_font::Glyph_buffer({
|
|
(char *)alloc.alloc(Tff_font::glyph_buffer_size(tff)),
|
|
Tff_font::glyph_buffer_size(tff) }),
|
|
_alloc(alloc)
|
|
{ }
|
|
|
|
~Allocated_glyph_buffer()
|
|
{
|
|
_alloc.free(ptr, size);
|
|
}
|
|
};
|
|
|
|
private:
|
|
|
|
typedef Genode::int32_t int32_t;
|
|
|
|
typedef Text_painter::Codepoint Codepoint;
|
|
typedef Text_painter::Area Area;
|
|
typedef Text_painter::Glyph Glyph;
|
|
|
|
Glyph_buffer &_buf;
|
|
|
|
enum { NUM_GLYPHS = 256, PAD_LEFT = 1 };
|
|
|
|
struct Tff
|
|
{
|
|
unsigned char const *img; /* font image */
|
|
int const img_w, img_h; /* size of font image */
|
|
int32_t const *otab; /* offset table */
|
|
int32_t const *wtab; /* width table */
|
|
|
|
Tff(void const *data)
|
|
:
|
|
img((unsigned char *)data + 2056),
|
|
|
|
img_w(*((int32_t *)((unsigned char *)data + 2048))),
|
|
img_h(*((int32_t *)((unsigned char *)data + 2052))),
|
|
|
|
otab((int32_t *)(data)),
|
|
wtab((int32_t *)((unsigned char *)data + 1024))
|
|
{ }
|
|
|
|
Area bounding_box() const
|
|
{
|
|
unsigned max_w = 0;
|
|
for (unsigned i = 0; i < NUM_GLYPHS; i++)
|
|
max_w = Genode::max(max_w, (unsigned)wtab[i]);
|
|
|
|
return Area(max_w, img_h);
|
|
}
|
|
|
|
bool _glyph_line_empty(unsigned char c, unsigned y) const
|
|
{
|
|
unsigned char const * const line = img + otab[c] + y*img_w;
|
|
for (unsigned i = 0; i < (unsigned)wtab[c]; i++)
|
|
if (line[i])
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
struct Vertical_metrics
|
|
{
|
|
unsigned vpos;
|
|
unsigned height;
|
|
};
|
|
|
|
Vertical_metrics vertical_metrics(unsigned char c) const
|
|
{
|
|
unsigned y_start = 0;
|
|
unsigned y_end = img_h;
|
|
|
|
/* determine empty lines below glyph */
|
|
for (; y_end > 0; y_end--)
|
|
if (!_glyph_line_empty(c, y_end - 1))
|
|
break;
|
|
|
|
/* determine empty lines above glyph */
|
|
for (; y_start < (unsigned)img_h; y_start++)
|
|
if (!_glyph_line_empty(c, y_start))
|
|
break;
|
|
|
|
return Vertical_metrics {
|
|
.vpos = y_start,
|
|
.height = (y_end > y_start) ? y_end - y_start : 0
|
|
};
|
|
}
|
|
};
|
|
|
|
Tff const _tff;
|
|
|
|
Tff::Vertical_metrics _vertical_metrics[NUM_GLYPHS];
|
|
|
|
Area const _bounding_box = _tff.bounding_box();
|
|
|
|
/*
|
|
* Noncopyable
|
|
*/
|
|
Tff_font(Tff_font const &);
|
|
Tff_font &operator = (Tff_font const &);
|
|
|
|
public:
|
|
|
|
struct Invalid_format : Genode::Exception { };
|
|
struct Insufficient_glyph_buffer : Genode::Exception { };
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* \param tff font data
|
|
* \param glyph_buffer buffer for rendered glyph
|
|
*
|
|
* \throw Invalid_format
|
|
* \throw Insufficient_glyph_buffer
|
|
*
|
|
* The 'glyph_buffer' should be dimensioned via 'glyph_buffer_size()'.
|
|
*/
|
|
Tff_font(void const *tff, Glyph_buffer &glyph_buffer)
|
|
:
|
|
_buf(glyph_buffer), _tff(tff)
|
|
{
|
|
if (_tff.img_h < 1 || _tff.img_w < 1)
|
|
throw Invalid_format();
|
|
|
|
if (_buf.size < glyph_buffer_size(tff))
|
|
throw Insufficient_glyph_buffer();
|
|
|
|
for (unsigned i = 0; i < NUM_GLYPHS; i++)
|
|
_vertical_metrics[i] = _tff.vertical_metrics((unsigned char)i);
|
|
}
|
|
|
|
/**
|
|
* Return required glyph-buffer size for a given font
|
|
*/
|
|
static Genode::size_t glyph_buffer_size(void const *tff)
|
|
{
|
|
/* account for four-times horizontal supersampling */
|
|
return Tff(tff).bounding_box().count()*4;
|
|
}
|
|
|
|
void _apply_glyph(Codepoint c, Apply_fn const &fn) const override
|
|
{
|
|
unsigned const ascii = c.value & 0xff;
|
|
|
|
unsigned const w = _tff.wtab[ascii],
|
|
h = _vertical_metrics[ascii].height,
|
|
vpos = _vertical_metrics[ascii].vpos;
|
|
|
|
unsigned char const *glyph_line = _tff.img + _tff.otab[ascii]
|
|
+ vpos*_tff.img_w;
|
|
|
|
Glyph::Opacity *dst = (Glyph::Opacity *)_buf.ptr;
|
|
|
|
for (unsigned j = 0; j < h; j++) {
|
|
|
|
/* insert padding in front */
|
|
for (unsigned k = 0; k < PAD_LEFT*4; k++)
|
|
*dst++ = Glyph::Opacity { 0 };
|
|
|
|
/* copy line from font image to glyph */
|
|
for (unsigned i = 0; i < w; i++) {
|
|
Glyph::Opacity const opacity { glyph_line[i] };
|
|
for (unsigned k = 0; k < 4; k++)
|
|
*dst++ = opacity;
|
|
}
|
|
glyph_line += _tff.img_w;
|
|
}
|
|
|
|
Glyph const glyph { .width = w + PAD_LEFT,
|
|
.height = h,
|
|
.vpos = vpos,
|
|
.advance = (int)w,
|
|
.values = (Glyph::Opacity *)_buf.ptr };
|
|
fn.apply(glyph);
|
|
}
|
|
|
|
Advance_info advance_info(Codepoint c) const override
|
|
{
|
|
unsigned const ascii = c.value & 0xff;
|
|
unsigned const w = _tff.wtab[ascii];
|
|
|
|
return Advance_info { .width = w + PAD_LEFT,
|
|
.advance = (int)w };
|
|
}
|
|
|
|
unsigned baseline() const override
|
|
{
|
|
Tff::Vertical_metrics const m = _vertical_metrics[(unsigned)'m'];
|
|
return m.vpos + m.height;
|
|
}
|
|
|
|
unsigned height() const override
|
|
{
|
|
return _bounding_box.h();
|
|
}
|
|
|
|
Area bounding_box() const override { return _bounding_box; }
|
|
};
|
|
|
|
#endif /* _INCLUDE__NITPICKER_GFX__TFF_FONT_H_ */
|