VARC.cc (13217B)
1 #include "VARC.hh" 2 3 #ifndef HB_NO_VAR_COMPOSITES 4 5 #include "../../../hb-draw.hh" 6 #include "../../../hb-ot-layout-common.hh" 7 #include "../../../hb-ot-layout-gdef-table.hh" 8 9 namespace OT { 10 11 //namespace Var { 12 13 14 #ifndef HB_NO_DRAW 15 16 struct hb_transforming_pen_context_t 17 { 18 hb_transform_t<> transform; 19 hb_draw_funcs_t *dfuncs; 20 void *data; 21 hb_draw_state_t *st; 22 }; 23 24 static void 25 hb_transforming_pen_move_to (hb_draw_funcs_t *dfuncs HB_UNUSED, 26 void *data, 27 hb_draw_state_t *st, 28 float to_x, float to_y, 29 void *user_data HB_UNUSED) 30 { 31 hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data; 32 33 c->transform.transform_point (to_x, to_y); 34 35 c->dfuncs->move_to (c->data, *c->st, to_x, to_y); 36 } 37 38 static void 39 hb_transforming_pen_line_to (hb_draw_funcs_t *dfuncs HB_UNUSED, 40 void *data, 41 hb_draw_state_t *st, 42 float to_x, float to_y, 43 void *user_data HB_UNUSED) 44 { 45 hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data; 46 47 c->transform.transform_point (to_x, to_y); 48 49 c->dfuncs->line_to (c->data, *c->st, to_x, to_y); 50 } 51 52 static void 53 hb_transforming_pen_quadratic_to (hb_draw_funcs_t *dfuncs HB_UNUSED, 54 void *data, 55 hb_draw_state_t *st, 56 float control_x, float control_y, 57 float to_x, float to_y, 58 void *user_data HB_UNUSED) 59 { 60 hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data; 61 62 c->transform.transform_point (control_x, control_y); 63 c->transform.transform_point (to_x, to_y); 64 65 c->dfuncs->quadratic_to (c->data, *c->st, control_x, control_y, to_x, to_y); 66 } 67 68 static void 69 hb_transforming_pen_cubic_to (hb_draw_funcs_t *dfuncs HB_UNUSED, 70 void *data, 71 hb_draw_state_t *st, 72 float control1_x, float control1_y, 73 float control2_x, float control2_y, 74 float to_x, float to_y, 75 void *user_data HB_UNUSED) 76 { 77 hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data; 78 79 c->transform.transform_point (control1_x, control1_y); 80 c->transform.transform_point (control2_x, control2_y); 81 c->transform.transform_point (to_x, to_y); 82 83 c->dfuncs->cubic_to (c->data, *c->st, control1_x, control1_y, control2_x, control2_y, to_x, to_y); 84 } 85 86 static void 87 hb_transforming_pen_close_path (hb_draw_funcs_t *dfuncs HB_UNUSED, 88 void *data, 89 hb_draw_state_t *st, 90 void *user_data HB_UNUSED) 91 { 92 hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data; 93 94 c->dfuncs->close_path (c->data, *c->st); 95 } 96 97 static inline void free_static_transforming_pen_funcs (); 98 99 static struct hb_transforming_pen_funcs_lazy_loader_t : hb_draw_funcs_lazy_loader_t<hb_transforming_pen_funcs_lazy_loader_t> 100 { 101 static hb_draw_funcs_t *create () 102 { 103 hb_draw_funcs_t *funcs = hb_draw_funcs_create (); 104 105 hb_draw_funcs_set_move_to_func (funcs, hb_transforming_pen_move_to, nullptr, nullptr); 106 hb_draw_funcs_set_line_to_func (funcs, hb_transforming_pen_line_to, nullptr, nullptr); 107 hb_draw_funcs_set_quadratic_to_func (funcs, hb_transforming_pen_quadratic_to, nullptr, nullptr); 108 hb_draw_funcs_set_cubic_to_func (funcs, hb_transforming_pen_cubic_to, nullptr, nullptr); 109 hb_draw_funcs_set_close_path_func (funcs, hb_transforming_pen_close_path, nullptr, nullptr); 110 111 hb_draw_funcs_make_immutable (funcs); 112 113 hb_atexit (free_static_transforming_pen_funcs); 114 115 return funcs; 116 } 117 } static_transforming_pen_funcs; 118 119 static inline 120 void free_static_transforming_pen_funcs () 121 { 122 static_transforming_pen_funcs.free_instance (); 123 } 124 125 static hb_draw_funcs_t * 126 hb_transforming_pen_get_funcs () 127 { 128 return static_transforming_pen_funcs.get_unconst (); 129 } 130 131 hb_ubytes_t 132 VarComponent::get_path_at (const hb_varc_context_t &c, 133 hb_codepoint_t parent_gid, 134 hb_array_t<const int> coords, 135 hb_transform_t<> total_transform, 136 hb_ubytes_t total_record, 137 hb_scalar_cache_t *cache) const 138 { 139 const unsigned char *end = total_record.arrayZ + total_record.length; 140 const unsigned char *record = total_record.arrayZ; 141 142 auto &VARC = *c.font->face->table.VARC->table; 143 auto &varStore = &VARC+VARC.varStore; 144 145 #define READ_UINT32VAR(name) \ 146 HB_STMT_START { \ 147 if (unlikely (unsigned (end - record) < HBUINT32VAR::min_size)) return hb_ubytes_t (); \ 148 hb_barrier (); \ 149 auto &varint = * (const HBUINT32VAR *) record; \ 150 unsigned size = varint.get_size (); \ 151 if (unlikely (unsigned (end - record) < size)) return hb_ubytes_t (); \ 152 name = (uint32_t) varint; \ 153 record += size; \ 154 } HB_STMT_END 155 156 uint32_t flags; 157 READ_UINT32VAR (flags); 158 159 // gid 160 161 hb_codepoint_t gid = 0; 162 if (flags & (unsigned) flags_t::GID_IS_24BIT) 163 { 164 if (unlikely (unsigned (end - record) < HBGlyphID24::static_size)) 165 return hb_ubytes_t (); 166 hb_barrier (); 167 gid = * (const HBGlyphID24 *) record; 168 record += HBGlyphID24::static_size; 169 } 170 else 171 { 172 if (unlikely (unsigned (end - record) < HBGlyphID16::static_size)) 173 return hb_ubytes_t (); 174 hb_barrier (); 175 gid = * (const HBGlyphID16 *) record; 176 record += HBGlyphID16::static_size; 177 } 178 179 // Condition 180 bool show = true; 181 if (flags & (unsigned) flags_t::HAVE_CONDITION) 182 { 183 unsigned conditionIndex; 184 READ_UINT32VAR (conditionIndex); 185 const auto &condition = (&VARC+VARC.conditionList)[conditionIndex]; 186 auto instancer = MultiItemVarStoreInstancer(&varStore, nullptr, coords, cache); 187 show = condition.evaluate (coords.arrayZ, coords.length, &instancer); 188 } 189 190 // Axis values 191 192 auto &axisIndices = c.scratch.axisIndices; 193 axisIndices.clear (); 194 auto &axisValues = c.scratch.axisValues; 195 axisValues.clear (); 196 if (flags & (unsigned) flags_t::HAVE_AXES) 197 { 198 unsigned axisIndicesIndex; 199 READ_UINT32VAR (axisIndicesIndex); 200 axisIndices.extend ((&VARC+VARC.axisIndicesList)[axisIndicesIndex]); 201 axisValues.resize (axisIndices.length); 202 const HBUINT8 *p = (const HBUINT8 *) record; 203 TupleValues::decompile (p, axisValues, (const HBUINT8 *) end); 204 record = (const unsigned char *) p; 205 } 206 207 // Apply variations if any 208 if (flags & (unsigned) flags_t::AXIS_VALUES_HAVE_VARIATION) 209 { 210 uint32_t axisValuesVarIdx; 211 READ_UINT32VAR (axisValuesVarIdx); 212 if (show && coords && !axisValues.in_error ()) 213 varStore.get_delta (axisValuesVarIdx, coords, axisValues.as_array (), cache); 214 } 215 216 auto component_coords = coords; 217 /* Copying coords is expensive; so we have put an arbitrary 218 * limit on the max number of coords for now. */ 219 if ((flags & (unsigned) flags_t::RESET_UNSPECIFIED_AXES) || 220 coords.length > HB_VAR_COMPOSITE_MAX_AXES) 221 component_coords = hb_array (c.font->coords, c.font->num_coords); 222 223 // Transform 224 225 uint32_t transformVarIdx = VarIdx::NO_VARIATION; 226 if (flags & (unsigned) flags_t::TRANSFORM_HAS_VARIATION) 227 READ_UINT32VAR (transformVarIdx); 228 229 #define PROCESS_TRANSFORM_COMPONENTS \ 230 HB_STMT_START { \ 231 PROCESS_TRANSFORM_COMPONENT (FWORD, 1.0f, HAVE_TRANSLATE_X, translateX); \ 232 PROCESS_TRANSFORM_COMPONENT (FWORD, 1.0f, HAVE_TRANSLATE_Y, translateY); \ 233 PROCESS_TRANSFORM_COMPONENT (F4DOT12, HB_PI, HAVE_ROTATION, rotation); \ 234 PROCESS_TRANSFORM_COMPONENT (F6DOT10, 1.0f, HAVE_SCALE_X, scaleX); \ 235 PROCESS_TRANSFORM_COMPONENT (F6DOT10, 1.0f, HAVE_SCALE_Y, scaleY); \ 236 PROCESS_TRANSFORM_COMPONENT (F4DOT12, HB_PI, HAVE_SKEW_X, skewX); \ 237 PROCESS_TRANSFORM_COMPONENT (F4DOT12, HB_PI, HAVE_SKEW_Y, skewY); \ 238 PROCESS_TRANSFORM_COMPONENT (FWORD, 1.0f, HAVE_TCENTER_X, tCenterX); \ 239 PROCESS_TRANSFORM_COMPONENT (FWORD, 1.0f, HAVE_TCENTER_Y, tCenterY); \ 240 } HB_STMT_END 241 242 hb_transform_decomposed_t<> transform; 243 244 // Read transform components 245 #define PROCESS_TRANSFORM_COMPONENT(type, mult, flag, name) \ 246 if (flags & (unsigned) flags_t::flag) \ 247 { \ 248 static_assert (type::static_size == HBINT16::static_size, ""); \ 249 if (unlikely (unsigned (end - record) < HBINT16::static_size)) \ 250 return hb_ubytes_t (); \ 251 hb_barrier (); \ 252 transform.name = mult * * (const HBINT16 *) record; \ 253 record += HBINT16::static_size; \ 254 } 255 PROCESS_TRANSFORM_COMPONENTS; 256 #undef PROCESS_TRANSFORM_COMPONENT 257 258 // Read reserved records 259 unsigned i = flags & (unsigned) flags_t::RESERVED_MASK; 260 while (i) 261 { 262 HB_UNUSED uint32_t discard; 263 READ_UINT32VAR (discard); 264 i &= i - 1; 265 } 266 267 /* Parsing is over now. */ 268 269 if (show) 270 { 271 // Only use coord_setter if there's actually any axis overrides. 272 coord_setter_t coord_setter (axisIndices ? component_coords : hb_array<int> ()); 273 // Go backwards, to reduce coord_setter vector reallocations. 274 for (unsigned i = axisIndices.length; i; i--) 275 coord_setter[axisIndices[i - 1]] = axisValues[i - 1]; 276 if (axisIndices) 277 component_coords = coord_setter.get_coords (); 278 279 // Apply transform variations if any 280 if (transformVarIdx != VarIdx::NO_VARIATION && coords) 281 { 282 float transformValues[9]; 283 unsigned numTransformValues = 0; 284 #define PROCESS_TRANSFORM_COMPONENT(type, mult, flag, name) \ 285 if (flags & (unsigned) flags_t::flag) \ 286 transformValues[numTransformValues++] = transform.name / mult; 287 PROCESS_TRANSFORM_COMPONENTS; 288 #undef PROCESS_TRANSFORM_COMPONENT 289 varStore.get_delta (transformVarIdx, coords, hb_array (transformValues, numTransformValues), cache); 290 numTransformValues = 0; 291 #define PROCESS_TRANSFORM_COMPONENT(type, mult, flag, name) \ 292 if (flags & (unsigned) flags_t::flag) \ 293 transform.name = transformValues[numTransformValues++] * mult; 294 PROCESS_TRANSFORM_COMPONENTS; 295 #undef PROCESS_TRANSFORM_COMPONENT 296 } 297 298 // Divide them by their divisors 299 #define PROCESS_TRANSFORM_COMPONENT(type, mult, flag, name) \ 300 if (flags & (unsigned) flags_t::flag) \ 301 { \ 302 HBINT16 int_v; \ 303 int_v = roundf (transform.name); \ 304 type typed_v = * (const type *) &int_v; \ 305 float float_v = (float) typed_v; \ 306 transform.name = float_v; \ 307 } 308 PROCESS_TRANSFORM_COMPONENTS; 309 #undef PROCESS_TRANSFORM_COMPONENT 310 311 if (!(flags & (unsigned) flags_t::HAVE_SCALE_Y)) 312 transform.scaleY = transform.scaleX; 313 314 total_transform.transform (transform.to_transform ()); 315 total_transform.scale (c.font->x_mult ? 1.f / c.font->x_multf : 0.f, 316 c.font->y_mult ? 1.f / c.font->y_multf : 0.f); 317 318 bool same_coords = component_coords.length == coords.length && 319 component_coords.arrayZ == coords.arrayZ; 320 321 c.depth_left--; 322 VARC.get_path_at (c, gid, 323 component_coords, total_transform, 324 parent_gid, 325 same_coords ? cache : nullptr); 326 c.depth_left++; 327 } 328 329 #undef PROCESS_TRANSFORM_COMPONENTS 330 #undef READ_UINT32VAR 331 332 return hb_ubytes_t (record, end - record); 333 } 334 335 bool 336 VARC::get_path_at (const hb_varc_context_t &c, 337 hb_codepoint_t glyph, 338 hb_array_t<const int> coords, 339 hb_transform_t<> transform, 340 hb_codepoint_t parent_glyph, 341 hb_scalar_cache_t *parent_cache) const 342 { 343 // Don't recurse on the same glyph. 344 unsigned idx = glyph == parent_glyph ? 345 NOT_COVERED : 346 (this+coverage).get_coverage (glyph); 347 if (idx == NOT_COVERED) 348 { 349 if (c.draw_session) 350 { 351 // Build a transforming pen to apply the transform. 352 hb_draw_funcs_t *transformer_funcs = hb_transforming_pen_get_funcs (); 353 hb_transforming_pen_context_t context {transform, 354 c.draw_session->funcs, 355 c.draw_session->draw_data, 356 &c.draw_session->st}; 357 hb_draw_session_t transformer_session {transformer_funcs, &context}; 358 hb_draw_session_t &shape_draw_session = transform.is_identity () ? *c.draw_session : transformer_session; 359 360 if (c.font->face->table.glyf->get_path_at (c.font, glyph, shape_draw_session, coords, c.scratch.glyf_scratch)) return true; 361 #ifndef HB_NO_CFF 362 if (c.font->face->table.cff2->get_path_at (c.font, glyph, shape_draw_session, coords)) return true; 363 if (c.font->face->table.cff1->get_path (c.font, glyph, shape_draw_session)) return true; // Doesn't have variations 364 #endif 365 return false; 366 } 367 else if (c.extents) 368 { 369 hb_glyph_extents_t glyph_extents; 370 if (!c.font->face->table.glyf->get_extents_at (c.font, glyph, &glyph_extents, coords)) 371 #ifndef HB_NO_CFF 372 if (!c.font->face->table.cff2->get_extents_at (c.font, glyph, &glyph_extents, coords)) 373 if (!c.font->face->table.cff1->get_extents (c.font, glyph, &glyph_extents)) // Doesn't have variations 374 #endif 375 return false; 376 377 hb_extents_t<> comp_extents (glyph_extents); 378 transform.transform_extents (comp_extents); 379 c.extents->union_ (comp_extents); 380 } 381 return true; 382 } 383 384 if (c.depth_left <= 0) 385 return true; 386 387 if (c.edges_left <= 0) 388 return true; 389 (c.edges_left)--; 390 391 hb_decycler_node_t node (c.decycler); 392 if (unlikely (!node.visit (glyph))) 393 return true; 394 395 hb_ubytes_t record = (this+glyphRecords)[idx]; 396 397 hb_scalar_cache_t static_cache; 398 hb_scalar_cache_t *cache = parent_cache ? 399 parent_cache : 400 (this+varStore).create_cache (&static_cache); 401 402 transform.scale (c.font->x_multf, c.font->y_multf); 403 404 VarCompositeGlyph::get_path_at (c, 405 glyph, 406 coords, transform, 407 record, 408 cache); 409 410 if (cache != parent_cache) 411 (this+varStore).destroy_cache (cache, &static_cache); 412 413 return true; 414 } 415 416 #endif 417 418 //} // namespace Var 419 } // namespace OT 420 421 #endif