blob: 6baa5fdf79a9fa8a78fa64c9083f41c7d80b962f [file]
/*
* 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
*/
#include "hb.hh"
#include "hb-raster-svg-defs.hh"
#include <string.h>
hb_svg_defs_t::~hb_svg_defs_t ()
{
for (unsigned i = 0; i < owned_id_strings.length; i++)
hb_free (owned_id_strings.arrayZ[i]);
}
bool
hb_svg_defs_t::add_id_mapping (hb_hashmap_t<hb_bytes_t, unsigned> *map,
const char *id,
unsigned idx)
{
hb_bytes_t key = hb_bytes_t (id, (unsigned) strlen (id));
if (map->has (key))
return true;
unsigned n = (unsigned) strlen (id);
char *owned = (char *) hb_malloc (n + 1);
if (unlikely (!owned))
return false;
hb_memcpy (owned, id, n + 1);
if (unlikely (!owned_id_strings.push (owned)))
{
hb_free (owned);
return false;
}
hb_bytes_t owned_key = hb_bytes_t (owned, n);
if (unlikely (!map->set (owned_key, idx)))
return false;
return true;
}
bool
hb_svg_defs_t::add_gradient (const char *id, const hb_svg_gradient_t &grad)
{
unsigned idx = gradients.length;
gradients.push (grad);
if (unlikely (gradients.in_error ()))
return false;
hb_svg_def_t def;
unsigned n = hb_min (strlen (id), (size_t) sizeof (def.id) - 1);
memcpy (def.id, id, n);
def.id[n] = '\0';
def.type = hb_svg_def_t::DEF_GRADIENT;
def.index = idx;
defs.push (def);
if (unlikely (defs.in_error ()))
{
gradients.pop ();
return false;
}
if (unlikely (!add_id_mapping (&gradient_by_id, def.id, idx)))
{
defs.pop ();
gradients.pop ();
return false;
}
return true;
}
const hb_svg_gradient_t *
hb_svg_defs_t::find_gradient (const char *id) const
{
unsigned *idx = nullptr;
if (id && gradient_by_id.has (hb_bytes_t (id, (unsigned) strlen (id)), &idx))
return &gradients[*idx];
for (unsigned i = 0; i < defs.length; i++)
if (defs[i].type == hb_svg_def_t::DEF_GRADIENT &&
strcmp (defs[i].id, id) == 0)
return &gradients[defs[i].index];
return nullptr;
}
bool
hb_svg_defs_t::add_clip_path (const char *id, const hb_svg_clip_path_def_t &clip)
{
unsigned idx = clip_paths.length;
clip_paths.push (clip);
if (unlikely (clip_paths.in_error ()))
return false;
hb_svg_def_t def;
unsigned n = hb_min (strlen (id), (size_t) sizeof (def.id) - 1);
memcpy (def.id, id, n);
def.id[n] = '\0';
def.type = hb_svg_def_t::DEF_CLIP_PATH;
def.index = idx;
defs.push (def);
if (unlikely (defs.in_error ()))
{
clip_paths.pop ();
return false;
}
if (unlikely (!add_id_mapping (&clip_path_by_id, def.id, idx)))
{
defs.pop ();
clip_paths.pop ();
return false;
}
return true;
}
const hb_svg_clip_path_def_t *
hb_svg_defs_t::find_clip_path (const char *id) const
{
unsigned *idx = nullptr;
if (id && clip_path_by_id.has (hb_bytes_t (id, (unsigned) strlen (id)), &idx))
return &clip_paths[*idx];
for (unsigned i = 0; i < defs.length; i++)
if (defs[i].type == hb_svg_def_t::DEF_CLIP_PATH &&
strcmp (defs[i].id, id) == 0)
return &clip_paths[defs[i].index];
return nullptr;
}