hb-ot-kern-table.hh 12.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
/*
 * Copyright © 2017  Google, Inc.
 *
 *  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.
 *
 * Google Author(s): Behdad Esfahbod
 */

#ifndef HB_OT_KERN_TABLE_HH
#define HB_OT_KERN_TABLE_HH

30
#include "hb-open-type.hh"
31 32 33 34 35 36 37
#include "hb-ot-shape.hh"
#include "hb-ot-layout-gsubgpos.hh"


template <typename Driver>
struct hb_kern_machine_t
{
38
  hb_kern_machine_t (const Driver &driver_) : driver (driver_) {}
39

40 41 42
  inline void kern (hb_font_t *font,
		    hb_buffer_t  *buffer,
		    hb_mask_t kern_mask) const
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
  {
    OT::hb_ot_apply_context_t c (1, font, buffer);
    c.set_lookup_mask (kern_mask);
    c.set_lookup_props (OT::LookupFlag::IgnoreMarks);
    OT::hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c.iter_input;
    skippy_iter.init (&c);

    bool horizontal = HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction);
    unsigned int count = buffer->len;
    hb_glyph_info_t *info = buffer->info;
    hb_glyph_position_t *pos = buffer->pos;
    for (unsigned int idx = 0; idx < count;)
    {
      if (!(info[idx].mask & kern_mask))
      {
	idx++;
	continue;
      }

      skippy_iter.reset (idx, 1);
      if (!skippy_iter.next ())
      {
	idx++;
	continue;
      }

      unsigned int i = idx;
      unsigned int j = skippy_iter.idx;
      hb_position_t kern = driver.get_kerning (info[i].codepoint,
					       info[j].codepoint);

      hb_position_t kern1 = kern >> 1;
      hb_position_t kern2 = kern - kern1;

      if (horizontal)
      {
	pos[i].x_advance += kern1;
	pos[j].x_advance += kern2;
	pos[j].x_offset += kern2;
      }
      else
      {
	pos[i].y_advance += kern1;
	pos[j].y_advance += kern2;
	pos[j].y_offset += kern2;
      }

      buffer->unsafe_to_break (i, j + 1);

      idx = skippy_iter.idx;
    }
  }

96
  const Driver &driver;
97 98
};

99 100 101

/*
 * kern -- Kerning
102 103
 * https://docs.microsoft.com/en-us/typography/opentype/spec/kern
 * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6kern.html
104 105 106
 */
#define HB_OT_TAG_kern HB_TAG('k','e','r','n')

107 108 109 110

namespace OT {


B
Behdad Esfahbod 已提交
111 112 113 114 115
struct hb_glyph_pair_t
{
  hb_codepoint_t left;
  hb_codepoint_t right;
};
116

B
Behdad Esfahbod 已提交
117
struct KernPair
B
Behdad Esfahbod 已提交
118
{
B
Behdad Esfahbod 已提交
119 120 121 122
  inline int get_kerning (void) const
  { return value; }

  inline int cmp (const hb_glyph_pair_t &o) const
B
Behdad Esfahbod 已提交
123
  {
B
Behdad Esfahbod 已提交
124 125 126
    int ret = left.cmp (o.left);
    if (ret) return ret;
    return right.cmp (o.right);
B
Behdad Esfahbod 已提交
127 128 129 130 131
  }

  inline bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
132 133
    return_trace (c->check_struct (this));
  }
B
Behdad Esfahbod 已提交
134

B
Behdad Esfahbod 已提交
135 136 137 138 139 140 141
  protected:
  GlyphID	left;
  GlyphID	right;
  FWORD		value;
  public:
  DEFINE_SIZE_STATIC (6);
};
B
Behdad Esfahbod 已提交
142

B
Behdad Esfahbod 已提交
143 144 145 146 147 148 149 150 151
struct KernSubTableFormat0
{
  inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
  {
    hb_glyph_pair_t pair = {left, right};
    int i = pairs.bsearch (pair);
    if (i == -1)
      return 0;
    return pairs[i].get_kerning ();
B
Behdad Esfahbod 已提交
152
  }
B
Behdad Esfahbod 已提交
153 154 155 156 157 158 159 160 161 162 163

  inline bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (pairs.sanitize (c));
  }

  protected:
  BinSearchArrayOf<KernPair> pairs;	/* Array of kerning pairs. */
  public:
  DEFINE_SIZE_ARRAY (8, pairs);
B
Behdad Esfahbod 已提交
164 165
};

166
struct KernClassTable
B
Behdad Esfahbod 已提交
167
{
168 169 170
  inline unsigned int get_class (hb_codepoint_t g) const { return classes[g - firstGlyph]; }

  inline bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
171
  {
172 173
    TRACE_SANITIZE (this);
    return_trace (firstGlyph.sanitize (c) && classes.sanitize (c));
B
Behdad Esfahbod 已提交
174 175
  }

176
  protected:
B
Behdad Esfahbod 已提交
177 178
  HBUINT16		firstGlyph;	/* First glyph in class range. */
  ArrayOf<HBUINT16>	classes;	/* Glyph classes. */
179 180 181 182 183 184
  public:
  DEFINE_SIZE_ARRAY (4, classes);
};

struct KernSubTableFormat2
{
185
  inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right, const char *end) const
B
Behdad Esfahbod 已提交
186
  {
187
    unsigned int l = (this+leftClassTable).get_class (left);
188
    unsigned int r = (this+rightClassTable).get_class (right);
189
    unsigned int offset = l + r;
190 191 192 193 194
    const FWORD *arr = &(this+array);
    if (unlikely ((const void *) arr < (const void *) this || (const void *) arr >= (const void *) end))
      return 0;
    const FWORD *v = &StructAtOffset<FWORD> (arr, offset);
    if (unlikely ((const void *) v < (const void *) arr || (const void *) (v + 1) > (const void *) end))
195 196
      return 0;
    return *v;
B
Behdad Esfahbod 已提交
197 198 199 200 201
  }

  inline bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
202 203 204 205
    return_trace (rowWidth.sanitize (c) &&
		  leftClassTable.sanitize (c, this) &&
		  rightClassTable.sanitize (c, this) &&
		  array.sanitize (c, this));
B
Behdad Esfahbod 已提交
206
  }
207 208

  protected:
B
Behdad Esfahbod 已提交
209
  HBUINT16	rowWidth;	/* The width, in bytes, of a row in the table. */
210 211 212 213 214 215 216 217 218 219 220
  OffsetTo<KernClassTable>
		leftClassTable;	/* Offset from beginning of this subtable to
				 * left-hand class table. */
  OffsetTo<KernClassTable>
		rightClassTable;/* Offset from beginning of this subtable to
				 * right-hand class table. */
  OffsetTo<FWORD>
		array;		/* Offset from beginning of this subtable to
				 * the start of the kerning array. */
  public:
  DEFINE_SIZE_MIN (8);
B
Behdad Esfahbod 已提交
221 222 223 224
};

struct KernSubTable
{
225
  inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right, const char *end, unsigned int format) const
B
Behdad Esfahbod 已提交
226 227 228
  {
    switch (format) {
    case 0: return u.format0.get_kerning (left, right);
229
    case 2: return u.format2.get_kerning (left, right, end);
B
Behdad Esfahbod 已提交
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
    default:return 0;
    }
  }

  inline bool sanitize (hb_sanitize_context_t *c, unsigned int format) const
  {
    TRACE_SANITIZE (this);
    switch (format) {
    case 0: return_trace (u.format0.sanitize (c));
    case 2: return_trace (u.format2.sanitize (c));
    default:return_trace (true);
    }
  }

  protected:
  union {
  KernSubTableFormat0	format0;
  KernSubTableFormat2	format2;
  } u;
  public:
  DEFINE_SIZE_MIN (0);
};

253 254 255 256 257 258 259

template <typename T>
struct KernSubTableWrapper
{
  /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
  inline const T* thiz (void) const { return static_cast<const T *> (this); }

B
Behdad Esfahbod 已提交
260
  inline bool is_horizontal (void) const
B
Behdad Esfahbod 已提交
261
  { return (thiz()->coverage & T::CheckFlags) == T::CheckHorizontal; }
B
Behdad Esfahbod 已提交
262 263

  inline bool is_override (void) const
B
Behdad Esfahbod 已提交
264
  { return bool (thiz()->coverage & T::Override); }
B
Behdad Esfahbod 已提交
265

266 267
  inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right, const char *end) const
  { return thiz()->subtable.get_kerning (left, right, end, thiz()->format); }
B
Behdad Esfahbod 已提交
268

269 270
  inline int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right, const char *end) const
  { return is_horizontal () ? get_kerning (left, right, end) : 0; }
B
Behdad Esfahbod 已提交
271

272 273 274 275 276
  inline unsigned int get_size (void) const { return thiz()->length; }

  inline bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
277
    return_trace (c->check_struct (thiz()) &&
278
		  thiz()->length >= T::min_size &&
279
		  c->check_array (thiz(), thiz()->length, 1) &&
280
		  thiz()->subtable.sanitize (c, thiz()->format));
281 282 283 284 285 286 287 288 289
  }
};

template <typename T>
struct KernTable
{
  /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
  inline const T* thiz (void) const { return static_cast<const T *> (this); }

290
  inline int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right, unsigned int table_length) const
B
Behdad Esfahbod 已提交
291 292
  {
    int v = 0;
293
    const typename T::SubTableWrapper *st = CastP<typename T::SubTableWrapper> (&thiz()->dataZ);
B
Behdad Esfahbod 已提交
294 295 296 297 298
    unsigned int count = thiz()->nTables;
    for (unsigned int i = 0; i < count; i++)
    {
      if (st->is_override ())
        v = 0;
299
      v += st->get_h_kerning (left, right, table_length + (const char *) this);
B
Behdad Esfahbod 已提交
300 301 302 303 304
      st = &StructAfter<typename T::SubTableWrapper> (*st);
    }
    return v;
  }

305 306 307 308 309 310 311
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    if (unlikely (!c->check_struct (thiz()) ||
		  thiz()->version != T::VERSION))
      return_trace (false);

312
    const typename T::SubTableWrapper *st = CastP<typename T::SubTableWrapper> (&thiz()->dataZ);
B
Behdad Esfahbod 已提交
313
    unsigned int count = thiz()->nTables;
314 315 316 317 318 319 320 321 322 323 324 325 326
    for (unsigned int i = 0; i < count; i++)
    {
      if (unlikely (!st->sanitize (c)))
	return_trace (false);
      st = &StructAfter<typename T::SubTableWrapper> (*st);
    }

    return_trace (true);
  }
};

struct KernOT : KernTable<KernOT>
{
327
  friend struct KernTable<KernOT>;
328 329 330 331 332

  static const uint16_t VERSION = 0x0000u;

  struct SubTableWrapper : KernSubTableWrapper<SubTableWrapper>
  {
333
    friend struct KernSubTableWrapper<SubTableWrapper>;
334

B
Behdad Esfahbod 已提交
335 336 337 338 339 340
    enum Coverage
    {
      Direction		= 0x01u,
      Minimum		= 0x02u,
      CrossStream	= 0x04u,
      Override		= 0x08u,
B
Behdad Esfahbod 已提交
341

B
Behdad Esfahbod 已提交
342
      Variation		= 0x00u, /* Not supported. */
B
Behdad Esfahbod 已提交
343

B
Behdad Esfahbod 已提交
344 345
      CheckFlags	= 0x07u,
      CheckHorizontal	= 0x01u
B
Behdad Esfahbod 已提交
346 347
    };

348
    protected:
B
Behdad Esfahbod 已提交
349 350 351 352
    HBUINT16	versionZ;	/* Unused. */
    HBUINT16	length;		/* Length of the subtable (including this header). */
    HBUINT8	format;		/* Subtable format. */
    HBUINT8	coverage;	/* Coverage bits. */
B
Behdad Esfahbod 已提交
353
    KernSubTable subtable;	/* Subtable data. */
354
    public:
B
Behdad Esfahbod 已提交
355
    DEFINE_SIZE_MIN (6);
356 357 358
  };

  protected:
359 360 361
  HBUINT16			version;	/* Version--0x0000u */
  HBUINT16			nTables;	/* Number of subtables in the kerning table. */
  UnsizedArrayOf<HBUINT8>	dataZ;
362
  public:
363
  DEFINE_SIZE_ARRAY (4, dataZ);
364 365 366 367
};

struct KernAAT : KernTable<KernAAT>
{
368
  friend struct KernTable<KernAAT>;
369 370 371 372 373

  static const uint32_t VERSION = 0x00010000u;

  struct SubTableWrapper : KernSubTableWrapper<SubTableWrapper>
  {
374
    friend struct KernSubTableWrapper<SubTableWrapper>;
375

B
Behdad Esfahbod 已提交
376 377 378 379 380
    enum Coverage
    {
      Direction		= 0x80u,
      CrossStream	= 0x40u,
      Variation		= 0x20u,
B
Behdad Esfahbod 已提交
381

B
Behdad Esfahbod 已提交
382
      Override		= 0x00u, /* Not supported. */
B
Behdad Esfahbod 已提交
383

B
Behdad Esfahbod 已提交
384 385
      CheckFlags	= 0xE0u,
      CheckHorizontal	= 0x00u
B
Behdad Esfahbod 已提交
386 387
    };

388
    protected:
B
Behdad Esfahbod 已提交
389 390 391 392
    HBUINT32	length;		/* Length of the subtable (including this header). */
    HBUINT8	coverage;	/* Coverage bits. */
    HBUINT8	format;		/* Subtable format. */
    HBUINT16	tupleIndex;	/* The tuple index (used for variations fonts).
393
				 * This value specifies which tuple this subtable covers. */
B
Behdad Esfahbod 已提交
394
    KernSubTable subtable;	/* Subtable data. */
395
    public:
B
Behdad Esfahbod 已提交
396
    DEFINE_SIZE_MIN (8);
397 398 399
  };

  protected:
400 401 402
  HBUINT32			version;	/* Version--0x00010000u */
  HBUINT32			nTables;	/* Number of subtables in the kerning table. */
  UnsizedArrayOf<HBUINT8>	dataZ;
403
  public:
404
  DEFINE_SIZE_ARRAY (8, dataZ);
405 406 407 408 409 410
};

struct kern
{
  static const hb_tag_t tableTag = HB_OT_TAG_kern;

411 412 413
  inline bool has_data (void) const
  { return u.version32 != 0; }

414
  inline int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right, unsigned int table_length) const
B
Behdad Esfahbod 已提交
415 416
  {
    switch (u.major) {
417 418
    case 0: return u.ot.get_h_kerning (left, right, table_length);
    case 1: return u.aat.get_h_kerning (left, right, table_length);
B
Behdad Esfahbod 已提交
419 420 421 422
    default:return 0;
    }
  }

423 424 425 426 427 428 429 430 431 432 433
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    if (!u.major.sanitize (c)) return_trace (false);
    switch (u.major) {
    case 0: return_trace (u.ot.sanitize (c));
    case 1: return_trace (u.aat.sanitize (c));
    default:return_trace (true);
    }
  }

434 435
  struct accelerator_t
  {
436
    inline void init (hb_face_t *face)
437
    {
B
Behdad Esfahbod 已提交
438
      blob = hb_sanitize_context_t().reference_table<kern> (face);
439
      table = blob->as<kern> ();
B
Minor  
Behdad Esfahbod 已提交
440
      table_length = blob->length;
441 442 443 444
    }
    inline void fini (void)
    {
      hb_blob_destroy (blob);
445 446
    }

447 448 449
    inline bool has_data (void) const
    { return table->has_data (); }

450 451 452
    inline int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right) const
    { return table->get_h_kerning (left, right, table_length); }

453 454 455
    inline int get_kerning (hb_codepoint_t first, hb_codepoint_t second) const
    { return get_h_kerning (first, second); }

456 457 458
    inline void apply (hb_font_t *font,
		       hb_buffer_t  *buffer,
		       hb_mask_t kern_mask) const
459 460 461 462 463 464
    {
      if (!HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
        return;

      hb_kern_machine_t<accelerator_t> machine (*this);

465
      machine.kern (font, buffer, kern_mask);
466 467
    }

468
    private:
469
    hb_blob_t *blob;
470 471 472 473
    const kern *table;
    unsigned int table_length;
  };

474 475
  protected:
  union {
B
Behdad Esfahbod 已提交
476
  HBUINT16		major;
477
  HBUINT32		version32;
478 479 480 481 482 483 484
  KernOT		ot;
  KernAAT		aat;
  } u;
  public:
  DEFINE_SIZE_UNION (2, major);
};

485 486
struct kern_accelerator_t : kern::accelerator_t {};

487 488 489 490
} /* namespace OT */


#endif /* HB_OT_KERN_TABLE_HH */