[ft-colr] Add a paint context

This commit is contained in:
Behdad Esfahbod 2022-12-23 11:48:41 -07:00
parent 7a4b4c64f2
commit 882c2bca2d
1 changed files with 95 additions and 72 deletions

View File

@ -153,22 +153,43 @@ _hb_ft_color_line_get_extend (hb_color_line_t *color_line,
}
}
typedef struct hb_ft_paint_context_t hb_ft_paint_context_t;
static void
_hb_ft_paint (FT_OpaquePaint opaque_paint,
const hb_ft_font_t *ft_font,
hb_font_t *font,
hb_paint_funcs_t *paint_funcs, void *paint_data,
FT_Color *palette,
hb_color_t foreground)
_hb_ft_paint (hb_ft_paint_context_t *c,
FT_OpaquePaint opaque_paint);
struct hb_ft_paint_context_t
{
FT_Face ft_face = ft_font->ft_face;
hb_ft_paint_context_t (const hb_ft_font_t *ft_font,
hb_font_t *font,
hb_paint_funcs_t *paint_funcs, void *paint_data,
FT_Color *palette,
hb_color_t foreground) :
ft_font (ft_font), font(font),
funcs (paint_funcs), data (paint_data),
palette (palette), foreground (foreground) {}
void recurse (FT_OpaquePaint paint) { _hb_ft_paint (this, paint);
}
const hb_ft_font_t *ft_font;
hb_font_t *font;
hb_paint_funcs_t *funcs;
void *data;
FT_Color *palette;
hb_color_t foreground;
};
void
_hb_ft_paint (hb_ft_paint_context_t *c,
FT_OpaquePaint opaque_paint)
{
FT_Face ft_face = c->ft_font->ft_face;
FT_COLR_Paint paint;
if (!FT_Get_Paint (ft_face, opaque_paint, &paint))
return;
#define paint_recurse(other_paint) \
_hb_ft_paint (other_paint, ft_font, font, paint_funcs, paint_data, palette, foreground)
switch (paint.format)
{
case FT_COLR_PAINTFORMAT_COLR_LAYERS:
@ -178,9 +199,9 @@ _hb_ft_paint (FT_OpaquePaint opaque_paint,
&paint.u.colr_layers.layer_iterator,
&other_paint))
{
paint_funcs->push_group (paint_data);
paint_recurse (other_paint);
paint_funcs->pop_group (paint_data, HB_PAINT_COMPOSITE_MODE_SRC_OVER);
c->funcs->push_group (c->data);
c->recurse (other_paint);
c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER);
}
}
break;
@ -189,31 +210,31 @@ _hb_ft_paint (FT_OpaquePaint opaque_paint,
bool is_foreground = paint.u.solid.color.palette_index == 0xFFFF;
hb_color_t color;
if (is_foreground)
color = HB_COLOR (hb_color_get_blue (foreground),
hb_color_get_green (foreground),
hb_color_get_red (foreground),
(hb_color_get_alpha (foreground) * paint.u.solid.color.alpha) >> 14);
color = HB_COLOR (hb_color_get_blue (c->foreground),
hb_color_get_green (c->foreground),
hb_color_get_red (c->foreground),
(hb_color_get_alpha (c->foreground) * paint.u.solid.color.alpha) >> 14);
else
{
FT_Color ft_color = palette[paint.u.solid.color.palette_index];
FT_Color ft_color = c->palette[paint.u.solid.color.palette_index];
color = HB_COLOR (ft_color.blue,
ft_color.green,
ft_color.red,
(ft_color.alpha * paint.u.solid.color.alpha) >> 14);
}
paint_funcs->color (paint_data, is_foreground, color);
c->funcs->color (c->data, is_foreground, color);
}
break;
case FT_COLR_PAINTFORMAT_LINEAR_GRADIENT:
{
_hb_ft_get_color_stops_data_t data = {ft_face, palette, foreground};
_hb_ft_get_color_stops_data_t data = {ft_face, c->palette, c->foreground};
hb_color_line_t cl = {
&paint.u.linear_gradient.colorline,
_hb_ft_color_line_get_color_stops, &data,
_hb_ft_color_line_get_extend, nullptr
};
paint_funcs->linear_gradient (paint_data, &cl,
c->funcs->linear_gradient (c->data, &cl,
paint.u.linear_gradient.p0.x / 65536.f,
paint.u.linear_gradient.p0.y / 65536.f,
paint.u.linear_gradient.p1.x / 65536.f,
@ -224,14 +245,14 @@ _hb_ft_paint (FT_OpaquePaint opaque_paint,
break;
case FT_COLR_PAINTFORMAT_RADIAL_GRADIENT:
{
_hb_ft_get_color_stops_data_t data = {ft_face, palette, foreground};
_hb_ft_get_color_stops_data_t data = {ft_face, c->palette, c->foreground};
hb_color_line_t cl = {
&paint.u.linear_gradient.colorline,
_hb_ft_color_line_get_color_stops, &data,
_hb_ft_color_line_get_extend, nullptr
};
paint_funcs->radial_gradient (paint_data, &cl,
c->funcs->radial_gradient (c->data, &cl,
paint.u.radial_gradient.c0.x / 65536.f,
paint.u.radial_gradient.c0.y / 65536.f,
(paint.u.radial_gradient.r0 / 65536.f),
@ -242,14 +263,14 @@ _hb_ft_paint (FT_OpaquePaint opaque_paint,
break;
case FT_COLR_PAINTFORMAT_SWEEP_GRADIENT:
{
_hb_ft_get_color_stops_data_t data = {ft_face, palette, foreground};
_hb_ft_get_color_stops_data_t data = {ft_face, c->palette, c->foreground};
hb_color_line_t cl = {
&paint.u.linear_gradient.colorline,
_hb_ft_color_line_get_color_stops, &data,
_hb_ft_color_line_get_extend, nullptr
};
paint_funcs->sweep_gradient (paint_data, &cl,
c->funcs->sweep_gradient (c->data, &cl,
paint.u.sweep_gradient.center.x / 65536.f,
paint.u.sweep_gradient.center.y / 65536.f,
(paint.u.sweep_gradient.start_angle / 65536.f + 1) * (float) M_PI,
@ -258,15 +279,15 @@ _hb_ft_paint (FT_OpaquePaint opaque_paint,
break;
case FT_COLR_PAINTFORMAT_GLYPH:
{
paint_funcs->push_inverse_root_transform (paint_data, font);
ft_font->lock.unlock ();
paint_funcs->push_clip_glyph (paint_data, paint.u.glyph.glyphID, font);
ft_font->lock.lock ();
paint_funcs->push_root_transform (paint_data, font);
paint_recurse (paint.u.glyph.paint);
paint_funcs->pop_root_transform (paint_data);
paint_funcs->pop_clip (paint_data);
paint_funcs->pop_inverse_root_transform (paint_data);
c->funcs->push_inverse_root_transform (c->data, c->font);
c->ft_font->lock.unlock ();
c->funcs->push_clip_glyph (c->data, paint.u.glyph.glyphID, c->font);
c->ft_font->lock.lock ();
c->funcs->push_root_transform (c->data, c->font);
c->recurse (paint.u.glyph.paint);
c->funcs->pop_root_transform (c->data);
c->funcs->pop_clip (c->data);
c->funcs->pop_inverse_root_transform (c->data);
}
break;
case FT_COLR_PAINTFORMAT_COLR_GLYPH:
@ -283,64 +304,64 @@ _hb_ft_paint (FT_OpaquePaint opaque_paint,
has_clip_box = 0;
if (has_clip_box)
paint_funcs->push_clip_rectangle (paint_data,
c->funcs->push_clip_rectangle (c->data,
clip_box.bottom_left.x / 64.f,
clip_box.bottom_left.y / 64.f,
clip_box.top_right.x / 64.f,
clip_box.top_right.y / 64.f);
paint_recurse (other_paint);
c->recurse (other_paint);
if (has_clip_box)
paint_funcs->pop_clip (paint_data);
c->funcs->pop_clip (c->data);
}
}
break;
case FT_COLR_PAINTFORMAT_TRANSFORM:
{
paint_funcs->push_transform (paint_data,
c->funcs->push_transform (c->data,
paint.u.transform.affine.xx / 65536.f,
paint.u.transform.affine.yx / 65536.f,
paint.u.transform.affine.xy / 65536.f,
paint.u.transform.affine.yy / 65536.f,
paint.u.transform.affine.dx / 65536.f,
paint.u.transform.affine.dy / 65536.f);
paint_recurse (paint.u.transform.paint);
paint_funcs->pop_transform (paint_data);
c->recurse (paint.u.transform.paint);
c->funcs->pop_transform (c->data);
}
break;
case FT_COLR_PAINTFORMAT_TRANSLATE:
{
paint_funcs->push_transform (paint_data,
c->funcs->push_transform (c->data,
0.f, 0.f, 0.f, 0.f,
paint.u.translate.dx / 65536.f,
paint.u.translate.dy / 65536.f);
paint_recurse (paint.u.translate.paint);
paint_funcs->pop_transform (paint_data);
c->recurse (paint.u.translate.paint);
c->funcs->pop_transform (c->data);
}
break;
case FT_COLR_PAINTFORMAT_SCALE:
{
bool has_translate = paint.u.scale.center_x != 0 || paint.u.scale.center_y != 0;
if (has_translate)
paint_funcs->push_transform (paint_data,
c->funcs->push_transform (c->data,
1.f, 0.f, 0.f, 1.f,
+paint.u.scale.center_x / 65536.f,
+paint.u.scale.center_y / 65536.f);
paint_funcs->push_transform (paint_data,
c->funcs->push_transform (c->data,
paint.u.scale.scale_x / 65536.f,
0.f, 0.f,
paint.u.scale.scale_y / 65536.f,
0.f, 0.f);
if (has_translate)
paint_funcs->push_transform (paint_data,
c->funcs->push_transform (c->data,
1.f, 0.f, 0.f, 1.f,
-paint.u.scale.center_x / 65536.f,
-paint.u.scale.center_y / 65536.f);
paint_recurse (paint.u.scale.paint);
paint_funcs->pop_transform (paint_data);
c->recurse (paint.u.scale.paint);
c->funcs->pop_transform (c->data);
if (has_translate)
{
paint_funcs->pop_transform (paint_data);
paint_funcs->pop_transform (paint_data);
c->funcs->pop_transform (c->data);
c->funcs->pop_transform (c->data);
}
}
break;
@ -349,48 +370,48 @@ _hb_ft_paint (FT_OpaquePaint opaque_paint,
float a = paint.u.rotate.angle / 65536.f;
float cc = cosf (a * (float) M_PI);
float ss = sinf (a * (float) M_PI);
paint_funcs->push_transform (paint_data,
c->funcs->push_transform (c->data,
1.f, 0.f, 0.f, 1.f,
+paint.u.rotate.center_x / 65536.f,
+paint.u.rotate.center_y / 65536.f);
paint_funcs->push_transform (paint_data, cc, ss, -ss, cc, 0., 0.);
paint_funcs->push_transform (paint_data,
c->funcs->push_transform (c->data, cc, ss, -ss, cc, 0., 0.);
c->funcs->push_transform (c->data,
1.f, 0.f, 0.f, 1.f,
-paint.u.rotate.center_x / 65536.f,
-paint.u.rotate.center_y / 65536.f);
paint_recurse (paint.u.rotate.paint);
paint_funcs->pop_transform (paint_data);
paint_funcs->pop_transform (paint_data);
paint_funcs->pop_transform (paint_data);
c->recurse (paint.u.rotate.paint);
c->funcs->pop_transform (c->data);
c->funcs->pop_transform (c->data);
c->funcs->pop_transform (c->data);
}
break;
case FT_COLR_PAINTFORMAT_SKEW:
{
float x = +tanf (paint.u.skew.x_skew_angle / 65536.f * (float) M_PI);
float y = -tanf (paint.u.skew.y_skew_angle / 65536.f * (float) M_PI);
paint_funcs->push_transform (paint_data,
c->funcs->push_transform (c->data,
1.f, 0.f, 0.f, 1.f,
+paint.u.skew.center_x / 65536.f,
+paint.u.skew.center_y / 65536.f);
paint_funcs->push_transform (paint_data, 1., y, x, 1., 0., 0.);
paint_funcs->push_transform (paint_data,
c->funcs->push_transform (c->data, 1., y, x, 1., 0., 0.);
c->funcs->push_transform (c->data,
1.f, 0.f, 0.f, 1.f,
-paint.u.skew.center_x / 65536.f,
-paint.u.skew.center_y / 65536.f);
paint_recurse (paint.u.skew.paint);
paint_funcs->pop_transform (paint_data);
paint_funcs->pop_transform (paint_data);
paint_funcs->pop_transform (paint_data);
c->recurse (paint.u.skew.paint);
c->funcs->pop_transform (c->data);
c->funcs->pop_transform (c->data);
c->funcs->pop_transform (c->data);
}
break;
case FT_COLR_PAINTFORMAT_COMPOSITE:
{
paint_funcs->push_group (paint_data);
paint_recurse (paint.u.composite.backdrop_paint);
paint_funcs->push_group (paint_data);
paint_recurse (paint.u.composite.source_paint);
paint_funcs->pop_group (paint_data, _hb_ft_paint_composite_mode (paint.u.composite.composite_mode));
paint_funcs->pop_group (paint_data, HB_PAINT_COMPOSITE_MODE_SRC_OVER);
c->funcs->push_group (c->data);
c->recurse (paint.u.composite.backdrop_paint);
c->funcs->push_group (c->data);
c->recurse (paint.u.composite.source_paint);
c->funcs->pop_group (c->data, _hb_ft_paint_composite_mode (paint.u.composite.composite_mode));
c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER);
}
break;
@ -445,7 +466,10 @@ hb_ft_paint_glyph_colr (hb_font_t *font,
paint_funcs->push_root_transform (paint_data, font);
paint_recurse (paint);
hb_ft_paint_context_t c (ft_font, font,
paint_funcs, paint_data,
palette, foreground);
_hb_ft_paint (&c, paint);
paint_funcs->pop_root_transform (paint_data);
if (has_clip)
@ -495,7 +519,6 @@ hb_ft_paint_glyph_colr (hb_font_t *font,
return false;
}
#undef paint_recurse
#endif