xref: /aosp_15_r20/external/harfbuzz_ng/src/OT/glyf/Glyph.hh (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
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 
11 
12 namespace OT {
13 
14 struct glyf_accelerator_t;
15 
16 namespace glyf_impl {
17 
18 
19 enum phantom_point_index_t
20 {
21   PHANTOM_LEFT   = 0,
22   PHANTOM_RIGHT  = 1,
23   PHANTOM_TOP    = 2,
24   PHANTOM_BOTTOM = 3,
25   PHANTOM_COUNT  = 4
26 };
27 
28 struct Glyph
29 {
30   enum glyph_type_t {
31     EMPTY,
32     SIMPLE,
33     COMPOSITE,
34   };
35 
36   public:
get_composite_iteratorOT::glyf_impl::Glyph37   composite_iter_t get_composite_iterator () const
38   {
39     if (type != COMPOSITE) return composite_iter_t ();
40     return CompositeGlyph (*header, bytes).iter ();
41   }
42 
trim_paddingOT::glyf_impl::Glyph43   const hb_bytes_t trim_padding () const
44   {
45     switch (type) {
46     case COMPOSITE: return CompositeGlyph (*header, bytes).trim_padding ();
47     case SIMPLE:    return SimpleGlyph (*header, bytes).trim_padding ();
48     case EMPTY:     return bytes;
49     default:        return bytes;
50     }
51   }
52 
drop_hintsOT::glyf_impl::Glyph53   void drop_hints ()
54   {
55     switch (type) {
56     case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints (); return;
57     case SIMPLE:    SimpleGlyph (*header, bytes).drop_hints (); return;
58     case EMPTY:     return;
59     }
60   }
61 
set_overlaps_flagOT::glyf_impl::Glyph62   void set_overlaps_flag ()
63   {
64     switch (type) {
65     case COMPOSITE: CompositeGlyph (*header, bytes).set_overlaps_flag (); return;
66     case SIMPLE:    SimpleGlyph (*header, bytes).set_overlaps_flag (); return;
67     case EMPTY:     return;
68     }
69   }
70 
drop_hints_bytesOT::glyf_impl::Glyph71   void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const
72   {
73     switch (type) {
74     case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints_bytes (dest_start); return;
75     case SIMPLE:    SimpleGlyph (*header, bytes).drop_hints_bytes (dest_start, dest_end); return;
76     case EMPTY:     return;
77     }
78   }
79 
is_compositeOT::glyf_impl::Glyph80   bool is_composite () const
81   { return type == COMPOSITE; }
82 
get_all_points_without_varOT::glyf_impl::Glyph83   bool get_all_points_without_var (const hb_face_t *face,
84                                    contour_point_vector_t &points /* OUT */) const
85   {
86     switch (type) {
87     case SIMPLE:
88       if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points)))
89         return false;
90       break;
91     case COMPOSITE:
92     {
93       for (auto &item : get_composite_iterator ())
94         if (unlikely (!item.get_points (points))) return false;
95       break;
96     }
97     case EMPTY:
98       break;
99     }
100 
101     /* Init phantom points */
102     if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false;
103     hb_array_t<contour_point_t> phantoms = points.as_array ().sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT);
104     {
105       int lsb = 0;
106       int h_delta = face->table.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb) ?
107                     (int) header->xMin - lsb : 0;
108       HB_UNUSED int tsb = 0;
109       int v_orig  = (int) header->yMax +
110 #ifndef HB_NO_VERTICAL
111                     ((void) face->table.vmtx->get_leading_bearing_without_var_unscaled (gid, &tsb), tsb)
112 #else
113                     0
114 #endif
115                     ;
116       unsigned h_adv = face->table.hmtx->get_advance_without_var_unscaled (gid);
117       unsigned v_adv =
118 #ifndef HB_NO_VERTICAL
119                        face->table.vmtx->get_advance_without_var_unscaled (gid)
120 #else
121                        - face->get_upem ()
122 #endif
123                        ;
124       phantoms[PHANTOM_LEFT].x = h_delta;
125       phantoms[PHANTOM_RIGHT].x = (int) h_adv + h_delta;
126       phantoms[PHANTOM_TOP].y = v_orig;
127       phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv;
128     }
129     return true;
130   }
131 
update_mtxOT::glyf_impl::Glyph132   void update_mtx (const hb_subset_plan_t *plan,
133                    int xMin, int xMax,
134                    int yMin, int yMax,
135                    const contour_point_vector_t &all_points) const
136   {
137     hb_codepoint_t new_gid = 0;
138     if (!plan->new_gid_for_old_gid (gid, &new_gid))
139       return;
140 
141     if (type != EMPTY)
142     {
143       plan->bounds_width_vec[new_gid] = xMax - xMin;
144       plan->bounds_height_vec[new_gid] = yMax - yMin;
145     }
146 
147     unsigned len = all_points.length;
148     float leftSideX = all_points[len - 4].x;
149     float rightSideX = all_points[len - 3].x;
150     float topSideY = all_points[len - 2].y;
151     float bottomSideY = all_points[len - 1].y;
152 
153     uint32_t hash = hb_hash (new_gid);
154 
155     signed hori_aw = roundf (rightSideX - leftSideX);
156     if (hori_aw < 0) hori_aw = 0;
157     int lsb = roundf (xMin - leftSideX);
158     plan->hmtx_map.set_with_hash (new_gid, hash, hb_pair ((unsigned) hori_aw, lsb));
159     //flag value should be computed using non-empty glyphs
160     if (type != EMPTY && lsb != xMin)
161       plan->head_maxp_info.allXMinIsLsb = false;
162 
163     signed vert_aw = roundf (topSideY - bottomSideY);
164     if (vert_aw < 0) vert_aw = 0;
165     int tsb = roundf (topSideY - yMax);
166     plan->vmtx_map.set_with_hash (new_gid, hash, hb_pair ((unsigned) vert_aw, tsb));
167   }
168 
compile_header_bytesOT::glyf_impl::Glyph169   bool compile_header_bytes (const hb_subset_plan_t *plan,
170                              const contour_point_vector_t &all_points,
171                              hb_bytes_t &dest_bytes /* OUT */) const
172   {
173     GlyphHeader *glyph_header = nullptr;
174     if (!plan->pinned_at_default && type != EMPTY && all_points.length >= 4)
175     {
176       glyph_header = (GlyphHeader *) hb_calloc (1, GlyphHeader::static_size);
177       if (unlikely (!glyph_header)) return false;
178     }
179 
180     float xMin = 0, xMax = 0;
181     float yMin = 0, yMax = 0;
182     if (all_points.length > 4)
183     {
184       xMin = xMax = all_points[0].x;
185       yMin = yMax = all_points[0].y;
186 
187       unsigned count = all_points.length - 4;
188       for (unsigned i = 1; i < count; i++)
189       {
190 	float x = all_points[i].x;
191 	float y = all_points[i].y;
192 	xMin = hb_min (xMin, x);
193 	xMax = hb_max (xMax, x);
194 	yMin = hb_min (yMin, y);
195 	yMax = hb_max (yMax, y);
196       }
197     }
198 
199 
200     // These are destined for storage in a 16 bit field to clamp the values to
201     // fit into a 16 bit signed integer.
202     int rounded_xMin = hb_clamp (roundf (xMin), -32768.0f, 32767.0f);
203     int rounded_xMax = hb_clamp (roundf (xMax), -32768.0f, 32767.0f);
204     int rounded_yMin = hb_clamp (roundf (yMin), -32768.0f, 32767.0f);
205     int rounded_yMax = hb_clamp (roundf (yMax), -32768.0f, 32767.0f);
206 
207     update_mtx (plan, rounded_xMin, rounded_xMax, rounded_yMin, rounded_yMax, all_points);
208 
209     if (type != EMPTY)
210     {
211       plan->head_maxp_info.xMin = hb_min (plan->head_maxp_info.xMin, rounded_xMin);
212       plan->head_maxp_info.yMin = hb_min (plan->head_maxp_info.yMin, rounded_yMin);
213       plan->head_maxp_info.xMax = hb_max (plan->head_maxp_info.xMax, rounded_xMax);
214       plan->head_maxp_info.yMax = hb_max (plan->head_maxp_info.yMax, rounded_yMax);
215     }
216 
217     /* when pinned at default, no need to compile glyph header
218      * and for empty glyphs: all_points only include phantom points.
219      * just update metrics and then return */
220     if (!glyph_header)
221       return true;
222 
223     glyph_header->numberOfContours = header->numberOfContours;
224 
225     glyph_header->xMin = rounded_xMin;
226     glyph_header->yMin = rounded_yMin;
227     glyph_header->xMax = rounded_xMax;
228     glyph_header->yMax = rounded_yMax;
229 
230     dest_bytes = hb_bytes_t ((const char *)glyph_header, GlyphHeader::static_size);
231     return true;
232   }
233 
compile_bytes_with_deltasOT::glyf_impl::Glyph234   bool compile_bytes_with_deltas (const hb_subset_plan_t *plan,
235                                   hb_font_t *font,
236                                   const glyf_accelerator_t &glyf,
237                                   hb_bytes_t &dest_start,  /* IN/OUT */
238                                   hb_bytes_t &dest_end /* OUT */)
239   {
240     contour_point_vector_t all_points, points_with_deltas;
241     unsigned composite_contours = 0;
242     head_maxp_info_t *head_maxp_info_p = &plan->head_maxp_info;
243     unsigned *composite_contours_p = &composite_contours;
244 
245     // don't compute head/maxp values when glyph has no contours(type is EMPTY)
246     // also ignore .notdef glyph when --notdef-outline is not enabled
247     if (type == EMPTY ||
248         (gid == 0 && !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)))
249     {
250       head_maxp_info_p = nullptr;
251       composite_contours_p = nullptr;
252     }
253 
254     if (!get_points (font, glyf, all_points, &points_with_deltas, head_maxp_info_p, composite_contours_p, false, false))
255       return false;
256 
257     // .notdef, set type to empty so we only update metrics and don't compile bytes for
258     // it
259     if (gid == 0 &&
260         !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
261     {
262       type = EMPTY;
263       dest_start = hb_bytes_t ();
264       dest_end = hb_bytes_t ();
265     }
266 
267     //dont compile bytes when pinned at default, just recalculate bounds
268     if (!plan->pinned_at_default)
269     {
270       switch (type)
271       {
272       case COMPOSITE:
273         if (!CompositeGlyph (*header, bytes).compile_bytes_with_deltas (dest_start,
274                                                                         points_with_deltas,
275                                                                         dest_end))
276           return false;
277         break;
278       case SIMPLE:
279         if (!SimpleGlyph (*header, bytes).compile_bytes_with_deltas (all_points,
280                                                                      plan->flags & HB_SUBSET_FLAGS_NO_HINTING,
281                                                                      dest_end))
282           return false;
283         break;
284       case EMPTY:
285         /* set empty bytes for empty glyph
286          * do not use source glyph's pointers */
287         dest_start = hb_bytes_t ();
288         dest_end = hb_bytes_t ();
289         break;
290       }
291     }
292 
293     if (!compile_header_bytes (plan, all_points, dest_start))
294     {
295       dest_end.fini ();
296       return false;
297     }
298     return true;
299   }
300 
301 
302   /* Note: Recursively calls itself.
303    * all_points includes phantom points
304    */
305   template <typename accelerator_t>
get_pointsOT::glyf_impl::Glyph306   bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator,
307 		   contour_point_vector_t &all_points /* OUT */,
308 		   contour_point_vector_t *points_with_deltas = nullptr, /* OUT */
309 		   head_maxp_info_t * head_maxp_info = nullptr, /* OUT */
310 		   unsigned *composite_contours = nullptr, /* OUT */
311 		   bool shift_points_hori = true,
312 		   bool use_my_metrics = true,
313 		   bool phantom_only = false,
314 		   hb_array_t<const int> coords = hb_array_t<const int> (),
315 		   hb_map_t *current_glyphs = nullptr,
316 		   unsigned int depth = 0,
317 		   unsigned *edge_count = nullptr) const
318   {
319     if (unlikely (depth > HB_MAX_NESTING_LEVEL)) return false;
320     unsigned stack_edge_count = 0;
321     if (!edge_count) edge_count = &stack_edge_count;
322     if (unlikely (*edge_count > HB_MAX_GRAPH_EDGE_COUNT)) return false;
323     (*edge_count)++;
324 
325     hb_map_t current_glyphs_stack;
326     if (current_glyphs == nullptr)
327       current_glyphs = &current_glyphs_stack;
328 
329     if (head_maxp_info)
330     {
331       head_maxp_info->maxComponentDepth = hb_max (head_maxp_info->maxComponentDepth, depth);
332     }
333 
334     if (!coords)
335       coords = hb_array (font->coords, font->num_coords);
336 
337     contour_point_vector_t stack_points;
338     contour_point_vector_t &points = type == SIMPLE ? all_points : stack_points;
339     unsigned old_length = points.length;
340 
341     switch (type) {
342     case SIMPLE:
343       if (depth == 0 && head_maxp_info)
344         head_maxp_info->maxContours = hb_max (head_maxp_info->maxContours, (unsigned) header->numberOfContours);
345       if (depth > 0 && composite_contours)
346         *composite_contours += (unsigned) header->numberOfContours;
347       if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (all_points, phantom_only)))
348 	return false;
349       break;
350     case COMPOSITE:
351     {
352       for (auto &item : get_composite_iterator ())
353         if (unlikely (!item.get_points (points))) return false;
354       break;
355     }
356     case EMPTY:
357       break;
358     }
359 
360     /* Init phantom points */
361     if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false;
362     hb_array_t<contour_point_t> phantoms = points.as_array ().sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT);
363     {
364       int lsb = 0;
365       int h_delta = glyf_accelerator.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb) ?
366 		    (int) header->xMin - lsb : 0;
367       HB_UNUSED int tsb = 0;
368       int v_orig  = (int) header->yMax +
369 #ifndef HB_NO_VERTICAL
370 		    ((void) glyf_accelerator.vmtx->get_leading_bearing_without_var_unscaled (gid, &tsb), tsb)
371 #else
372 		    0
373 #endif
374 		    ;
375       unsigned h_adv = glyf_accelerator.hmtx->get_advance_without_var_unscaled (gid);
376       unsigned v_adv =
377 #ifndef HB_NO_VERTICAL
378 		       glyf_accelerator.vmtx->get_advance_without_var_unscaled (gid)
379 #else
380 		       - font->face->get_upem ()
381 #endif
382 		       ;
383       phantoms[PHANTOM_LEFT].x = h_delta;
384       phantoms[PHANTOM_RIGHT].x = (int) h_adv + h_delta;
385       phantoms[PHANTOM_TOP].y = v_orig;
386       phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv;
387     }
388 
389 #ifndef HB_NO_VAR
390     if (coords)
391       glyf_accelerator.gvar->apply_deltas_to_points (gid,
392 						     coords,
393 						     points.as_array ().sub_array (old_length),
394 						     phantom_only && type == SIMPLE);
395 #endif
396 
397     // mainly used by CompositeGlyph calculating new X/Y offset value so no need to extend it
398     // with child glyphs' points
399     if (points_with_deltas != nullptr && depth == 0 && type == COMPOSITE)
400     {
401       if (unlikely (!points_with_deltas->resize (points.length))) return false;
402       *points_with_deltas = points;
403     }
404 
405     switch (type) {
406     case SIMPLE:
407       if (depth == 0 && head_maxp_info)
408         head_maxp_info->maxPoints = hb_max (head_maxp_info->maxPoints, all_points.length - old_length - 4);
409       break;
410     case COMPOSITE:
411     {
412       unsigned int comp_index = 0;
413       for (auto &item : get_composite_iterator ())
414       {
415 	hb_codepoint_t item_gid = item.get_gid ();
416 
417         if (unlikely (current_glyphs->has (item_gid)))
418 	  continue;
419 
420 	current_glyphs->add (item_gid);
421 
422 	unsigned old_count = all_points.length;
423 
424 	if (unlikely ((!phantom_only || (use_my_metrics && item.is_use_my_metrics ())) &&
425 		      !glyf_accelerator.glyph_for_gid (item_gid)
426 				       .get_points (font,
427 						    glyf_accelerator,
428 						    all_points,
429 						    points_with_deltas,
430 						    head_maxp_info,
431 						    composite_contours,
432 						    shift_points_hori,
433 						    use_my_metrics,
434 						    phantom_only,
435 						    coords,
436 						    current_glyphs,
437 						    depth + 1,
438 						    edge_count)))
439 	{
440 	  current_glyphs->del (item_gid);
441 	  return false;
442 	}
443 
444 	auto comp_points = all_points.as_array ().sub_array (old_count);
445 
446 	/* Copy phantom points from component if USE_MY_METRICS flag set */
447 	if (use_my_metrics && item.is_use_my_metrics ())
448 	  for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
449 	    phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
450 
451 	if (comp_points) // Empty in case of phantom_only
452 	{
453 	  float matrix[4];
454 	  contour_point_t default_trans;
455 	  item.get_transformation (matrix, default_trans);
456 
457 	  /* Apply component transformation & translation (with deltas applied) */
458 	  item.transform_points (comp_points, matrix, points[comp_index]);
459 	}
460 
461 	if (item.is_anchored () && !phantom_only)
462 	{
463 	  unsigned int p1, p2;
464 	  item.get_anchor_points (p1, p2);
465 	  if (likely (p1 < all_points.length && p2 < comp_points.length))
466 	  {
467 	    contour_point_t delta;
468 	    delta.init (all_points[p1].x - comp_points[p2].x,
469 			all_points[p1].y - comp_points[p2].y);
470 
471 	    item.translate (delta, comp_points);
472 	  }
473 	}
474 
475 	all_points.resize (all_points.length - PHANTOM_COUNT);
476 
477 	if (all_points.length > HB_GLYF_MAX_POINTS)
478 	{
479 	  current_glyphs->del (item_gid);
480 	  return false;
481 	}
482 
483 	comp_index++;
484         current_glyphs->del (item_gid);
485       }
486 
487       if (head_maxp_info && depth == 0)
488       {
489         if (composite_contours)
490           head_maxp_info->maxCompositeContours = hb_max (head_maxp_info->maxCompositeContours, *composite_contours);
491         head_maxp_info->maxCompositePoints = hb_max (head_maxp_info->maxCompositePoints, all_points.length);
492         head_maxp_info->maxComponentElements = hb_max (head_maxp_info->maxComponentElements, comp_index);
493       }
494       all_points.extend (phantoms);
495     } break;
496     case EMPTY:
497       all_points.extend (phantoms);
498       break;
499     }
500 
501     if (depth == 0 && shift_points_hori) /* Apply at top level */
502     {
503       /* Undocumented rasterizer behavior:
504        * Shift points horizontally by the updated left side bearing
505        */
506       float v = -phantoms[PHANTOM_LEFT].x;
507       if (v)
508         for (auto &point : all_points)
509 	  point.x += v;
510     }
511 
512     return !all_points.in_error ();
513   }
514 
get_extents_without_var_scaledOT::glyf_impl::Glyph515   bool get_extents_without_var_scaled (hb_font_t *font, const glyf_accelerator_t &glyf_accelerator,
516 				       hb_glyph_extents_t *extents) const
517   {
518     if (type == EMPTY) return true; /* Empty glyph; zero extents. */
519     return header->get_extents_without_var_scaled (font, glyf_accelerator, gid, extents);
520   }
521 
get_bytesOT::glyf_impl::Glyph522   hb_bytes_t get_bytes () const { return bytes; }
get_typeOT::glyf_impl::Glyph523   glyph_type_t get_type () const { return type; }
get_headerOT::glyf_impl::Glyph524   const GlyphHeader *get_header () const { return header; }
525 
GlyphOT::glyf_impl::Glyph526   Glyph () : bytes (),
527              header (bytes.as<GlyphHeader> ()),
528              gid (-1),
529              type(EMPTY)
530   {}
531 
GlyphOT::glyf_impl::Glyph532   Glyph (hb_bytes_t bytes_,
533 	 hb_codepoint_t gid_ = (unsigned) -1) : bytes (bytes_),
534                                                 header (bytes.as<GlyphHeader> ()),
535                                                 gid (gid_)
536   {
537     int num_contours = header->numberOfContours;
538     if (unlikely (num_contours == 0)) type = EMPTY;
539     else if (num_contours > 0) type = SIMPLE;
540     else if (num_contours <= -1) type = COMPOSITE;
541     else type = EMPTY; // Spec deviation; Spec says COMPOSITE, but not seen in the wild.
542   }
543 
544   protected:
545   hb_bytes_t bytes;
546   const GlyphHeader *header;
547   hb_codepoint_t gid;
548   glyph_type_t type;
549 };
550 
551 
552 } /* namespace glyf_impl */
553 } /* namespace OT */
554 
555 
556 #endif /* OT_GLYF_GLYPH_HH */
557