1 /* 2 * Copyright © 2017 Google, Inc. 3 * 4 * This is part of HarfBuzz, a text shaping library. 5 * 6 * Permission is hereby granted, without written agreement and without 7 * license or royalty fees, to use, copy, modify, and distribute this 8 * software and its documentation for any purpose, provided that the 9 * above copyright notice and the following two paragraphs appear in 10 * all copies of this software. 11 * 12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 16 * DAMAGE. 17 * 18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 23 * 24 * Google Author(s): Behdad Esfahbod 25 */ 26 27 #ifndef HB_KERN_HH 28 #define HB_KERN_HH 29 30 #include "hb-open-type.hh" 31 #include "hb-aat-layout-common.hh" 32 #include "hb-ot-layout-gpos-table.hh" 33 34 35 namespace OT { 36 37 38 template <typename Driver> 39 struct hb_kern_machine_t 40 { hb_kern_machine_tOT::hb_kern_machine_t41 hb_kern_machine_t (const Driver &driver_, 42 bool crossStream_ = false) : 43 driver (driver_), 44 crossStream (crossStream_) {} 45 46 HB_NO_SANITIZE_SIGNED_INTEGER_OVERFLOW kernOT::hb_kern_machine_t47 void kern (hb_font_t *font, 48 hb_buffer_t *buffer, 49 hb_mask_t kern_mask, 50 bool scale = true) const 51 { 52 OT::hb_ot_apply_context_t c (1, font, buffer); 53 c.set_lookup_mask (kern_mask); 54 c.set_lookup_props (OT::LookupFlag::IgnoreMarks); 55 OT::hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c.iter_input; 56 skippy_iter.init (&c); 57 58 bool horizontal = HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction); 59 unsigned int count = buffer->len; 60 hb_glyph_info_t *info = buffer->info; 61 hb_glyph_position_t *pos = buffer->pos; 62 for (unsigned int idx = 0; idx < count;) 63 { 64 if (!(info[idx].mask & kern_mask)) 65 { 66 idx++; 67 continue; 68 } 69 70 skippy_iter.reset (idx, 1); 71 if (!skippy_iter.next ()) 72 { 73 idx++; 74 continue; 75 } 76 77 unsigned int i = idx; 78 unsigned int j = skippy_iter.idx; 79 80 hb_position_t kern = driver.get_kerning (info[i].codepoint, 81 info[j].codepoint); 82 83 84 if (likely (!kern)) 85 goto skip; 86 87 if (horizontal) 88 { 89 if (scale) 90 kern = font->em_scale_x (kern); 91 if (crossStream) 92 { 93 pos[j].y_offset = kern; 94 buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT; 95 } 96 else 97 { 98 hb_position_t kern1 = kern >> 1; 99 hb_position_t kern2 = kern - kern1; 100 pos[i].x_advance += kern1; 101 pos[j].x_advance += kern2; 102 pos[j].x_offset += kern2; 103 } 104 } 105 else 106 { 107 if (scale) 108 kern = font->em_scale_y (kern); 109 if (crossStream) 110 { 111 pos[j].x_offset = kern; 112 buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT; 113 } 114 else 115 { 116 hb_position_t kern1 = kern >> 1; 117 hb_position_t kern2 = kern - kern1; 118 pos[i].y_advance += kern1; 119 pos[j].y_advance += kern2; 120 pos[j].y_offset += kern2; 121 } 122 } 123 124 buffer->unsafe_to_break (i, j + 1); 125 126 skip: 127 idx = skippy_iter.idx; 128 } 129 } 130 131 const Driver &driver; 132 bool crossStream; 133 }; 134 135 136 } /* namespace OT */ 137 138 139 #endif /* HB_KERN_HH */ 140