Compare commits
7 Commits
main
...
glyph-cach
Author | SHA1 | Date | |
---|---|---|---|
|
c476c45007 | ||
|
5d05270ca7 | ||
|
34fb85afd1 | ||
|
05bc4a86c7 | ||
|
93302cc42d | ||
|
976f45e614 | ||
|
befccc943a |
@@ -11,6 +11,7 @@
|
||||
#include "gdk/gdkprofilerprivate.h"
|
||||
|
||||
#include "gsk/gskdebugprivate.h"
|
||||
#include "gsk/gskprivate.h"
|
||||
|
||||
#define MAX_SLICES_PER_ATLAS 64
|
||||
|
||||
@@ -32,6 +33,37 @@ typedef struct _GskGpuCachedGlyph GskGpuCachedGlyph;
|
||||
typedef struct _GskGpuCachedTexture GskGpuCachedTexture;
|
||||
typedef struct _GskGpuDevicePrivate GskGpuDevicePrivate;
|
||||
|
||||
typedef struct {
|
||||
PangoFont *font;
|
||||
float scale;
|
||||
} FontCacheKey;
|
||||
|
||||
typedef struct {
|
||||
PangoGlyph glyph;
|
||||
GskGpuGlyphLookupFlags flags;
|
||||
} GlyphCacheKey;
|
||||
|
||||
typedef struct {
|
||||
FontCacheKey key;
|
||||
|
||||
GHashTable *cache;
|
||||
} FontGlyphCache;
|
||||
|
||||
static void
|
||||
font_glyph_cache_free (gpointer data)
|
||||
{
|
||||
FontGlyphCache *cache = data;
|
||||
|
||||
g_object_unref (cache->key.font);
|
||||
g_hash_table_unref (cache->cache);
|
||||
g_free (cache);
|
||||
}
|
||||
|
||||
static FontGlyphCache no_font_cache = {
|
||||
.key = { .font = NULL, .scale = -1 },
|
||||
.cache = NULL
|
||||
};
|
||||
|
||||
struct _GskGpuDevicePrivate
|
||||
{
|
||||
GdkDisplay *display;
|
||||
@@ -44,6 +76,7 @@ struct _GskGpuDevicePrivate
|
||||
|
||||
GHashTable *texture_cache;
|
||||
GHashTable *glyph_cache;
|
||||
FontGlyphCache *last_font_cache;
|
||||
|
||||
GskGpuCachedAtlas *current_atlas;
|
||||
|
||||
@@ -68,14 +101,15 @@ struct _GskGpuCachedClass
|
||||
struct _GskGpuCached
|
||||
{
|
||||
const GskGpuCachedClass *class;
|
||||
|
||||
GskGpuCachedAtlas *atlas;
|
||||
GskGpuCached *next;
|
||||
GskGpuCached *prev;
|
||||
|
||||
gint64 timestamp;
|
||||
gboolean stale;
|
||||
guint pixels; /* For glyphs and textures, pixels. For atlases, dead pixels */
|
||||
|
||||
unsigned int stale : 1;
|
||||
unsigned int pixels : 31; /* For glyphs and textures, pixels. For atlases, dead pixels */
|
||||
|
||||
};
|
||||
|
||||
static inline void
|
||||
@@ -360,10 +394,8 @@ struct _GskGpuCachedGlyph
|
||||
{
|
||||
GskGpuCached parent;
|
||||
|
||||
PangoFont *font;
|
||||
PangoGlyph glyph;
|
||||
GskGpuGlyphLookupFlags flags;
|
||||
float scale;
|
||||
FontGlyphCache *font_cache;
|
||||
GlyphCacheKey glyph_key;
|
||||
|
||||
GskGpuImage *image;
|
||||
graphene_rect_t bounds;
|
||||
@@ -376,10 +408,17 @@ gsk_gpu_cached_glyph_free (GskGpuDevice *device,
|
||||
{
|
||||
GskGpuDevicePrivate *priv = gsk_gpu_device_get_instance_private (device);
|
||||
GskGpuCachedGlyph *self = (GskGpuCachedGlyph *) cached;
|
||||
FontGlyphCache *font_cache;
|
||||
|
||||
g_hash_table_remove (priv->glyph_cache, self);
|
||||
font_cache = self->font_cache;
|
||||
g_hash_table_remove (font_cache->cache, self);
|
||||
if (g_hash_table_size (font_cache->cache) == 0)
|
||||
{
|
||||
if (priv->last_font_cache == font_cache)
|
||||
priv->last_font_cache = &no_font_cache;
|
||||
g_hash_table_remove (priv->glyph_cache, font_cache);
|
||||
}
|
||||
|
||||
g_object_unref (self->font);
|
||||
g_object_unref (self->image);
|
||||
|
||||
g_free (self);
|
||||
@@ -402,15 +441,35 @@ gsk_gpu_cached_glyph_should_collect (GskGpuDevice *device,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static guint
|
||||
gsk_gpu_cached_font_hash (gconstpointer data)
|
||||
{
|
||||
const FontGlyphCache *cache = data;
|
||||
const FontCacheKey *key = &cache->key;
|
||||
|
||||
return GPOINTER_TO_UINT (key->font) ^ ((guint) key->scale * PANGO_SCALE);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_gpu_cached_font_equal (gconstpointer v1,
|
||||
gconstpointer v2)
|
||||
{
|
||||
const FontGlyphCache *c1 = v1;
|
||||
const FontCacheKey *key1 = &c1->key;
|
||||
const FontGlyphCache *c2 = v2;
|
||||
const FontCacheKey *key2 = &c2->key;
|
||||
|
||||
return key1->font == key2->font &&
|
||||
key1->scale == key2->scale;
|
||||
}
|
||||
|
||||
static guint
|
||||
gsk_gpu_cached_glyph_hash (gconstpointer data)
|
||||
{
|
||||
const GskGpuCachedGlyph *glyph = data;
|
||||
const GlyphCacheKey *key = &glyph->glyph_key;
|
||||
|
||||
return GPOINTER_TO_UINT (glyph->font) ^
|
||||
glyph->glyph ^
|
||||
(glyph->flags << 24) ^
|
||||
((guint) glyph->scale * PANGO_SCALE);
|
||||
return key->glyph ^ (key->flags << 24);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -419,11 +478,11 @@ gsk_gpu_cached_glyph_equal (gconstpointer v1,
|
||||
{
|
||||
const GskGpuCachedGlyph *glyph1 = v1;
|
||||
const GskGpuCachedGlyph *glyph2 = v2;
|
||||
const GlyphCacheKey *key1 = &glyph1->glyph_key;
|
||||
const GlyphCacheKey *key2 = &glyph2->glyph_key;
|
||||
|
||||
return glyph1->font == glyph2->font
|
||||
&& glyph1->glyph == glyph2->glyph
|
||||
&& glyph1->flags == glyph2->flags
|
||||
&& glyph1->scale == glyph2->scale;
|
||||
return key1->glyph == key2->glyph &&
|
||||
key1->flags == key2->flags;
|
||||
}
|
||||
|
||||
static const GskGpuCachedClass GSK_GPU_CACHED_GLYPH_CLASS =
|
||||
@@ -622,10 +681,13 @@ gsk_gpu_device_init (GskGpuDevice *self)
|
||||
{
|
||||
GskGpuDevicePrivate *priv = gsk_gpu_device_get_instance_private (self);
|
||||
|
||||
priv->glyph_cache = g_hash_table_new (gsk_gpu_cached_glyph_hash,
|
||||
gsk_gpu_cached_glyph_equal);
|
||||
priv->glyph_cache = g_hash_table_new_full (gsk_gpu_cached_font_hash,
|
||||
gsk_gpu_cached_font_equal,
|
||||
NULL,
|
||||
font_glyph_cache_free);
|
||||
priv->texture_cache = g_hash_table_new (g_direct_hash,
|
||||
g_direct_equal);
|
||||
priv->last_font_cache = &no_font_cache;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -889,40 +951,71 @@ gsk_gpu_device_lookup_glyph_image (GskGpuDevice *self,
|
||||
GskGpuGlyphLookupFlags flags,
|
||||
float scale,
|
||||
graphene_rect_t *out_bounds,
|
||||
graphene_point_t *out_origin)
|
||||
graphene_point_t *out_origin,
|
||||
PangoFont **out_scaled_font)
|
||||
{
|
||||
GskGpuDevicePrivate *priv = gsk_gpu_device_get_instance_private (self);
|
||||
GskGpuCachedGlyph lookup = {
|
||||
.font = font,
|
||||
.glyph = glyph,
|
||||
.flags = flags,
|
||||
.scale = scale
|
||||
FontGlyphCache font_lookup = {
|
||||
.key = { .font = font, .scale = scale }
|
||||
};
|
||||
GskGpuCachedGlyph *cache;
|
||||
GskGpuCachedGlyph glyph_lookup = {
|
||||
.glyph_key = { .glyph = glyph, .flags = flags }
|
||||
};
|
||||
FontGlyphCache *font_cache = NULL;
|
||||
GskGpuCachedGlyph *cache = NULL;
|
||||
PangoRectangle ink_rect;
|
||||
graphene_rect_t rect;
|
||||
graphene_point_t origin;
|
||||
GskGpuImage *image;
|
||||
gsize atlas_x, atlas_y, padding;
|
||||
float subpixel_x, subpixel_y;
|
||||
PangoFont *scaled_font;
|
||||
|
||||
cache = g_hash_table_lookup (priv->glyph_cache, &lookup);
|
||||
if (cache)
|
||||
if (priv->last_font_cache->key.font == font &&
|
||||
priv->last_font_cache->key.scale == scale)
|
||||
font_cache = priv->last_font_cache;
|
||||
else
|
||||
font_cache = g_hash_table_lookup (priv->glyph_cache, &font_lookup);
|
||||
|
||||
if (font_cache)
|
||||
{
|
||||
gsk_gpu_cached_use (self, (GskGpuCached *) cache, gsk_gpu_frame_get_timestamp (frame));
|
||||
cache = g_hash_table_lookup (font_cache->cache, &glyph_lookup);
|
||||
if (cache)
|
||||
{
|
||||
gsk_gpu_cached_use (self, (GskGpuCached *) cache, gsk_gpu_frame_get_timestamp (frame));
|
||||
|
||||
*out_bounds = cache->bounds;
|
||||
*out_origin = cache->origin;
|
||||
return cache->image;
|
||||
*out_bounds = cache->bounds;
|
||||
*out_origin = cache->origin;
|
||||
|
||||
priv->last_font_cache = font_cache;
|
||||
|
||||
return cache->image;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
font_cache = g_new (FontGlyphCache, 1);
|
||||
font_cache->key.font = g_object_ref (font);
|
||||
font_cache->key.scale = scale;
|
||||
font_cache->cache = g_hash_table_new (gsk_gpu_cached_glyph_hash,
|
||||
gsk_gpu_cached_glyph_equal);
|
||||
g_hash_table_insert (priv->glyph_cache, font_cache, font_cache);
|
||||
}
|
||||
|
||||
priv->last_font_cache = font_cache;
|
||||
|
||||
if (*out_scaled_font)
|
||||
scaled_font = *out_scaled_font;
|
||||
else
|
||||
scaled_font = gsk_get_scaled_font (font, scale);
|
||||
|
||||
subpixel_x = (flags & 3) / 4.f;
|
||||
subpixel_y = ((flags >> 2) & 3) / 4.f;
|
||||
pango_font_get_glyph_extents (font, glyph, &ink_rect, NULL);
|
||||
origin.x = floor (ink_rect.x * scale / PANGO_SCALE + subpixel_x);
|
||||
origin.y = floor (ink_rect.y * scale / PANGO_SCALE + subpixel_y);
|
||||
rect.size.width = ceil ((ink_rect.x + ink_rect.width) * scale / PANGO_SCALE + subpixel_x) - origin.x;
|
||||
rect.size.height = ceil ((ink_rect.y + ink_rect.height) * scale / PANGO_SCALE + subpixel_y) - origin.y;
|
||||
pango_font_get_glyph_extents (scaled_font, glyph, &ink_rect, NULL);
|
||||
origin.x = floor (ink_rect.x * 1.0 / PANGO_SCALE + subpixel_x);
|
||||
origin.y = floor (ink_rect.y * 1.0 / PANGO_SCALE + subpixel_y);
|
||||
rect.size.width = ceil ((ink_rect.x + ink_rect.width) * 1.0 / PANGO_SCALE + subpixel_x) - origin.x;
|
||||
rect.size.height = ceil ((ink_rect.y + ink_rect.height) * 1.0 / PANGO_SCALE + subpixel_y) - origin.y;
|
||||
padding = 1;
|
||||
|
||||
image = gsk_gpu_device_add_atlas_image (self,
|
||||
@@ -944,10 +1037,9 @@ gsk_gpu_device_lookup_glyph_image (GskGpuDevice *self,
|
||||
cache = gsk_gpu_cached_new (self, &GSK_GPU_CACHED_GLYPH_CLASS, NULL);
|
||||
}
|
||||
|
||||
cache->font = g_object_ref (font);
|
||||
cache->glyph = glyph;
|
||||
cache->flags = flags;
|
||||
cache->scale = scale;
|
||||
cache->font_cache = font_cache;
|
||||
cache->glyph_key.glyph = glyph;
|
||||
cache->glyph_key.flags = flags;
|
||||
cache->bounds = rect;
|
||||
cache->image = image;
|
||||
cache->origin = GRAPHENE_POINT_INIT (- origin.x + subpixel_x,
|
||||
@@ -956,7 +1048,7 @@ gsk_gpu_device_lookup_glyph_image (GskGpuDevice *self,
|
||||
|
||||
gsk_gpu_upload_glyph_op (frame,
|
||||
cache->image,
|
||||
font,
|
||||
scaled_font,
|
||||
glyph,
|
||||
&(cairo_rectangle_int_t) {
|
||||
.x = rect.origin.x - padding,
|
||||
@@ -964,15 +1056,16 @@ gsk_gpu_device_lookup_glyph_image (GskGpuDevice *self,
|
||||
.width = rect.size.width + 2 * padding,
|
||||
.height = rect.size.height + 2 * padding,
|
||||
},
|
||||
scale,
|
||||
&GRAPHENE_POINT_INIT (cache->origin.x + padding,
|
||||
cache->origin.y + padding));
|
||||
|
||||
g_hash_table_insert (priv->glyph_cache, cache, cache);
|
||||
g_hash_table_insert (font_cache->cache, cache, cache);
|
||||
gsk_gpu_cached_use (self, (GskGpuCached *) cache, gsk_gpu_frame_get_timestamp (frame));
|
||||
|
||||
*out_bounds = cache->bounds;
|
||||
*out_origin = cache->origin;
|
||||
*out_scaled_font = scaled_font;
|
||||
|
||||
return cache->image;
|
||||
}
|
||||
|
||||
|
@@ -96,7 +96,8 @@ GskGpuImage * gsk_gpu_device_lookup_glyph_image (GskGpuD
|
||||
GskGpuGlyphLookupFlags flags,
|
||||
float scale,
|
||||
graphene_rect_t *out_bounds,
|
||||
graphene_point_t *out_origin);
|
||||
graphene_point_t *out_origin,
|
||||
PangoFont **out_scaled_font);
|
||||
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GskGpuDevice, g_object_unref)
|
||||
|
@@ -2992,11 +2992,15 @@ gsk_gpu_node_processor_add_glyph_node (GskGpuNodeProcessor *self,
|
||||
GskGpuDevice *device;
|
||||
const PangoGlyphInfo *glyphs;
|
||||
PangoFont *font;
|
||||
PangoFont *scaled_font = NULL;
|
||||
graphene_point_t offset;
|
||||
guint i, num_glyphs;
|
||||
float scale, inv_scale;
|
||||
GdkRGBA color;
|
||||
gboolean glyph_align;
|
||||
GskGpuImage *last_image;
|
||||
guint32 descriptor = 0;
|
||||
GskGpuClip old_clip;
|
||||
|
||||
if (self->opacity < 1.0 &&
|
||||
gsk_text_node_has_color_glyphs (node))
|
||||
@@ -3005,6 +3009,10 @@ gsk_gpu_node_processor_add_glyph_node (GskGpuNodeProcessor *self,
|
||||
return;
|
||||
}
|
||||
|
||||
gsk_gpu_clip_init_copy (&old_clip, &self->clip);
|
||||
if (gsk_gpu_clip_contains_rect (&self->clip, &self->offset, &node->bounds))
|
||||
gsk_gpu_clip_init_contained (&self->clip, &node->bounds);
|
||||
|
||||
glyph_align = gsk_gpu_frame_should_optimize (self->frame, GSK_GPU_OPTIMIZE_GLYPH_ALIGN) &&
|
||||
gsk_transform_get_category (self->modelview) >= GSK_TRANSFORM_CATEGORY_2D;
|
||||
device = gsk_gpu_frame_get_device (self->frame);
|
||||
@@ -3020,12 +3028,12 @@ gsk_gpu_node_processor_add_glyph_node (GskGpuNodeProcessor *self,
|
||||
scale = MAX (graphene_vec2_get_x (&self->scale), graphene_vec2_get_y (&self->scale));
|
||||
inv_scale = 1.f / scale;
|
||||
|
||||
last_image = NULL;
|
||||
for (i = 0; i < num_glyphs; i++)
|
||||
{
|
||||
GskGpuImage *image;
|
||||
graphene_rect_t glyph_bounds, glyph_tex_rect;
|
||||
graphene_point_t glyph_offset, glyph_origin;
|
||||
guint32 descriptor;
|
||||
GskGpuGlyphLookupFlags flags;
|
||||
|
||||
glyph_origin = GRAPHENE_POINT_INIT (offset.x + (float) glyphs[i].geometry.x_offset / PANGO_SCALE,
|
||||
@@ -3051,13 +3059,20 @@ gsk_gpu_node_processor_add_glyph_node (GskGpuNodeProcessor *self,
|
||||
flags,
|
||||
scale,
|
||||
&glyph_bounds,
|
||||
&glyph_offset);
|
||||
&glyph_offset,
|
||||
&scaled_font);
|
||||
|
||||
gsk_rect_scale (&GRAPHENE_RECT_INIT (-glyph_bounds.origin.x, -glyph_bounds.origin.y, gsk_gpu_image_get_width (image), gsk_gpu_image_get_height (image)), inv_scale, inv_scale, &glyph_tex_rect);
|
||||
gsk_rect_scale (&GRAPHENE_RECT_INIT(0, 0, glyph_bounds.size.width, glyph_bounds.size.height), inv_scale, inv_scale, &glyph_bounds);
|
||||
glyph_origin = GRAPHENE_POINT_INIT (glyph_origin.x - glyph_offset.x * inv_scale,
|
||||
glyph_origin.y - glyph_offset.y * inv_scale);
|
||||
descriptor = gsk_gpu_node_processor_add_image (self, image, GSK_GPU_SAMPLER_DEFAULT);
|
||||
|
||||
if (image != last_image)
|
||||
{
|
||||
descriptor = gsk_gpu_node_processor_add_image (self, image, GSK_GPU_SAMPLER_DEFAULT);
|
||||
last_image = image;
|
||||
}
|
||||
|
||||
if (glyphs[i].attr.is_color)
|
||||
gsk_gpu_texture_op (self->frame,
|
||||
gsk_gpu_clip_get_shader_clip (&self->clip, &glyph_offset, &glyph_bounds),
|
||||
@@ -3078,6 +3093,10 @@ gsk_gpu_node_processor_add_glyph_node (GskGpuNodeProcessor *self,
|
||||
|
||||
offset.x += (float) glyphs[i].geometry.width / PANGO_SCALE;
|
||||
}
|
||||
|
||||
g_clear_object (&scaled_font);
|
||||
|
||||
gsk_gpu_clip_init_copy (&self->clip, &old_clip);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -3087,6 +3106,7 @@ gsk_gpu_node_processor_create_glyph_pattern (GskGpuPatternWriter *self,
|
||||
GskGpuDevice *device;
|
||||
const PangoGlyphInfo *glyphs;
|
||||
PangoFont *font;
|
||||
PangoFont *scaled_font = NULL;
|
||||
guint num_glyphs;
|
||||
gsize i;
|
||||
float scale, inv_scale;
|
||||
@@ -3126,12 +3146,13 @@ gsk_gpu_node_processor_create_glyph_pattern (GskGpuPatternWriter *self,
|
||||
0,
|
||||
scale,
|
||||
&glyph_bounds,
|
||||
&glyph_offset);
|
||||
&glyph_offset,
|
||||
&scaled_font);
|
||||
|
||||
if (image != last_image)
|
||||
{
|
||||
if (!gsk_gpu_pattern_writer_add_image (self, image, GSK_GPU_SAMPLER_DEFAULT, &tex_id))
|
||||
return FALSE;
|
||||
break;
|
||||
|
||||
last_image = image;
|
||||
}
|
||||
@@ -3160,7 +3181,9 @@ gsk_gpu_node_processor_create_glyph_pattern (GskGpuPatternWriter *self,
|
||||
offset.x += (float) glyphs[i].geometry.width / PANGO_SCALE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
g_clear_object (&scaled_font);
|
||||
|
||||
return i == num_glyphs;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@@ -485,7 +485,6 @@ struct _GskGpuUploadGlyphOp
|
||||
cairo_rectangle_int_t area;
|
||||
PangoFont *font;
|
||||
PangoGlyph glyph;
|
||||
float scale;
|
||||
graphene_point_t origin;
|
||||
|
||||
GskGpuBuffer *buffer;
|
||||
@@ -509,11 +508,19 @@ gsk_gpu_upload_glyph_op_print (GskGpuOp *op,
|
||||
guint indent)
|
||||
{
|
||||
GskGpuUploadGlyphOp *self = (GskGpuUploadGlyphOp *) op;
|
||||
PangoFontDescription *desc;
|
||||
char *str;
|
||||
|
||||
desc = pango_font_describe_with_absolute_size (self->font);
|
||||
str = pango_font_description_to_string (desc);
|
||||
|
||||
gsk_gpu_print_op (string, indent, "upload-glyph");
|
||||
gsk_gpu_print_int_rect (string, &self->area);
|
||||
g_string_append_printf (string, "glyph %u @ %g ", self->glyph, self->scale);
|
||||
g_string_append_printf (string, "glyph %u font %s ", self->glyph, str);
|
||||
gsk_gpu_print_newline (string);
|
||||
|
||||
g_free (str);
|
||||
pango_font_description_free (desc);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -531,7 +538,6 @@ gsk_gpu_upload_glyph_op_draw (GskGpuOp *op,
|
||||
self->area.height,
|
||||
stride);
|
||||
cairo_surface_set_device_offset (surface, self->origin.x, self->origin.y);
|
||||
cairo_surface_set_device_scale (surface, self->scale, self->scale);
|
||||
|
||||
cr = cairo_create (surface);
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
|
||||
@@ -610,7 +616,6 @@ gsk_gpu_upload_glyph_op (GskGpuFrame *frame,
|
||||
PangoFont *font,
|
||||
const PangoGlyph glyph,
|
||||
const cairo_rectangle_int_t *area,
|
||||
float scale,
|
||||
const graphene_point_t *origin)
|
||||
{
|
||||
GskGpuUploadGlyphOp *self;
|
||||
@@ -621,6 +626,5 @@ gsk_gpu_upload_glyph_op (GskGpuFrame *frame,
|
||||
self->area = *area;
|
||||
self->font = g_object_ref (font);
|
||||
self->glyph = glyph;
|
||||
self->scale = scale;
|
||||
self->origin = *origin;
|
||||
}
|
||||
|
@@ -25,7 +25,6 @@ void gsk_gpu_upload_glyph_op (GskGpuF
|
||||
PangoFont *font,
|
||||
PangoGlyph glyph,
|
||||
const cairo_rectangle_int_t *area,
|
||||
float scale,
|
||||
const graphene_point_t *origin);
|
||||
|
||||
G_END_DECLS
|
||||
|
@@ -1,6 +1,10 @@
|
||||
#include "gskresources.h"
|
||||
#include "gskprivate.h"
|
||||
|
||||
#include <cairo.h>
|
||||
#include <pango/pangocairo.h>
|
||||
#include <math.h>
|
||||
|
||||
static gpointer
|
||||
register_resources (gpointer data)
|
||||
{
|
||||
@@ -15,3 +19,78 @@ gsk_ensure_resources (void)
|
||||
|
||||
g_once (®ister_resources_once, register_resources, NULL);
|
||||
}
|
||||
|
||||
/*< private >
|
||||
* gsk_get_scaled_font:
|
||||
* @font: a `PangoFont`
|
||||
* @scale: the scale
|
||||
*
|
||||
* Returns a font that is just like @font, at a size that
|
||||
* is multiplied by @scale.
|
||||
*
|
||||
* Returns: (transfer full): a scaled version of @font
|
||||
*/
|
||||
PangoFont *
|
||||
gsk_get_scaled_font (PangoFont *font,
|
||||
float scale)
|
||||
{
|
||||
if (scale == 1.0)
|
||||
return g_object_ref (font);
|
||||
|
||||
#if PANGO_VERSION_CHECK (1, 52, 0)
|
||||
return pango_font_map_reload_font (pango_font_get_font_map (font), font, scale, NULL, NULL);
|
||||
#else
|
||||
GHashTable *fonts;
|
||||
int key;
|
||||
PangoFont *font2;
|
||||
PangoFontDescription *desc;
|
||||
int size;
|
||||
PangoFontMap *fontmap;
|
||||
PangoContext *context;
|
||||
cairo_scaled_font_t *sf;
|
||||
cairo_font_options_t *options;
|
||||
|
||||
key = (int) roundf (scale * PANGO_SCALE);
|
||||
|
||||
fonts = (GHashTable *) g_object_get_data (G_OBJECT (font), "gsk-scaled-fonts");
|
||||
|
||||
if (fonts)
|
||||
{
|
||||
font2 = g_hash_table_lookup (fonts, GINT_TO_POINTER (key));
|
||||
if (font2)
|
||||
return g_object_ref (font2);
|
||||
}
|
||||
else
|
||||
{
|
||||
fonts = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref);
|
||||
g_object_set_data_full (G_OBJECT (font), "gsk-scaled-fonts",
|
||||
fonts, (GDestroyNotify) g_hash_table_unref);
|
||||
}
|
||||
|
||||
desc = pango_font_describe (font);
|
||||
size = pango_font_description_get_size (desc);
|
||||
|
||||
if (pango_font_description_get_size_is_absolute (desc))
|
||||
pango_font_description_set_absolute_size (desc, size * scale);
|
||||
else
|
||||
pango_font_description_set_size (desc, (int) roundf (size * scale));
|
||||
|
||||
fontmap = pango_font_get_font_map (font);
|
||||
context = pango_font_map_create_context (fontmap);
|
||||
|
||||
sf = pango_cairo_font_get_scaled_font (PANGO_CAIRO_FONT (font));
|
||||
options = cairo_font_options_create ();
|
||||
cairo_scaled_font_get_font_options (sf, options);
|
||||
pango_cairo_context_set_font_options (context, options);
|
||||
cairo_font_options_destroy (options);
|
||||
|
||||
font2 = pango_font_map_load_font (fontmap, context, desc);
|
||||
|
||||
pango_font_description_free (desc);
|
||||
g_object_unref (context);
|
||||
|
||||
g_hash_table_insert (fonts, GINT_TO_POINTER (key), font2);
|
||||
|
||||
return g_object_ref (font2);
|
||||
#endif
|
||||
}
|
||||
|
@@ -5,7 +5,10 @@
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
void gsk_ensure_resources (void);
|
||||
void gsk_ensure_resources (void);
|
||||
|
||||
PangoFont *gsk_get_scaled_font (PangoFont *font,
|
||||
float scale);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
Reference in New Issue
Block a user