/* * \brief Functor for drawing glyphs * \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__GLYPH_PAINTER_H_ #define _INCLUDE__NITPICKER_GFX__GLYPH_PAINTER_H_ #include #include #include struct Glyph_painter { /** * Subpixel positions are represented as fixpoint numbers that use 24 bits * for the decimal and 8 bits for the fractional part. */ struct Fixpoint_number { int value; Fixpoint_number(float value) : value(value*256) { }; Fixpoint_number(int decimal) : value(decimal << 8) { }; int decimal() const { return value >> 8; } }; typedef Genode::Point Position; struct Glyph { unsigned const width; unsigned const height; unsigned const vpos; Fixpoint_number const advance; struct Opacity { unsigned char value; }; /** * Pointer to opacity values (0 = transparent, 255 = opaque) * * The 'values' buffer contains the glyph horizontally scaled by four. * Its size is width*4*height bytes. The first row (four values) of each * line as well as the last line contains padding space, which does not * need to be drawn in order to obtain the complete shape. */ Opacity const * const values; unsigned num_values() const { return 4*width*height; } }; /** * Draw single glyph on a 'dst' buffer, with clipping applied * * In contrast to most painter functions, which operate on a 'Surface', * this function has a lower-level interface. It is intended as a utility * called by painter implementations, not by applications directly. */ template static inline void paint(Position const position, Glyph const &glyph, PT *dst, unsigned const dst_line_len, int const clip_top, int const clip_bottom, int const clip_left, int const clip_right, PT const color, int const alpha) { Fixpoint_number const x = position.x(); int const y = position.y().decimal(); int const dst_y1 = y + glyph.vpos, dst_y2 = dst_y1 + glyph.height; unsigned const clipped_from_top = clip_top > dst_y1 ? clip_top - dst_y1 : 0; unsigned const clipped_from_bottom = dst_y2 > clip_bottom ? dst_y2 - clip_bottom : 0; if (clipped_from_top + clipped_from_bottom >= glyph.height) return; unsigned const num_lines = glyph.height - clipped_from_top - clipped_from_bottom; int const w = glyph.width; int const start = Genode::max(0, clip_left - x.decimal()); int const end = Genode::min(w - 1, clip_right - x.decimal()); int const dst_x = start + ((x.value) >> 8); int const glyph_x = start*4 + 3 - ((x.value & 0xc0) >> 6); unsigned const glyph_line_len = 4*glyph.width; PT *dst_column = dst + dst_x + dst_line_len*(dst_y1 + clipped_from_top); typedef Glyph::Opacity Opacity; Opacity const *glyph_column = glyph.values + glyph_x + glyph_line_len*clipped_from_top; /* iterate over the visible columns of the glyph */ for (int i = start; i < end; i++) { /* weights of the two sampled values (horizontal neighbors)*/ int const u0 = x.value*4 & 0xff; int const u1 = 0x100 - u0; PT *d = dst_column; Opacity const *s = glyph_column; /* iterate over one column */ for (unsigned j = 0; j < num_lines; j++) { /* sample values from glyph image */ unsigned const v0 = s->value; unsigned const v1 = (s + 1)->value; /* apply weights */ int const value = (v0*u0 + v1*u1) >> 8; /* transfer pixel */ if (value) *d = (value == 255 && alpha == 255) ? color : PT::mix(*d, color, (alpha*value) >> 8); s += glyph_line_len; d += dst_line_len; } dst_column += 1; glyph_column += 4; } } }; #endif /* _INCLUDE__NITPICKER_GFX__GLYPH_PAINTER_H_ */