mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-21 06:33:31 +00:00
19c13877ca
Issue #5227
178 lines
4.6 KiB
C++
178 lines
4.6 KiB
C++
/*
|
|
* \brief Functor for drawing text on a surface
|
|
* \author Norman Feske
|
|
* \date 2006-08-04
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2006-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__TEXT_PAINTER_H_
|
|
#define _INCLUDE__NITPICKER_GFX__TEXT_PAINTER_H_
|
|
|
|
#include <util/interface.h>
|
|
#include <util/utf8.h>
|
|
#include <nitpicker_gfx/glyph_painter.h>
|
|
|
|
|
|
struct Text_painter
|
|
{
|
|
using Point = Genode::Surface_base::Point;
|
|
using Area = Genode::Surface_base::Area;
|
|
using Rect = Genode::Surface_base::Rect;
|
|
using Codepoint = Genode::Codepoint;
|
|
using Fixpoint_number = Glyph_painter::Fixpoint_number;
|
|
using Position = Glyph_painter::Position;
|
|
using Glyph = Glyph_painter::Glyph;
|
|
|
|
|
|
/***************************************
|
|
** Interface for accessing font data **
|
|
***************************************/
|
|
|
|
class Font : public Genode::Interface
|
|
{
|
|
protected:
|
|
|
|
struct Apply_fn : Genode::Interface
|
|
{
|
|
virtual void apply(Glyph const &) const = 0;
|
|
};
|
|
|
|
virtual void _apply_glyph(Codepoint c, Apply_fn const &) const = 0;
|
|
|
|
public:
|
|
|
|
template <typename FN>
|
|
void apply_glyph(Codepoint c, FN const &fn) const
|
|
{
|
|
/* helper to pass lambda 'fn' to virtual '_apply_glyph' method */
|
|
struct Wrapped_fn : Apply_fn
|
|
{
|
|
FN const &_fn;
|
|
void apply(Glyph const &glyph) const override { _fn(glyph); }
|
|
Wrapped_fn(FN const &fn) : _fn(fn) { }
|
|
};
|
|
|
|
_apply_glyph(c, Wrapped_fn(fn));
|
|
}
|
|
|
|
struct Advance_info
|
|
{
|
|
unsigned const width;
|
|
Fixpoint_number const advance;
|
|
};
|
|
|
|
virtual Advance_info advance_info(Codepoint c) const = 0;
|
|
|
|
/**
|
|
* Return distance from the top of a glyph the baseline of the font
|
|
*/
|
|
virtual unsigned baseline() const = 0;
|
|
|
|
/**
|
|
* Return height of text in pixels when rendered with the font
|
|
*/
|
|
virtual unsigned height() const = 0;
|
|
|
|
/**
|
|
* Return the bounding box that fits each single glyph of the font
|
|
*/
|
|
virtual Area bounding_box() const = 0;
|
|
|
|
/**
|
|
* Compute width of UTF8 string in pixels when rendered with the font
|
|
*/
|
|
Fixpoint_number string_width(Genode::Utf8_ptr utf8,
|
|
Genode::size_t len = ~0UL) const
|
|
{
|
|
Fixpoint_number result { (int)0 };
|
|
|
|
for (; utf8.complete() && len--; utf8 = utf8.next())
|
|
result.value += advance_info(utf8.codepoint()).advance.value;
|
|
|
|
return result;
|
|
}
|
|
|
|
unsigned index_at_xpos(Genode::Utf8_ptr utf8, unsigned xpos) const
|
|
{
|
|
unsigned index = 0;
|
|
Fixpoint_number x { (int)0 };
|
|
|
|
for (; utf8.complete(); utf8 = utf8.next(), index++) {
|
|
x.value += advance_info(utf8.codepoint()).advance.value;
|
|
if (x.decimal() > (int)xpos)
|
|
break;
|
|
}
|
|
|
|
return index;
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* Paint UTF8 string to surface
|
|
*/
|
|
template <typename PT>
|
|
static inline void paint(Genode::Surface<PT> &surface,
|
|
Position position,
|
|
Font const &font,
|
|
Genode::Color color,
|
|
char const *string)
|
|
{
|
|
/* use sub-pixel positioning horizontally */
|
|
Fixpoint_number x = position.x;
|
|
Fixpoint_number const y = position.y;
|
|
|
|
int const clip_top = surface.clip().y1(),
|
|
clip_bottom = surface.clip().y2() + 1,
|
|
clip_left = surface.clip().x1(),
|
|
clip_right = surface.clip().x2() + 1;
|
|
|
|
Genode::Utf8_ptr utf8(string);
|
|
|
|
/* skip glyphs hidden behind left clipping border */
|
|
bool skip = true;
|
|
while (skip && utf8.complete()) {
|
|
auto const glyph = font.advance_info(utf8.codepoint());
|
|
skip = x.decimal() + (int)glyph.width < clip_left;
|
|
if (skip) {
|
|
x.value += glyph.advance.value;
|
|
utf8 = utf8.next();
|
|
}
|
|
}
|
|
|
|
int const x_start = x.decimal();
|
|
|
|
unsigned const dst_line_len = surface.size().w;
|
|
|
|
PT * const dst = surface.addr();
|
|
|
|
PT const pixel(color.r, color.g, color.b);
|
|
int const alpha = color.a;
|
|
|
|
/* draw glyphs */
|
|
for ( ; utf8.complete() && (x.decimal() <= clip_right); utf8 = utf8.next()) {
|
|
|
|
font.apply_glyph(utf8.codepoint(), [&] (Glyph const &glyph) {
|
|
|
|
Glyph_painter::paint(Position(x, y), glyph, dst, dst_line_len,
|
|
clip_top, clip_bottom, clip_left, clip_right,
|
|
pixel, alpha);
|
|
|
|
x.value += glyph.advance.value;
|
|
});
|
|
}
|
|
|
|
surface.flush_pixels(Rect(Point(x_start, y.decimal()),
|
|
Area(x.decimal() - x_start + 1,
|
|
font.bounding_box().h)));
|
|
}
|
|
};
|
|
|
|
#endif /* _INCLUDE__NITPICKER_GFX__TEXT_PAINTER_H_ */
|