aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFrancesco Abbate <francesco.bbt@gmail.com>2020-05-30 18:07:31 +0200
committerFrancesco Abbate <francesco.bbt@gmail.com>2020-05-30 18:07:31 +0200
commit103336945e4879d599025cd3e43b0de7f785cc0e (patch)
tree5e0187af5d447566fe7729607177d48f030f7ceb /src
parent010966d60db2537f2238e3dc2073e19ae22452d1 (diff)
downloadlite-xl-103336945e4879d599025cd3e43b0de7f785cc0e.tar.gz
lite-xl-103336945e4879d599025cd3e43b0de7f785cc0e.zip
Add pixel format to render font in bitmap format
The purpose it to add later subpixel by storing the bitmap with RGB channels to have subpixel LCD coverage information. The colorization and gamma blending will be done when blitting the glyph on the destination surface.
Diffstat (limited to 'src')
-rw-r--r--src/agg_pixfmt_alpha8.h93
-rw-r--r--src/font_renderer_alpha.h160
2 files changed, 253 insertions, 0 deletions
diff --git a/src/agg_pixfmt_alpha8.h b/src/agg_pixfmt_alpha8.h
new file mode 100644
index 00000000..b7b84f8d
--- /dev/null
+++ b/src/agg_pixfmt_alpha8.h
@@ -0,0 +1,93 @@
+#pragma once
+
+#include <string.h>
+#include "agg_basics.h"
+#include "agg_rendering_buffer.h"
+
+namespace agg
+{
+ // This is a special purpose color type that only has the alpha channel.
+ // It can be thought as a gray color but with the intensity always on.
+ // It is actually used to store coverage information.
+ struct alpha8
+ {
+ typedef int8u value_type;
+ typedef int32u calc_type;
+ typedef int32 long_type;
+ enum base_scale_e
+ {
+ base_shift = 8,
+ base_scale = 1 << base_shift,
+ base_mask = base_scale - 1
+ };
+
+ value_type a;
+
+ //--------------------------------------------------------------------
+ alpha8(unsigned a_=base_mask) :
+ a(int8u(a_)) {}
+ };
+
+ // Pixer format to store coverage information.
+ class pixfmt_alpha8
+ {
+ public:
+ typedef alpha8 color_type;
+ typedef int8u value_type;
+ typedef int32u calc_type;
+ typedef typename agg::rendering_buffer::row_data row_data;
+
+ //--------------------------------------------------------------------
+ pixfmt_alpha8(rendering_buffer& rb): m_rbuf(&rb)
+ {
+ }
+
+ //--------------------------------------------------------------------
+ unsigned width() const {
+ return m_rbuf->width();
+ }
+ unsigned height() const {
+ return m_rbuf->height();
+ }
+
+ // This method should never be called when using the scanline_u8.
+ // The use of scanline_p8 should be avoided because if does not works
+ // properly for rendering fonts because single hspan are split in many
+ // hline/hspan elements and pixel whitening happens.
+ void blend_hline(int x, int y, unsigned len,
+ const color_type& c, int8u cover)
+ { }
+
+ void copy_hline(int x, int y, unsigned len, const color_type& c)
+ {
+ value_type* p = (value_type*) m_rbuf->row_ptr(y) + x;
+ do
+ {
+ *p = c.a;
+ p++;
+ }
+ while(--len);
+ }
+
+ //--------------------------------------------------------------------
+ void blend_solid_hspan(int x, int y,
+ unsigned len,
+ const color_type& c,
+ const int8u* covers)
+ {
+ value_type* p = (value_type*) m_rbuf->row_ptr(y) + x;
+ do
+ {
+ calc_type alpha = (calc_type(c.a) * (calc_type(*covers) + 1)) >> 8;
+ *p = alpha;
+ p++;
+ ++covers;
+ }
+ while(--len);
+ }
+
+ private:
+ rendering_buffer* m_rbuf;
+ };
+
+}
diff --git a/src/font_renderer_alpha.h b/src/font_renderer_alpha.h
new file mode 100644
index 00000000..5d8681f5
--- /dev/null
+++ b/src/font_renderer_alpha.h
@@ -0,0 +1,160 @@
+#pragma once
+
+#include "agg_basics.h"
+#include "agg_conv_curve.h"
+#include "agg_conv_transform.h"
+#include "agg_gamma_lut.h"
+#include "agg_font_freetype.h"
+#include "agg_pixfmt_alpha8.h"
+#include "agg_rasterizer_scanline_aa.h"
+#include "agg_renderer_primitives.h"
+#include "agg_renderer_scanline.h"
+#include "agg_rendering_buffer.h"
+#include "agg_scanline_u.h"
+
+class font_renderer_alpha
+{
+ typedef agg::pixfmt_alpha8 pixfmt_type;
+ typedef agg::renderer_base<pixfmt_type> base_ren_type;
+ typedef agg::renderer_scanline_aa_solid<base_ren_type> renderer_solid;
+ typedef agg::font_engine_freetype_int32 font_engine_type;
+ typedef agg::font_cache_manager<font_engine_type> font_manager_type;
+
+ font_engine_type m_feng;
+ font_manager_type m_fman;
+
+ // Font rendering options.
+ bool m_hinting;
+ bool m_kerning;
+
+ bool m_font_loaded;
+
+ // Pipeline to process the vectors glyph paths (curves + contour)
+ agg::trans_affine m_mtx;
+ agg::conv_curve<font_manager_type::path_adaptor_type> m_curves;
+ agg::conv_transform<agg::conv_curve<font_manager_type::path_adaptor_type> > m_trans;
+public:
+ typedef agg::pixfmt_alpha8::color_type color_type;
+
+ font_renderer_alpha(bool hinting, bool kerning):
+ m_feng(),
+ m_fman(m_feng),
+ m_hinting(hinting),
+ m_kerning(kerning),
+ m_font_loaded(false),
+ m_curves(m_fman.path_adaptor()),
+ m_trans(m_curves, m_mtx)
+ { }
+
+ bool get_font_vmetrics(int& ascender, int& descender) {
+ int face_height = m_feng.face_height();
+ if (face_height > 0) {
+ double current_height = m_feng.height();
+ m_feng.height(1.0);
+ ascender = m_feng.ascender() * face_height;
+ descender = m_feng.descender() * face_height;
+ m_feng.height(current_height);
+ return true;
+ }
+ return false;
+ }
+
+ float scale_for_em_to_pixels(float size) {
+ int units_per_em = m_feng.face_units_em();
+ if (units_per_em > 0) {
+ return size / units_per_em;
+ }
+ return 0.0;
+ }
+
+ bool load_font(const char *font_filename) {
+ if(m_feng.load_font(font_filename, 0, agg::glyph_ren_outline)) {
+ m_font_loaded = true;
+ }
+ return m_font_loaded;
+ }
+
+ template<class Rasterizer, class Scanline, class RenSolid>
+ void draw_text(Rasterizer& ras, Scanline& sl,
+ RenSolid& ren_solid, const color_type color,
+ const char* text,
+ double& x, double& y, double height)
+ {
+ const double scale_x = 100;
+
+ m_feng.height(height);
+ m_feng.width(height * scale_x);
+ m_feng.hinting(m_hinting);
+
+ const char* p = text;
+
+ // Represent the delta in x scaled by scale_x.
+ double x_delta = 0;
+ double start_x = x;
+
+ while(*p)
+ {
+ if(*p == '\n')
+ {
+ x_delta = 0;
+ y -= height * 1.25;
+ ++p;
+ continue;
+ }
+
+ const agg::glyph_cache* glyph = m_fman.glyph(*p);
+ if(glyph)
+ {
+ if(m_kerning)
+ {
+ m_fman.add_kerning(&x_delta, &y);
+ }
+
+ m_fman.init_embedded_adaptors(glyph, 0, 0);
+ if(glyph->data_type == agg::glyph_data_outline)
+ {
+ double ty = m_hinting ? floor(y + 0.5) : y;
+ ras.reset();
+ m_mtx.reset();
+ m_mtx *= agg::trans_affine_scaling(1.0 / scale_x, 1);
+ m_mtx *= agg::trans_affine_translation(start_x + x_delta / scale_x, ty);
+ ras.add_path(m_trans);
+ ren_solid.color(color);
+ agg::render_scanlines(ras, sl, ren_solid);
+ }
+
+ // increment pen position
+ x_delta += glyph->advance_x;
+ y += glyph->advance_y;
+ }
+ ++p;
+ }
+ // Update x value befor returning.
+ x += x_delta / scale_x;
+ }
+
+ void clear(agg::rendering_buffer& ren_buf, const color_type color) {
+ pixfmt_type pf(ren_buf);
+ base_ren_type ren_base(pf);
+ ren_base.clear(color);
+ }
+
+ void render_text(agg::rendering_buffer& ren_buf,
+ const double text_size,
+ const color_type text_color,
+ double& x, double& y,
+ const char *text)
+ {
+ if (!m_font_loaded) {
+ return;
+ }
+ agg::scanline_u8 sl;
+ agg::rasterizer_scanline_aa<> ras;
+ ras.clip_box(0, 0, ren_buf.width(), ren_buf.height());
+
+ agg::pixfmt_alpha8 pf(ren_buf);
+ base_ren_type ren_base(pf);
+ renderer_solid ren_solid(ren_base);
+ draw_text(ras, sl, ren_solid, text_color, text, x, y, text_size);
+ }
+};