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 struct ValueBase {}; // Dummy base class tag for OffsetTo<Value> bases. 13 14 typedef UnsizedArrayOf<Value> ValueRecord; 15 16 struct ValueFormat : HBUINT16 17 { 18 enum Flags { 19 xPlacement = 0x0001u, /* Includes horizontal adjustment for placement */ 20 yPlacement = 0x0002u, /* Includes vertical adjustment for placement */ 21 xAdvance = 0x0004u, /* Includes horizontal adjustment for advance */ 22 yAdvance = 0x0008u, /* Includes vertical adjustment for advance */ 23 xPlaDevice = 0x0010u, /* Includes horizontal Device table for placement */ 24 yPlaDevice = 0x0020u, /* Includes vertical Device table for placement */ 25 xAdvDevice = 0x0040u, /* Includes horizontal Device table for advance */ 26 yAdvDevice = 0x0080u, /* Includes vertical Device table for advance */ 27 ignored = 0x0F00u, /* Was used in TrueType Open for MM fonts */ 28 reserved = 0xF000u, /* For future use */ 29 30 devices = 0x00F0u /* Mask for having any Device table */ 31 }; 32 33 /* All fields are options. Only those available advance the value pointer. */ 34 #if 0 35 HBINT16 xPlacement; /* Horizontal adjustment for 36 * placement--in design units */ 37 HBINT16 yPlacement; /* Vertical adjustment for 38 * placement--in design units */ 39 HBINT16 xAdvance; /* Horizontal adjustment for 40 * advance--in design units (only used 41 * for horizontal writing) */ 42 HBINT16 yAdvance; /* Vertical adjustment for advance--in 43 * design units (only used for vertical 44 * writing) */ 45 Offset16To<Device> xPlaDevice; /* Offset to Device table for 46 * horizontal placement--measured from 47 * beginning of PosTable (may be NULL) */ 48 Offset16To<Device> yPlaDevice; /* Offset to Device table for vertical 49 * placement--measured from beginning 50 * of PosTable (may be NULL) */ 51 Offset16To<Device> xAdvDevice; /* Offset to Device table for 52 * horizontal advance--measured from 53 * beginning of PosTable (may be NULL) */ 54 Offset16To<Device> yAdvDevice; /* Offset to Device table for vertical 55 * advance--measured from beginning of 56 * PosTable (may be NULL) */ 57 #endif 58 operator =OT::Layout::GPOS_impl::ValueFormat59 IntType& operator = (uint16_t i) { v = i; return *this; } 60 get_lenOT::Layout::GPOS_impl::ValueFormat61 unsigned int get_len () const { return hb_popcount ((unsigned int) *this); } get_sizeOT::Layout::GPOS_impl::ValueFormat62 unsigned int get_size () const { return get_len () * Value::static_size; } 63 get_device_table_indicesOT::Layout::GPOS_impl::ValueFormat64 hb_vector_t<unsigned> get_device_table_indices () const { 65 unsigned i = 0; 66 hb_vector_t<unsigned> result; 67 unsigned format = *this; 68 69 if (format & xPlacement) i++; 70 if (format & yPlacement) i++; 71 if (format & xAdvance) i++; 72 if (format & yAdvance) i++; 73 74 if (format & xPlaDevice) result.push (i++); 75 if (format & yPlaDevice) result.push (i++); 76 if (format & xAdvDevice) result.push (i++); 77 if (format & yAdvDevice) result.push (i++); 78 79 return result; 80 } 81 apply_valueOT::Layout::GPOS_impl::ValueFormat82 bool apply_value (hb_ot_apply_context_t *c, 83 const ValueBase *base, 84 const Value *values, 85 hb_glyph_position_t &glyph_pos) const 86 { 87 bool ret = false; 88 unsigned int format = *this; 89 if (!format) return ret; 90 91 hb_font_t *font = c->font; 92 bool horizontal = 93 #ifndef HB_NO_VERTICAL 94 HB_DIRECTION_IS_HORIZONTAL (c->direction) 95 #else 96 true 97 #endif 98 ; 99 100 if (format & xPlacement) glyph_pos.x_offset += font->em_scale_x (get_short (values++, &ret)); 101 if (format & yPlacement) glyph_pos.y_offset += font->em_scale_y (get_short (values++, &ret)); 102 if (format & xAdvance) { 103 if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values, &ret)); 104 values++; 105 } 106 /* y_advance values grow downward but font-space grows upward, hence negation */ 107 if (format & yAdvance) { 108 if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values, &ret)); 109 values++; 110 } 111 112 if (!has_device ()) return ret; 113 114 bool use_x_device = font->x_ppem || font->num_coords; 115 bool use_y_device = font->y_ppem || font->num_coords; 116 117 if (!use_x_device && !use_y_device) return ret; 118 119 const ItemVariationStore &store = c->var_store; 120 auto *cache = c->var_store_cache; 121 122 /* pixel -> fractional pixel */ 123 if (format & xPlaDevice) 124 { 125 if (use_x_device) glyph_pos.x_offset += get_device (values, &ret, base, c->sanitizer).get_x_delta (font, store, cache); 126 values++; 127 } 128 if (format & yPlaDevice) 129 { 130 if (use_y_device) glyph_pos.y_offset += get_device (values, &ret, base, c->sanitizer).get_y_delta (font, store, cache); 131 values++; 132 } 133 if (format & xAdvDevice) 134 { 135 if (horizontal && use_x_device) glyph_pos.x_advance += get_device (values, &ret, base, c->sanitizer).get_x_delta (font, store, cache); 136 values++; 137 } 138 if (format & yAdvDevice) 139 { 140 /* y_advance values grow downward but font-space grows upward, hence negation */ 141 if (!horizontal && use_y_device) glyph_pos.y_advance -= get_device (values, &ret, base, c->sanitizer).get_y_delta (font, store, cache); 142 values++; 143 } 144 return ret; 145 } 146 get_effective_formatOT::Layout::GPOS_impl::ValueFormat147 unsigned int get_effective_format (const Value *values, bool strip_hints, bool strip_empty, const ValueBase *base, 148 const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map) const 149 { 150 unsigned int format = *this; 151 for (unsigned flag = xPlacement; flag <= yAdvDevice; flag = flag << 1) { 152 if (format & flag) 153 { 154 if (strip_hints && flag >= xPlaDevice) 155 { 156 format = format & ~flag; 157 values++; 158 continue; 159 } 160 if (varidx_delta_map && flag >= xPlaDevice) 161 { 162 update_var_flag (values++, (Flags) flag, &format, base, varidx_delta_map); 163 continue; 164 } 165 /* do not strip empty when instancing, cause we don't know whether the new 166 * default value is 0 or not */ 167 if (strip_empty) should_drop (*values, (Flags) flag, &format); 168 values++; 169 } 170 } 171 172 return format; 173 } 174 175 template<typename Iterator, 176 hb_requires (hb_is_iterator (Iterator))> get_effective_formatOT::Layout::GPOS_impl::ValueFormat177 unsigned int get_effective_format (Iterator it, bool strip_hints, bool strip_empty, const ValueBase *base, 178 const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map) const { 179 unsigned int new_format = 0; 180 181 for (const hb_array_t<const Value>& values : it) 182 new_format = new_format | get_effective_format (&values, strip_hints, strip_empty, base, varidx_delta_map); 183 184 return new_format; 185 } 186 copy_valuesOT::Layout::GPOS_impl::ValueFormat187 void copy_values (hb_serialize_context_t *c, 188 unsigned int new_format, 189 const ValueBase *base, 190 const Value *values, 191 const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const 192 { 193 unsigned int format = *this; 194 if (!format) return; 195 196 HBINT16 *x_placement = nullptr, *y_placement = nullptr, *x_adv = nullptr, *y_adv = nullptr; 197 if (format & xPlacement) x_placement = copy_value (c, new_format, xPlacement, *values++); 198 if (format & yPlacement) y_placement = copy_value (c, new_format, yPlacement, *values++); 199 if (format & xAdvance) x_adv = copy_value (c, new_format, xAdvance, *values++); 200 if (format & yAdvance) y_adv = copy_value (c, new_format, yAdvance, *values++); 201 202 if (!has_device ()) 203 return; 204 205 if (format & xPlaDevice) 206 { 207 add_delta_to_value (x_placement, base, values, layout_variation_idx_delta_map); 208 copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, xPlaDevice); 209 } 210 211 if (format & yPlaDevice) 212 { 213 add_delta_to_value (y_placement, base, values, layout_variation_idx_delta_map); 214 copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, yPlaDevice); 215 } 216 217 if (format & xAdvDevice) 218 { 219 add_delta_to_value (x_adv, base, values, layout_variation_idx_delta_map); 220 copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, xAdvDevice); 221 } 222 223 if (format & yAdvDevice) 224 { 225 add_delta_to_value (y_adv, base, values, layout_variation_idx_delta_map); 226 copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, yAdvDevice); 227 } 228 } 229 copy_valueOT::Layout::GPOS_impl::ValueFormat230 HBINT16* copy_value (hb_serialize_context_t *c, 231 unsigned int new_format, 232 Flags flag, 233 Value value) const 234 { 235 // Filter by new format. 236 if (!(new_format & flag)) return nullptr; 237 return reinterpret_cast<HBINT16 *> (c->copy (value)); 238 } 239 collect_variation_indicesOT::Layout::GPOS_impl::ValueFormat240 void collect_variation_indices (hb_collect_variation_indices_context_t *c, 241 const ValueBase *base, 242 const hb_array_t<const Value>& values) const 243 { 244 unsigned format = *this; 245 unsigned i = 0; 246 if (format & xPlacement) i++; 247 if (format & yPlacement) i++; 248 if (format & xAdvance) i++; 249 if (format & yAdvance) i++; 250 if (format & xPlaDevice) 251 { 252 (base + get_device (&(values[i]))).collect_variation_indices (c); 253 i++; 254 } 255 256 if (format & ValueFormat::yPlaDevice) 257 { 258 (base + get_device (&(values[i]))).collect_variation_indices (c); 259 i++; 260 } 261 262 if (format & ValueFormat::xAdvDevice) 263 { 264 (base + get_device (&(values[i]))).collect_variation_indices (c); 265 i++; 266 } 267 268 if (format & ValueFormat::yAdvDevice) 269 { 270 (base + get_device (&(values[i]))).collect_variation_indices (c); 271 i++; 272 } 273 } 274 275 private: sanitize_value_devicesOT::Layout::GPOS_impl::ValueFormat276 bool sanitize_value_devices (hb_sanitize_context_t *c, const ValueBase *base, const Value *values) const 277 { 278 unsigned int format = *this; 279 280 if (format & xPlacement) values++; 281 if (format & yPlacement) values++; 282 if (format & xAdvance) values++; 283 if (format & yAdvance) values++; 284 285 if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false; 286 if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false; 287 if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false; 288 if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false; 289 290 return true; 291 } 292 get_deviceOT::Layout::GPOS_impl::ValueFormat293 static inline Offset16To<Device, ValueBase>& get_device (Value* value) 294 { 295 return *static_cast<Offset16To<Device, ValueBase> *> (value); 296 } get_deviceOT::Layout::GPOS_impl::ValueFormat297 static inline const Offset16To<Device, ValueBase>& get_device (const Value* value) 298 { 299 return *static_cast<const Offset16To<Device, ValueBase> *> (value); 300 } get_deviceOT::Layout::GPOS_impl::ValueFormat301 static inline const Device& get_device (const Value* value, 302 bool *worked, 303 const ValueBase *base, 304 hb_sanitize_context_t &c) 305 { 306 if (worked) *worked |= bool (*value); 307 auto &offset = *static_cast<const Offset16To<Device> *> (value); 308 309 if (unlikely (!offset.sanitize (&c, base))) 310 return Null(Device); 311 hb_barrier (); 312 313 return base + offset; 314 } 315 add_delta_to_valueOT::Layout::GPOS_impl::ValueFormat316 void add_delta_to_value (HBINT16 *value, 317 const ValueBase *base, 318 const Value *src_value, 319 const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const 320 { 321 if (!value) return; 322 unsigned varidx = (base + get_device (src_value)).get_variation_index (); 323 hb_pair_t<unsigned, int> *varidx_delta; 324 if (!layout_variation_idx_delta_map->has (varidx, &varidx_delta)) return; 325 326 *value += hb_second (*varidx_delta); 327 } 328 copy_deviceOT::Layout::GPOS_impl::ValueFormat329 bool copy_device (hb_serialize_context_t *c, 330 const ValueBase *base, 331 const Value *src_value, 332 const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map, 333 unsigned int new_format, Flags flag) const 334 { 335 // Filter by new format. 336 if (!(new_format & flag)) return true; 337 338 Value *dst_value = c->copy (*src_value); 339 340 if (!dst_value) return false; 341 if (*dst_value == 0) return true; 342 343 *dst_value = 0; 344 c->push (); 345 if ((base + get_device (src_value)).copy (c, layout_variation_idx_delta_map)) 346 { 347 c->add_link (*dst_value, c->pop_pack ()); 348 return true; 349 } 350 else 351 { 352 c->pop_discard (); 353 return false; 354 } 355 } 356 get_shortOT::Layout::GPOS_impl::ValueFormat357 static inline const HBINT16& get_short (const Value* value, bool *worked=nullptr) 358 { 359 if (worked) *worked |= bool (*value); 360 return *reinterpret_cast<const HBINT16 *> (value); 361 } 362 363 public: 364 has_deviceOT::Layout::GPOS_impl::ValueFormat365 bool has_device () const 366 { 367 unsigned int format = *this; 368 return (format & devices) != 0; 369 } 370 sanitize_valueOT::Layout::GPOS_impl::ValueFormat371 bool sanitize_value (hb_sanitize_context_t *c, const ValueBase *base, const Value *values) const 372 { 373 TRACE_SANITIZE (this); 374 375 if (unlikely (!c->check_range (values, get_size ()))) return_trace (false); 376 377 if (c->lazy_some_gpos) 378 return_trace (true); 379 380 return_trace (!has_device () || sanitize_value_devices (c, base, values)); 381 } 382 sanitize_valuesOT::Layout::GPOS_impl::ValueFormat383 bool sanitize_values (hb_sanitize_context_t *c, const ValueBase *base, const Value *values, unsigned int count) const 384 { 385 TRACE_SANITIZE (this); 386 unsigned size = get_size (); 387 388 if (!c->check_range (values, count, size)) return_trace (false); 389 390 if (c->lazy_some_gpos) 391 return_trace (true); 392 393 hb_barrier (); 394 return_trace (sanitize_values_stride_unsafe (c, base, values, count, size)); 395 } 396 397 /* Just sanitize referenced Device tables. Doesn't check the values themselves. */ sanitize_values_stride_unsafeOT::Layout::GPOS_impl::ValueFormat398 bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const ValueBase *base, const Value *values, unsigned int count, unsigned int stride) const 399 { 400 TRACE_SANITIZE (this); 401 402 if (!has_device ()) return_trace (true); 403 404 for (unsigned int i = 0; i < count; i++) { 405 if (!sanitize_value_devices (c, base, values)) 406 return_trace (false); 407 values = &StructAtOffset<const Value> (values, stride); 408 } 409 410 return_trace (true); 411 } 412 413 private: 414 should_dropOT::Layout::GPOS_impl::ValueFormat415 void should_drop (Value value, Flags flag, unsigned int* format) const 416 { 417 if (value) return; 418 *format = *format & ~flag; 419 } 420 update_var_flagOT::Layout::GPOS_impl::ValueFormat421 void update_var_flag (const Value* value, Flags flag, 422 unsigned int* format, const ValueBase *base, 423 const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map) const 424 { 425 if (*value) 426 { 427 unsigned varidx = (base + get_device (value)).get_variation_index (); 428 hb_pair_t<unsigned, int> *varidx_delta; 429 if (varidx_delta_map->has (varidx, &varidx_delta) && 430 varidx_delta->first != HB_OT_LAYOUT_NO_VARIATIONS_INDEX) 431 return; 432 } 433 *format = *format & ~flag; 434 } 435 }; 436 437 } 438 } 439 } 440 441 #endif // #ifndef OT_LAYOUT_GPOS_VALUEFORMAT_HH 442