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