[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_funcs_set_color_func
|
||||||
HB_PAINT_IMAGE_FORMAT_PNG
|
HB_PAINT_IMAGE_FORMAT_PNG
|
||||||
HB_PAINT_IMAGE_FORMAT_SVG
|
HB_PAINT_IMAGE_FORMAT_SVG
|
||||||
|
HB_PAINT_IMAGE_FORMAT_BGRA
|
||||||
hb_paint_image_func_t
|
hb_paint_image_func_t
|
||||||
hb_paint_funcs_set_image_func
|
hb_paint_funcs_set_image_func
|
||||||
hb_color_line_t
|
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_origin_for_direction
|
||||||
hb_font_get_glyph_name
|
hb_font_get_glyph_name
|
||||||
hb_font_get_glyph_shape
|
hb_font_get_glyph_shape
|
||||||
|
hb_font_draw_glyph
|
||||||
hb_font_paint_glyph
|
hb_font_paint_glyph
|
||||||
hb_font_get_nominal_glyph
|
hb_font_get_nominal_glyph
|
||||||
hb_font_get_nominal_glyphs
|
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_funcs_set_glyph_name_func
|
||||||
hb_font_get_glyph_shape_func_t
|
hb_font_get_glyph_shape_func_t
|
||||||
hb_font_funcs_set_glyph_shape_func
|
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_paint_glyph_func_t
|
||||||
hb_font_funcs_set_paint_glyph_func
|
hb_font_funcs_set_paint_glyph_func
|
||||||
hb_font_get_nominal_glyph_func_t
|
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
|
/* We release the lock before calling into callbacks, such that
|
||||||
* eg. draw API can call back into the face.*/
|
* 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;
|
return;
|
||||||
|
|
||||||
if (ft_face->glyph->format == FT_GLYPH_FORMAT_OUTLINE)
|
if (ft_face->glyph->format == FT_GLYPH_FORMAT_OUTLINE)
|
||||||
|
@ -898,6 +899,42 @@ hb_ft_paint_glyph (hb_font_t *font,
|
||||||
return;
|
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. */
|
/* TODO Support image, COLRv0/1. */
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -227,17 +227,31 @@ typedef void (*hb_paint_color_func_t) (hb_paint_funcs_t *funcs,
|
||||||
/**
|
/**
|
||||||
* HB_PAINT_IMAGE_FORMAT_PNG:
|
* 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',' ')
|
#define HB_PAINT_IMAGE_FORMAT_PNG HB_TAG('p','n','g',' ')
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HB_PAINT_IMAGE_FORMAT_SVG:
|
* 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',' ')
|
#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:
|
* hb_paint_image_func_t:
|
||||||
* @funcs: paint functions object
|
* @funcs: paint functions object
|
||||||
|
|
|
@ -98,6 +98,14 @@ read_blob (void *closure,
|
||||||
}
|
}
|
||||||
#endif
|
#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
|
void
|
||||||
hb_cairo_paint_glyph_image (cairo_t *cr,
|
hb_cairo_paint_glyph_image (cairo_t *cr,
|
||||||
hb_blob_t *blob,
|
hb_blob_t *blob,
|
||||||
|
@ -107,19 +115,68 @@ hb_cairo_paint_glyph_image (cairo_t *cr,
|
||||||
float slant,
|
float slant,
|
||||||
hb_glyph_extents_t *extents)
|
hb_glyph_extents_t *extents)
|
||||||
{
|
{
|
||||||
#ifdef CAIRO_HAS_PNG_FUNCTIONS
|
if (!extents) /* SVG currently. */
|
||||||
if (format != HB_PAINT_IMAGE_FORMAT_PNG || !extents)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
cairo_surface_t *surface = NULL;
|
||||||
|
|
||||||
|
#ifdef CAIRO_HAS_PNG_FUNCTIONS
|
||||||
|
if (format == HB_PAINT_IMAGE_FORMAT_PNG)
|
||||||
|
{
|
||||||
read_blob_data_t r;
|
read_blob_data_t r;
|
||||||
r.blob = blob;
|
r.blob = blob;
|
||||||
r.offset = 0;
|
r.offset = 0;
|
||||||
cairo_surface_t *surface = cairo_image_surface_create_from_png_stream (read_blob, &r);
|
surface = cairo_image_surface_create_from_png_stream (read_blob, &r);
|
||||||
|
|
||||||
/* For PNG, width,height can be unreliable, as is the case for NotoColorEmoji :(.
|
/* For PNG, width,height can be unreliable, as is the case for NotoColorEmoji :(.
|
||||||
* Just pull them out of the surface. */
|
* Just pull them out of the surface. */
|
||||||
width = cairo_image_surface_get_width (surface);
|
width = cairo_image_surface_get_width (surface);
|
||||||
height = 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_t *pattern = cairo_pattern_create_for_surface (surface);
|
||||||
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
|
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_pattern_destroy (pattern);
|
||||||
cairo_surface_destroy (surface);
|
cairo_surface_destroy (surface);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
Loading…
Reference in New Issue