Source code

Revision control

Copy as Markdown

Other Tools

/*
* Copyright © 2026 Behdad Esfahbod
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Author(s): Behdad Esfahbod
*/
#ifndef HB_VECTOR_INTERNAL_HH
#define HB_VECTOR_INTERNAL_HH
#include "hb-vector.h"
struct hb_vector_blob_meta_t
{
char *data;
int allocated;
bool transferred;
bool in_replace;
};
static hb_user_data_key_t hb_vector_blob_meta_user_data_key;
static inline void
hb_vector_blob_meta_set_buffer (hb_vector_blob_meta_t *meta,
char *data,
int allocated)
{
meta->data = data;
meta->allocated = allocated;
meta->transferred = false;
}
static inline void
hb_vector_blob_meta_release_buffer (hb_vector_blob_meta_t *meta)
{
if (!meta)
return;
if (!meta->transferred && meta->data)
hb_free (meta->data);
meta->data = nullptr;
meta->allocated = 0;
meta->transferred = true;
}
static inline void
hb_vector_blob_meta_destroy (void *data)
{
auto *meta = (hb_vector_blob_meta_t *) data;
hb_vector_blob_meta_release_buffer (meta);
if (meta->in_replace)
{
meta->in_replace = false;
return;
}
hb_free (meta);
}
static inline hb_blob_t *
hb_buf_blob_from (hb_blob_t **recycled_blob,
hb_vector_buf_t *buf)
{
unsigned len = 0;
int allocated = 0;
char *data = buf->steal (&len, &allocated);
if (!data)
return nullptr;
hb_blob_t *blob = nullptr;
if (*recycled_blob)
blob = *recycled_blob;
bool reused_blob = blob && blob != hb_blob_get_empty ();
bool new_meta = false;
auto *meta = reused_blob
? (hb_vector_blob_meta_t *) hb_blob_get_user_data (blob, &hb_vector_blob_meta_user_data_key)
: nullptr;
if (!meta)
{
meta = (hb_vector_blob_meta_t *) hb_malloc (sizeof (hb_vector_blob_meta_t));
if (!meta)
{
hb_free (data);
return nullptr;
}
meta->data = nullptr;
meta->allocated = 0;
meta->transferred = true;
meta->in_replace = false;
new_meta = true;
}
if (reused_blob)
{
meta->in_replace = true;
blob->replace_buffer (data, len, HB_MEMORY_MODE_WRITABLE, meta, hb_vector_blob_meta_destroy);
hb_vector_blob_meta_set_buffer (meta, data, allocated);
}
else
{
hb_vector_blob_meta_set_buffer (meta, data, allocated);
blob = hb_blob_create_or_fail (data, len, HB_MEMORY_MODE_WRITABLE, meta, hb_vector_blob_meta_destroy);
if (unlikely (!blob))
return nullptr;
}
if (unlikely (blob == hb_blob_get_empty ()))
{
if (new_meta)
hb_free (meta);
hb_free (data);
return nullptr;
}
if (new_meta &&
!hb_blob_set_user_data (blob,
&hb_vector_blob_meta_user_data_key,
meta,
nullptr,
true))
{
if (!reused_blob)
hb_blob_destroy (blob);
return nullptr;
}
if (*recycled_blob)
*recycled_blob = nullptr;
return blob;
}
static inline void
hb_buf_recover_recycled (hb_blob_t *blob,
hb_vector_buf_t *buf)
{
if (!blob)
return;
auto *meta = (hb_vector_blob_meta_t *) hb_blob_get_user_data (blob, &hb_vector_blob_meta_user_data_key);
if (!meta || meta->transferred || !meta->data)
return;
buf->recycle_buffer (meta->data, 0, meta->allocated);
meta->data = nullptr;
meta->allocated = 0;
meta->transferred = true;
}
static inline void
hb_vector_transform_point (const hb_transform_t<> &t,
float x_scale_factor,
float y_scale_factor,
float x, float y,
float *tx, float *ty)
{
float xx = x, yy = y;
t.transform_point (xx, yy);
/* Setters force scale factors > 0; trust them here. */
*tx = xx / x_scale_factor;
*ty = yy / y_scale_factor;
}
static inline hb_bool_t
hb_vector_set_glyph_extents_common (const hb_transform_t<> &transform,
float x_scale_factor,
float y_scale_factor,
const hb_glyph_extents_t *glyph_extents,
hb_vector_extents_t *extents,
hb_bool_t *has_extents)
{
float x0 = (float) glyph_extents->x_bearing;
float y0 = (float) glyph_extents->y_bearing;
float x1 = x0 + glyph_extents->width;
float y1 = y0 + glyph_extents->height;
float px[4] = {x0, x0, x1, x1};
float py[4] = {y0, y1, y0, y1};
float tx, ty;
hb_vector_transform_point (transform, x_scale_factor, y_scale_factor, px[0], py[0], &tx, &ty);
float tx_min = tx, tx_max = tx;
float ty_min = ty, ty_max = ty;
for (unsigned i = 1; i < 4; i++)
{
hb_vector_transform_point (transform, x_scale_factor, y_scale_factor, px[i], py[i], &tx, &ty);
tx_min = hb_min (tx_min, tx);
tx_max = hb_max (tx_max, tx);
ty_min = hb_min (ty_min, ty);
ty_max = hb_max (ty_max, ty);
}
if (tx_max <= tx_min || ty_max <= ty_min)
return false;
if (*has_extents)
{
float x0 = hb_min (extents->x, tx_min);
float y0 = hb_min (extents->y, ty_min);
float x1 = hb_max (extents->x + extents->width, tx_max);
float y1 = hb_max (extents->y + extents->height, ty_max);
*extents = {x0, y0, x1 - x0, y1 - y0};
}
else
{
*extents = {tx_min, ty_min, tx_max - tx_min, ty_max - ty_min};
*has_extents = true;
}
return true;
}
static inline void
hb_vector_svg_append_instance_transform (hb_vector_buf_t *out,
unsigned precision,
float x_scale_factor,
float y_scale_factor,
float xx, float yx,
float xy, float yy,
float tx, float ty)
{
if (xx == 1.f && yx == 0.f && xy == 0.f && yy == 1.f)
{
out->append_str ("translate(");
out->append_num (tx / x_scale_factor, precision);
out->append_c (',');
out->append_num (-ty / y_scale_factor, precision);
out->append_str (") scale(1,-1)");
}
else
{
unsigned sprec = out->scale_precision ();
out->append_str ("matrix(");
out->append_num (xx, sprec);
out->append_c (',');
out->append_num (yx, sprec);
out->append_c (',');
out->append_num (-xy, sprec);
out->append_c (',');
out->append_num (-yy, sprec);
out->append_c (',');
out->append_num (tx / x_scale_factor, precision);
out->append_c (',');
out->append_num (-ty / y_scale_factor, precision);
out->append_c (')');
}
}
#endif /* HB_VECTOR_INTERNAL_HH */