1 /*
   2  * Copyright © 2009  Red Hat, Inc.
   3  * Copyright © 2011  Google, Inc.
   4  *
   5  *  This is part of HarfBuzz, a text shaping library.
   6  *
   7  * Permission is hereby granted, without written agreement and without
   8  * license or royalty fees, to use, copy, modify, and distribute this
   9  * software and its documentation for any purpose, provided that the
  10  * above copyright notice and the following two paragraphs appear in
  11  * all copies of this software.
  12  *
  13  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
  14  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
  15  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
  16  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
  17  * DAMAGE.
  18  *
  19  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
  20  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  21  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  22  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  23  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  24  *
  25  * Red Hat Author(s): Behdad Esfahbod
  26  * Google Author(s): Behdad Esfahbod
  27  */
  28 
  29 #ifndef HB_FONT_PRIVATE_HH
  30 #define HB_FONT_PRIVATE_HH
  31 
  32 #include "hb-private.hh"
  33 
  34 #include "hb-object-private.hh"
  35 #include "hb-face-private.hh"
  36 #include "hb-shaper-private.hh"
  37 
  38 
  39 
  40 /*
  41  * hb_font_funcs_t
  42  */
  43 
  44 #define HB_FONT_FUNCS_IMPLEMENT_CALLBACKS \
  45   HB_FONT_FUNC_IMPLEMENT (glyph) \
  46   HB_FONT_FUNC_IMPLEMENT (glyph_h_advance) \
  47   HB_FONT_FUNC_IMPLEMENT (glyph_v_advance) \
  48   HB_FONT_FUNC_IMPLEMENT (glyph_h_origin) \
  49   HB_FONT_FUNC_IMPLEMENT (glyph_v_origin) \
  50   HB_FONT_FUNC_IMPLEMENT (glyph_h_kerning) \
  51   HB_FONT_FUNC_IMPLEMENT (glyph_v_kerning) \
  52   HB_FONT_FUNC_IMPLEMENT (glyph_extents) \
  53   HB_FONT_FUNC_IMPLEMENT (glyph_contour_point) \
  54   HB_FONT_FUNC_IMPLEMENT (glyph_name) \
  55   HB_FONT_FUNC_IMPLEMENT (glyph_from_name) \
  56   /* ^--- Add new callbacks here */
  57 
  58 struct hb_font_funcs_t {
  59   hb_object_header_t header;
  60   ASSERT_POD ();
  61 
  62   hb_bool_t immutable;
  63 
  64   /* Don't access these directly.  Call hb_font_get_*() instead. */
  65 
  66   struct {
  67 #define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_func_t name;
  68     HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
  69 #undef HB_FONT_FUNC_IMPLEMENT
  70   } get;
  71 
  72   struct {
  73 #define HB_FONT_FUNC_IMPLEMENT(name) void *name;
  74     HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
  75 #undef HB_FONT_FUNC_IMPLEMENT
  76   } user_data;
  77 
  78   struct {
  79 #define HB_FONT_FUNC_IMPLEMENT(name) hb_destroy_func_t name;
  80     HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
  81 #undef HB_FONT_FUNC_IMPLEMENT
  82   } destroy;
  83 };
  84 
  85 
  86 
  87 /*
  88  * hb_font_t
  89  */
  90 
  91 struct hb_font_t {
  92   hb_object_header_t header;
  93   ASSERT_POD ();
  94 
  95   hb_bool_t immutable;
  96 
  97   hb_font_t *parent;
  98   hb_face_t *face;
  99 
 100   int x_scale;
 101   int y_scale;
 102 
 103   unsigned int x_ppem;
 104   unsigned int y_ppem;
 105 
 106   hb_font_funcs_t   *klass;
 107   void              *user_data;
 108   hb_destroy_func_t  destroy;
 109 
 110   struct hb_shaper_data_t shaper_data;
 111 
 112 
 113   /* Convert from font-space to user-space */
 114   inline hb_position_t em_scale_x (int16_t v) { return em_scale (v, this->x_scale); }
 115   inline hb_position_t em_scale_y (int16_t v) { return em_scale (v, this->y_scale); }
 116 
 117   /* Convert from parent-font user-space to our user-space */
 118   inline hb_position_t parent_scale_x_distance (hb_position_t v) {
 119     if (unlikely (parent && parent->x_scale != x_scale))
 120       return (hb_position_t) (v * (int64_t) this->x_scale / this->parent->x_scale);
 121     return v;
 122   }
 123   inline hb_position_t parent_scale_y_distance (hb_position_t v) {
 124     if (unlikely (parent && parent->y_scale != y_scale))
 125       return (hb_position_t) (v * (int64_t) this->y_scale / this->parent->y_scale);
 126     return v;
 127   }
 128   inline hb_position_t parent_scale_x_position (hb_position_t v) {
 129     return parent_scale_x_distance (v);
 130   }
 131   inline hb_position_t parent_scale_y_position (hb_position_t v) {
 132     return parent_scale_y_distance (v);
 133   }
 134 
 135   inline void parent_scale_distance (hb_position_t *x, hb_position_t *y) {
 136     *x = parent_scale_x_distance (*x);
 137     *y = parent_scale_y_distance (*y);
 138   }
 139   inline void parent_scale_position (hb_position_t *x, hb_position_t *y) {
 140     *x = parent_scale_x_position (*x);
 141     *y = parent_scale_y_position (*y);
 142   }
 143 
 144 
 145   /* Public getters */
 146 
 147   inline hb_bool_t has_glyph (hb_codepoint_t unicode)
 148   {
 149     hb_codepoint_t glyph;
 150     return get_glyph (unicode, 0, &glyph);
 151   }
 152 
 153   inline hb_bool_t get_glyph (hb_codepoint_t unicode, hb_codepoint_t variation_selector,
 154                               hb_codepoint_t *glyph)
 155   {
 156     *glyph = 0;
 157     return klass->get.glyph (this, user_data,
 158                              unicode, variation_selector, glyph,
 159                              klass->user_data.glyph);
 160   }
 161 
 162   inline hb_position_t get_glyph_h_advance (hb_codepoint_t glyph)
 163   {
 164     return klass->get.glyph_h_advance (this, user_data,
 165                                        glyph,
 166                                        klass->user_data.glyph_h_advance);
 167   }
 168 
 169   inline hb_position_t get_glyph_v_advance (hb_codepoint_t glyph)
 170   {
 171     return klass->get.glyph_v_advance (this, user_data,
 172                                        glyph,
 173                                        klass->user_data.glyph_v_advance);
 174   }
 175 
 176   inline hb_bool_t get_glyph_h_origin (hb_codepoint_t glyph,
 177                                        hb_position_t *x, hb_position_t *y)
 178   {
 179     *x = *y = 0;
 180     return klass->get.glyph_h_origin (this, user_data,
 181                                       glyph, x, y,
 182                                       klass->user_data.glyph_h_origin);
 183   }
 184 
 185   inline hb_bool_t get_glyph_v_origin (hb_codepoint_t glyph,
 186                                        hb_position_t *x, hb_position_t *y)
 187   {
 188     *x = *y = 0;
 189     return klass->get.glyph_v_origin (this, user_data,
 190                                       glyph, x, y,
 191                                       klass->user_data.glyph_v_origin);
 192   }
 193 
 194   inline hb_position_t get_glyph_h_kerning (hb_codepoint_t left_glyph, hb_codepoint_t right_glyph)
 195   {
 196     return klass->get.glyph_h_kerning (this, user_data,
 197                                        left_glyph, right_glyph,
 198                                        klass->user_data.glyph_h_kerning);
 199   }
 200 
 201   inline hb_position_t get_glyph_v_kerning (hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph)
 202   {
 203     return klass->get.glyph_v_kerning (this, user_data,
 204                                        top_glyph, bottom_glyph,
 205                                        klass->user_data.glyph_v_kerning);
 206   }
 207 
 208   inline hb_bool_t get_glyph_extents (hb_codepoint_t glyph,
 209                                       hb_glyph_extents_t *extents)
 210   {
 211     memset (extents, 0, sizeof (*extents));
 212     return klass->get.glyph_extents (this, user_data,
 213                                      glyph,
 214                                      extents,
 215                                      klass->user_data.glyph_extents);
 216   }
 217 
 218   inline hb_bool_t get_glyph_contour_point (hb_codepoint_t glyph, unsigned int point_index,
 219                                             hb_position_t *x, hb_position_t *y)
 220   {
 221     *x = *y = 0;
 222     return klass->get.glyph_contour_point (this, user_data,
 223                                            glyph, point_index,
 224                                            x, y,
 225                                            klass->user_data.glyph_contour_point);
 226   }
 227 
 228   inline hb_bool_t get_glyph_name (hb_codepoint_t glyph,
 229                                    char *name, unsigned int size)
 230   {
 231     if (size) *name = '\0';
 232     return klass->get.glyph_name (this, user_data,
 233                                   glyph,
 234                                   name, size,
 235                                   klass->user_data.glyph_name);
 236   }
 237 
 238   inline hb_bool_t get_glyph_from_name (const char *name, int len, /* -1 means nul-terminated */
 239                                         hb_codepoint_t *glyph)
 240   {
 241     *glyph = 0;
 242     if (len == -1) len = strlen (name);
 243     return klass->get.glyph_from_name (this, user_data,
 244                                        name, len,
 245                                        glyph,
 246                                        klass->user_data.glyph_from_name);
 247   }
 248 
 249 
 250   /* A bit higher-level, and with fallback */
 251 
 252   inline void get_glyph_advance_for_direction (hb_codepoint_t glyph,
 253                                                hb_direction_t direction,
 254                                                hb_position_t *x, hb_position_t *y)
 255   {
 256     if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
 257       *x = get_glyph_h_advance (glyph);
 258       *y = 0;
 259     } else {
 260       *x = 0;
 261       *y = get_glyph_v_advance (glyph);
 262     }
 263   }
 264 
 265   /* Internal only */
 266   inline void guess_v_origin_minus_h_origin (hb_codepoint_t glyph,
 267                                              hb_position_t *x, hb_position_t *y)
 268   {
 269     *x = get_glyph_h_advance (glyph) / 2;
 270 
 271     /* TODO use font_metrics.ascent */
 272     *y = y_scale;
 273   }
 274 
 275   inline void get_glyph_origin_for_direction (hb_codepoint_t glyph,
 276                                               hb_direction_t direction,
 277                                               hb_position_t *x, hb_position_t *y)
 278   {
 279     if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
 280     {
 281       if (!get_glyph_h_origin (glyph, x, y) &&
 282            get_glyph_v_origin (glyph, x, y))
 283       {
 284         hb_position_t dx, dy;
 285         guess_v_origin_minus_h_origin (glyph, &dx, &dy);
 286         *x -= dx; *y -= dy;
 287       }
 288     }
 289     else
 290     {
 291       if (!get_glyph_v_origin (glyph, x, y) &&
 292            get_glyph_h_origin (glyph, x, y))
 293       {
 294         hb_position_t dx, dy;
 295         guess_v_origin_minus_h_origin (glyph, &dx, &dy);
 296         *x += dx; *y += dy;
 297       }
 298     }
 299   }
 300 
 301   inline void add_glyph_origin_for_direction (hb_codepoint_t glyph,
 302                                               hb_direction_t direction,
 303                                               hb_position_t *x, hb_position_t *y)
 304   {
 305     hb_position_t origin_x, origin_y;
 306 
 307     get_glyph_origin_for_direction (glyph, direction, &origin_x, &origin_y);
 308 
 309     *x += origin_x;
 310     *y += origin_y;
 311   }
 312 
 313   inline void subtract_glyph_origin_for_direction (hb_codepoint_t glyph,
 314                                                    hb_direction_t direction,
 315                                                    hb_position_t *x, hb_position_t *y)
 316   {
 317     hb_position_t origin_x, origin_y;
 318 
 319     get_glyph_origin_for_direction (glyph, direction, &origin_x, &origin_y);
 320 
 321     *x -= origin_x;
 322     *y -= origin_y;
 323   }
 324 
 325   inline void get_glyph_kerning_for_direction (hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
 326                                                hb_direction_t direction,
 327                                                hb_position_t *x, hb_position_t *y)
 328   {
 329     if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
 330       *x = get_glyph_h_kerning (first_glyph, second_glyph);
 331       *y = 0;
 332     } else {
 333       *x = 0;
 334       *y = get_glyph_v_kerning (first_glyph, second_glyph);
 335     }
 336   }
 337 
 338   inline hb_bool_t get_glyph_extents_for_origin (hb_codepoint_t glyph,
 339                                                  hb_direction_t direction,
 340                                                  hb_glyph_extents_t *extents)
 341   {
 342     hb_bool_t ret = get_glyph_extents (glyph, extents);
 343 
 344     if (ret)
 345       subtract_glyph_origin_for_direction (glyph, direction, &extents->x_bearing, &extents->y_bearing);
 346 
 347     return ret;
 348   }
 349 
 350   inline hb_bool_t get_glyph_contour_point_for_origin (hb_codepoint_t glyph, unsigned int point_index,
 351                                                        hb_direction_t direction,
 352                                                        hb_position_t *x, hb_position_t *y)
 353   {
 354     hb_bool_t ret = get_glyph_contour_point (glyph, point_index, x, y);
 355 
 356     if (ret)
 357       subtract_glyph_origin_for_direction (glyph, direction, x, y);
 358 
 359     return ret;
 360   }
 361 
 362   /* Generates gidDDD if glyph has no name. */
 363   inline void
 364   glyph_to_string (hb_codepoint_t glyph,
 365                    char *s, unsigned int size)
 366   {
 367     if (get_glyph_name (glyph, s, size)) return;
 368 
 369     if (size && snprintf (s, size, "gid%u", glyph) < 0)
 370       *s = '\0';
 371   }
 372 
 373   /* Parses gidDDD and uniUUUU strings automatically. */
 374   inline hb_bool_t
 375   glyph_from_string (const char *s, int len, /* -1 means nul-terminated */
 376                      hb_codepoint_t *glyph)
 377   {
 378     if (get_glyph_from_name (s, len, glyph)) return true;
 379 
 380     if (len == -1) len = strlen (s);
 381 
 382     /* Straight glyph index. */
 383     if (hb_codepoint_parse (s, len, 10, glyph))
 384       return true;
 385 
 386     if (len > 3)
 387     {
 388       /* gidDDD syntax for glyph indices. */
 389       if (0 == strncmp (s, "gid", 3) &&
 390           hb_codepoint_parse (s + 3, len - 3, 10, glyph))
 391         return true;
 392 
 393       /* uniUUUU and other Unicode character indices. */
 394       hb_codepoint_t unichar;
 395       if (0 == strncmp (s, "uni", 3) &&
 396           hb_codepoint_parse (s + 3, len - 3, 16, &unichar) &&
 397           get_glyph (unichar, 0, glyph))
 398         return true;
 399     }
 400 
 401     return false;
 402   }
 403 
 404   private:
 405   inline hb_position_t em_scale (int16_t v, int scale) { return (hb_position_t) (v * (int64_t) scale / face->get_upem ()); }
 406 };
 407 
 408 #define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
 409 #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_PROTOTYPE(shaper, font);
 410 #include "hb-shaper-list.hh"
 411 #undef HB_SHAPER_IMPLEMENT
 412 #undef HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
 413 
 414 
 415 #endif /* HB_FONT_PRIVATE_HH */