Path: blob/master/thirdparty/harfbuzz/src/OT/Var/VARC/VARC.cc
21730 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 {111213#ifndef HB_NO_DRAW1415struct hb_transforming_pen_context_t16{17hb_transform_t<> transform;18hb_draw_funcs_t *dfuncs;19void *data;20hb_draw_state_t *st;21};2223static void24hb_transforming_pen_move_to (hb_draw_funcs_t *dfuncs HB_UNUSED,25void *data,26hb_draw_state_t *st,27float to_x, float to_y,28void *user_data HB_UNUSED)29{30hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data;3132c->transform.transform_point (to_x, to_y);3334c->dfuncs->move_to (c->data, *c->st, to_x, to_y);35}3637static void38hb_transforming_pen_line_to (hb_draw_funcs_t *dfuncs HB_UNUSED,39void *data,40hb_draw_state_t *st,41float to_x, float to_y,42void *user_data HB_UNUSED)43{44hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data;4546c->transform.transform_point (to_x, to_y);4748c->dfuncs->line_to (c->data, *c->st, to_x, to_y);49}5051static void52hb_transforming_pen_quadratic_to (hb_draw_funcs_t *dfuncs HB_UNUSED,53void *data,54hb_draw_state_t *st,55float control_x, float control_y,56float to_x, float to_y,57void *user_data HB_UNUSED)58{59hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data;6061c->transform.transform_point (control_x, control_y);62c->transform.transform_point (to_x, to_y);6364c->dfuncs->quadratic_to (c->data, *c->st, control_x, control_y, to_x, to_y);65}6667static void68hb_transforming_pen_cubic_to (hb_draw_funcs_t *dfuncs HB_UNUSED,69void *data,70hb_draw_state_t *st,71float control1_x, float control1_y,72float control2_x, float control2_y,73float to_x, float to_y,74void *user_data HB_UNUSED)75{76hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data;7778c->transform.transform_point (control1_x, control1_y);79c->transform.transform_point (control2_x, control2_y);80c->transform.transform_point (to_x, to_y);8182c->dfuncs->cubic_to (c->data, *c->st, control1_x, control1_y, control2_x, control2_y, to_x, to_y);83}8485static void86hb_transforming_pen_close_path (hb_draw_funcs_t *dfuncs HB_UNUSED,87void *data,88hb_draw_state_t *st,89void *user_data HB_UNUSED)90{91hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data;9293c->dfuncs->close_path (c->data, *c->st);94}9596static inline void free_static_transforming_pen_funcs ();9798static struct hb_transforming_pen_funcs_lazy_loader_t : hb_draw_funcs_lazy_loader_t<hb_transforming_pen_funcs_lazy_loader_t>99{100static hb_draw_funcs_t *create ()101{102hb_draw_funcs_t *funcs = hb_draw_funcs_create ();103104hb_draw_funcs_set_move_to_func (funcs, hb_transforming_pen_move_to, nullptr, nullptr);105hb_draw_funcs_set_line_to_func (funcs, hb_transforming_pen_line_to, nullptr, nullptr);106hb_draw_funcs_set_quadratic_to_func (funcs, hb_transforming_pen_quadratic_to, nullptr, nullptr);107hb_draw_funcs_set_cubic_to_func (funcs, hb_transforming_pen_cubic_to, nullptr, nullptr);108hb_draw_funcs_set_close_path_func (funcs, hb_transforming_pen_close_path, nullptr, nullptr);109110hb_draw_funcs_make_immutable (funcs);111112hb_atexit (free_static_transforming_pen_funcs);113114return funcs;115}116} static_transforming_pen_funcs;117118static inline119void free_static_transforming_pen_funcs ()120{121static_transforming_pen_funcs.free_instance ();122}123124static hb_draw_funcs_t *125hb_transforming_pen_get_funcs ()126{127return static_transforming_pen_funcs.get_unconst ();128}129130hb_ubytes_t131VarComponent::get_path_at (const hb_varc_context_t &c,132hb_codepoint_t parent_gid,133hb_array_t<const int> coords,134hb_transform_t<> total_transform,135hb_ubytes_t total_record,136hb_scalar_cache_t *cache) const137{138const unsigned char *end = total_record.arrayZ + total_record.length;139const unsigned char *record = total_record.arrayZ;140141auto &VARC = *c.font->face->table.VARC->table;142auto &varStore = &VARC+VARC.varStore;143144#define READ_UINT32VAR(name) \145HB_STMT_START { \146if (unlikely (unsigned (end - record) < HBUINT32VAR::min_size)) return hb_ubytes_t (); \147hb_barrier (); \148auto &varint = * (const HBUINT32VAR *) record; \149unsigned size = varint.get_size (); \150if (unlikely (unsigned (end - record) < size)) return hb_ubytes_t (); \151name = (uint32_t) varint; \152record += size; \153} HB_STMT_END154155uint32_t flags;156READ_UINT32VAR (flags);157158// gid159160hb_codepoint_t gid = 0;161if (flags & (unsigned) flags_t::GID_IS_24BIT)162{163if (unlikely (unsigned (end - record) < HBGlyphID24::static_size))164return hb_ubytes_t ();165hb_barrier ();166gid = * (const HBGlyphID24 *) record;167record += HBGlyphID24::static_size;168}169else170{171if (unlikely (unsigned (end - record) < HBGlyphID16::static_size))172return hb_ubytes_t ();173hb_barrier ();174gid = * (const HBGlyphID16 *) record;175record += HBGlyphID16::static_size;176}177178// Condition179bool show = true;180if (flags & (unsigned) flags_t::HAVE_CONDITION)181{182unsigned conditionIndex;183READ_UINT32VAR (conditionIndex);184const auto &condition = (&VARC+VARC.conditionList)[conditionIndex];185auto instancer = MultiItemVarStoreInstancer(&varStore, nullptr, coords, cache);186show = condition.evaluate (coords.arrayZ, coords.length, &instancer);187}188189// Axis values190191auto &axisIndices = c.scratch.axisIndices;192axisIndices.clear ();193auto &axisValues = c.scratch.axisValues;194axisValues.clear ();195if (flags & (unsigned) flags_t::HAVE_AXES)196{197unsigned axisIndicesIndex;198READ_UINT32VAR (axisIndicesIndex);199axisIndices.extend ((&VARC+VARC.axisIndicesList)[axisIndicesIndex]);200axisValues.resize (axisIndices.length);201const HBUINT8 *p = (const HBUINT8 *) record;202TupleValues::decompile (p, axisValues, (const HBUINT8 *) end);203record = (const unsigned char *) p;204}205206// Apply variations if any207if (flags & (unsigned) flags_t::AXIS_VALUES_HAVE_VARIATION)208{209uint32_t axisValuesVarIdx;210READ_UINT32VAR (axisValuesVarIdx);211if (show && coords && !axisValues.in_error ())212varStore.get_delta (axisValuesVarIdx, coords, axisValues.as_array (), cache);213}214215auto component_coords = coords;216/* Copying coords is expensive; so we have put an arbitrary217* limit on the max number of coords for now. */218if ((flags & (unsigned) flags_t::RESET_UNSPECIFIED_AXES) ||219coords.length > HB_VAR_COMPOSITE_MAX_AXES)220component_coords = hb_array (c.font->coords, c.font->num_coords);221222// Transform223224uint32_t transformVarIdx = VarIdx::NO_VARIATION;225if (flags & (unsigned) flags_t::TRANSFORM_HAS_VARIATION)226READ_UINT32VAR (transformVarIdx);227228#define PROCESS_TRANSFORM_COMPONENTS \229HB_STMT_START { \230PROCESS_TRANSFORM_COMPONENT (FWORD, 1.0f, HAVE_TRANSLATE_X, translateX); \231PROCESS_TRANSFORM_COMPONENT (FWORD, 1.0f, HAVE_TRANSLATE_Y, translateY); \232PROCESS_TRANSFORM_COMPONENT (F4DOT12, HB_PI, HAVE_ROTATION, rotation); \233PROCESS_TRANSFORM_COMPONENT (F6DOT10, 1.0f, HAVE_SCALE_X, scaleX); \234PROCESS_TRANSFORM_COMPONENT (F6DOT10, 1.0f, HAVE_SCALE_Y, scaleY); \235PROCESS_TRANSFORM_COMPONENT (F4DOT12, HB_PI, HAVE_SKEW_X, skewX); \236PROCESS_TRANSFORM_COMPONENT (F4DOT12, HB_PI, HAVE_SKEW_Y, skewY); \237PROCESS_TRANSFORM_COMPONENT (FWORD, 1.0f, HAVE_TCENTER_X, tCenterX); \238PROCESS_TRANSFORM_COMPONENT (FWORD, 1.0f, HAVE_TCENTER_Y, tCenterY); \239} HB_STMT_END240241hb_transform_decomposed_t<> transform;242243// Read transform components244#define PROCESS_TRANSFORM_COMPONENT(type, mult, flag, name) \245if (flags & (unsigned) flags_t::flag) \246{ \247static_assert (type::static_size == HBINT16::static_size, ""); \248if (unlikely (unsigned (end - record) < HBINT16::static_size)) \249return hb_ubytes_t (); \250hb_barrier (); \251transform.name = mult * * (const HBINT16 *) record; \252record += HBINT16::static_size; \253}254PROCESS_TRANSFORM_COMPONENTS;255#undef PROCESS_TRANSFORM_COMPONENT256257// Read reserved records258unsigned i = flags & (unsigned) flags_t::RESERVED_MASK;259while (i)260{261HB_UNUSED uint32_t discard;262READ_UINT32VAR (discard);263i &= i - 1;264}265266/* Parsing is over now. */267268if (show)269{270// Only use coord_setter if there's actually any axis overrides.271coord_setter_t coord_setter (axisIndices ? component_coords : hb_array<int> ());272// Go backwards, to reduce coord_setter vector reallocations.273for (unsigned i = axisIndices.length; i; i--)274coord_setter[axisIndices[i - 1]] = axisValues[i - 1];275if (axisIndices)276component_coords = coord_setter.get_coords ();277278// Apply transform variations if any279if (transformVarIdx != VarIdx::NO_VARIATION && coords)280{281float transformValues[9];282unsigned numTransformValues = 0;283#define PROCESS_TRANSFORM_COMPONENT(type, mult, flag, name) \284if (flags & (unsigned) flags_t::flag) \285transformValues[numTransformValues++] = transform.name / mult;286PROCESS_TRANSFORM_COMPONENTS;287#undef PROCESS_TRANSFORM_COMPONENT288varStore.get_delta (transformVarIdx, coords, hb_array (transformValues, numTransformValues), cache);289numTransformValues = 0;290#define PROCESS_TRANSFORM_COMPONENT(type, mult, flag, name) \291if (flags & (unsigned) flags_t::flag) \292transform.name = transformValues[numTransformValues++] * mult;293PROCESS_TRANSFORM_COMPONENTS;294#undef PROCESS_TRANSFORM_COMPONENT295}296297// Divide them by their divisors298#define PROCESS_TRANSFORM_COMPONENT(type, mult, flag, name) \299if (flags & (unsigned) flags_t::flag) \300{ \301HBINT16 int_v; \302int_v = roundf (transform.name); \303type typed_v = * (const type *) &int_v; \304float float_v = (float) typed_v; \305transform.name = float_v; \306}307PROCESS_TRANSFORM_COMPONENTS;308#undef PROCESS_TRANSFORM_COMPONENT309310if (!(flags & (unsigned) flags_t::HAVE_SCALE_Y))311transform.scaleY = transform.scaleX;312313total_transform.transform (transform.to_transform ());314total_transform.scale (c.font->x_mult ? 1.f / c.font->x_multf : 0.f,315c.font->y_mult ? 1.f / c.font->y_multf : 0.f);316317bool same_coords = component_coords.length == coords.length &&318component_coords.arrayZ == coords.arrayZ;319320c.depth_left--;321VARC.get_path_at (c, gid,322component_coords, total_transform,323parent_gid,324same_coords ? cache : nullptr);325c.depth_left++;326}327328#undef PROCESS_TRANSFORM_COMPONENTS329#undef READ_UINT32VAR330331return hb_ubytes_t (record, end - record);332}333334bool335VARC::get_path_at (const hb_varc_context_t &c,336hb_codepoint_t glyph,337hb_array_t<const int> coords,338hb_transform_t<> transform,339hb_codepoint_t parent_glyph,340hb_scalar_cache_t *parent_cache) const341{342// Don't recurse on the same glyph.343unsigned idx = glyph == parent_glyph ?344NOT_COVERED :345(this+coverage).get_coverage (glyph);346if (idx == NOT_COVERED)347{348if (c.draw_session)349{350// Build a transforming pen to apply the transform.351hb_draw_funcs_t *transformer_funcs = hb_transforming_pen_get_funcs ();352hb_transforming_pen_context_t context {transform,353c.draw_session->funcs,354c.draw_session->draw_data,355&c.draw_session->st};356hb_draw_session_t transformer_session {transformer_funcs, &context};357hb_draw_session_t &shape_draw_session = transform.is_identity () ? *c.draw_session : transformer_session;358359if (c.font->face->table.glyf->get_path_at (c.font, glyph, shape_draw_session, coords, c.scratch.glyf_scratch)) return true;360#ifndef HB_NO_CFF361if (c.font->face->table.cff2->get_path_at (c.font, glyph, shape_draw_session, coords)) return true;362if (c.font->face->table.cff1->get_path (c.font, glyph, shape_draw_session)) return true; // Doesn't have variations363#endif364return false;365}366else if (c.extents)367{368hb_glyph_extents_t glyph_extents;369if (!c.font->face->table.glyf->get_extents_at (c.font, glyph, &glyph_extents, coords))370#ifndef HB_NO_CFF371if (!c.font->face->table.cff2->get_extents_at (c.font, glyph, &glyph_extents, coords))372if (!c.font->face->table.cff1->get_extents (c.font, glyph, &glyph_extents)) // Doesn't have variations373#endif374return false;375376hb_extents_t<> comp_extents (glyph_extents);377transform.transform_extents (comp_extents);378c.extents->union_ (comp_extents);379}380return true;381}382383if (c.depth_left <= 0)384return true;385386if (c.edges_left <= 0)387return true;388(c.edges_left)--;389390hb_decycler_node_t node (c.decycler);391if (unlikely (!node.visit (glyph)))392return true;393394hb_ubytes_t record = (this+glyphRecords)[idx];395396hb_scalar_cache_t static_cache;397hb_scalar_cache_t *cache = parent_cache ?398parent_cache :399(this+varStore).create_cache (&static_cache);400401transform.scale (c.font->x_multf, c.font->y_multf);402403VarCompositeGlyph::get_path_at (c,404glyph,405coords, transform,406record,407cache);408409if (cache != parent_cache)410(this+varStore).destroy_cache (cache, &static_cache);411412return true;413}414415#endif416417//} // namespace Var418} // namespace OT419420#endif421422423