1 #ifndef OT_LAYOUT_GPOS_VALUEFORMAT_HH 2 #define OT_LAYOUT_GPOS_VALUEFORMAT_HH 3 4 #include "../../../hb-ot-layout-gsubgpos.hh" 5 6 namespace OT { 7 namespace Layout { 8 namespace GPOS_impl { 9 10 typedef HBUINT16 Value; 11 12 typedef UnsizedArrayOf<Value> ValueRecord; 13 14 struct ValueFormat : HBUINT16 15 { 16 enum Flags { 17 xPlacement = 0x0001u, /* Includes horizontal adjustment for placement */ 18 yPlacement = 0x0002u, /* Includes vertical adjustment for placement */ 19 xAdvance = 0x0004u, /* Includes horizontal adjustment for advance */ 20 yAdvance = 0x0008u, /* Includes vertical adjustment for advance */ 21 xPlaDevice = 0x0010u, /* Includes horizontal Device table for placement */ 22 yPlaDevice = 0x0020u, /* Includes vertical Device table for placement */ 23 xAdvDevice = 0x0040u, /* Includes horizontal Device table for advance */ 24 yAdvDevice = 0x0080u, /* Includes vertical Device table for advance */ 25 ignored = 0x0F00u, /* Was used in TrueType Open for MM fonts */ 26 reserved = 0xF000u, /* For future use */ 27 28 devices = 0x00F0u /* Mask for having any Device table */ 29 }; 30 31 /* All fields are options. Only those available advance the value pointer. */ 32 #if 0 33 HBINT16 xPlacement; /* Horizontal adjustment for 34 * placement--in design units */ 35 HBINT16 yPlacement; /* Vertical adjustment for 36 * placement--in design units */ 37 HBINT16 xAdvance; /* Horizontal adjustment for 38 * advance--in design units (only used 39 * for horizontal writing) */ 40 HBINT16 yAdvance; /* Vertical adjustment for advance--in 41 * design units (only used for vertical 42 * writing) */ 43 Offset16To<Device> xPlaDevice; /* Offset to Device table for 44 * horizontal placement--measured from 45 * beginning of PosTable (may be NULL) */ 46 Offset16To<Device> yPlaDevice; /* Offset to Device table for vertical 47 * placement--measured from beginning 48 * of PosTable (may be NULL) */ 49 Offset16To<Device> xAdvDevice; /* Offset to Device table for 50 * horizontal advance--measured from 51 * beginning of PosTable (may be NULL) */ 52 Offset16To<Device> yAdvDevice; /* Offset to Device table for vertical 53 * advance--measured from beginning of 54 * PosTable (may be NULL) */ 55 #endif 56 operator =OT::Layout::GPOS_impl::ValueFormat57 IntType& operator = (uint16_t i) { v = i; return *this; } 58 get_lenOT::Layout::GPOS_impl::ValueFormat59 unsigned int get_len () const { return hb_popcount ((unsigned int) *this); } get_sizeOT::Layout::GPOS_impl::ValueFormat60 unsigned int get_size () const { return get_len () * Value::static_size; } 61 get_device_table_indicesOT::Layout::GPOS_impl::ValueFormat62 hb_vector_t<unsigned> get_device_table_indices () const { 63 unsigned i = 0; 64 hb_vector_t<unsigned> result; 65 unsigned format = *this; 66 67 if (format & xPlacement) i++; 68 if (format & yPlacement) i++; 69 if (format & xAdvance) i++; 70 if (format & yAdvance) i++; 71 72 if (format & xPlaDevice) result.push (i++); 73 if (format & yPlaDevice) result.push (i++); 74 if (format & xAdvDevice) result.push (i++); 75 if (format & yAdvDevice) result.push (i++); 76 77 return result; 78 } 79 apply_valueOT::Layout::GPOS_impl::ValueFormat80 bool apply_value (hb_ot_apply_context_t *c, 81 const void *base, 82 const Value *values, 83 hb_glyph_position_t &glyph_pos) const 84 { 85 bool ret = false; 86 unsigned int format = *this; 87 if (!format) return ret; 88 89 hb_font_t *font = c->font; 90 bool horizontal = 91 #ifndef HB_NO_VERTICAL 92 HB_DIRECTION_IS_HORIZONTAL (c->direction) 93 #else 94 true 95 #endif 96 ; 97 98 if (format & xPlacement) glyph_pos.x_offset += font->em_scale_x (get_short (values++, &ret)); 99 if (format & yPlacement) glyph_pos.y_offset += font->em_scale_y (get_short (values++, &ret)); 100 if (format & xAdvance) { 101 if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values, &ret)); 102 values++; 103 } 104 /* y_advance values grow downward but font-space grows upward, hence negation */ 105 if (format & yAdvance) { 106 if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values, &ret)); 107 values++; 108 } 109 110 if (!has_device ()) return ret; 111 112 bool use_x_device = font->x_ppem || font->num_coords; 113 bool use_y_device = font->y_ppem || font->num_coords; 114 115 if (!use_x_device && !use_y_device) return ret; 116 117 const VariationStore &store = c->var_store; 118 auto *cache = c->var_store_cache; 119 120 /* pixel -> fractional pixel */ 121 if (format & xPlaDevice) { 122 if (use_x_device) glyph_pos.x_offset += (base + get_device (values, &ret)).get_x_delta (font, store, cache); 123 values++; 124 } 125 if (format & yPlaDevice) { 126 if (use_y_device) glyph_pos.y_offset += (base + get_device (values, &ret)).get_y_delta (font, store, cache); 127 values++; 128 } 129 if (format & xAdvDevice) { 130 if (horizontal && use_x_device) glyph_pos.x_advance += (base + get_device (values, &ret)).get_x_delta (font, store, cache); 131 values++; 132 } 133 if (format & yAdvDevice) { 134 /* y_advance values grow downward but font-space grows upward, hence negation */ 135 if (!horizontal && use_y_device) glyph_pos.y_advance -= (base + get_device (values, &ret)).get_y_delta (font, store, cache); 136 values++; 137 } 138 return ret; 139 } 140 get_effective_formatOT::Layout::GPOS_impl::ValueFormat141 unsigned int get_effective_format (const Value *values) const 142 { 143 unsigned int format = *this; 144 for (unsigned flag = xPlacement; flag <= yAdvDevice; flag = flag << 1) { 145 if (format & flag) should_drop (*values++, (Flags) flag, &format); 146 } 147 148 return format; 149 } 150 151 template<typename Iterator, 152 hb_requires (hb_is_iterator (Iterator))> get_effective_formatOT::Layout::GPOS_impl::ValueFormat153 unsigned int get_effective_format (Iterator it) const { 154 unsigned int new_format = 0; 155 156 for (const hb_array_t<const Value>& values : it) 157 new_format = new_format | get_effective_format (&values); 158 159 return new_format; 160 } 161 copy_valuesOT::Layout::GPOS_impl::ValueFormat162 void copy_values (hb_serialize_context_t *c, 163 unsigned int new_format, 164 const void *base, 165 const Value *values, 166 const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const 167 { 168 unsigned int format = *this; 169 if (!format) return; 170 171 HBINT16 *x_placement = nullptr, *y_placement = nullptr, *x_adv = nullptr, *y_adv = nullptr; 172 if (format & xPlacement) x_placement = copy_value (c, new_format, xPlacement, *values++); 173 if (format & yPlacement) y_placement = copy_value (c, new_format, yPlacement, *values++); 174 if (format & xAdvance) x_adv = copy_value (c, new_format, xAdvance, *values++); 175 if (format & yAdvance) y_adv = copy_value (c, new_format, yAdvance, *values++); 176 177 if (format & xPlaDevice) 178 { 179 add_delta_to_value (x_placement, base, values, layout_variation_idx_delta_map); 180 copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, xPlaDevice); 181 } 182 183 if (format & yPlaDevice) 184 { 185 add_delta_to_value (y_placement, base, values, layout_variation_idx_delta_map); 186 copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, yPlaDevice); 187 } 188 189 if (format & xAdvDevice) 190 { 191 add_delta_to_value (x_adv, base, values, layout_variation_idx_delta_map); 192 copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, xAdvDevice); 193 } 194 195 if (format & yAdvDevice) 196 { 197 add_delta_to_value (y_adv, base, values, layout_variation_idx_delta_map); 198 copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, yAdvDevice); 199 } 200 } 201 copy_valueOT::Layout::GPOS_impl::ValueFormat202 HBINT16* copy_value (hb_serialize_context_t *c, 203 unsigned int new_format, 204 Flags flag, 205 Value value) const 206 { 207 // Filter by new format. 208 if (!(new_format & flag)) return nullptr; 209 return reinterpret_cast<HBINT16 *> (c->copy (value)); 210 } 211 collect_variation_indicesOT::Layout::GPOS_impl::ValueFormat212 void collect_variation_indices (hb_collect_variation_indices_context_t *c, 213 const void *base, 214 const hb_array_t<const Value>& values) const 215 { 216 unsigned format = *this; 217 unsigned i = 0; 218 if (format & xPlacement) i++; 219 if (format & yPlacement) i++; 220 if (format & xAdvance) i++; 221 if (format & yAdvance) i++; 222 if (format & xPlaDevice) 223 { 224 (base + get_device (&(values[i]))).collect_variation_indices (c); 225 i++; 226 } 227 228 if (format & ValueFormat::yPlaDevice) 229 { 230 (base + get_device (&(values[i]))).collect_variation_indices (c); 231 i++; 232 } 233 234 if (format & ValueFormat::xAdvDevice) 235 { 236 237 (base + get_device (&(values[i]))).collect_variation_indices (c); 238 i++; 239 } 240 241 if (format & ValueFormat::yAdvDevice) 242 { 243 244 (base + get_device (&(values[i]))).collect_variation_indices (c); 245 i++; 246 } 247 } 248 drop_device_table_flagsOT::Layout::GPOS_impl::ValueFormat249 unsigned drop_device_table_flags () const 250 { 251 unsigned format = *this; 252 for (unsigned flag = xPlaDevice; flag <= yAdvDevice; flag = flag << 1) 253 format = format & ~flag; 254 255 return format; 256 } 257 258 private: sanitize_value_devicesOT::Layout::GPOS_impl::ValueFormat259 bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const 260 { 261 unsigned int format = *this; 262 263 if (format & xPlacement) values++; 264 if (format & yPlacement) values++; 265 if (format & xAdvance) values++; 266 if (format & yAdvance) values++; 267 268 if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false; 269 if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false; 270 if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false; 271 if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false; 272 273 return true; 274 } 275 get_deviceOT::Layout::GPOS_impl::ValueFormat276 static inline Offset16To<Device>& get_device (Value* value) 277 { 278 return *static_cast<Offset16To<Device> *> (value); 279 } get_deviceOT::Layout::GPOS_impl::ValueFormat280 static inline const Offset16To<Device>& get_device (const Value* value, bool *worked=nullptr) 281 { 282 if (worked) *worked |= bool (*value); 283 return *static_cast<const Offset16To<Device> *> (value); 284 } 285 add_delta_to_valueOT::Layout::GPOS_impl::ValueFormat286 void add_delta_to_value (HBINT16 *value, 287 const void *base, 288 const Value *src_value, 289 const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const 290 { 291 if (!value) return; 292 unsigned varidx = (base + get_device (src_value)).get_variation_index (); 293 hb_pair_t<unsigned, int> *varidx_delta; 294 if (!layout_variation_idx_delta_map->has (varidx, &varidx_delta)) return; 295 296 *value += hb_second (*varidx_delta); 297 } 298 copy_deviceOT::Layout::GPOS_impl::ValueFormat299 bool copy_device (hb_serialize_context_t *c, const void *base, 300 const Value *src_value, 301 const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map, 302 unsigned int new_format, Flags flag) const 303 { 304 // Filter by new format. 305 if (!(new_format & flag)) return true; 306 307 Value *dst_value = c->copy (*src_value); 308 309 if (!dst_value) return false; 310 if (*dst_value == 0) return true; 311 312 *dst_value = 0; 313 c->push (); 314 if ((base + get_device (src_value)).copy (c, layout_variation_idx_delta_map)) 315 { 316 c->add_link (*dst_value, c->pop_pack ()); 317 return true; 318 } 319 else 320 { 321 c->pop_discard (); 322 return false; 323 } 324 } 325 get_shortOT::Layout::GPOS_impl::ValueFormat326 static inline const HBINT16& get_short (const Value* value, bool *worked=nullptr) 327 { 328 if (worked) *worked |= bool (*value); 329 return *reinterpret_cast<const HBINT16 *> (value); 330 } 331 332 public: 333 has_deviceOT::Layout::GPOS_impl::ValueFormat334 bool has_device () const 335 { 336 unsigned int format = *this; 337 return (format & devices) != 0; 338 } 339 sanitize_valueOT::Layout::GPOS_impl::ValueFormat340 bool sanitize_value (hb_sanitize_context_t *c, const void *base, const Value *values) const 341 { 342 TRACE_SANITIZE (this); 343 return_trace (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values))); 344 } 345 sanitize_valuesOT::Layout::GPOS_impl::ValueFormat346 bool sanitize_values (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count) const 347 { 348 TRACE_SANITIZE (this); 349 unsigned int len = get_len (); 350 351 if (!c->check_range (values, count, get_size ())) return_trace (false); 352 353 if (!has_device ()) return_trace (true); 354 355 for (unsigned int i = 0; i < count; i++) { 356 if (!sanitize_value_devices (c, base, values)) 357 return_trace (false); 358 values += len; 359 } 360 361 return_trace (true); 362 } 363 364 /* Just sanitize referenced Device tables. Doesn't check the values themselves. */ sanitize_values_stride_unsafeOT::Layout::GPOS_impl::ValueFormat365 bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count, unsigned int stride) const 366 { 367 TRACE_SANITIZE (this); 368 369 if (!has_device ()) return_trace (true); 370 371 for (unsigned int i = 0; i < count; i++) { 372 if (!sanitize_value_devices (c, base, values)) 373 return_trace (false); 374 values += stride; 375 } 376 377 return_trace (true); 378 } 379 380 private: 381 should_dropOT::Layout::GPOS_impl::ValueFormat382 void should_drop (Value value, Flags flag, unsigned int* format) const 383 { 384 if (value) return; 385 *format = *format & ~flag; 386 } 387 388 }; 389 390 } 391 } 392 } 393 394 #endif // #ifndef OT_LAYOUT_GPOS_VALUEFORMAT_HH 395