[paint] Add HB_PAINT_IMAGE_FORMAT_BGRA and use it in hb-ft
Now hb-ft can render color emoji as well. Just left COLRv2.
This commit is contained in:
parent
63db0d2aed
commit
381d410b1e
|
@ -244,6 +244,7 @@ hb_paint_color_func_t
|
|||
hb_paint_funcs_set_color_func
|
||||
HB_PAINT_IMAGE_FORMAT_PNG
|
||||
HB_PAINT_IMAGE_FORMAT_SVG
|
||||
HB_PAINT_IMAGE_FORMAT_BGRA
|
||||
hb_paint_image_func_t
|
||||
hb_paint_funcs_set_image_func
|
||||
hb_color_line_t
|
||||
|
@ -373,6 +374,7 @@ hb_font_get_glyph_v_origin
|
|||
hb_font_get_glyph_origin_for_direction
|
||||
hb_font_get_glyph_name
|
||||
hb_font_get_glyph_shape
|
||||
hb_font_draw_glyph
|
||||
hb_font_paint_glyph
|
||||
hb_font_get_nominal_glyph
|
||||
hb_font_get_nominal_glyphs
|
||||
|
@ -436,6 +438,8 @@ hb_font_get_glyph_name_func_t
|
|||
hb_font_funcs_set_glyph_name_func
|
||||
hb_font_get_glyph_shape_func_t
|
||||
hb_font_funcs_set_glyph_shape_func
|
||||
hb_font_draw_glyph_func_t
|
||||
hb_font_funcs_set_draw_glyph_func
|
||||
hb_font_paint_glyph_func_t
|
||||
hb_font_funcs_set_paint_glyph_func
|
||||
hb_font_get_nominal_glyph_func_t
|
||||
|
|
39
src/hb-ft.cc
39
src/hb-ft.cc
|
@ -830,7 +830,8 @@ hb_ft_paint_glyph (hb_font_t *font,
|
|||
/* We release the lock before calling into callbacks, such that
|
||||
* eg. draw API can call back into the face.*/
|
||||
|
||||
if (unlikely (FT_Load_Glyph (ft_face, gid, ft_font->load_flags)))
|
||||
if (unlikely (FT_Load_Glyph (ft_face, gid,
|
||||
ft_font->load_flags | FT_LOAD_COLOR)))
|
||||
return;
|
||||
|
||||
if (ft_face->glyph->format == FT_GLYPH_FORMAT_OUTLINE)
|
||||
|
@ -898,6 +899,42 @@ hb_ft_paint_glyph (hb_font_t *font,
|
|||
return;
|
||||
}
|
||||
|
||||
auto *glyph = ft_face->glyph;
|
||||
if (glyph->format == FT_GLYPH_FORMAT_BITMAP)
|
||||
{
|
||||
auto &bitmap = glyph->bitmap;
|
||||
if (bitmap.pixel_mode == FT_PIXEL_MODE_BGRA)
|
||||
{
|
||||
if (bitmap.pitch != (signed) bitmap.width * 4)
|
||||
return;
|
||||
|
||||
ft_font->lock.unlock ();
|
||||
|
||||
hb_blob_t *blob = hb_blob_create ((const char *) bitmap.buffer,
|
||||
bitmap.pitch * bitmap.rows,
|
||||
HB_MEMORY_MODE_DUPLICATE,
|
||||
nullptr, nullptr);
|
||||
|
||||
hb_glyph_extents_t extents;
|
||||
if (!hb_font_get_glyph_extents (font, gid, &extents))
|
||||
goto out;
|
||||
|
||||
paint_funcs->image (paint_data,
|
||||
blob,
|
||||
bitmap.width,
|
||||
bitmap.rows,
|
||||
HB_PAINT_IMAGE_FORMAT_BGRA,
|
||||
font->slant_xy,
|
||||
&extents);
|
||||
|
||||
out:
|
||||
hb_blob_destroy (blob);
|
||||
ft_font->lock.lock ();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* TODO Support image, COLRv0/1. */
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -227,17 +227,31 @@ typedef void (*hb_paint_color_func_t) (hb_paint_funcs_t *funcs,
|
|||
/**
|
||||
* HB_PAINT_IMAGE_FORMAT_PNG:
|
||||
*
|
||||
* Tag identifying png images in #hb_paint_image_func_t callbacks.
|
||||
* Tag identifying PNG images in #hb_paint_image_func_t callbacks.
|
||||
*
|
||||
* Since: REPLACEME
|
||||
*/
|
||||
#define HB_PAINT_IMAGE_FORMAT_PNG HB_TAG('p','n','g',' ')
|
||||
|
||||
/**
|
||||
* HB_PAINT_IMAGE_FORMAT_SVG:
|
||||
*
|
||||
* Tag identifying svg images in #hb_paint_image_func_t callbacks.
|
||||
* Tag identifying SVG images in #hb_paint_image_func_t callbacks.
|
||||
*
|
||||
* Since: REPLACEME
|
||||
*/
|
||||
#define HB_PAINT_IMAGE_FORMAT_SVG HB_TAG('s','v','g',' ')
|
||||
|
||||
/**
|
||||
* HB_PAINT_IMAGE_FORMAT_BGRA:
|
||||
*
|
||||
* Tag identifying raw pixel-data images in #hb_paint_image_func_t callbacks.
|
||||
* The data is in BGRA pre-multiplied sRGBA color-space format.
|
||||
*
|
||||
* Since: REPLACEME
|
||||
*/
|
||||
#define HB_PAINT_IMAGE_FORMAT_BGRA HB_TAG('B','G','R','A')
|
||||
|
||||
/**
|
||||
* hb_paint_image_func_t:
|
||||
* @funcs: paint functions object
|
||||
|
|
|
@ -98,6 +98,14 @@ read_blob (void *closure,
|
|||
}
|
||||
#endif
|
||||
|
||||
static const cairo_user_data_key_t *_hb_cairo_surface_blob_user_data_key = {0};
|
||||
|
||||
static void
|
||||
_hb_cairo_destroy_blob (void *p)
|
||||
{
|
||||
hb_blob_destroy ((hb_blob_t *) p);
|
||||
}
|
||||
|
||||
void
|
||||
hb_cairo_paint_glyph_image (cairo_t *cr,
|
||||
hb_blob_t *blob,
|
||||
|
@ -107,19 +115,68 @@ hb_cairo_paint_glyph_image (cairo_t *cr,
|
|||
float slant,
|
||||
hb_glyph_extents_t *extents)
|
||||
{
|
||||
#ifdef CAIRO_HAS_PNG_FUNCTIONS
|
||||
if (format != HB_PAINT_IMAGE_FORMAT_PNG || !extents)
|
||||
if (!extents) /* SVG currently. */
|
||||
return;
|
||||
|
||||
read_blob_data_t r;
|
||||
r.blob = blob;
|
||||
r.offset = 0;
|
||||
cairo_surface_t *surface = cairo_image_surface_create_from_png_stream (read_blob, &r);
|
||||
cairo_surface_t *surface = NULL;
|
||||
|
||||
/* For PNG, width,height can be unreliable, as is the case for NotoColorEmoji :(.
|
||||
* Just pull them out of the surface. */
|
||||
width = cairo_image_surface_get_width (surface);
|
||||
height = cairo_image_surface_get_width (surface);
|
||||
#ifdef CAIRO_HAS_PNG_FUNCTIONS
|
||||
if (format == HB_PAINT_IMAGE_FORMAT_PNG)
|
||||
{
|
||||
read_blob_data_t r;
|
||||
r.blob = blob;
|
||||
r.offset = 0;
|
||||
surface = cairo_image_surface_create_from_png_stream (read_blob, &r);
|
||||
|
||||
/* For PNG, width,height can be unreliable, as is the case for NotoColorEmoji :(.
|
||||
* Just pull them out of the surface. */
|
||||
width = cairo_image_surface_get_width (surface);
|
||||
height = cairo_image_surface_get_width (surface);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (format == HB_PAINT_IMAGE_FORMAT_BGRA)
|
||||
{
|
||||
/* Byte-endian conversion. */
|
||||
unsigned data_size = hb_blob_get_length (blob);
|
||||
if (data_size < width * height * 4)
|
||||
return;
|
||||
|
||||
unsigned char *data;
|
||||
if (__BYTE_ORDER == __BIG_ENDIAN)
|
||||
{
|
||||
data = (unsigned char *) hb_blob_get_data_writable (blob, NULL);
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
unsigned count = width * height * 4;
|
||||
for (unsigned i = 0; i < count; i += 4)
|
||||
{
|
||||
unsigned char b;
|
||||
b = data[i];
|
||||
data[i] = data[i+3];
|
||||
data[i+3] = b;
|
||||
b = data[i+1];
|
||||
data[i+1] = data[i+2];
|
||||
data[i+2] = b;
|
||||
}
|
||||
}
|
||||
else
|
||||
data = (unsigned char *) hb_blob_get_data (blob, NULL);
|
||||
|
||||
surface = cairo_image_surface_create_for_data (data,
|
||||
CAIRO_FORMAT_ARGB32,
|
||||
width, height,
|
||||
width * 4);
|
||||
|
||||
cairo_surface_set_user_data (surface,
|
||||
_hb_cairo_surface_blob_user_data_key,
|
||||
hb_blob_reference (blob),
|
||||
_hb_cairo_destroy_blob);
|
||||
}
|
||||
|
||||
if (!surface)
|
||||
return;
|
||||
|
||||
cairo_pattern_t *pattern = cairo_pattern_create_for_surface (surface);
|
||||
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
|
||||
|
@ -141,7 +198,6 @@ hb_cairo_paint_glyph_image (cairo_t *cr,
|
|||
|
||||
cairo_pattern_destroy (pattern);
|
||||
cairo_surface_destroy (surface);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
Loading…
Reference in New Issue