xref: /aosp_15_r20/external/harfbuzz_ng/src/OT/Layout/GPOS/GPOS.hh (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
1 #ifndef OT_LAYOUT_GPOS_GPOS_HH
2 #define OT_LAYOUT_GPOS_GPOS_HH
3 
4 #include "../../../hb-ot-layout-common.hh"
5 #include "../../../hb-ot-layout-gsubgpos.hh"
6 #include "Common.hh"
7 #include "PosLookup.hh"
8 
9 namespace OT {
10 
11 using Layout::GPOS_impl::PosLookup;
12 
13 namespace Layout {
14 
15 static void
16 propagate_attachment_offsets (hb_glyph_position_t *pos,
17                               unsigned int len,
18                               unsigned int i,
19                               hb_direction_t direction,
20                               unsigned nesting_level = HB_MAX_NESTING_LEVEL);
21 
22 /*
23  * GPOS -- Glyph Positioning
24  * https://docs.microsoft.com/en-us/typography/opentype/spec/gpos
25  */
26 
27 struct GPOS : GSUBGPOS
28 {
29   static constexpr hb_tag_t tableTag = HB_OT_TAG_GPOS;
30 
31   using Lookup = PosLookup;
32 
get_lookupOT::Layout::GPOS33   const PosLookup& get_lookup (unsigned int i) const
34   { return static_cast<const PosLookup &> (GSUBGPOS::get_lookup (i)); }
35 
36   static inline void position_start (hb_font_t *font, hb_buffer_t *buffer);
37   static inline void position_finish_advances (hb_font_t *font, hb_buffer_t *buffer);
38   static inline void position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer);
39 
subsetOT::Layout::GPOS40   bool subset (hb_subset_context_t *c) const
41   {
42     hb_subset_layout_context_t l (c, tableTag);
43     return GSUBGPOS::subset<PosLookup> (&l);
44   }
45 
sanitizeOT::Layout::GPOS46   bool sanitize (hb_sanitize_context_t *c) const
47   {
48     TRACE_SANITIZE (this);
49     return_trace (GSUBGPOS::sanitize<PosLookup> (c));
50   }
51 
52   HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
53                                    hb_face_t *face) const;
54 
collect_variation_indicesOT::Layout::GPOS55   void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
56   {
57     for (unsigned i = 0; i < GSUBGPOS::get_lookup_count (); i++)
58     {
59       if (!c->gpos_lookups->has (i)) continue;
60       const PosLookup &l = get_lookup (i);
61       l.dispatch (c);
62     }
63   }
64 
closure_lookupsOT::Layout::GPOS65   void closure_lookups (hb_face_t      *face,
66                         const hb_set_t *glyphs,
67                         hb_set_t       *lookup_indexes /* IN/OUT */) const
68   { GSUBGPOS::closure_lookups<PosLookup> (face, glyphs, lookup_indexes); }
69 
70   typedef GSUBGPOS::accelerator_t<GPOS> accelerator_t;
71 };
72 
73 
74 static void
propagate_attachment_offsets(hb_glyph_position_t * pos,unsigned int len,unsigned int i,hb_direction_t direction,unsigned nesting_level)75 propagate_attachment_offsets (hb_glyph_position_t *pos,
76                               unsigned int len,
77                               unsigned int i,
78                               hb_direction_t direction,
79                               unsigned nesting_level)
80 {
81   /* Adjusts offsets of attached glyphs (both cursive and mark) to accumulate
82    * offset of glyph they are attached to. */
83   int chain = pos[i].attach_chain(), type = pos[i].attach_type();
84   if (likely (!chain))
85     return;
86 
87   pos[i].attach_chain() = 0;
88 
89   unsigned int j = (int) i + chain;
90 
91   if (unlikely (j >= len))
92     return;
93 
94   if (unlikely (!nesting_level))
95     return;
96 
97   propagate_attachment_offsets (pos, len, j, direction, nesting_level - 1);
98 
99   assert (!!(type & GPOS_impl::ATTACH_TYPE_MARK) ^ !!(type & GPOS_impl::ATTACH_TYPE_CURSIVE));
100 
101   if (type & GPOS_impl::ATTACH_TYPE_CURSIVE)
102   {
103     if (HB_DIRECTION_IS_HORIZONTAL (direction))
104       pos[i].y_offset += pos[j].y_offset;
105     else
106       pos[i].x_offset += pos[j].x_offset;
107   }
108   else /*if (type & GPOS_impl::ATTACH_TYPE_MARK)*/
109   {
110     pos[i].x_offset += pos[j].x_offset;
111     pos[i].y_offset += pos[j].y_offset;
112 
113     assert (j < i);
114     if (HB_DIRECTION_IS_FORWARD (direction))
115       for (unsigned int k = j; k < i; k++) {
116         pos[i].x_offset -= pos[k].x_advance;
117         pos[i].y_offset -= pos[k].y_advance;
118       }
119     else
120       for (unsigned int k = j + 1; k < i + 1; k++) {
121         pos[i].x_offset += pos[k].x_advance;
122         pos[i].y_offset += pos[k].y_advance;
123       }
124   }
125 }
126 
127 void
position_start(hb_font_t * font HB_UNUSED,hb_buffer_t * buffer)128 GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
129 {
130   unsigned int count = buffer->len;
131   for (unsigned int i = 0; i < count; i++)
132     buffer->pos[i].attach_chain() = buffer->pos[i].attach_type() = 0;
133 }
134 
135 void
position_finish_advances(hb_font_t * font HB_UNUSED,hb_buffer_t * buffer HB_UNUSED)136 GPOS::position_finish_advances (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSED)
137 {
138   //_hb_buffer_assert_gsubgpos_vars (buffer);
139 }
140 
141 void
position_finish_offsets(hb_font_t * font,hb_buffer_t * buffer)142 GPOS::position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer)
143 {
144   _hb_buffer_assert_gsubgpos_vars (buffer);
145 
146   unsigned int len;
147   hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len);
148   hb_direction_t direction = buffer->props.direction;
149 
150   /* Handle attachments */
151   if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT)
152     for (unsigned i = 0; i < len; i++)
153       propagate_attachment_offsets (pos, len, i, direction);
154 
155   if (unlikely (font->slant))
156   {
157     for (unsigned i = 0; i < len; i++)
158       if (unlikely (pos[i].y_offset))
159         pos[i].x_offset += roundf (font->slant_xy * pos[i].y_offset);
160   }
161 }
162 
163 }
164 
165 struct GPOS_accelerator_t : Layout::GPOS::accelerator_t {
GPOS_accelerator_tOT::GPOS_accelerator_t166   GPOS_accelerator_t (hb_face_t *face) : Layout::GPOS::accelerator_t (face) {}
167 };
168 
169 }
170 
171 #endif  /* OT_LAYOUT_GPOS_GPOS_HH */
172