xref: /aosp_15_r20/external/harfbuzz_ng/src/OT/Var/VARC/VARC.hh (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
1 #ifndef OT_VAR_VARC_VARC_HH
2 #define OT_VAR_VARC_VARC_HH
3 
4 #include "../../../hb-ot-layout-common.hh"
5 #include "../../../hb-ot-glyf-table.hh"
6 #include "../../../hb-ot-cff2-table.hh"
7 #include "../../../hb-ot-cff1-table.hh"
8 
9 #include "coord-setter.hh"
10 
11 namespace OT {
12 
13 //namespace Var {
14 
15 /*
16  * VARC -- Variable Composites
17  * https://github.com/harfbuzz/boring-expansion-spec/blob/main/VARC.md
18  */
19 
20 #ifndef HB_NO_VAR_COMPOSITES
21 
22 struct VarComponent
23 {
24   enum class flags_t : uint32_t
25   {
26     RESET_UNSPECIFIED_AXES	= 1u << 0,
27     HAVE_AXES			= 1u << 1,
28     AXIS_VALUES_HAVE_VARIATION	= 1u << 2,
29     TRANSFORM_HAS_VARIATION	= 1u << 3,
30     HAVE_TRANSLATE_X		= 1u << 4,
31     HAVE_TRANSLATE_Y		= 1u << 5,
32     HAVE_ROTATION		= 1u << 6,
33     HAVE_CONDITION		= 1u << 7,
34     HAVE_SCALE_X		= 1u << 8,
35     HAVE_SCALE_Y		= 1u << 9,
36     HAVE_TCENTER_X		= 1u << 10,
37     HAVE_TCENTER_Y		= 1u << 11,
38     GID_IS_24BIT		= 1u << 12,
39     HAVE_SKEW_X			= 1u << 13,
40     HAVE_SKEW_Y			= 1u << 14,
41     RESERVED_MASK		= ~((1u << 15) - 1),
42   };
43 
44   HB_INTERNAL hb_ubytes_t
45   get_path_at (hb_font_t *font,
46 	       hb_codepoint_t parent_gid,
47 	       hb_draw_session_t &draw_session,
48 	       hb_array_t<const int> coords,
49 	       hb_ubytes_t record,
50 	       hb_set_t *visited,
51 	       signed *edges_left,
52 	       signed depth_left,
53 	       VarRegionList::cache_t *cache = nullptr) const;
54 };
55 
56 struct VarCompositeGlyph
57 {
58   static void
get_path_atOT::VarCompositeGlyph59   get_path_at (hb_font_t *font,
60 	       hb_codepoint_t glyph,
61 	       hb_draw_session_t &draw_session,
62 	       hb_array_t<const int> coords,
63 	       hb_ubytes_t record,
64 	       hb_set_t *visited,
65 	       signed *edges_left,
66 	       signed depth_left,
67 	       VarRegionList::cache_t *cache = nullptr)
68   {
69     while (record)
70     {
71       const VarComponent &comp = * (const VarComponent *) (record.arrayZ);
72       record = comp.get_path_at (font, glyph,
73 				 draw_session, coords,
74 				 record,
75 				 visited, edges_left, depth_left, cache);
76     }
77   }
78 };
79 
80 HB_MARK_AS_FLAG_T (VarComponent::flags_t);
81 
82 struct VARC
83 {
84   friend struct VarComponent;
85 
86   static constexpr hb_tag_t tableTag = HB_TAG ('V', 'A', 'R', 'C');
87 
88   bool
get_path_atOT::VARC89   get_path_at (hb_font_t *font,
90 	       hb_codepoint_t glyph,
91 	       hb_draw_session_t &draw_session,
92 	       hb_array_t<const int> coords,
93 	       hb_codepoint_t parent_glyph = HB_CODEPOINT_INVALID,
94 	       hb_set_t *visited = nullptr,
95 	       signed *edges_left = nullptr,
96 	       signed depth_left = HB_MAX_NESTING_LEVEL) const
97   {
98     hb_set_t stack_set;
99     if (visited == nullptr)
100       visited = &stack_set;
101     signed stack_edges = HB_MAX_GRAPH_EDGE_COUNT;
102     if (edges_left == nullptr)
103       edges_left = &stack_edges;
104 
105     // Don't recurse on the same glyph.
106     unsigned idx = glyph == parent_glyph ?
107 		   NOT_COVERED :
108 		   (this+coverage).get_coverage (glyph);
109     if (idx == NOT_COVERED)
110     {
111       if (!font->face->table.glyf->get_path_at (font, glyph, draw_session, coords))
112 #ifndef HB_NO_CFF
113       if (!font->face->table.cff2->get_path_at (font, glyph, draw_session, coords))
114       if (!font->face->table.cff1->get_path (font, glyph, draw_session)) // Doesn't have variations
115 #endif
116 	return false;
117       return true;
118     }
119 
120     if (depth_left <= 0)
121       return true;
122 
123     if (*edges_left <= 0)
124       return true;
125     (*edges_left)--;
126 
127     if (visited->has (glyph) || visited->in_error ())
128       return true;
129     visited->add (glyph);
130 
131     hb_ubytes_t record = (this+glyphRecords)[idx];
132 
133     VarRegionList::cache_t *cache = record.length >= 64 ? // Heuristic
134 				   (this+varStore).create_cache ()
135 				   : nullptr;
136 
137     VarCompositeGlyph::get_path_at (font, glyph,
138 				    draw_session, coords,
139 				    record,
140 				    visited, edges_left, depth_left,
141 				    cache);
142 
143     (this+varStore).destroy_cache (cache);
144 
145     visited->del (glyph);
146 
147     return true;
148   }
149 
150   bool
get_pathOT::VARC151   get_path (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session) const
152   { return get_path_at (font, gid, draw_session, hb_array (font->coords, font->num_coords)); }
153 
paint_glyphOT::VARC154   bool paint_glyph (hb_font_t *font, hb_codepoint_t gid, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const
155   {
156     funcs->push_clip_glyph (data, gid, font);
157     funcs->color (data, true, foreground);
158     funcs->pop_clip (data);
159 
160     return true;
161   }
162 
sanitizeOT::VARC163   bool sanitize (hb_sanitize_context_t *c) const
164   {
165     TRACE_SANITIZE (this);
166     return_trace (version.sanitize (c) &&
167 		  hb_barrier () &&
168 		  version.major == 1 &&
169 		  coverage.sanitize (c, this) &&
170 		  varStore.sanitize (c, this) &&
171 		  conditionList.sanitize (c, this) &&
172 		  axisIndicesList.sanitize (c, this) &&
173 		  glyphRecords.sanitize (c, this));
174   }
175 
176   protected:
177   FixedVersion<> version; /* Version identifier */
178   Offset32To<Coverage> coverage;
179   Offset32To<MultiItemVariationStore> varStore;
180   Offset32To<ConditionList> conditionList;
181   Offset32To<TupleList> axisIndicesList;
182   Offset32To<CFF2Index/*Of<VarCompositeGlyph>*/> glyphRecords;
183   public:
184   DEFINE_SIZE_STATIC (24);
185 };
186 
187 #endif
188 
189 //}
190 
191 }
192 
193 #endif  /* OT_VAR_VARC_VARC_HH */
194