|
|
71e4f2 |
|
|
|
71e4f2 |
#include <cstring></cstring>
|
|
|
71e4f2 |
|
|
|
71e4f2 |
#include <freetype2 ft2build.h=""></freetype2>
|
|
|
71e4f2 |
#include FT_BITMAP_H
|
|
|
71e4f2 |
|
|
|
71e4f2 |
#include <pango pangoft2.h=""></pango>
|
|
|
71e4f2 |
|
|
|
71e4f2 |
|
|
|
71e4f2 |
#include "surface.h"
|
|
|
71e4f2 |
#include "matrix.h"
|
|
|
71e4f2 |
|
|
|
71e4f2 |
#include "labpangorenderer.h"
|
|
|
71e4f2 |
|
|
|
71e4f2 |
|
|
|
71e4f2 |
|
|
|
71e4f2 |
struct _LabPangoRenderer {
|
|
|
71e4f2 |
PangoRenderer parent_instance;
|
|
|
f77c6c |
LabPangoRendererParams params;
|
|
|
71e4f2 |
};
|
|
|
71e4f2 |
|
|
|
71e4f2 |
struct _LabPangoRendererClass {
|
|
|
71e4f2 |
PangoRendererClass parent_class;
|
|
|
71e4f2 |
};
|
|
|
71e4f2 |
|
|
|
71e4f2 |
G_DEFINE_TYPE(LabPangoRenderer, lab_pango_renderer, PANGO_TYPE_RENDERER)
|
|
|
71e4f2 |
|
|
|
71e4f2 |
|
|
|
71e4f2 |
|
|
|
71e4f2 |
static void
|
|
|
71e4f2 |
put_ft_bitmap(Surface &surface, FT_Bitmap &bitmap, int x, int y, const Color &color) {
|
|
|
71e4f2 |
if (x >= surface.width() || y >= surface.height())
|
|
|
71e4f2 |
return;
|
|
|
71e4f2 |
if (x + (int)bitmap.width <= 0 || y + (int)bitmap.rows <= 0)
|
|
|
71e4f2 |
return;
|
|
|
71e4f2 |
|
|
|
71e4f2 |
const int bx = std::max(0, -x);
|
|
|
71e4f2 |
const int by = std::max(0, -y);
|
|
|
71e4f2 |
x = std::max(0, x);
|
|
|
71e4f2 |
y = std::max(0, y);
|
|
|
71e4f2 |
const int w = std::min(surface.width() - x, (int)bitmap.width - bx);
|
|
|
71e4f2 |
const int h = std::min(surface.height() - y, (int)bitmap.rows - by);
|
|
|
71e4f2 |
const int pitch = surface.pitch();
|
|
|
71e4f2 |
|
|
|
71e4f2 |
Color *dst_pixel = &surface[y][x];
|
|
|
71e4f2 |
const int dst_row_step = pitch - w;
|
|
|
71e4f2 |
|
|
|
71e4f2 |
const unsigned char *src_pixel = bitmap.buffer + by*bitmap.pitch + bx;
|
|
|
71e4f2 |
const int src_row_step = bitmap.pitch - w;
|
|
|
71e4f2 |
|
|
|
71e4f2 |
for(const Color *end = dst_pixel + pitch*h; dst_pixel != end; dst_pixel += dst_row_step, src_pixel += src_row_step) {
|
|
|
71e4f2 |
for(const Color *row_end = dst_pixel + w; dst_pixel != row_end; ++dst_pixel, ++src_pixel) {
|
|
|
71e4f2 |
Real a = *src_pixel * (1/255.0);
|
|
|
71e4f2 |
*dst_pixel = *dst_pixel*(1-a) + color*a;
|
|
|
71e4f2 |
}
|
|
|
71e4f2 |
}
|
|
|
71e4f2 |
}
|
|
|
71e4f2 |
|
|
|
71e4f2 |
|
|
|
71e4f2 |
static void
|
|
|
f77c6c |
put_ft_bitmap_mono(Surface &surface, FT_Bitmap &bitmap, int x, int y, const Color &color) {
|
|
|
f77c6c |
if (x >= surface.width() || y >= surface.height())
|
|
|
f77c6c |
return;
|
|
|
f77c6c |
if (x + (int)bitmap.width <= 0 || y + (int)bitmap.rows <= 0)
|
|
|
f77c6c |
return;
|
|
|
f77c6c |
|
|
|
f77c6c |
const int bx = std::max(0, -x);
|
|
|
f77c6c |
const int by = std::max(0, -y);
|
|
|
f77c6c |
x = std::max(0, x);
|
|
|
f77c6c |
y = std::max(0, y);
|
|
|
f77c6c |
const int w = std::min(surface.width() - x, (int)bitmap.width - bx);
|
|
|
f77c6c |
const int h = std::min(surface.height() - y, (int)bitmap.rows - by);
|
|
|
f77c6c |
const int pitch = surface.pitch();
|
|
|
f77c6c |
|
|
|
f77c6c |
Color *dst_pixel = &surface[y][x];
|
|
|
f77c6c |
const int dst_row_step = pitch - w;
|
|
|
f77c6c |
|
|
|
f77c6c |
const unsigned char *src_row = bitmap.buffer + by*bitmap.pitch;
|
|
|
f77c6c |
const int src_row_end = bx + w;
|
|
|
f77c6c |
|
|
|
f77c6c |
for(const Color *end = dst_pixel + pitch*h; dst_pixel != end; dst_pixel += dst_row_step, src_row += bitmap.pitch)
|
|
|
f77c6c |
for(int src_x = bx; src_x < src_row_end; ++dst_pixel, ++src_x)
|
|
|
f77c6c |
if (src_row[src_x/8] & (128 >> (src_x%8)))
|
|
|
f77c6c |
*dst_pixel = color;
|
|
|
f77c6c |
}
|
|
|
f77c6c |
|
|
|
f77c6c |
|
|
|
f77c6c |
static void
|
|
|
71e4f2 |
lab_pango_renderer_draw_glyph(
|
|
|
71e4f2 |
PangoRenderer *renderer,
|
|
|
71e4f2 |
PangoFont *font,
|
|
|
71e4f2 |
PangoGlyph glyph,
|
|
|
71e4f2 |
double x,
|
|
|
71e4f2 |
double y )
|
|
|
71e4f2 |
{
|
|
|
f77c6c |
const LabPangoRendererParams ¶ms = ((LabPangoRenderer*)renderer)->params;
|
|
|
f77c6c |
if (!params.surface)
|
|
|
71e4f2 |
return;
|
|
|
71e4f2 |
|
|
|
f77c6c |
Vector3 pos = params.matrix*Vector3(x, y, 1);
|
|
|
71e4f2 |
|
|
|
71e4f2 |
const int fx = (int)round(pos.x*64);
|
|
|
71e4f2 |
const int fy = (int)round(pos.y*64);
|
|
|
f77c6c |
int ix = fx / 64;
|
|
|
f77c6c |
int iy = fy / 64;
|
|
|
f77c6c |
|
|
|
71e4f2 |
FT_Vector vec = {};
|
|
|
71e4f2 |
vec.x = fx % 64;
|
|
|
71e4f2 |
vec.y = fy % 64;
|
|
|
71e4f2 |
|
|
|
f77c6c |
if (params.hinting) {
|
|
|
f77c6c |
if (vec.x >= 32) ++ix;
|
|
|
f77c6c |
if (vec.y >= 32) ++iy;
|
|
|
f77c6c |
vec.x = 0;
|
|
|
f77c6c |
vec.y = 0;
|
|
|
f77c6c |
}
|
|
|
f77c6c |
vec.y = -vec.y;
|
|
|
f77c6c |
|
|
|
f77c6c |
FT_Matrix mat = {};
|
|
|
f77c6c |
mat.xx = (int)round( params.glyph_matrix.m00*65536);
|
|
|
f77c6c |
mat.xy = (int)round(-params.glyph_matrix.m10*65536);
|
|
|
f77c6c |
mat.yx = (int)round(-params.glyph_matrix.m01*65536);
|
|
|
f77c6c |
mat.yy = (int)round( params.glyph_matrix.m11*65536);
|
|
|
f77c6c |
|
|
|
71e4f2 |
FT_Face face = pango_fc_font_lock_face((PangoFcFont*)font);
|
|
|
f77c6c |
FT_Set_Transform(face, &mat, &vec);
|
|
|
f77c6c |
if (!FT_Load_Glyph(face, glyph, params.hinting ? FT_LOAD_DEFAULT : FT_LOAD_NO_HINTING)) {
|
|
|
f77c6c |
if (!FT_Render_Glyph(face->glyph, params.antialiasing ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO)) {
|
|
|
f77c6c |
if (params.antialiasing) {
|
|
|
f77c6c |
put_ft_bitmap(
|
|
|
f77c6c |
*params.surface,
|
|
|
f77c6c |
face->glyph->bitmap,
|
|
|
f77c6c |
face->glyph->bitmap_left + ix,
|
|
|
f77c6c |
iy - face->glyph->bitmap_top,
|
|
|
f77c6c |
params.color );
|
|
|
f77c6c |
} else {
|
|
|
f77c6c |
put_ft_bitmap_mono(
|
|
|
f77c6c |
*params.surface,
|
|
|
f77c6c |
face->glyph->bitmap,
|
|
|
f77c6c |
face->glyph->bitmap_left + ix,
|
|
|
f77c6c |
iy - face->glyph->bitmap_top,
|
|
|
f77c6c |
params.color );
|
|
|
f77c6c |
}
|
|
|
71e4f2 |
}
|
|
|
71e4f2 |
}
|
|
|
71e4f2 |
pango_fc_font_unlock_face((PangoFcFont*)font);
|
|
|
71e4f2 |
}
|
|
|
71e4f2 |
|
|
|
71e4f2 |
|
|
|
71e4f2 |
static void
|
|
|
71e4f2 |
lab_pango_renderer_init(LabPangoRenderer *renderer) {
|
|
|
f77c6c |
memset(&renderer->params, 0, sizeof(renderer->params));
|
|
|
f77c6c |
renderer->params = LabPangoRendererParams();
|
|
|
71e4f2 |
}
|
|
|
71e4f2 |
|
|
|
71e4f2 |
static void
|
|
|
71e4f2 |
lab_pango_renderer_class_init(LabPangoRendererClass *klass)
|
|
|
71e4f2 |
{
|
|
|
71e4f2 |
PangoRendererClass *renderer_class = PANGO_RENDERER_CLASS(klass);
|
|
|
71e4f2 |
renderer_class->draw_glyph = lab_pango_renderer_draw_glyph;
|
|
|
71e4f2 |
}
|
|
|
71e4f2 |
|
|
|
71e4f2 |
|
|
|
71e4f2 |
static void
|
|
|
f77c6c |
lab_pango_fc_pattern_set_substitute(FcPattern *pattern, gpointer data) {
|
|
|
f77c6c |
const int &args = *(const int*)data;
|
|
|
71e4f2 |
FcPatternDel(pattern, FC_HINTING);
|
|
|
f77c6c |
FcPatternDel(pattern, FC_ANTIALIAS);
|
|
|
f77c6c |
FcPatternAddBool(pattern, FC_HINTING, (args & 1) ? FcTrue : FcFalse);
|
|
|
f77c6c |
FcPatternAddBool(pattern, FC_ANTIALIAS, (args & 2) ? FcTrue : FcFalse);
|
|
|
71e4f2 |
}
|
|
|
71e4f2 |
|
|
|
71e4f2 |
|
|
|
71e4f2 |
PangoRenderer*
|
|
|
f77c6c |
lab_pango_renderer_new(LabPangoRendererParams *params) {
|
|
|
f77c6c |
PangoRenderer *renderer = (PangoRenderer*)g_object_new(LAB_TYPE_PANGO_RENDERER, nullptr);
|
|
|
f77c6c |
lab_pango_renderer_set_params((LabPangoRenderer*)renderer, params);
|
|
|
f77c6c |
return renderer;
|
|
|
f77c6c |
}
|
|
|
71e4f2 |
|
|
|
71e4f2 |
void
|
|
|
f77c6c |
lab_pango_renderer_set_params(LabPangoRenderer *renderer, LabPangoRendererParams *params)
|
|
|
f77c6c |
{ if (params) renderer->params = *params; }
|
|
|
71e4f2 |
|
|
|
71e4f2 |
void
|
|
|
f77c6c |
lab_pango_renderer_get_params(LabPangoRenderer *renderer, LabPangoRendererParams *params)
|
|
|
f77c6c |
{ if (params) *params = renderer->params; }
|
|
|
71e4f2 |
|
|
|
71e4f2 |
|
|
|
71e4f2 |
PangoFontMap*
|
|
|
f77c6c |
lab_pango_font_map_new(bool hinting, bool antialiasing) {
|
|
|
f77c6c |
static int args[4] { 0, 1, 2, 3 }; // to avoid encoding of int into pointer
|
|
|
f77c6c |
|
|
|
71e4f2 |
PangoFontMap *font_map = pango_ft2_font_map_new();
|
|
|
71e4f2 |
pango_ft2_font_map_set_default_substitute(
|
|
|
71e4f2 |
(PangoFT2FontMap*)font_map,
|
|
|
f77c6c |
lab_pango_fc_pattern_set_substitute,
|
|
|
f77c6c |
args + (hinting ? 1 : 0) + (antialiasing ? 2 : 0),
|
|
|
71e4f2 |
nullptr );
|
|
|
71e4f2 |
return font_map;
|
|
|
71e4f2 |
}
|
|
|
71e4f2 |
|