• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef OT_GLYF_GLYPH_HH
2 #define OT_GLYF_GLYPH_HH
3 
4 
5 #include "../../hb-open-type.hh"
6 
7 #include "GlyphHeader.hh"
8 #include "SimpleGlyph.hh"
9 #include "CompositeGlyph.hh"
10 #include "VarCompositeGlyph.hh"
11 #include "coord-setter.hh"
12 
13 
14 namespace OT {
15 
16 struct glyf_accelerator_t;
17 
18 namespace glyf_impl {
19 
20 
21 #ifndef HB_GLYF_MAX_POINTS
22 #define HB_GLYF_MAX_POINTS 10000
23 #endif
24 
25 
26 enum phantom_point_index_t
27 {
28   PHANTOM_LEFT   = 0,
29   PHANTOM_RIGHT  = 1,
30   PHANTOM_TOP    = 2,
31   PHANTOM_BOTTOM = 3,
32   PHANTOM_COUNT  = 4
33 };
34 
35 struct Glyph
36 {
37   enum glyph_type_t { EMPTY, SIMPLE, COMPOSITE, VAR_COMPOSITE };
38 
39   public:
get_composite_iteratorOT::glyf_impl::Glyph40   composite_iter_t get_composite_iterator () const
41   {
42     if (type != COMPOSITE) return composite_iter_t ();
43     return CompositeGlyph (*header, bytes).iter ();
44   }
get_var_composite_iteratorOT::glyf_impl::Glyph45   var_composite_iter_t get_var_composite_iterator () const
46   {
47     if (type != VAR_COMPOSITE) return var_composite_iter_t ();
48     return VarCompositeGlyph (*header, bytes).iter ();
49   }
50 
trim_paddingOT::glyf_impl::Glyph51   const hb_bytes_t trim_padding () const
52   {
53     switch (type) {
54     case COMPOSITE: return CompositeGlyph (*header, bytes).trim_padding ();
55     case SIMPLE:    return SimpleGlyph (*header, bytes).trim_padding ();
56     default:        return bytes;
57     }
58   }
59 
drop_hintsOT::glyf_impl::Glyph60   void drop_hints ()
61   {
62     switch (type) {
63     case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints (); return;
64     case SIMPLE:    SimpleGlyph (*header, bytes).drop_hints (); return;
65     default:        return;
66     }
67   }
68 
set_overlaps_flagOT::glyf_impl::Glyph69   void set_overlaps_flag ()
70   {
71     switch (type) {
72     case COMPOSITE: CompositeGlyph (*header, bytes).set_overlaps_flag (); return;
73     case SIMPLE:    SimpleGlyph (*header, bytes).set_overlaps_flag (); return;
74     default:        return;
75     }
76   }
77 
drop_hints_bytesOT::glyf_impl::Glyph78   void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const
79   {
80     switch (type) {
81     case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints_bytes (dest_start); return;
82     case SIMPLE:    SimpleGlyph (*header, bytes).drop_hints_bytes (dest_start, dest_end); return;
83     default:        return;
84     }
85   }
86 
update_mtxOT::glyf_impl::Glyph87   void update_mtx (const hb_subset_plan_t *plan,
88                    int xMin, int yMax,
89                    const contour_point_vector_t &all_points) const
90   {
91     hb_codepoint_t new_gid = 0;
92     if (!plan->new_gid_for_old_gid (gid, &new_gid))
93       return;
94 
95     unsigned len = all_points.length;
96     float leftSideX = all_points[len - 4].x;
97     float rightSideX = all_points[len - 3].x;
98     float topSideY = all_points[len - 2].y;
99     float bottomSideY = all_points[len - 1].y;
100 
101     int hori_aw = roundf (rightSideX - leftSideX);
102     if (hori_aw < 0) hori_aw = 0;
103     int lsb = roundf (xMin - leftSideX);
104     plan->hmtx_map->set (new_gid, hb_pair (hori_aw, lsb));
105 
106     int vert_aw = roundf (topSideY - bottomSideY);
107     if (vert_aw < 0) vert_aw = 0;
108     int tsb = roundf (topSideY - yMax);
109     plan->vmtx_map->set (new_gid, hb_pair (vert_aw, tsb));
110   }
111 
compile_header_bytesOT::glyf_impl::Glyph112   bool compile_header_bytes (const hb_subset_plan_t *plan,
113                              const contour_point_vector_t &all_points,
114                              hb_bytes_t &dest_bytes /* OUT */) const
115   {
116     GlyphHeader *glyph_header = nullptr;
117     if (type != EMPTY && all_points.length > 4)
118     {
119       glyph_header = (GlyphHeader *) hb_calloc (1, GlyphHeader::static_size);
120       if (unlikely (!glyph_header)) return false;
121     }
122 
123     float xMin = 0, xMax = 0;
124     float yMin = 0, yMax = 0;
125     if (all_points.length > 4)
126     {
127       xMin = xMax = all_points[0].x;
128       yMin = yMax = all_points[0].y;
129     }
130 
131     for (unsigned i = 1; i < all_points.length - 4; i++)
132     {
133       float x = all_points[i].x;
134       float y = all_points[i].y;
135       xMin = hb_min (xMin, x);
136       xMax = hb_max (xMax, x);
137       yMin = hb_min (yMin, y);
138       yMax = hb_max (yMax, y);
139     }
140 
141     update_mtx (plan, roundf (xMin), roundf (yMax), all_points);
142 
143     /*for empty glyphs: all_points only include phantom points.
144      *just update metrics and then return */
145     if (!glyph_header)
146       return true;
147 
148     glyph_header->numberOfContours = header->numberOfContours;
149     glyph_header->xMin = roundf (xMin);
150     glyph_header->yMin = roundf (yMin);
151     glyph_header->xMax = roundf (xMax);
152     glyph_header->yMax = roundf (yMax);
153 
154     dest_bytes = hb_bytes_t ((const char *)glyph_header, GlyphHeader::static_size);
155     return true;
156   }
157 
compile_bytes_with_deltasOT::glyf_impl::Glyph158   bool compile_bytes_with_deltas (const hb_subset_plan_t *plan,
159                                   hb_font_t *font,
160                                   const glyf_accelerator_t &glyf,
161                                   hb_bytes_t &dest_start,  /* IN/OUT */
162                                   hb_bytes_t &dest_end /* OUT */)
163   {
164     contour_point_vector_t all_points, deltas;
165     if (!get_points (font, glyf, all_points, &deltas, false, false))
166       return false;
167 
168     // .notdef, set type to empty so we only update metrics and don't compile bytes for
169     // it
170     if (gid == 0 &&
171         !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
172       type = EMPTY;
173 
174     switch (type) {
175     case COMPOSITE:
176       if (!CompositeGlyph (*header, bytes).compile_bytes_with_deltas (dest_start,
177                                                                       deltas,
178                                                                       dest_end))
179         return false;
180       break;
181     case SIMPLE:
182       if (!SimpleGlyph (*header, bytes).compile_bytes_with_deltas (all_points,
183                                                                    plan->flags & HB_SUBSET_FLAGS_NO_HINTING,
184                                                                    dest_end))
185         return false;
186       break;
187     default:
188       /* set empty bytes for empty glyph
189        * do not use source glyph's pointers */
190       dest_start = hb_bytes_t ();
191       dest_end = hb_bytes_t ();
192       break;
193     }
194 
195     if (!compile_header_bytes (plan, all_points, dest_start))
196     {
197       dest_end.fini ();
198       return false;
199     }
200     return true;
201   }
202 
203 
204   /* Note: Recursively calls itself.
205    * all_points includes phantom points
206    */
207   template <typename accelerator_t>
get_pointsOT::glyf_impl::Glyph208   bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator,
209 		   contour_point_vector_t &all_points /* OUT */,
210 		   contour_point_vector_t *deltas = nullptr, /* OUT */
211 		   bool shift_points_hori = true,
212 		   bool use_my_metrics = true,
213 		   bool phantom_only = false,
214 		   hb_array_t<int> coords = hb_array_t<int> (),
215 		   unsigned int depth = 0) const
216   {
217     if (unlikely (depth > HB_MAX_NESTING_LEVEL)) return false;
218 
219     if (!coords)
220       coords = hb_array (font->coords, font->num_coords);
221 
222     contour_point_vector_t stack_points;
223     bool inplace = type == SIMPLE && all_points.length == 0;
224     /* Load into all_points if it's empty, as an optimization. */
225     contour_point_vector_t &points = inplace ? all_points : stack_points;
226 
227     switch (type) {
228     case SIMPLE:
229       if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points, phantom_only)))
230 	return false;
231       break;
232     case COMPOSITE:
233     {
234       /* pseudo component points for each component in composite glyph */
235       unsigned num_points = hb_len (CompositeGlyph (*header, bytes).iter ());
236       if (unlikely (!points.resize (num_points))) return false;
237       break;
238     }
239 #ifndef HB_NO_VAR_COMPOSITES
240     case VAR_COMPOSITE:
241     {
242       for (auto &item : get_var_composite_iterator ())
243         if (unlikely (!item.get_points (points))) return false;
244     }
245 #endif
246     default:
247       break;
248     }
249 
250     /* Init phantom points */
251     if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false;
252     hb_array_t<contour_point_t> phantoms = points.as_array ().sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT);
253     {
254       int lsb = 0;
255       int h_delta = glyf_accelerator.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb) ?
256 		    (int) header->xMin - lsb : 0;
257       HB_UNUSED int tsb = 0;
258       int v_orig  = (int) header->yMax +
259 #ifndef HB_NO_VERTICAL
260 		    ((void) glyf_accelerator.vmtx->get_leading_bearing_without_var_unscaled (gid, &tsb), tsb)
261 #else
262 		    0
263 #endif
264 		    ;
265       unsigned h_adv = glyf_accelerator.hmtx->get_advance_without_var_unscaled (gid);
266       unsigned v_adv =
267 #ifndef HB_NO_VERTICAL
268 		       glyf_accelerator.vmtx->get_advance_without_var_unscaled (gid)
269 #else
270 		       - font->face->get_upem ()
271 #endif
272 		       ;
273       phantoms[PHANTOM_LEFT].x = h_delta;
274       phantoms[PHANTOM_RIGHT].x = h_adv + h_delta;
275       phantoms[PHANTOM_TOP].y = v_orig;
276       phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv;
277     }
278 
279     if (deltas != nullptr && depth == 0 && type == COMPOSITE)
280     {
281       if (unlikely (!deltas->resize (points.length))) return false;
282       deltas->copy_vector (points);
283     }
284 
285 #ifndef HB_NO_VAR
286     glyf_accelerator.gvar->apply_deltas_to_points (gid,
287 						   coords,
288 						   points.as_array ());
289 #endif
290 
291     // mainly used by CompositeGlyph calculating new X/Y offset value so no need to extend it
292     // with child glyphs' points
293     if (deltas != nullptr && depth == 0 && type == COMPOSITE)
294     {
295       for (unsigned i = 0 ; i < points.length; i++)
296       {
297         deltas->arrayZ[i].x = points.arrayZ[i].x - deltas->arrayZ[i].x;
298         deltas->arrayZ[i].y = points.arrayZ[i].y - deltas->arrayZ[i].y;
299       }
300     }
301 
302     switch (type) {
303     case SIMPLE:
304       if (!inplace)
305 	all_points.extend (points.as_array ());
306       break;
307     case COMPOSITE:
308     {
309       contour_point_vector_t comp_points;
310       unsigned int comp_index = 0;
311       for (auto &item : get_composite_iterator ())
312       {
313         comp_points.reset ();
314 
315 	if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ())
316 				       .get_points (font,
317 						    glyf_accelerator,
318 						    comp_points,
319 						    deltas,
320 						    shift_points_hori,
321 						    use_my_metrics,
322 						    phantom_only,
323 						    coords,
324 						    depth + 1)))
325 	  return false;
326 
327 	/* Copy phantom points from component if USE_MY_METRICS flag set */
328 	if (use_my_metrics && item.is_use_my_metrics ())
329 	  for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
330 	    phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
331 
332 	/* Apply component transformation & translation */
333 	item.transform_points (comp_points);
334 
335 	/* Apply translation from gvar */
336 	comp_points.translate (points[comp_index]);
337 
338 	if (item.is_anchored ())
339 	{
340 	  unsigned int p1, p2;
341 	  item.get_anchor_points (p1, p2);
342 	  if (likely (p1 < all_points.length && p2 < comp_points.length))
343 	  {
344 	    contour_point_t delta;
345 	    delta.init (all_points[p1].x - comp_points[p2].x,
346 			all_points[p1].y - comp_points[p2].y);
347 
348 	    comp_points.translate (delta);
349 	  }
350 	}
351 
352 	all_points.extend (comp_points.as_array ().sub_array (0, comp_points.length - PHANTOM_COUNT));
353 
354 	if (all_points.length > HB_GLYF_MAX_POINTS)
355 	  return false;
356 
357 	comp_index++;
358       }
359 
360       all_points.extend (phantoms);
361     } break;
362 #ifndef HB_NO_VAR_COMPOSITES
363     case VAR_COMPOSITE:
364     {
365       contour_point_vector_t comp_points;
366       hb_array_t<contour_point_t> points_left = points.as_array ();
367       for (auto &item : get_var_composite_iterator ())
368       {
369 	hb_array_t<contour_point_t> record_points = points_left.sub_array (0, item.get_num_points ());
370 
371         comp_points.reset ();
372 
373 	coord_setter_t coord_setter (coords);
374 	item.set_variations (coord_setter, record_points);
375 
376 	if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ())
377 				       .get_points (font,
378 						    glyf_accelerator,
379 						    comp_points,
380 						    deltas,
381 						    shift_points_hori,
382 						    use_my_metrics,
383 						    phantom_only,
384 						    coord_setter.get_coords (),
385 						    depth + 1)))
386 	  return false;
387 
388 	/* Apply component transformation */
389 	item.transform_points (record_points, comp_points);
390 
391 	/* Copy phantom points from component if USE_MY_METRICS flag set */
392 	if (use_my_metrics && item.is_use_my_metrics ())
393 	  for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
394 	    phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
395 
396 	all_points.extend (comp_points.as_array ().sub_array (0, comp_points.length - PHANTOM_COUNT));
397 
398 	if (all_points.length > HB_GLYF_MAX_POINTS)
399 	  return false;
400 
401 	points_left += item.get_num_points ();
402       }
403       all_points.extend (phantoms);
404     } break;
405 #endif
406     default:
407       all_points.extend (phantoms);
408       break;
409     }
410 
411     if (depth == 0 && shift_points_hori) /* Apply at top level */
412     {
413       /* Undocumented rasterizer behavior:
414        * Shift points horizontally by the updated left side bearing
415        */
416       contour_point_t delta;
417       delta.init (-phantoms[PHANTOM_LEFT].x, 0.f);
418       if (delta.x) all_points.translate (delta);
419     }
420 
421     return !all_points.in_error ();
422   }
423 
get_extents_without_var_scaledOT::glyf_impl::Glyph424   bool get_extents_without_var_scaled (hb_font_t *font, const glyf_accelerator_t &glyf_accelerator,
425 				       hb_glyph_extents_t *extents) const
426   {
427     if (type == EMPTY) return true; /* Empty glyph; zero extents. */
428     return header->get_extents_without_var_scaled (font, glyf_accelerator, gid, extents);
429   }
430 
get_bytesOT::glyf_impl::Glyph431   hb_bytes_t get_bytes () const { return bytes; }
432 
GlyphOT::glyf_impl::Glyph433   Glyph () : bytes (),
434              header (bytes.as<GlyphHeader> ()),
435              gid (-1),
436              type(EMPTY)
437   {}
438 
GlyphOT::glyf_impl::Glyph439   Glyph (hb_bytes_t bytes_,
440 	 hb_codepoint_t gid_ = (unsigned) -1) : bytes (bytes_),
441                                                 header (bytes.as<GlyphHeader> ()),
442                                                 gid (gid_)
443   {
444     int num_contours = header->numberOfContours;
445     if (unlikely (num_contours == 0)) type = EMPTY;
446     else if (num_contours > 0) type = SIMPLE;
447     else if (num_contours == -2) type = VAR_COMPOSITE;
448     else type = COMPOSITE; /* negative numbers */
449   }
450 
451   protected:
452   hb_bytes_t bytes;
453   const GlyphHeader *header;
454   hb_codepoint_t gid;
455   unsigned type;
456 };
457 
458 
459 } /* namespace glyf_impl */
460 } /* namespace OT */
461 
462 
463 #endif /* OT_GLYF_GLYPH_HH */
464