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 { 123 if (use_x_device) glyph_pos.x_offset += get_device (values, &ret, base, c->sanitizer).get_x_delta (font, store, cache); 124 values++; 125 } 126 if (format & yPlaDevice) 127 { 128 if (use_y_device) glyph_pos.y_offset += get_device (values, &ret, base, c->sanitizer).get_y_delta (font, store, cache); 129 values++; 130 } 131 if (format & xAdvDevice) 132 { 133 if (horizontal && use_x_device) glyph_pos.x_advance += get_device (values, &ret, base, c->sanitizer).get_x_delta (font, store, cache); 134 values++; 135 } 136 if (format & yAdvDevice) 137 { 138 /* y_advance values grow downward but font-space grows upward, hence negation */ 139 if (!horizontal && use_y_device) glyph_pos.y_advance -= get_device (values, &ret, base, c->sanitizer).get_y_delta (font, store, cache); 140 values++; 141 } 142 return ret; 143 } 144 get_effective_formatOT::Layout::GPOS_impl::ValueFormat145 unsigned int get_effective_format (const Value *values) const 146 { 147 unsigned int format = *this; 148 for (unsigned flag = xPlacement; flag <= yAdvDevice; flag = flag << 1) { 149 if (format & flag) should_drop (*values++, (Flags) flag, &format); 150 } 151 152 return format; 153 } 154 155 template<typename Iterator, 156 hb_requires (hb_is_iterator (Iterator))> get_effective_formatOT::Layout::GPOS_impl::ValueFormat157 unsigned int get_effective_format (Iterator it) const { 158 unsigned int new_format = 0; 159 160 for (const hb_array_t<const Value>& values : it) 161 new_format = new_format | get_effective_format (&values); 162 163 return new_format; 164 } 165 copy_valuesOT::Layout::GPOS_impl::ValueFormat166 void copy_values (hb_serialize_context_t *c, 167 unsigned int new_format, 168 const void *base, 169 const Value *values, 170 const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const 171 { 172 unsigned int format = *this; 173 if (!format) return; 174 175 HBINT16 *x_placement = nullptr, *y_placement = nullptr, *x_adv = nullptr, *y_adv = nullptr; 176 if (format & xPlacement) x_placement = copy_value (c, new_format, xPlacement, *values++); 177 if (format & yPlacement) y_placement = copy_value (c, new_format, yPlacement, *values++); 178 if (format & xAdvance) x_adv = copy_value (c, new_format, xAdvance, *values++); 179 if (format & yAdvance) y_adv = copy_value (c, new_format, yAdvance, *values++); 180 181 if (!has_device ()) 182 return; 183 184 if (format & xPlaDevice) 185 { 186 add_delta_to_value (x_placement, base, values, layout_variation_idx_delta_map); 187 copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, xPlaDevice); 188 } 189 190 if (format & yPlaDevice) 191 { 192 add_delta_to_value (y_placement, base, values, layout_variation_idx_delta_map); 193 copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, yPlaDevice); 194 } 195 196 if (format & xAdvDevice) 197 { 198 add_delta_to_value (x_adv, base, values, layout_variation_idx_delta_map); 199 copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, xAdvDevice); 200 } 201 202 if (format & yAdvDevice) 203 { 204 add_delta_to_value (y_adv, base, values, layout_variation_idx_delta_map); 205 copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, yAdvDevice); 206 } 207 } 208 copy_valueOT::Layout::GPOS_impl::ValueFormat209 HBINT16* copy_value (hb_serialize_context_t *c, 210 unsigned int new_format, 211 Flags flag, 212 Value value) const 213 { 214 // Filter by new format. 215 if (!(new_format & flag)) return nullptr; 216 return reinterpret_cast<HBINT16 *> (c->copy (value)); 217 } 218 collect_variation_indicesOT::Layout::GPOS_impl::ValueFormat219 void collect_variation_indices (hb_collect_variation_indices_context_t *c, 220 const void *base, 221 const hb_array_t<const Value>& values) const 222 { 223 unsigned format = *this; 224 unsigned i = 0; 225 if (format & xPlacement) i++; 226 if (format & yPlacement) i++; 227 if (format & xAdvance) i++; 228 if (format & yAdvance) i++; 229 if (format & xPlaDevice) 230 { 231 (base + get_device (&(values[i]))).collect_variation_indices (c); 232 i++; 233 } 234 235 if (format & ValueFormat::yPlaDevice) 236 { 237 (base + get_device (&(values[i]))).collect_variation_indices (c); 238 i++; 239 } 240 241 if (format & ValueFormat::xAdvDevice) 242 { 243 (base + get_device (&(values[i]))).collect_variation_indices (c); 244 i++; 245 } 246 247 if (format & ValueFormat::yAdvDevice) 248 { 249 (base + get_device (&(values[i]))).collect_variation_indices (c); 250 i++; 251 } 252 } 253 drop_device_table_flagsOT::Layout::GPOS_impl::ValueFormat254 unsigned drop_device_table_flags () const 255 { 256 unsigned format = *this; 257 for (unsigned flag = xPlaDevice; flag <= yAdvDevice; flag = flag << 1) 258 format = format & ~flag; 259 260 return format; 261 } 262 263 private: sanitize_value_devicesOT::Layout::GPOS_impl::ValueFormat264 bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const 265 { 266 unsigned int format = *this; 267 268 if (format & xPlacement) values++; 269 if (format & yPlacement) values++; 270 if (format & xAdvance) values++; 271 if (format & yAdvance) values++; 272 273 if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false; 274 if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false; 275 if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false; 276 if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false; 277 278 return true; 279 } 280 get_deviceOT::Layout::GPOS_impl::ValueFormat281 static inline Offset16To<Device>& get_device (Value* value) 282 { 283 return *static_cast<Offset16To<Device> *> (value); 284 } get_deviceOT::Layout::GPOS_impl::ValueFormat285 static inline const Offset16To<Device>& get_device (const Value* value) 286 { 287 return *static_cast<const Offset16To<Device> *> (value); 288 } get_deviceOT::Layout::GPOS_impl::ValueFormat289 static inline const Device& get_device (const Value* value, 290 bool *worked, 291 const void *base, 292 hb_sanitize_context_t &c) 293 { 294 if (worked) *worked |= bool (*value); 295 auto &offset = *static_cast<const Offset16To<Device> *> (value); 296 297 if (unlikely (!offset.sanitize (&c, base))) 298 return Null(Device); 299 300 return base + offset; 301 } 302 add_delta_to_valueOT::Layout::GPOS_impl::ValueFormat303 void add_delta_to_value (HBINT16 *value, 304 const void *base, 305 const Value *src_value, 306 const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const 307 { 308 if (!value) return; 309 unsigned varidx = (base + get_device (src_value)).get_variation_index (); 310 hb_pair_t<unsigned, int> *varidx_delta; 311 if (!layout_variation_idx_delta_map->has (varidx, &varidx_delta)) return; 312 313 *value += hb_second (*varidx_delta); 314 } 315 copy_deviceOT::Layout::GPOS_impl::ValueFormat316 bool copy_device (hb_serialize_context_t *c, const void *base, 317 const Value *src_value, 318 const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map, 319 unsigned int new_format, Flags flag) const 320 { 321 // Filter by new format. 322 if (!(new_format & flag)) return true; 323 324 Value *dst_value = c->copy (*src_value); 325 326 if (!dst_value) return false; 327 if (*dst_value == 0) return true; 328 329 *dst_value = 0; 330 c->push (); 331 if ((base + get_device (src_value)).copy (c, layout_variation_idx_delta_map)) 332 { 333 c->add_link (*dst_value, c->pop_pack ()); 334 return true; 335 } 336 else 337 { 338 c->pop_discard (); 339 return false; 340 } 341 } 342 get_shortOT::Layout::GPOS_impl::ValueFormat343 static inline const HBINT16& get_short (const Value* value, bool *worked=nullptr) 344 { 345 if (worked) *worked |= bool (*value); 346 return *reinterpret_cast<const HBINT16 *> (value); 347 } 348 349 public: 350 has_deviceOT::Layout::GPOS_impl::ValueFormat351 bool has_device () const 352 { 353 unsigned int format = *this; 354 return (format & devices) != 0; 355 } 356 sanitize_valueOT::Layout::GPOS_impl::ValueFormat357 bool sanitize_value (hb_sanitize_context_t *c, const void *base, const Value *values) const 358 { 359 TRACE_SANITIZE (this); 360 361 if (unlikely (!c->check_range (values, get_size ()))) return_trace (false); 362 363 if (c->lazy_some_gpos) 364 return_trace (true); 365 366 return_trace (!has_device () || sanitize_value_devices (c, base, values)); 367 } 368 sanitize_valuesOT::Layout::GPOS_impl::ValueFormat369 bool sanitize_values (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count) const 370 { 371 TRACE_SANITIZE (this); 372 unsigned size = get_size (); 373 374 if (!c->check_range (values, count, size)) return_trace (false); 375 376 if (c->lazy_some_gpos) 377 return_trace (true); 378 379 return_trace (sanitize_values_stride_unsafe (c, base, values, count, size)); 380 } 381 382 /* Just sanitize referenced Device tables. Doesn't check the values themselves. */ sanitize_values_stride_unsafeOT::Layout::GPOS_impl::ValueFormat383 bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count, unsigned int stride) const 384 { 385 TRACE_SANITIZE (this); 386 387 if (!has_device ()) return_trace (true); 388 389 for (unsigned int i = 0; i < count; i++) { 390 if (!sanitize_value_devices (c, base, values)) 391 return_trace (false); 392 values = &StructAtOffset<const Value> (values, stride); 393 } 394 395 return_trace (true); 396 } 397 398 private: 399 should_dropOT::Layout::GPOS_impl::ValueFormat400 void should_drop (Value value, Flags flag, unsigned int* format) const 401 { 402 if (value) return; 403 *format = *format & ~flag; 404 } 405 406 }; 407 408 } 409 } 410 } 411 412 #endif // #ifndef OT_LAYOUT_GPOS_VALUEFORMAT_HH 413