Path: blob/master/thirdparty/harfbuzz/src/OT/Var/VARC/VARC.cc
9918 views
#include "VARC.hh"12#ifndef HB_NO_VAR_COMPOSITES34#include "../../../hb-draw.hh"5#include "../../../hb-ot-layout-common.hh"6#include "../../../hb-ot-layout-gdef-table.hh"78namespace OT {910//namespace Var {111213struct hb_transforming_pen_context_t14{15hb_transform_t<> transform;16hb_draw_funcs_t *dfuncs;17void *data;18hb_draw_state_t *st;19};2021static void22hb_transforming_pen_move_to (hb_draw_funcs_t *dfuncs HB_UNUSED,23void *data,24hb_draw_state_t *st,25float to_x, float to_y,26void *user_data HB_UNUSED)27{28hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data;2930c->transform.transform_point (to_x, to_y);3132c->dfuncs->move_to (c->data, *c->st, to_x, to_y);33}3435static void36hb_transforming_pen_line_to (hb_draw_funcs_t *dfuncs HB_UNUSED,37void *data,38hb_draw_state_t *st,39float to_x, float to_y,40void *user_data HB_UNUSED)41{42hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data;4344c->transform.transform_point (to_x, to_y);4546c->dfuncs->line_to (c->data, *c->st, to_x, to_y);47}4849static void50hb_transforming_pen_quadratic_to (hb_draw_funcs_t *dfuncs HB_UNUSED,51void *data,52hb_draw_state_t *st,53float control_x, float control_y,54float to_x, float to_y,55void *user_data HB_UNUSED)56{57hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data;5859c->transform.transform_point (control_x, control_y);60c->transform.transform_point (to_x, to_y);6162c->dfuncs->quadratic_to (c->data, *c->st, control_x, control_y, to_x, to_y);63}6465static void66hb_transforming_pen_cubic_to (hb_draw_funcs_t *dfuncs HB_UNUSED,67void *data,68hb_draw_state_t *st,69float control1_x, float control1_y,70float control2_x, float control2_y,71float to_x, float to_y,72void *user_data HB_UNUSED)73{74hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data;7576c->transform.transform_point (control1_x, control1_y);77c->transform.transform_point (control2_x, control2_y);78c->transform.transform_point (to_x, to_y);7980c->dfuncs->cubic_to (c->data, *c->st, control1_x, control1_y, control2_x, control2_y, to_x, to_y);81}8283static void84hb_transforming_pen_close_path (hb_draw_funcs_t *dfuncs HB_UNUSED,85void *data,86hb_draw_state_t *st,87void *user_data HB_UNUSED)88{89hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data;9091c->dfuncs->close_path (c->data, *c->st);92}9394static inline void free_static_transforming_pen_funcs ();9596static struct hb_transforming_pen_funcs_lazy_loader_t : hb_draw_funcs_lazy_loader_t<hb_transforming_pen_funcs_lazy_loader_t>97{98static hb_draw_funcs_t *create ()99{100hb_draw_funcs_t *funcs = hb_draw_funcs_create ();101102hb_draw_funcs_set_move_to_func (funcs, hb_transforming_pen_move_to, nullptr, nullptr);103hb_draw_funcs_set_line_to_func (funcs, hb_transforming_pen_line_to, nullptr, nullptr);104hb_draw_funcs_set_quadratic_to_func (funcs, hb_transforming_pen_quadratic_to, nullptr, nullptr);105hb_draw_funcs_set_cubic_to_func (funcs, hb_transforming_pen_cubic_to, nullptr, nullptr);106hb_draw_funcs_set_close_path_func (funcs, hb_transforming_pen_close_path, nullptr, nullptr);107108hb_draw_funcs_make_immutable (funcs);109110hb_atexit (free_static_transforming_pen_funcs);111112return funcs;113}114} static_transforming_pen_funcs;115116static inline117void free_static_transforming_pen_funcs ()118{119static_transforming_pen_funcs.free_instance ();120}121122static hb_draw_funcs_t *123hb_transforming_pen_get_funcs ()124{125return static_transforming_pen_funcs.get_unconst ();126}127128hb_ubytes_t129VarComponent::get_path_at (const hb_varc_context_t &c,130hb_codepoint_t parent_gid,131hb_array_t<const int> coords,132hb_transform_t<> total_transform,133hb_ubytes_t total_record,134hb_scalar_cache_t *cache) const135{136const unsigned char *end = total_record.arrayZ + total_record.length;137const unsigned char *record = total_record.arrayZ;138139auto &VARC = *c.font->face->table.VARC->table;140auto &varStore = &VARC+VARC.varStore;141142#define READ_UINT32VAR(name) \143HB_STMT_START { \144if (unlikely (unsigned (end - record) < HBUINT32VAR::min_size)) return hb_ubytes_t (); \145hb_barrier (); \146auto &varint = * (const HBUINT32VAR *) record; \147unsigned size = varint.get_size (); \148if (unlikely (unsigned (end - record) < size)) return hb_ubytes_t (); \149name = (uint32_t) varint; \150record += size; \151} HB_STMT_END152153uint32_t flags;154READ_UINT32VAR (flags);155156// gid157158hb_codepoint_t gid = 0;159if (flags & (unsigned) flags_t::GID_IS_24BIT)160{161if (unlikely (unsigned (end - record) < HBGlyphID24::static_size))162return hb_ubytes_t ();163hb_barrier ();164gid = * (const HBGlyphID24 *) record;165record += HBGlyphID24::static_size;166}167else168{169if (unlikely (unsigned (end - record) < HBGlyphID16::static_size))170return hb_ubytes_t ();171hb_barrier ();172gid = * (const HBGlyphID16 *) record;173record += HBGlyphID16::static_size;174}175176// Condition177bool show = true;178if (flags & (unsigned) flags_t::HAVE_CONDITION)179{180unsigned conditionIndex;181READ_UINT32VAR (conditionIndex);182const auto &condition = (&VARC+VARC.conditionList)[conditionIndex];183auto instancer = MultiItemVarStoreInstancer(&varStore, nullptr, coords, cache);184show = condition.evaluate (coords.arrayZ, coords.length, &instancer);185}186187// Axis values188189auto &axisIndices = c.scratch.axisIndices;190axisIndices.clear ();191auto &axisValues = c.scratch.axisValues;192axisValues.clear ();193if (flags & (unsigned) flags_t::HAVE_AXES)194{195unsigned axisIndicesIndex;196READ_UINT32VAR (axisIndicesIndex);197axisIndices.extend ((&VARC+VARC.axisIndicesList)[axisIndicesIndex]);198axisValues.resize (axisIndices.length);199const HBUINT8 *p = (const HBUINT8 *) record;200TupleValues::decompile (p, axisValues, (const HBUINT8 *) end);201record = (const unsigned char *) p;202}203204// Apply variations if any205if (flags & (unsigned) flags_t::AXIS_VALUES_HAVE_VARIATION)206{207uint32_t axisValuesVarIdx;208READ_UINT32VAR (axisValuesVarIdx);209if (show && coords && !axisValues.in_error ())210varStore.get_delta (axisValuesVarIdx, coords, axisValues.as_array (), cache);211}212213auto component_coords = coords;214/* Copying coords is expensive; so we have put an arbitrary215* limit on the max number of coords for now. */216if ((flags & (unsigned) flags_t::RESET_UNSPECIFIED_AXES) ||217coords.length > HB_VAR_COMPOSITE_MAX_AXES)218component_coords = hb_array (c.font->coords, c.font->num_coords);219220// Transform221222uint32_t transformVarIdx = VarIdx::NO_VARIATION;223if (flags & (unsigned) flags_t::TRANSFORM_HAS_VARIATION)224READ_UINT32VAR (transformVarIdx);225226#define PROCESS_TRANSFORM_COMPONENTS \227HB_STMT_START { \228PROCESS_TRANSFORM_COMPONENT (FWORD, 1.0f, HAVE_TRANSLATE_X, translateX); \229PROCESS_TRANSFORM_COMPONENT (FWORD, 1.0f, HAVE_TRANSLATE_Y, translateY); \230PROCESS_TRANSFORM_COMPONENT (F4DOT12, HB_PI, HAVE_ROTATION, rotation); \231PROCESS_TRANSFORM_COMPONENT (F6DOT10, 1.0f, HAVE_SCALE_X, scaleX); \232PROCESS_TRANSFORM_COMPONENT (F6DOT10, 1.0f, HAVE_SCALE_Y, scaleY); \233PROCESS_TRANSFORM_COMPONENT (F4DOT12, HB_PI, HAVE_SKEW_X, skewX); \234PROCESS_TRANSFORM_COMPONENT (F4DOT12, HB_PI, HAVE_SKEW_Y, skewY); \235PROCESS_TRANSFORM_COMPONENT (FWORD, 1.0f, HAVE_TCENTER_X, tCenterX); \236PROCESS_TRANSFORM_COMPONENT (FWORD, 1.0f, HAVE_TCENTER_Y, tCenterY); \237} HB_STMT_END238239hb_transform_decomposed_t<> transform;240241// Read transform components242#define PROCESS_TRANSFORM_COMPONENT(type, mult, flag, name) \243if (flags & (unsigned) flags_t::flag) \244{ \245static_assert (type::static_size == HBINT16::static_size, ""); \246if (unlikely (unsigned (end - record) < HBINT16::static_size)) \247return hb_ubytes_t (); \248hb_barrier (); \249transform.name = mult * * (const HBINT16 *) record; \250record += HBINT16::static_size; \251}252PROCESS_TRANSFORM_COMPONENTS;253#undef PROCESS_TRANSFORM_COMPONENT254255// Read reserved records256unsigned i = flags & (unsigned) flags_t::RESERVED_MASK;257while (i)258{259HB_UNUSED uint32_t discard;260READ_UINT32VAR (discard);261i &= i - 1;262}263264/* Parsing is over now. */265266if (show)267{268// Only use coord_setter if there's actually any axis overrides.269coord_setter_t coord_setter (axisIndices ? component_coords : hb_array<int> ());270// Go backwards, to reduce coord_setter vector reallocations.271for (unsigned i = axisIndices.length; i; i--)272coord_setter[axisIndices[i - 1]] = axisValues[i - 1];273if (axisIndices)274component_coords = coord_setter.get_coords ();275276// Apply transform variations if any277if (transformVarIdx != VarIdx::NO_VARIATION && coords)278{279float transformValues[9];280unsigned numTransformValues = 0;281#define PROCESS_TRANSFORM_COMPONENT(type, mult, flag, name) \282if (flags & (unsigned) flags_t::flag) \283transformValues[numTransformValues++] = transform.name / mult;284PROCESS_TRANSFORM_COMPONENTS;285#undef PROCESS_TRANSFORM_COMPONENT286varStore.get_delta (transformVarIdx, coords, hb_array (transformValues, numTransformValues), cache);287numTransformValues = 0;288#define PROCESS_TRANSFORM_COMPONENT(type, mult, flag, name) \289if (flags & (unsigned) flags_t::flag) \290transform.name = transformValues[numTransformValues++] * mult;291PROCESS_TRANSFORM_COMPONENTS;292#undef PROCESS_TRANSFORM_COMPONENT293}294295// Divide them by their divisors296#define PROCESS_TRANSFORM_COMPONENT(type, mult, flag, name) \297if (flags & (unsigned) flags_t::flag) \298{ \299HBINT16 int_v; \300int_v = roundf (transform.name); \301type typed_v = * (const type *) &int_v; \302float float_v = (float) typed_v; \303transform.name = float_v; \304}305PROCESS_TRANSFORM_COMPONENTS;306#undef PROCESS_TRANSFORM_COMPONENT307308if (!(flags & (unsigned) flags_t::HAVE_SCALE_Y))309transform.scaleY = transform.scaleX;310311total_transform.transform (transform.to_transform ());312total_transform.scale (c.font->x_mult ? 1.f / c.font->x_multf : 0.f,313c.font->y_mult ? 1.f / c.font->y_multf : 0.f);314315bool same_coords = component_coords.length == coords.length &&316component_coords.arrayZ == coords.arrayZ;317318c.depth_left--;319VARC.get_path_at (c, gid,320component_coords, total_transform,321parent_gid,322same_coords ? cache : nullptr);323c.depth_left++;324}325326#undef PROCESS_TRANSFORM_COMPONENTS327#undef READ_UINT32VAR328329return hb_ubytes_t (record, end - record);330}331332bool333VARC::get_path_at (const hb_varc_context_t &c,334hb_codepoint_t glyph,335hb_array_t<const int> coords,336hb_transform_t<> transform,337hb_codepoint_t parent_glyph,338hb_scalar_cache_t *parent_cache) const339{340// Don't recurse on the same glyph.341unsigned idx = glyph == parent_glyph ?342NOT_COVERED :343(this+coverage).get_coverage (glyph);344if (idx == NOT_COVERED)345{346if (c.draw_session)347{348// Build a transforming pen to apply the transform.349hb_draw_funcs_t *transformer_funcs = hb_transforming_pen_get_funcs ();350hb_transforming_pen_context_t context {transform,351c.draw_session->funcs,352c.draw_session->draw_data,353&c.draw_session->st};354hb_draw_session_t transformer_session {transformer_funcs, &context};355hb_draw_session_t &shape_draw_session = transform.is_identity () ? *c.draw_session : transformer_session;356357if (c.font->face->table.glyf->get_path_at (c.font, glyph, shape_draw_session, coords, c.scratch.glyf_scratch)) return true;358#ifndef HB_NO_CFF359if (c.font->face->table.cff2->get_path_at (c.font, glyph, shape_draw_session, coords)) return true;360if (c.font->face->table.cff1->get_path (c.font, glyph, shape_draw_session)) return true; // Doesn't have variations361#endif362return false;363}364else if (c.extents)365{366hb_glyph_extents_t glyph_extents;367if (!c.font->face->table.glyf->get_extents_at (c.font, glyph, &glyph_extents, coords))368#ifndef HB_NO_CFF369if (!c.font->face->table.cff2->get_extents_at (c.font, glyph, &glyph_extents, coords))370if (!c.font->face->table.cff1->get_extents (c.font, glyph, &glyph_extents)) // Doesn't have variations371#endif372return false;373374hb_extents_t<> comp_extents (glyph_extents);375transform.transform_extents (comp_extents);376c.extents->union_ (comp_extents);377}378return true;379}380381if (c.depth_left <= 0)382return true;383384if (c.edges_left <= 0)385return true;386(c.edges_left)--;387388hb_decycler_node_t node (c.decycler);389if (unlikely (!node.visit (glyph)))390return true;391392hb_ubytes_t record = (this+glyphRecords)[idx];393394hb_scalar_cache_t static_cache;395hb_scalar_cache_t *cache = parent_cache ?396parent_cache :397(this+varStore).create_cache (&static_cache);398399transform.scale (c.font->x_multf, c.font->y_multf);400401VarCompositeGlyph::get_path_at (c,402glyph,403coords, transform,404record,405cache);406407if (cache != parent_cache)408(this+varStore).destroy_cache (cache, &static_cache);409410return true;411}412413//} // namespace Var414} // namespace OT415416#endif417418419