ValueFormat.hh (15834B)
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 59 NumType& operator = (uint16_t i) { v = i; return *this; } 60 61 // Note: spec says skip 2 bytes per bit in the valueformat. But reports 62 // from Microsoft developers indicate that only the fields that are 63 // currently defined are counted. We don't expect any new fields to 64 // be added to ValueFormat. As such, we use the faster hb_popcount8 65 // that only processes the lowest 8 bits. 66 unsigned int get_len () const { return hb_popcount8 ((uint8_t) *this); } 67 unsigned int get_size () const { return get_len () * Value::static_size; } 68 69 hb_vector_t<unsigned> get_device_table_indices () const { 70 unsigned i = 0; 71 hb_vector_t<unsigned> result; 72 unsigned format = *this; 73 74 if (format & xPlacement) i++; 75 if (format & yPlacement) i++; 76 if (format & xAdvance) i++; 77 if (format & yAdvance) i++; 78 79 if (format & xPlaDevice) result.push (i++); 80 if (format & yPlaDevice) result.push (i++); 81 if (format & xAdvDevice) result.push (i++); 82 if (format & yAdvDevice) result.push (i++); 83 84 return result; 85 } 86 87 bool apply_value (hb_ot_apply_context_t *c, 88 const ValueBase *base, 89 const Value *values, 90 hb_glyph_position_t &glyph_pos) const 91 { 92 bool ret = false; 93 unsigned int format = *this; 94 if (!format) return ret; 95 96 hb_font_t *font = c->font; 97 bool horizontal = 98 #ifndef HB_NO_VERTICAL 99 HB_DIRECTION_IS_HORIZONTAL (c->direction) 100 #else 101 true 102 #endif 103 ; 104 105 if (format & xPlacement) glyph_pos.x_offset += font->em_scale_x (get_short (values++, &ret)); 106 if (format & yPlacement) glyph_pos.y_offset += font->em_scale_y (get_short (values++, &ret)); 107 if (format & xAdvance) { 108 if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values, &ret)); 109 values++; 110 } 111 /* y_advance values grow downward but font-space grows upward, hence negation */ 112 if (format & yAdvance) { 113 if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values, &ret)); 114 values++; 115 } 116 117 if (!has_device ()) return ret; 118 119 bool use_x_device = font->x_ppem || font->has_nonzero_coords; 120 bool use_y_device = font->y_ppem || font->has_nonzero_coords; 121 122 if (!use_x_device && !use_y_device) return ret; 123 124 const ItemVariationStore &store = c->var_store; 125 auto *cache = c->var_store_cache; 126 127 /* pixel -> fractional pixel */ 128 if (format & xPlaDevice) 129 { 130 if (use_x_device) glyph_pos.x_offset += get_device (values, &ret, base, c->sanitizer).get_x_delta (font, store, cache); 131 values++; 132 } 133 if (format & yPlaDevice) 134 { 135 if (use_y_device) glyph_pos.y_offset += get_device (values, &ret, base, c->sanitizer).get_y_delta (font, store, cache); 136 values++; 137 } 138 if (format & xAdvDevice) 139 { 140 if (horizontal && use_x_device) glyph_pos.x_advance += get_device (values, &ret, base, c->sanitizer).get_x_delta (font, store, cache); 141 values++; 142 } 143 if (format & yAdvDevice) 144 { 145 /* y_advance values grow downward but font-space grows upward, hence negation */ 146 if (!horizontal && use_y_device) glyph_pos.y_advance -= get_device (values, &ret, base, c->sanitizer).get_y_delta (font, store, cache); 147 values++; 148 } 149 return ret; 150 } 151 152 unsigned int get_effective_format (const Value *values, bool strip_hints, bool strip_empty, const ValueBase *base, 153 const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map) const 154 { 155 unsigned int format = *this; 156 for (unsigned flag = xPlacement; flag <= yAdvDevice; flag = flag << 1) { 157 if (format & flag) 158 { 159 if (strip_hints && flag >= xPlaDevice) 160 { 161 format = format & ~flag; 162 values++; 163 continue; 164 } 165 if (varidx_delta_map && flag >= xPlaDevice) 166 { 167 update_var_flag (values++, (Flags) flag, &format, base, varidx_delta_map); 168 continue; 169 } 170 /* do not strip empty when instancing, cause we don't know whether the new 171 * default value is 0 or not */ 172 if (strip_empty) should_drop (*values, (Flags) flag, &format); 173 values++; 174 } 175 } 176 177 return format; 178 } 179 180 template<typename Iterator, 181 hb_requires (hb_is_iterator (Iterator))> 182 unsigned int get_effective_format (Iterator it, bool strip_hints, bool strip_empty, const ValueBase *base, 183 const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map) const { 184 unsigned int new_format = 0; 185 186 for (const hb_array_t<const Value>& values : it) 187 new_format = new_format | get_effective_format (&values, strip_hints, strip_empty, base, varidx_delta_map); 188 189 return new_format; 190 } 191 192 void copy_values (hb_serialize_context_t *c, 193 unsigned int new_format, 194 const ValueBase *base, 195 const Value *values, 196 const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const 197 { 198 unsigned int format = *this; 199 if (!format) return; 200 201 HBINT16 *x_placement = nullptr, *y_placement = nullptr, *x_adv = nullptr, *y_adv = nullptr; 202 if (format & xPlacement) x_placement = copy_value (c, new_format, xPlacement, *values++); 203 if (format & yPlacement) y_placement = copy_value (c, new_format, yPlacement, *values++); 204 if (format & xAdvance) x_adv = copy_value (c, new_format, xAdvance, *values++); 205 if (format & yAdvance) y_adv = copy_value (c, new_format, yAdvance, *values++); 206 207 if (!has_device ()) 208 return; 209 210 if (format & xPlaDevice) 211 { 212 add_delta_to_value (x_placement, base, values, layout_variation_idx_delta_map); 213 copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, xPlaDevice); 214 } 215 216 if (format & yPlaDevice) 217 { 218 add_delta_to_value (y_placement, base, values, layout_variation_idx_delta_map); 219 copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, yPlaDevice); 220 } 221 222 if (format & xAdvDevice) 223 { 224 add_delta_to_value (x_adv, base, values, layout_variation_idx_delta_map); 225 copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, xAdvDevice); 226 } 227 228 if (format & yAdvDevice) 229 { 230 add_delta_to_value (y_adv, base, values, layout_variation_idx_delta_map); 231 copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, yAdvDevice); 232 } 233 } 234 235 HBINT16* copy_value (hb_serialize_context_t *c, 236 unsigned int new_format, 237 Flags flag, 238 Value value) const 239 { 240 // Filter by new format. 241 if (!(new_format & flag)) return nullptr; 242 return reinterpret_cast<HBINT16 *> (c->copy (value)); 243 } 244 245 void collect_variation_indices (hb_collect_variation_indices_context_t *c, 246 const ValueBase *base, 247 const hb_array_t<const Value>& values) const 248 { 249 unsigned format = *this; 250 unsigned i = 0; 251 if (format & xPlacement) i++; 252 if (format & yPlacement) i++; 253 if (format & xAdvance) i++; 254 if (format & yAdvance) i++; 255 if (format & xPlaDevice) 256 { 257 (base + get_device (&(values[i]))).collect_variation_indices (c); 258 i++; 259 } 260 261 if (format & ValueFormat::yPlaDevice) 262 { 263 (base + get_device (&(values[i]))).collect_variation_indices (c); 264 i++; 265 } 266 267 if (format & ValueFormat::xAdvDevice) 268 { 269 (base + get_device (&(values[i]))).collect_variation_indices (c); 270 i++; 271 } 272 273 if (format & ValueFormat::yAdvDevice) 274 { 275 (base + get_device (&(values[i]))).collect_variation_indices (c); 276 i++; 277 } 278 } 279 280 private: 281 bool sanitize_value_devices (hb_sanitize_context_t *c, const ValueBase *base, const Value *values) const 282 { 283 unsigned int format = *this; 284 285 if (format & xPlacement) values++; 286 if (format & yPlacement) values++; 287 if (format & xAdvance) values++; 288 if (format & yAdvance) values++; 289 290 if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false; 291 if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false; 292 if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false; 293 if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false; 294 295 return true; 296 } 297 298 static inline Offset16To<Device, ValueBase>& get_device (Value* value) 299 { 300 return *static_cast<Offset16To<Device, ValueBase> *> (value); 301 } 302 static inline const Offset16To<Device, ValueBase>& get_device (const Value* value) 303 { 304 return *static_cast<const Offset16To<Device, ValueBase> *> (value); 305 } 306 static inline const Device& get_device (const Value* value, 307 bool *worked, 308 const ValueBase *base, 309 hb_sanitize_context_t &c) 310 { 311 if (worked) *worked |= bool (*value); 312 auto &offset = *static_cast<const Offset16To<Device> *> (value); 313 314 if (unlikely (!offset.sanitize (&c, base))) 315 return Null(Device); 316 hb_barrier (); 317 318 return base + offset; 319 } 320 321 void add_delta_to_value (HBINT16 *value, 322 const ValueBase *base, 323 const Value *src_value, 324 const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const 325 { 326 if (!value) return; 327 unsigned varidx = (base + get_device (src_value)).get_variation_index (); 328 hb_pair_t<unsigned, int> *varidx_delta; 329 if (!layout_variation_idx_delta_map->has (varidx, &varidx_delta)) return; 330 331 *value += hb_second (*varidx_delta); 332 } 333 334 bool copy_device (hb_serialize_context_t *c, 335 const ValueBase *base, 336 const Value *src_value, 337 const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map, 338 unsigned int new_format, Flags flag) const 339 { 340 // Filter by new format. 341 if (!(new_format & flag)) return true; 342 343 Value *dst_value = c->copy (*src_value); 344 345 if (!dst_value) return false; 346 if (*dst_value == 0) return true; 347 348 *dst_value = 0; 349 c->push (); 350 if ((base + get_device (src_value)).copy (c, layout_variation_idx_delta_map)) 351 { 352 c->add_link (*dst_value, c->pop_pack ()); 353 return true; 354 } 355 else 356 { 357 c->pop_discard (); 358 return false; 359 } 360 } 361 362 static inline const HBINT16& get_short (const Value* value, bool *worked=nullptr) 363 { 364 if (worked) *worked |= bool (*value); 365 return *reinterpret_cast<const HBINT16 *> (value); 366 } 367 368 public: 369 370 bool has_device () const 371 { 372 unsigned int format = *this; 373 return (format & devices) != 0; 374 } 375 376 bool sanitize_value (hb_sanitize_context_t *c, const ValueBase *base, const Value *values) const 377 { 378 TRACE_SANITIZE (this); 379 380 if (unlikely (!c->check_range (values, get_size ()))) return_trace (false); 381 382 if (c->lazy_some_gpos) 383 return_trace (true); 384 385 return_trace (!has_device () || sanitize_value_devices (c, base, values)); 386 } 387 388 bool sanitize_values (hb_sanitize_context_t *c, const ValueBase *base, const Value *values, unsigned int count) const 389 { 390 TRACE_SANITIZE (this); 391 unsigned size = get_size (); 392 393 if (!c->check_range (values, count, size)) return_trace (false); 394 395 if (c->lazy_some_gpos) 396 return_trace (true); 397 398 hb_barrier (); 399 return_trace (sanitize_values_stride_unsafe (c, base, values, count, size)); 400 } 401 402 /* Just sanitize referenced Device tables. Doesn't check the values themselves. */ 403 bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const ValueBase *base, const Value *values, unsigned int count, unsigned int stride) const 404 { 405 TRACE_SANITIZE (this); 406 407 if (!has_device ()) return_trace (true); 408 409 for (unsigned int i = 0; i < count; i++) { 410 if (!sanitize_value_devices (c, base, values)) 411 return_trace (false); 412 values = &StructAtOffset<const Value> (values, stride); 413 } 414 415 return_trace (true); 416 } 417 418 private: 419 420 void should_drop (Value value, Flags flag, unsigned int* format) const 421 { 422 if (value) return; 423 *format = *format & ~flag; 424 } 425 426 void update_var_flag (const Value* value, Flags flag, 427 unsigned int* format, const ValueBase *base, 428 const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map) const 429 { 430 if (*value) 431 { 432 unsigned varidx = (base + get_device (value)).get_variation_index (); 433 hb_pair_t<unsigned, int> *varidx_delta; 434 if (varidx_delta_map->has (varidx, &varidx_delta) && 435 varidx_delta->first != HB_OT_LAYOUT_NO_VARIATIONS_INDEX) 436 return; 437 } 438 *format = *format & ~flag; 439 } 440 }; 441 442 } 443 } 444 } 445 446 #endif // #ifndef OT_LAYOUT_GPOS_VALUEFORMAT_HH