• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef OT_LAYOUT_GSUB_LIGATURE_HH
2 #define OT_LAYOUT_GSUB_LIGATURE_HH
3 
4 #include "Common.hh"
5 
6 namespace OT {
7 namespace Layout {
8 namespace GSUB_impl {
9 
10 template <typename Types>
11 struct Ligature
12 {
13   protected:
14   typename Types::HBGlyphID
15 		ligGlyph;               /* GlyphID of ligature to substitute */
16   HeadlessArrayOf<typename Types::HBGlyphID>
17 		component;              /* Array of component GlyphIDs--start
18                                          * with the second  component--ordered
19                                          * in writing direction */
20   public:
21   DEFINE_SIZE_ARRAY (Types::size + 2, component);
22 
sanitizeOT::Layout::GSUB_impl::Ligature23   bool sanitize (hb_sanitize_context_t *c) const
24   {
25     TRACE_SANITIZE (this);
26     return_trace (ligGlyph.sanitize (c) && component.sanitize (c));
27   }
28 
intersectsOT::Layout::GSUB_impl::Ligature29   bool intersects (const hb_set_t *glyphs) const
30   { return hb_all (component, glyphs); }
31 
closureOT::Layout::GSUB_impl::Ligature32   void closure (hb_closure_context_t *c) const
33   {
34     if (!intersects (c->glyphs)) return;
35     c->output->add (ligGlyph);
36   }
37 
collect_glyphsOT::Layout::GSUB_impl::Ligature38   void collect_glyphs (hb_collect_glyphs_context_t *c) const
39   {
40     c->input->add_array (component.arrayZ, component.get_length ());
41     c->output->add (ligGlyph);
42   }
43 
would_applyOT::Layout::GSUB_impl::Ligature44   bool would_apply (hb_would_apply_context_t *c) const
45   {
46     if (c->len != component.lenP1)
47       return false;
48 
49     for (unsigned int i = 1; i < c->len; i++)
50       if (likely (c->glyphs[i] != component[i]))
51         return false;
52 
53     return true;
54   }
55 
applyOT::Layout::GSUB_impl::Ligature56   bool apply (hb_ot_apply_context_t *c) const
57   {
58     TRACE_APPLY (this);
59     unsigned int count = component.lenP1;
60 
61     if (unlikely (!count)) return_trace (false);
62 
63     /* Special-case to make it in-place and not consider this
64      * as a "ligated" substitution. */
65     if (unlikely (count == 1))
66     {
67 
68       if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
69       {
70 	c->buffer->sync_so_far ();
71 	c->buffer->message (c->font,
72 			    "replacing glyph at %d (ligature substitution)",
73 			    c->buffer->idx);
74       }
75 
76       c->replace_glyph (ligGlyph);
77 
78       if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
79       {
80 	c->buffer->message (c->font,
81 			    "replaced glyph at %d (ligature substitution)",
82 			    c->buffer->idx - 1);
83       }
84 
85       return_trace (true);
86     }
87 
88     unsigned int total_component_count = 0;
89 
90     unsigned int match_end = 0;
91     unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
92 
93     if (likely (!match_input (c, count,
94                               &component[1],
95                               match_glyph,
96                               nullptr,
97                               &match_end,
98                               match_positions,
99                               &total_component_count)))
100     {
101       c->buffer->unsafe_to_concat (c->buffer->idx, match_end);
102       return_trace (false);
103     }
104 
105     unsigned pos = 0;
106     if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
107     {
108       unsigned delta = c->buffer->sync_so_far ();
109 
110       pos = c->buffer->idx;
111 
112       char buf[HB_MAX_CONTEXT_LENGTH * 16] = {0};
113       char *p = buf;
114 
115       match_end += delta;
116       for (unsigned i = 0; i < count; i++)
117       {
118 	match_positions[i] += delta;
119 	if (i)
120 	  *p++ = ',';
121 	snprintf (p, sizeof(buf) - (p - buf), "%u", match_positions[i]);
122 	p += strlen(p);
123       }
124 
125       c->buffer->message (c->font,
126 			  "ligating glyphs at %s",
127 			  buf);
128     }
129 
130     ligate_input (c,
131                   count,
132                   match_positions,
133                   match_end,
134                   ligGlyph,
135                   total_component_count);
136 
137     if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
138     {
139       c->buffer->sync_so_far ();
140       c->buffer->message (c->font,
141 			  "ligated glyph at %d",
142 			  pos);
143     }
144 
145     return_trace (true);
146   }
147 
148   template <typename Iterator,
149             hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
serializeOT::Layout::GSUB_impl::Ligature150   bool serialize (hb_serialize_context_t *c,
151                   hb_codepoint_t ligature,
152                   Iterator components /* Starting from second */)
153   {
154     TRACE_SERIALIZE (this);
155     if (unlikely (!c->extend_min (this))) return_trace (false);
156     ligGlyph = ligature;
157     if (unlikely (!component.serialize (c, components))) return_trace (false);
158     return_trace (true);
159   }
160 
subsetOT::Layout::GSUB_impl::Ligature161   bool subset (hb_subset_context_t *c, unsigned coverage_idx) const
162   {
163     TRACE_SUBSET (this);
164     const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
165     const hb_map_t &glyph_map = *c->plan->glyph_map;
166 
167     if (!intersects (&glyphset) || !glyphset.has (ligGlyph)) return_trace (false);
168     // Ensure Coverage table is always packed after this.
169     c->serializer->add_virtual_link (coverage_idx);
170 
171     auto it =
172       + hb_iter (component)
173       | hb_map (glyph_map)
174       ;
175 
176     auto *out = c->serializer->start_embed (*this);
177     return_trace (out->serialize (c->serializer,
178                                   glyph_map[ligGlyph],
179                                   it));  }
180 };
181 
182 
183 }
184 }
185 }
186 
187 #endif  /* OT_LAYOUT_GSUB_LIGATURE_HH */
188