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 auto &skippy_iter = c.iter_input; 56 57 bool horizontal = HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction); 58 unsigned int count = buffer->len; 59 hb_glyph_info_t *info = buffer->info; 60 hb_glyph_position_t *pos = buffer->pos; 61 for (unsigned int idx = 0; idx < count;) 62 { 63 if (!(info[idx].mask & kern_mask)) 64 { 65 idx++; 66 continue; 67 } 68 69 skippy_iter.reset (idx, 1); 70 if (!skippy_iter.next ()) 71 { 72 idx++; 73 continue; 74 } 75 76 unsigned int i = idx; 77 unsigned int j = skippy_iter.idx; 78 79 hb_position_t kern = driver.get_kerning (info[i].codepoint, 80 info[j].codepoint); 81 82 83 if (likely (!kern)) 84 goto skip; 85 86 if (horizontal) 87 { 88 if (scale) 89 kern = font->em_scale_x (kern); 90 if (crossStream) 91 { 92 pos[j].y_offset = kern; 93 buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT; 94 } 95 else 96 { 97 hb_position_t kern1 = kern >> 1; 98 hb_position_t kern2 = kern - kern1; 99 pos[i].x_advance += kern1; 100 pos[j].x_advance += kern2; 101 pos[j].x_offset += kern2; 102 } 103 } 104 else 105 { 106 if (scale) 107 kern = font->em_scale_y (kern); 108 if (crossStream) 109 { 110 pos[j].x_offset = kern; 111 buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT; 112 } 113 else 114 { 115 hb_position_t kern1 = kern >> 1; 116 hb_position_t kern2 = kern - kern1; 117 pos[i].y_advance += kern1; 118 pos[j].y_advance += kern2; 119 pos[j].y_offset += kern2; 120 } 121 } 122 123 buffer->unsafe_to_break (i, j + 1); 124 125 skip: 126 idx = skippy_iter.idx; 127 } 128 } 129 130 const Driver &driver; 131 bool crossStream; 132 }; 133 134 135 } /* namespace OT */ 136 137 138 #endif /* HB_KERN_HH */ 139