• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef OT_LAYOUT_GPOS_MARKLIGPOSFORMAT1_HH
2 #define OT_LAYOUT_GPOS_MARKLIGPOSFORMAT1_HH
3 
4 #include "LigatureArray.hh"
5 
6 namespace OT {
7 namespace Layout {
8 namespace GPOS_impl {
9 
10 
11 template <typename Types>
12 struct MarkLigPosFormat1_2
13 {
14   protected:
15   HBUINT16      format;                 /* Format identifier--format = 1 */
16   typename Types::template OffsetTo<Coverage>
17                 markCoverage;           /* Offset to Mark Coverage table--from
18                                          * beginning of MarkLigPos subtable */
19   typename Types::template OffsetTo<Coverage>
20                 ligatureCoverage;       /* Offset to Ligature Coverage
21                                          * table--from beginning of MarkLigPos
22                                          * subtable */
23   HBUINT16      classCount;             /* Number of defined mark classes */
24   typename Types::template OffsetTo<MarkArray>
25                 markArray;              /* Offset to MarkArray table--from
26                                          * beginning of MarkLigPos subtable */
27   typename Types::template OffsetTo<LigatureArray>
28                 ligatureArray;          /* Offset to LigatureArray table--from
29                                          * beginning of MarkLigPos subtable */
30   public:
31   DEFINE_SIZE_STATIC (4 + 4 * Types::size);
32 
sanitizeOT::Layout::GPOS_impl::MarkLigPosFormat1_233   bool sanitize (hb_sanitize_context_t *c) const
34   {
35     TRACE_SANITIZE (this);
36     return_trace (c->check_struct (this) &&
37                   markCoverage.sanitize (c, this) &&
38                   ligatureCoverage.sanitize (c, this) &&
39                   markArray.sanitize (c, this) &&
40                   ligatureArray.sanitize (c, this, (unsigned int) classCount));
41   }
42 
intersectsOT::Layout::GPOS_impl::MarkLigPosFormat1_243   bool intersects (const hb_set_t *glyphs) const
44   {
45     return (this+markCoverage).intersects (glyphs) &&
46            (this+ligatureCoverage).intersects (glyphs);
47   }
48 
closure_lookupsOT::Layout::GPOS_impl::MarkLigPosFormat1_249   void closure_lookups (hb_closure_lookups_context_t *c) const {}
50 
collect_variation_indicesOT::Layout::GPOS_impl::MarkLigPosFormat1_251   void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
52   {
53     + hb_zip (this+markCoverage, this+markArray)
54     | hb_filter (c->glyph_set, hb_first)
55     | hb_map (hb_second)
56     | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+markArray)); })
57     ;
58 
59     hb_map_t klass_mapping;
60     Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, *c->glyph_set, &klass_mapping);
61 
62     unsigned ligcount = (this+ligatureArray).len;
63     auto lig_iter =
64     + hb_zip (this+ligatureCoverage, hb_range (ligcount))
65     | hb_filter (c->glyph_set, hb_first)
66     | hb_map (hb_second)
67     ;
68 
69     const LigatureArray& lig_array = this+ligatureArray;
70     for (const unsigned i : lig_iter)
71     {
72       hb_sorted_vector_t<unsigned> lig_indexes;
73       unsigned row_count = lig_array[i].rows;
74       for (unsigned row : + hb_range (row_count))
75       {
76         + hb_range ((unsigned) classCount)
77         | hb_filter (klass_mapping)
78         | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
79         | hb_sink (lig_indexes)
80         ;
81       }
82 
83       lig_array[i].collect_variation_indices (c, lig_indexes.iter ());
84     }
85   }
86 
collect_glyphsOT::Layout::GPOS_impl::MarkLigPosFormat1_287   void collect_glyphs (hb_collect_glyphs_context_t *c) const
88   {
89     if (unlikely (!(this+markCoverage).collect_coverage (c->input))) return;
90     if (unlikely (!(this+ligatureCoverage).collect_coverage (c->input))) return;
91   }
92 
get_coverageOT::Layout::GPOS_impl::MarkLigPosFormat1_293   const Coverage &get_coverage () const { return this+markCoverage; }
94 
applyOT::Layout::GPOS_impl::MarkLigPosFormat1_295   bool apply (hb_ot_apply_context_t *c) const
96   {
97     TRACE_APPLY (this);
98     hb_buffer_t *buffer = c->buffer;
99     unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
100     if (likely (mark_index == NOT_COVERED)) return_trace (false);
101 
102     /* Now we search backwards for a non-mark glyph */
103     hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
104     skippy_iter.reset (buffer->idx, 1);
105     skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
106     unsigned unsafe_from;
107     if (!skippy_iter.prev (&unsafe_from))
108     {
109       buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1);
110       return_trace (false);
111     }
112 
113     /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */
114     //if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { return_trace (false); }
115 
116     unsigned int j = skippy_iter.idx;
117     unsigned int lig_index = (this+ligatureCoverage).get_coverage  (buffer->info[j].codepoint);
118     if (lig_index == NOT_COVERED)
119     {
120       buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
121       return_trace (false);
122     }
123 
124     const LigatureArray& lig_array = this+ligatureArray;
125     const LigatureAttach& lig_attach = lig_array[lig_index];
126 
127     /* Find component to attach to */
128     unsigned int comp_count = lig_attach.rows;
129     if (unlikely (!comp_count))
130     {
131       buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
132       return_trace (false);
133     }
134 
135     /* We must now check whether the ligature ID of the current mark glyph
136      * is identical to the ligature ID of the found ligature.  If yes, we
137      * can directly use the component index.  If not, we attach the mark
138      * glyph to the last component of the ligature. */
139     unsigned int comp_index;
140     unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[j]);
141     unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur());
142     unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
143     if (lig_id && lig_id == mark_id && mark_comp > 0)
144       comp_index = hb_min (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1;
145     else
146       comp_index = comp_count - 1;
147 
148     return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j));
149   }
150 
subsetOT::Layout::GPOS_impl::MarkLigPosFormat1_2151   bool subset (hb_subset_context_t *c) const
152   {
153     TRACE_SUBSET (this);
154     const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
155     const hb_map_t &glyph_map = *c->plan->glyph_map;
156 
157     auto *out = c->serializer->start_embed (*this);
158     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
159     out->format = format;
160 
161     hb_map_t klass_mapping;
162     Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, glyphset, &klass_mapping);
163 
164     if (!klass_mapping.get_population ()) return_trace (false);
165     out->classCount = klass_mapping.get_population ();
166 
167     auto mark_iter =
168     + hb_zip (this+markCoverage, this+markArray)
169     | hb_filter (glyphset, hb_first)
170     ;
171 
172     auto new_mark_coverage =
173     + mark_iter
174     | hb_map_retains_sorting (hb_first)
175     | hb_map_retains_sorting (glyph_map)
176     ;
177 
178     if (!out->markCoverage.serialize_serialize (c->serializer, new_mark_coverage))
179       return_trace (false);
180 
181     out->markArray.serialize_subset (c, markArray, this,
182                                      (this+markCoverage).iter (),
183                                      &klass_mapping);
184 
185     auto new_ligature_coverage =
186     + hb_iter (this + ligatureCoverage)
187     | hb_filter (glyphset)
188     | hb_map_retains_sorting (glyph_map)
189     ;
190 
191     if (!out->ligatureCoverage.serialize_serialize (c->serializer, new_ligature_coverage))
192       return_trace (false);
193 
194     out->ligatureArray.serialize_subset (c, ligatureArray, this,
195                                          hb_iter (this+ligatureCoverage), classCount, &klass_mapping);
196 
197     return_trace (true);
198   }
199 
200 };
201 
202 }
203 }
204 }
205 
206 #endif /* OT_LAYOUT_GPOS_MARKLIGPOSFORMAT1_HH */
207