sylware / charfbuzz (public) (License: LGPLv3) (since 2019-09-09) (hash sha1)
partial C implementation of harfbuzz C API for roman scripts

/hb-font.c (ba271fab87b5d9d6534bf971604b6079eabfc9f5) (30726 bytes) (mode 100644) (type blob)

// C99 port from c++ is protected by a GNU Lesser GPLv3
// Copyright © 2013 Sylvain BERTRAND <sylvain.bertrand@gmail.com>
//                                   <sylware@legeek.net>       
#include <stdlib.h>
#include <string.h>

#include <ft2build.h>
#include FT_FREETYPE_H

#include "hb.h"
#include "hb-private.h"
#include "hb-atomic-private.h"
#include "hb-shaper-private.h"
#include "hb-face-private.h"
#include "hb-font-private.h"

void
hb_font_destroy(hb_font_t *font)
{
  if (!font)
    return;
  if (hb_atomic_int32_get(&font->ref_cnt) == REF_CNT_INVALID_VAL)
    return;
  hb_atomic_int32_add(&font->ref_cnt, -1);
  if (hb_atomic_int32_get(&font->ref_cnt) > 0)
    return;
  hb_atomic_int32_set(&font->ref_cnt, REF_CNT_INVALID_VAL);

#ifdef HAVE_GRAPHITE2
  if (font->shaper_data.graphite2
      && font->shaper_data.graphite2 != HB_SHAPER_DATA_INVALID
      && font->shaper_data.graphite2 != HB_SHAPER_DATA_SUCCEEDED)
    hb_graphite2_shaper_font_data_destroy(font->shaper_data.graphite2);
#endif
#ifdef HAVE_OT
  if (font->shaper_data.ot
      && font->shaper_data.ot != HB_SHAPER_DATA_INVALID
      && font->shaper_data.ot != HB_SHAPER_DATA_SUCCEEDED)
    hb_ot_shaper_font_data_destroy(font->shaper_data.ot);
#endif
  if (font->shaper_data.fallback
      && font->shaper_data.fallback != HB_SHAPER_DATA_INVALID
      && font->shaper_data.fallback != HB_SHAPER_DATA_SUCCEEDED)
    hb_fallback_shaper_font_data_destroy(font->shaper_data.fallback);

  if (font->destroy)
    font->destroy(font->user_data);

  hb_font_destroy(font->parent);
  hb_face_destroy(font->face);
  hb_font_funcs_destroy(font->klass);
  free(font);
}

hb_bool_t
hb_font_get_glyph(hb_font_t *font,
                  hb_codepoint_t unicode,
                  hb_codepoint_t variation_selector,
                  hb_codepoint_t *glyph)
{
  *glyph = 0;
  return font->klass->get.glyph(font,
                                font->user_data,
                                unicode,
                                variation_selector,
                                glyph,
                                font->klass->user_data.glyph);
}

//Convert from parent-font user-space to our user-space
hb_position_t
hb_font_parent_scale_x_distance(hb_font_t *font,
                                hb_position_t v)
{
  if (font->parent && font->parent->x_scale != font->x_scale)
    return v * (int64_t) font->x_scale / font->parent->x_scale;
  return v;
}

hb_position_t
hb_font_parent_scale_y_distance(hb_font_t *font,
                                hb_position_t v)
{
  if (font->parent && font->parent->y_scale != font->y_scale)
    return v * (int64_t) font->y_scale / font->parent->y_scale;
  return v;
}

hb_position_t
hb_font_parent_scale_x_position(hb_font_t *font,
                                hb_position_t v)
{
  return hb_font_parent_scale_x_distance(font, v);
}

hb_position_t
hb_font_parent_scale_y_position(hb_font_t *font,
                                hb_position_t v)
{
  return hb_font_parent_scale_y_distance(font, v);
}

void
hb_font_parent_scale_position(hb_font_t *font,
                              hb_position_t *x,
                              hb_position_t *y)
{
  *x = hb_font_parent_scale_x_position(font, *x);
  *y = hb_font_parent_scale_y_position(font, *y);
}

void
hb_font_parent_scale_distance(hb_font_t *font,
                              hb_position_t *x,
                              hb_position_t *y)
{
  *x = hb_font_parent_scale_x_distance(font, *x);
  *y = hb_font_parent_scale_y_distance(font, *y);
}

hb_position_t
hb_font_get_glyph_h_advance(hb_font_t *font,
                            hb_codepoint_t glyph)
{
  return font->klass->get.glyph_h_advance(
                                        font,
                                        font->user_data,
                                        glyph,
                                        font->klass->user_data.glyph_h_advance);
}


hb_position_t
hb_font_get_glyph_v_advance(hb_font_t *font,
                            hb_codepoint_t glyph)
{
  return font->klass->get.glyph_v_advance(
                                        font,
                                        font->user_data,
                                        glyph,
                                        font->klass->user_data.glyph_v_advance);
}

hb_bool_t
hb_font_get_glyph_h_origin(hb_font_t *font,
                           hb_codepoint_t glyph,
                           hb_position_t *x,
                           hb_position_t *y)
{
  *x = *y = 0;
  return font->klass->get.glyph_h_origin(font,
                                         font->user_data,
                                         glyph,
                                         x, y,
                                         font->klass->user_data.glyph_h_origin);
}

hb_bool_t
hb_font_get_glyph_v_origin(hb_font_t *font,
                           hb_codepoint_t glyph,
                           hb_position_t *x,
                           hb_position_t *y)
{
  *x = *y = 0;
  return font->klass->get.glyph_v_origin(font,
                                         font->user_data,
                                         glyph,
                                         x, y,
                                         font->klass->user_data.glyph_v_origin);
}

hb_position_t
hb_font_get_glyph_h_kerning(hb_font_t *font,
                            hb_codepoint_t left_glyph,
                            hb_codepoint_t right_glyph)
{
  return font->klass->get.glyph_h_kerning(
                                        font,
                                        font->user_data,
                                        left_glyph,
                                        right_glyph,
                                        font->klass->user_data.glyph_h_kerning);
}

hb_position_t
hb_font_get_glyph_v_kerning(hb_font_t *font,
                            hb_codepoint_t top_glyph,
                            hb_codepoint_t bottom_glyph)
{
  return font->klass->get.glyph_v_kerning(
                                        font,
                                        font->user_data,
                                        top_glyph,
                                        bottom_glyph,
                                        font->klass->user_data.glyph_v_kerning);
}

hb_bool_t
hb_font_get_glyph_extents(hb_font_t *font,
                          hb_codepoint_t glyph,
                          hb_glyph_extents_t *extents)
{
  memset(extents, 0, sizeof(*extents));
  return font->klass->get.glyph_extents(font,
                                        font->user_data,
                                        glyph,
                                        extents,
                                        font->klass->user_data.glyph_extents);
}

hb_bool_t
hb_font_get_glyph_contour_point(hb_font_t *font,
                                hb_codepoint_t glyph,
                                unsigned int point_index,
                                hb_position_t *x,
                                hb_position_t *y)
{
  *x = *y = 0;
  return font->klass->get.glyph_contour_point(
                                    font,
                                    font->user_data,
                                    glyph, point_index,
                                    x, y,
                                    font->klass->user_data.glyph_contour_point);
}

hb_bool_t
hb_font_get_glyph_name(hb_font_t *font,
                       hb_codepoint_t glyph,
                       char *name,
                       unsigned int size)
{
  if (size) *name = '\0';
  return font->klass->get.glyph_name(font,
                                     font->user_data,
                                     glyph,
                                     name,
                                     size,
                                     font->klass->user_data.glyph_name);
}

hb_bool_t
hb_font_get_glyph_from_name(hb_font_t *font,
                            const char *name,
                            int len,//-1 means nul-terminated
                            hb_codepoint_t *glyph)
{
  *glyph = 0;
  if (len == -1) len = strlen(name);
  return font->klass->get.glyph_from_name(
                                        font,
                                        font->user_data,
                                        name,
                                        len,
                                        glyph,
                                        font->klass->user_data.glyph_from_name);
}

static hb_bool_t
hb_font_get_glyph_nil(hb_font_t *font,
                      void *font_data HB_UNUSED,
                      hb_codepoint_t unicode,
                      hb_codepoint_t variation_selector,
                      hb_codepoint_t *glyph,
                      void *user_data HB_UNUSED)
{
  if (font->parent)
    return hb_font_get_glyph(font->parent,
                             unicode,
                             variation_selector,
                             glyph);

  *glyph = 0;
  return FALSE;
}

static hb_position_t
hb_font_get_glyph_h_advance_nil(hb_font_t *font,
                                void *font_data HB_UNUSED,
                                hb_codepoint_t glyph,
                                void *user_data HB_UNUSED)
{
  if (font->parent)
    return hb_font_parent_scale_x_distance(font, hb_font_get_glyph_h_advance(
                                                                   font->parent,
                                                                   glyph));
  return font->x_scale;
}

static hb_position_t
hb_font_get_glyph_v_advance_nil(hb_font_t *font,
                                void *font_data HB_UNUSED,
                                hb_codepoint_t glyph,
                                void *user_data HB_UNUSED)
{
  if (font->parent)
    return hb_font_parent_scale_y_distance(font, hb_font_get_glyph_v_advance(
                                                                   font->parent,
                                                                   glyph));
  return font->y_scale;
}

static hb_bool_t
hb_font_get_glyph_h_origin_nil(hb_font_t *font,
                               void *font_data HB_UNUSED,
                               hb_codepoint_t glyph,
                               hb_position_t *x,
                               hb_position_t *y,
                               void *user_data HB_UNUSED)
{
  if (font->parent) {
    hb_bool_t ret = hb_font_get_glyph_h_origin(font->parent, glyph, x, y);
    if (ret)
      hb_font_parent_scale_position(font, x, y);
    return ret;
  }

  *x = *y = 0;
  return FALSE;
}

static hb_bool_t
hb_font_get_glyph_v_origin_nil(hb_font_t *font,
                               void *font_data HB_UNUSED,
                               hb_codepoint_t glyph,
                               hb_position_t *x,
                               hb_position_t *y,
                               void *user_data HB_UNUSED)
{
  if (font->parent) {
    hb_bool_t ret = hb_font_get_glyph_v_origin(font->parent, glyph, x, y);
    if (ret)
      hb_font_parent_scale_position(font, x, y);
    return ret;
  }

  *x = *y = 0;
  return FALSE;
}

static hb_position_t
hb_font_get_glyph_h_kerning_nil(hb_font_t *font,
                                void *font_data HB_UNUSED,
                                hb_codepoint_t left_glyph,
                                hb_codepoint_t right_glyph,
                                void *user_data HB_UNUSED)
{
  if (font->parent)
    return hb_font_parent_scale_x_distance(font, hb_font_get_glyph_h_kerning(
                                                                  font->parent,
                                                                  left_glyph,
                                                                  right_glyph));
  return 0;
}

static hb_position_t
hb_font_get_glyph_v_kerning_nil(hb_font_t *font,
                                void *font_data HB_UNUSED,
                                hb_codepoint_t top_glyph,
                                hb_codepoint_t bottom_glyph,
                                void *user_data HB_UNUSED)
{
  if (font->parent)
    return hb_font_parent_scale_y_distance(font, hb_font_get_glyph_v_kerning(
                                                                 font->parent,
                                                                 top_glyph,
                                                                 bottom_glyph));
  return 0;
}

static hb_bool_t
hb_font_get_glyph_extents_nil(hb_font_t *font,
                              void *font_data HB_UNUSED,
                              hb_codepoint_t glyph,
                              hb_glyph_extents_t *extents,
                              void *user_data HB_UNUSED)
{
  if (font->parent) {
    hb_bool_t ret = hb_font_get_glyph_extents(font->parent, glyph, extents);
    if (ret) {
      hb_font_parent_scale_position(font,
                                    &extents->x_bearing,
                                    &extents->y_bearing);
      hb_font_parent_scale_distance(font, &extents->width, &extents->height);
    }
    return ret;
  }

  memset(extents, 0, sizeof(*extents));
  return FALSE;
}

static hb_bool_t
hb_font_get_glyph_contour_point_nil(hb_font_t *font,
                                    void *font_data HB_UNUSED,
                                    hb_codepoint_t glyph,
                                    unsigned int point_index,
                                    hb_position_t *x,
                                    hb_position_t *y,
                                    void *user_data HB_UNUSED)
{
  if (font->parent) {
    hb_bool_t ret = hb_font_get_glyph_contour_point(font->parent,
                                                    glyph,
                                                    point_index,
                                                    x, y);
    if (ret)
      hb_font_parent_scale_position(font, x, y);
    return ret;
  }

  *x = *y = 0;
  return FALSE;
}

static hb_bool_t
hb_font_get_glyph_name_nil(hb_font_t *font,
                           void *font_data HB_UNUSED,
                           hb_codepoint_t glyph,
                           char *name, unsigned int size,
                           void *user_data HB_UNUSED)
{
  if (font->parent)
    return hb_font_get_glyph_name(font->parent, glyph, name, size);

  if (size) *name = '\0';
  return FALSE;
}

static hb_bool_t
hb_font_get_glyph_from_name_nil(hb_font_t *font,
                                void *font_data HB_UNUSED,
                                const char *name,
                                int len,//-1 means nul-terminated
                                hb_codepoint_t *glyph,
                                void *user_data HB_UNUSED)
{
  if (font->parent)
    return hb_font_get_glyph_from_name(font->parent, name, len, glyph);

  *glyph = 0;
  return FALSE;
}

//A bit higher-level, and with fallback

void
hb_font_get_glyph_advance_for_direction(hb_font_t *font,
                                        hb_codepoint_t glyph,
                                        hb_direction_t direction,
                                        hb_position_t *x, hb_position_t *y)
{
  if (HB_DIRECTION_IS_HORIZONTAL(direction)) {
    *x = hb_font_get_glyph_h_advance(font, glyph);
    *y = 0;
  } else {
    *x = 0;
    *y = hb_font_get_glyph_v_advance(font, glyph);
  }
}

//Internal only
static void
hb_font_guess_v_origin_minus_h_origin(hb_font_t *font,
                                      hb_codepoint_t glyph,
                                      hb_position_t *x, hb_position_t *y)
{
  *x = hb_font_get_glyph_h_advance(font, glyph) / 2;

  //TODO:use font_metics.ascent
  *y = font->y_scale;
}

void
hb_font_get_glyph_origin_for_direction(hb_font_t *font,
                                       hb_codepoint_t glyph,
                                       hb_direction_t direction,
                                       hb_position_t *x, hb_position_t *y)
{
  if (HB_DIRECTION_IS_HORIZONTAL(direction)) {
    if (!hb_font_get_glyph_h_origin(font, glyph, x, y)
                             && hb_font_get_glyph_v_origin(font, glyph, x, y)) {
      hb_position_t dx, dy;
      hb_font_guess_v_origin_minus_h_origin(font, glyph, &dx, &dy);
      *x -= dx; *y -= dy;
    }
  } else {
    if (!hb_font_get_glyph_v_origin(font, glyph, x, y)
                             && hb_font_get_glyph_h_origin(font, glyph, x, y)) {
      hb_position_t dx, dy;
      hb_font_guess_v_origin_minus_h_origin(font, glyph, &dx, &dy);
      *x += dx; *y += dy;
    }
  }
}

void
hb_font_subtract_glyph_origin_for_direction(hb_font_t *font,
                                            hb_codepoint_t glyph,
                                            hb_direction_t direction,
                                            hb_position_t *x, hb_position_t *y)
{
  hb_position_t origin_x, origin_y;

  hb_font_get_glyph_origin_for_direction(font, glyph, direction, &origin_x,
                                                                     &origin_y);

  *x -= origin_x;
  *y -= origin_y;
}

static hb_font_funcs_t hb_font_funcs_nil = {
  REF_CNT_INVALID_VAL,//ref_cnt
  TRUE,//immutable
  {//get
    hb_font_get_glyph_nil,
    hb_font_get_glyph_h_advance_nil,
    hb_font_get_glyph_v_advance_nil,
    hb_font_get_glyph_h_origin_nil,
    hb_font_get_glyph_v_origin_nil,
    hb_font_get_glyph_h_kerning_nil,
    hb_font_get_glyph_v_kerning_nil,
    hb_font_get_glyph_extents_nil,
    hb_font_get_glyph_contour_point_nil,
    hb_font_get_glyph_name_nil,
    hb_font_get_glyph_from_name_nil,
  },
  {//user_data
    NULL,//glyph
    NULL,//glyph_h_advance
    NULL,//glyph_v_advance
    NULL,//glyph_h_origin
    NULL,//glyph_v_origin
    NULL,//glyph_h_kerning
    NULL,//glyph_v_kerning
    NULL,//glyph_extents
    NULL,//glyph_contour_po
    NULL,//glyph_name
    NULL,//glyph_from_name
  },
  {//destroy
    NULL,//glyph
    NULL,//glyph_h_advance
    NULL,//glyph_v_advance
    NULL,//glyph_h_origin
    NULL,//glyph_v_origin
    NULL,//glyph_h_kerning
    NULL,//glyph_v_kerning
    NULL,//glyph_extents
    NULL,//glyph_contour_po
    NULL,//glyph_name
    NULL,//glyph_from_name
  }
};

static hb_font_t hb_font_nil = {
  REF_CNT_INVALID_VAL,//ref_cnt
  TRUE,//immutable
  NULL,//parent
  NULL,//face
  0,//x_scale
  0,//y_scale
  0,//x_ppem
  0,//y_ppem
  NULL,//klass
  NULL,//user_data
  NULL,//destroy
  {
#ifdef HAVE_GRAPHITE2
    HB_SHAPER_DATA_INVALID,
#endif
#ifdef HAVE_OT
    HB_SHAPER_DATA_INVALID,
#endif
    HB_SHAPER_DATA_INVALID//fallback
  },
};

hb_font_funcs_t *
hb_font_funcs_get_empty(void)
{
  return &hb_font_funcs_nil;
}

hb_font_t *
hb_font_get_empty(void)
{
  return &hb_font_nil;
}

void
hb_font_funcs_destroy(hb_font_funcs_t *ffuncs)
{
  if (!ffuncs)
    return;
  if (hb_atomic_int32_get(&ffuncs->ref_cnt) == REF_CNT_INVALID_VAL)
    return;
  hb_atomic_int32_add(&ffuncs->ref_cnt, -1);
  if (hb_atomic_int32_get(&ffuncs->ref_cnt) > 0)
    return;
  hb_atomic_int32_set(&ffuncs->ref_cnt, REF_CNT_INVALID_VAL);

  if (ffuncs->destroy.glyph)
    ffuncs->destroy.glyph(ffuncs->user_data.glyph);
  if (ffuncs->destroy.glyph_h_advance)
    ffuncs->destroy.glyph_h_advance(ffuncs->user_data.glyph_h_advance);
  if (ffuncs->destroy.glyph_v_advance)
    ffuncs->destroy.glyph_v_advance(ffuncs->user_data.glyph_v_advance);
  if (ffuncs->destroy.glyph_h_origin)
    ffuncs->destroy.glyph_h_origin(ffuncs->user_data.glyph_h_origin);
  if (ffuncs->destroy.glyph_v_origin)
    ffuncs->destroy.glyph_v_origin(ffuncs->user_data.glyph_v_origin);
  if (ffuncs->destroy.glyph_h_kerning)
    ffuncs->destroy.glyph_h_kerning(ffuncs->user_data.glyph_h_kerning);
  if (ffuncs->destroy.glyph_v_kerning)
    ffuncs->destroy.glyph_v_kerning(ffuncs->user_data.glyph_v_kerning);
  if (ffuncs->destroy.glyph_extents)
    ffuncs->destroy.glyph_extents(ffuncs->user_data.glyph_extents);
  if (ffuncs->destroy.glyph_contour_point)
    ffuncs->destroy.glyph_contour_point(ffuncs->user_data.glyph_contour_point);
  if (ffuncs->destroy.glyph_name)
    ffuncs->destroy.glyph_name(ffuncs->user_data.glyph_name);
  if (ffuncs->destroy.glyph_from_name)
    ffuncs->destroy.glyph_from_name(ffuncs->user_data.glyph_from_name);

  free(ffuncs);
}

hb_font_t *
hb_font_create(hb_face_t *face)
{
  if (!face)
    face = hb_face_get_empty();

  if (face->ref_cnt == REF_CNT_INVALID_VAL)
    return hb_font_get_empty();

  hb_font_t *font = calloc(1, sizeof(*font));
  if (!font)
    return hb_font_get_empty();

  hb_atomic_int32_set(&font->ref_cnt, 1);
  hb_face_make_immutable(face);
  font->face = hb_face_reference(face);
  font->klass = hb_font_funcs_get_empty();
  return font;
}

void 
hb_font_funcs_set_glyph_func(hb_font_funcs_t *ffuncs,
                             hb_font_get_glyph_func_t func,
                             void *user_data,
                             hb_destroy_func_t destroy)
{
  if (ffuncs->immutable) {
    if (destroy)
      destroy(user_data);
    return;
  }
  
  if (ffuncs->destroy.glyph)
    ffuncs->destroy.glyph(ffuncs->user_data.glyph);

  if (func) {
    ffuncs->get.glyph = func;
    ffuncs->user_data.glyph = user_data;
    ffuncs->destroy.glyph = destroy;
  } else {
    ffuncs->get.glyph = hb_font_get_glyph_nil;
    ffuncs->user_data.glyph = NULL;
    ffuncs->destroy.glyph = NULL;
  }
}

void 
hb_font_funcs_set_glyph_h_advance_func(hb_font_funcs_t *ffuncs,
                                       hb_font_get_glyph_h_advance_func_t func,
                                       void *user_data,
                                       hb_destroy_func_t destroy)
{
  if (ffuncs->immutable) {
    if (destroy)
      destroy(user_data);
    return;
  }

  if (ffuncs->destroy.glyph_h_advance)
    ffuncs->destroy.glyph_h_advance(ffuncs->user_data.glyph_h_advance);

  if (func) {
    ffuncs->get.glyph_h_advance = func;
    ffuncs->user_data.glyph_h_advance = user_data;
    ffuncs->destroy.glyph_h_advance = destroy;
  } else {
    ffuncs->get.glyph_h_advance = hb_font_get_glyph_h_advance_nil;
    ffuncs->user_data.glyph_h_advance = NULL;
    ffuncs->destroy.glyph_h_advance = NULL;
  }
}

void 
hb_font_funcs_set_glyph_v_advance_func(hb_font_funcs_t *ffuncs,
                                       hb_font_get_glyph_v_advance_func_t func,
                                       void *user_data,
                                       hb_destroy_func_t destroy)
{
  if (ffuncs->immutable) {
    if (destroy)
      destroy(user_data);
    return;
  }

  if (ffuncs->destroy.glyph_v_advance)
    ffuncs->destroy.glyph_v_advance(ffuncs->user_data.glyph_v_advance);

  if (func) {
    ffuncs->get.glyph_v_advance = func;
    ffuncs->user_data.glyph_v_advance = user_data;
    ffuncs->destroy.glyph_v_advance = destroy;
  } else {
    ffuncs->get.glyph_v_advance = hb_font_get_glyph_v_advance_nil;
    ffuncs->user_data.glyph_v_advance = NULL;
    ffuncs->destroy.glyph_v_advance = NULL;
  }
}

void 
hb_font_funcs_set_glyph_h_origin_func(hb_font_funcs_t *ffuncs,
                                      hb_font_get_glyph_h_origin_func_t func,
                                      void *user_data,
                                      hb_destroy_func_t destroy)
{
  if (ffuncs->immutable) {
    if (destroy)
      destroy(user_data);
    return;
  }

  if (ffuncs->destroy.glyph_h_origin)
    ffuncs->destroy.glyph_h_origin(ffuncs->user_data.glyph_h_origin);

  if (func) {
    ffuncs->get.glyph_h_origin = func;
    ffuncs->user_data.glyph_h_origin = user_data;
    ffuncs->destroy.glyph_h_origin = destroy;
  } else {
    ffuncs->get.glyph_h_origin = hb_font_get_glyph_h_origin_nil;
    ffuncs->user_data.glyph_h_origin = NULL;
    ffuncs->destroy.glyph_h_origin = NULL;
  }
}

void 
hb_font_funcs_set_glyph_v_origin_func(hb_font_funcs_t *ffuncs,
                                      hb_font_get_glyph_v_origin_func_t func,
                                      void *user_data,
                                      hb_destroy_func_t destroy)
{
  if (ffuncs->immutable) {
    if (destroy)
      destroy(user_data);
    return;
  }

  if (ffuncs->destroy.glyph_v_origin)
    ffuncs->destroy.glyph_v_origin(ffuncs->user_data.glyph_v_origin);

  if (func) {
    ffuncs->get.glyph_v_origin = func;
    ffuncs->user_data.glyph_v_origin = user_data;
    ffuncs->destroy.glyph_v_origin = destroy;
  } else {
    ffuncs->get.glyph_v_origin = hb_font_get_glyph_v_origin_nil;
    ffuncs->user_data.glyph_v_origin = NULL;
    ffuncs->destroy.glyph_v_origin = NULL;
  }
}

void 
hb_font_funcs_set_glyph_h_kerning_func(hb_font_funcs_t *ffuncs,
                                       hb_font_get_glyph_h_kerning_func_t func,
                                       void *user_data,
                                       hb_destroy_func_t destroy)
{
  if (ffuncs->immutable) {
    if (destroy)
      destroy(user_data);
    return;
  }

  if (ffuncs->destroy.glyph_h_kerning)
    ffuncs->destroy.glyph_h_kerning(ffuncs->user_data.glyph_h_kerning);

  if (func) {
    ffuncs->get.glyph_h_kerning = func;
    ffuncs->user_data.glyph_h_kerning = user_data;
    ffuncs->destroy.glyph_h_kerning = destroy;
  } else {
    ffuncs->get.glyph_h_kerning = hb_font_get_glyph_h_kerning_nil;
    ffuncs->user_data.glyph_h_kerning = NULL;
    ffuncs->destroy.glyph_h_kerning = NULL;
  }
}

void 
hb_font_funcs_set_glyph_v_kerning_func(hb_font_funcs_t *ffuncs,
                                       hb_font_get_glyph_v_kerning_func_t func,
                                       void *user_data,
                                       hb_destroy_func_t destroy)
{
  if (ffuncs->immutable) {
    if (destroy)
      destroy(user_data);
    return;
  }

  if (ffuncs->destroy.glyph_v_kerning)
    ffuncs->destroy.glyph_v_kerning(ffuncs->user_data.glyph_v_kerning);

  if (func) {
    ffuncs->get.glyph_v_kerning = func;
    ffuncs->user_data.glyph_v_kerning = user_data;
    ffuncs->destroy.glyph_v_kerning = destroy;
  } else {
    ffuncs->get.glyph_v_kerning = hb_font_get_glyph_v_kerning_nil;
    ffuncs->user_data.glyph_v_kerning = NULL;
    ffuncs->destroy.glyph_v_kerning = NULL;
  }
}

void 
hb_font_funcs_set_glyph_extents_func(hb_font_funcs_t *ffuncs,
                                     hb_font_get_glyph_extents_func_t func,
                                     void *user_data,
                                     hb_destroy_func_t destroy)
{
  if (ffuncs->immutable) {
    if (destroy)
      destroy(user_data);
    return;
  }

  if (ffuncs->destroy.glyph_extents)
    ffuncs->destroy.glyph_extents(ffuncs->user_data.glyph_extents);

  if (func) {
    ffuncs->get.glyph_extents = func;
    ffuncs->user_data.glyph_extents = user_data;
    ffuncs->destroy.glyph_extents = destroy;
  } else {
    ffuncs->get.glyph_extents = hb_font_get_glyph_extents_nil;
    ffuncs->user_data.glyph_extents = NULL;
    ffuncs->destroy.glyph_extents = NULL;
  }
}

void 
hb_font_funcs_set_glyph_contour_point_func(
                                    hb_font_funcs_t *ffuncs,
                                    hb_font_get_glyph_contour_point_func_t func,
                                    void *user_data,
                                    hb_destroy_func_t destroy)
{
  if (ffuncs->immutable) {
    if (destroy)
      destroy(user_data);
    return;
  }

  if (ffuncs->destroy.glyph_contour_point)
    ffuncs->destroy.glyph_contour_point(ffuncs->user_data.glyph_contour_point);

  if (func) {
    ffuncs->get.glyph_contour_point = func;
    ffuncs->user_data.glyph_contour_point = user_data;
    ffuncs->destroy.glyph_contour_point = destroy;
  } else {
    ffuncs->get.glyph_contour_point = hb_font_get_glyph_contour_point_nil;
    ffuncs->user_data.glyph_contour_point = NULL;
    ffuncs->destroy.glyph_contour_point = NULL;
  }
}

void 
hb_font_funcs_set_glyph_name_func(hb_font_funcs_t *ffuncs,
                                  hb_font_get_glyph_name_func_t func,
                                  void *user_data,
                                  hb_destroy_func_t destroy)
{
  if (ffuncs->immutable) {
    if (destroy)
      destroy(user_data);
    return;
  }

  if (ffuncs->destroy.glyph_name)
    ffuncs->destroy.glyph_name(ffuncs->user_data.glyph_name);

  if (func) {
    ffuncs->get.glyph_name = func;
    ffuncs->user_data.glyph_name = user_data;
    ffuncs->destroy.glyph_name = destroy;
  } else {
    ffuncs->get.glyph_name = hb_font_get_glyph_name_nil;
    ffuncs->user_data.glyph_name = NULL;
    ffuncs->destroy.glyph_name = NULL;
  }
}

void 
hb_font_funcs_set_glyph_from_name_func(hb_font_funcs_t *ffuncs,
                                       hb_font_get_glyph_from_name_func_t func,
                                       void *user_data,
                                       hb_destroy_func_t destroy)
{
  if (ffuncs->immutable) {
    if (destroy)
      destroy(user_data);
    return;
  }

  if (ffuncs->destroy.glyph_from_name)
    ffuncs->destroy.glyph_from_name(ffuncs->user_data.glyph_from_name);

  if (func) {
    ffuncs->get.glyph_from_name = func;
    ffuncs->user_data.glyph_from_name = user_data;
    ffuncs->destroy.glyph_from_name = destroy;
  } else {
    ffuncs->get.glyph_from_name = hb_font_get_glyph_from_name_nil;
    ffuncs->user_data.glyph_from_name = NULL;
    ffuncs->destroy.glyph_from_name = NULL;
  }
}

hb_font_funcs_t *
hb_font_funcs_create(void)
{
  hb_font_funcs_t *ffuncs = calloc(1, sizeof(*ffuncs));
  if (!ffuncs)
    return hb_font_funcs_get_empty();
  hb_atomic_int32_set(&ffuncs->ref_cnt, 1);

  ffuncs->get = hb_font_funcs_nil.get;
  return ffuncs;
}

void
hb_font_set_funcs(hb_font_t *font,
                  hb_font_funcs_t *klass,
                  void *font_data,
                  hb_destroy_func_t destroy)
{
  if (font->immutable) {
    if (destroy)
      destroy(font_data);
    return;
  }

  if (font->destroy)
    font->destroy(font->user_data);

  if (!klass)
    klass = hb_font_funcs_get_empty();

  hb_font_funcs_reference(klass);
  hb_font_funcs_destroy(font->klass);
  font->klass = klass;
  font->user_data = font_data;
  font->destroy = destroy;
}

hb_font_funcs_t *
hb_font_funcs_reference(hb_font_funcs_t *ffuncs)
{
  if (hb_atomic_int32_get(&ffuncs->ref_cnt) != REF_CNT_INVALID_VAL)
    hb_atomic_int32_add(&ffuncs->ref_cnt, 1);
  return ffuncs;
}

void
hb_font_set_scale(hb_font_t *font,
                  int x_scale,
                  int y_scale)
{
  if (font->immutable)
    return;

  font->x_scale = x_scale;
  font->y_scale = y_scale;
}

void
hb_font_set_ppem(hb_font_t *font,
                 unsigned int x_ppem,
                 unsigned int y_ppem)
{
  if (font->immutable)
    return;

  font->x_ppem = x_ppem;
  font->y_ppem = y_ppem;
}


Mode Type Size Ref File
100644 blob 200 1a0b33b52f3f0b8f3567e0fb7b411e88c4b3c2c9 ABBREVIATIONS
100644 blob 119 8bbabe4337eabadd3f5ed07192b85e02d50f5bad FIXME
100644 blob 100 8a85692a2fc36a478ef9662ba2db214375a79254 README
100644 blob 223 7f27bbbdef02188df78858a31e0c38bda3fe4443 harfbuzz.pc.in
100644 blob 1478 2931ccaca651b04a927605232dd3500f7a661dce hb-atomic-private.h
100644 blob 120 ee630543fb4ef3e9fa49f7362026407c0fd0a858 hb-blob-private.h
100644 blob 4983 607f12b39c30bbe160c4e3a6781b5a58b64de2fc hb-blob.c
100644 blob 3467 d3d0f41b11c3b100cdee91525924c23226acd0cf hb-blob.h
100644 blob 1299 045519300e0994a11484696fa5c533663e4338db hb-buffer-private.h
100644 blob 11835 a3b6deceb732205dfeb4b3798227732f4632ed8b hb-buffer.c
100644 blob 8424 87c4ce58e83744e68765567e4107533dae9d5b7f hb-buffer.h
100644 blob 3363 f5141f528597232bb1a0214b7f1469cc9af008b8 hb-common.c
100644 blob 12423 40c1887296421c6d63f32e479cd318d4c4d79d19 hb-common.h
100644 blob 1407 c4954fa1b2cadb133a419584de60fe16263f148b hb-coretext.h
100644 blob 1584 30ae4b1caf76dd03cc682eda7458728b5380ad6c hb-deprecated.h
100644 blob 1226 3ea9861f08c6fcc0422092c8bb38dd808b5c8757 hb-face-private.h
100644 blob 5452 4489a99ae3f4ebded37dab45f8cde0bf32cc43f1 hb-face.c
100644 blob 2815 f682c468de58095fb0a7c4cdd577b34a9cb78077 hb-face.h
100644 blob 3705 f027e1e59453b39ecb722e2c7ffd9126b579b1a5 hb-fallback-shape.c
100644 blob 3222 172e69a09927c17f177947f2d5f18318dd3f4545 hb-font-private.h
100644 blob 30726 ba271fab87b5d9d6534bf971604b6079eabfc9f5 hb-font.c
100644 blob 12957 7273db43edaf542ef9d6e969fa2d8408e7d5100e hb-font.h
100644 blob 2570 bb44c035ff48e7655a397e5b95872d75b92945ad hb-ft.c
100644 blob 1756 696251e143f31987eb599f8cb16db4f12ff8d901 hb-ft.h
100644 blob 4016 91eaa7075c5f9fe797de93912301d2e03d6b7248 hb-glib.c
100644 blob 1496 63a9d3366c58a0110881ad00d971830924b73a2a hb-glib.h
100644 blob 3185 4a88d569e8d3be4daa2eaf39192891426da46514 hb-gobject-structs.h
100644 blob 1334 ea1bd25df82d46a222436a1ad078d0fc95d5c303 hb-gobject.h
100644 blob 1441 3eae54acbd81dbf3e534c4ad2e42d57611f7024e hb-graphite2.h
100644 blob 1495 f2f35f0f2ce13b6b5c46453128e452ea9380eabf hb-icu.h
100644 blob 2180 7172c280ad7dbb708d6818d386bdbb6e852d80c8 hb-open-file-private.h
100644 blob 2659 c4079cec956598ccf9521c874408a618fe7c29dc hb-open-file.c
100644 blob 65 642c3d3d45fdc42619d000cc9f7b3c890bdc0190 hb-ot-face-private.h
100644 blob 2806 ecfd5b109b43f549366a61efff16daa92db87349 hb-ot-layout.c
100644 blob 9212 d2a314cad6cbf94ba04ff9eaf513a74714eec732 hb-ot-layout.h
100644 blob 753 42faaca3f7ebdafc1232c6810b5ea2124896a95b hb-ot-tag.c
100644 blob 1688 1bf12ab3c09b9aef612515871e587c7c9ca7e62b hb-ot-tag.h
100644 blob 1526 80739063991cf14c4b65cc9247f751226f7f7277 hb-ot.h
100644 blob 1528 ae4bc85a37900c9f54cb91986dadc216f620a358 hb-private.h
100644 blob 3544 bafdae96333f9c81a4b20a4435e6eadaa31a7d32 hb-set.h
100644 blob 1647 1a90aed635a86f8e1d7002ffa8c7d300a3dd8acf hb-shape-plan-private.h
100644 blob 15942 929804aae7b6e5271cef5e9f1d654dcce7a8ca95 hb-shape-plan.c
100644 blob 2747 8f54552f90ba504f6ba2e9cf01459621fc73f9b2 hb-shape-plan.h
100644 blob 1370 1ff445b5de783fb0aa041f34d75919614b21ad34 hb-shape.c
100644 blob 2232 10a35cb517e14c96670d71bbcff266fce23cad91 hb-shape.h
100644 blob 1129 78e3fe4e3529b39789c0763b7f8e1019b3d5a725 hb-shaper-private.h
100644 blob 2184 d1c8f9740fec1b4d19e0967f60391f1c5b17d155 hb-shaper.c
100644 blob 1261 86293900edd4d5fab1013bd0c32eeaad2abef41e hb-unicode-private.h
100644 blob 8084 462ddc1b9bcad35a3d4b3babb64772c93650e75c hb-unicode.c
100644 blob 14218 1c4e097b92d5ba628455fefe25b6f4697cc16f11 hb-unicode.h
100644 blob 1427 51887c8794bce4e37b35c4bb9c675baf55b63052 hb-uniscribe.h
100644 blob 5070 97eb7798f1dc725aad02cc651ffe859044647582 hb-utf-private.c
100644 blob 1423 636ce353798d395c780be99bb68350c3352f40a3 hb-utf-private.h
100644 blob 1849 43634f91ce8a10250c8279b19a1993843feb0f38 hb-version.h.in
100644 blob 1470 c5a938a3818c9aca6de00a961c1c8f73bb2c47db hb.h
100644 blob 7651 65c5ca88a67c30becee01c5a8816d964b03862f9 license.md
100755 blob 5635 fedeb110245a5460039167ccc6cec1abca82c271 make
Hints:
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://rocketgit.com/user/sylware/charfbuzz

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@ssh.rocketgit.com/user/sylware/charfbuzz

Clone this repository using git:
git clone git://git.rocketgit.com/user/sylware/charfbuzz

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a merge request:
... clone the repository ...
... make some changes and some commits ...
git push origin main