[HB] More buffer cleanup
[framework/uifw/harfbuzz.git] / src / hb-ot-layout-gpos-private.h
1 /*
2  * Copyright (C) 2007,2008,2009  Red Hat, Inc.
3  *
4  *  This is part of HarfBuzz, an OpenType Layout engine library.
5  *
6  * Permission is hereby granted, without written agreement and without
7  * license or royalty fees, to use, copy, modify, and distribute this
8  * software and its documentation for any purpose, provided that the
9  * above copyright notice and the following two paragraphs appear in
10  * all copies of this software.
11  *
12  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16  * DAMAGE.
17  *
18  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
21  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23  *
24  * Red Hat Author(s): Behdad Esfahbod
25  */
26
27 #ifndef HB_OT_LAYOUT_GPOS_PRIVATE_H
28 #define HB_OT_LAYOUT_GPOS_PRIVATE_H
29
30 #include "hb-ot-layout-gsubgpos-private.h"
31
32 #define HB_OT_LAYOUT_GPOS_NO_LAST ((unsigned int) -1)
33
34 /* Shared Tables: ValueRecord, Anchor Table, and MarkArray */
35
36 typedef SHORT Value;
37 typedef Value ValueRecord[];
38
39 struct ValueFormat : USHORT
40 {
41   enum
42   {
43     xPlacement  = 0x0001,       /* Includes horizontal adjustment for placement */
44     yPlacement  = 0x0002,       /* Includes vertical adjustment for placement */
45     xAdvance    = 0x0004,       /* Includes horizontal adjustment for advance */
46     yAdvance    = 0x0008,       /* Includes vertical adjustment for advance */
47     xPlaDevice  = 0x0010,       /* Includes horizontal Device table for placement */
48     yPlaDevice  = 0x0020,       /* Includes vertical Device table for placement */
49     xAdvDevice  = 0x0040,       /* Includes horizontal Device table for advance */
50     yAdvDevice  = 0x0080,       /* Includes vertical Device table for advance */
51     reserved    = 0xF000,       /* For future use */
52   };
53
54   inline unsigned int get_len () const
55   {
56     return _hb_popcount32 ((unsigned int) *this);
57   }
58
59   const void apply_value (hb_ot_layout_t      *layout,
60                           const char          *base,
61                           const Value         *values,
62                           hb_glyph_position_t *glyph_pos) const
63   {
64     unsigned int x_ppem, y_ppem;
65     hb_16dot16_t x_scale, y_scale;
66     unsigned int pixel_value;
67     unsigned int format = *this;
68
69     if (!format)
70       return;
71
72     /* All fields are options.  Only those available advance the value
73      * pointer. */
74 #if 0
75 struct ValueRecord {
76   SHORT         xPlacement;             /* Horizontal adjustment for
77                                          * placement--in design units */
78   SHORT         yPlacement;             /* Vertical adjustment for
79                                          * placement--in design units */
80   SHORT         xAdvance;               /* Horizontal adjustment for
81                                          * advance--in design units (only used
82                                          * for horizontal writing) */
83   SHORT         yAdvance;               /* Vertical adjustment for advance--in
84                                          * design units (only used for vertical
85                                          * writing) */
86   Offset        xPlaDevice;             /* Offset to Device table for
87                                          * horizontal placement--measured from
88                                          * beginning of PosTable (may be NULL) */
89   Offset        yPlaDevice;             /* Offset to Device table for vertical
90                                          * placement--measured from beginning
91                                          * of PosTable (may be NULL) */
92   Offset        xAdvDevice;             /* Offset to Device table for
93                                          * horizontal advance--measured from
94                                          * beginning of PosTable (may be NULL) */
95   Offset        yAdvDevice;             /* Offset to Device table for vertical
96                                          * advance--measured from beginning of
97                                          * PosTable (may be NULL) */
98 };
99 #endif
100
101     x_scale = layout->gpos_info.x_scale;
102     y_scale = layout->gpos_info.y_scale;
103     /* design units -> fractional pixel */
104     if (format & xPlacement)
105       glyph_pos->x_pos += x_scale * *(USHORT*)values++ / 0x10000;
106     if (format & yPlacement)
107       glyph_pos->y_pos += y_scale * *(USHORT*)values++ / 0x10000;
108     if (format & xAdvance)
109       glyph_pos->x_advance += x_scale * *(USHORT*)values++ / 0x10000;
110     if (format & yAdvance)
111       glyph_pos->y_advance += y_scale * *(USHORT*)values++ / 0x10000;
112
113     if (HB_LIKELY (!layout->gpos_info.dvi))
114     {
115       x_ppem = layout->gpos_info.x_ppem;
116       y_ppem = layout->gpos_info.y_ppem;
117       /* pixel -> fractional pixel */
118       if (format & xPlaDevice)
119         glyph_pos->x_pos += (base+*(OffsetTo<Device>*)values++).get_delta (x_ppem) << 6;
120       if (format & yPlaDevice)
121         glyph_pos->y_pos += (base+*(OffsetTo<Device>*)values++).get_delta (y_ppem) << 6;
122       if (format & xAdvDevice)
123         glyph_pos->x_advance += (base+*(OffsetTo<Device>*)values++).get_delta (x_ppem) << 6;
124       if (format & yAdvDevice)
125         glyph_pos->y_advance += (base+*(OffsetTo<Device>*)values++).get_delta (y_ppem) << 6;
126     }
127   }
128 };
129 ASSERT_SIZE (ValueFormat, 2);
130
131
132 struct AnchorFormat1
133 {
134   friend struct Anchor;
135
136   private:
137   inline void get_anchor (hb_ot_layout_t *layout, hb_codepoint_t glyph_id,
138                           hb_position_t *x, hb_position_t *y) const
139   {
140       *x = layout->gpos_info.x_scale * xCoordinate / 0x10000;
141       *y = layout->gpos_info.y_scale * yCoordinate / 0x10000;
142   }
143
144   private:
145   USHORT        format;                 /* Format identifier--format = 1 */
146   SHORT         xCoordinate;            /* Horizontal value--in design units */
147   SHORT         yCoordinate;            /* Vertical value--in design units */
148 };
149 ASSERT_SIZE (AnchorFormat1, 6);
150
151 struct AnchorFormat2
152 {
153   friend struct Anchor;
154
155   private:
156   inline void get_anchor (hb_ot_layout_t *layout, hb_codepoint_t glyph_id,
157                           hb_position_t *x, hb_position_t *y) const
158   {
159       /* TODO Contour */
160       *x = layout->gpos_info.x_scale * xCoordinate / 0x10000;
161       *y = layout->gpos_info.y_scale * yCoordinate / 0x10000;
162   }
163
164   private:
165   USHORT        format;                 /* Format identifier--format = 2 */
166   SHORT         xCoordinate;            /* Horizontal value--in design units */
167   SHORT         yCoordinate;            /* Vertical value--in design units */
168   USHORT        anchorPoint;            /* Index to glyph contour point */
169 };
170 ASSERT_SIZE (AnchorFormat2, 8);
171
172 struct AnchorFormat3
173 {
174   friend struct Anchor;
175
176   private:
177   inline void get_anchor (hb_ot_layout_t *layout, hb_codepoint_t glyph_id,
178                           hb_position_t *x, hb_position_t *y) const
179   {
180       *x = layout->gpos_info.x_scale * xCoordinate / 0x10000;
181       *y = layout->gpos_info.y_scale * yCoordinate / 0x10000;
182
183       if (!layout->gpos_info.dvi)
184       {
185         *x += (this+xDeviceTable).get_delta (layout->gpos_info.x_ppem) << 6;
186         *y += (this+yDeviceTable).get_delta (layout->gpos_info.y_ppem) << 6;
187       }
188   }
189
190   private:
191   USHORT        format;                 /* Format identifier--format = 3 */
192   SHORT         xCoordinate;            /* Horizontal value--in design units */
193   SHORT         yCoordinate;            /* Vertical value--in design units */
194   OffsetTo<Device>
195                 xDeviceTable;           /* Offset to Device table for X
196                                          * coordinate-- from beginning of
197                                          * Anchor table (may be NULL) */
198   OffsetTo<Device>
199                 yDeviceTable;           /* Offset to Device table for Y
200                                          * coordinate-- from beginning of
201                                          * Anchor table (may be NULL) */
202 };
203 ASSERT_SIZE (AnchorFormat3, 10);
204
205 struct Anchor
206 {
207   inline void get_anchor (hb_ot_layout_t *layout, hb_codepoint_t glyph_id,
208                           hb_position_t *x, hb_position_t *y) const
209   {
210     *x = *y = 0;
211     switch (u.format) {
212     case 1: u.format1->get_anchor (layout, glyph_id, x, y); return;
213     case 2: u.format2->get_anchor (layout, glyph_id, x, y); return;
214     case 3: u.format3->get_anchor (layout, glyph_id, x, y); return;
215     default:                                                return;
216     }
217   }
218
219   private:
220   union {
221   USHORT                format;         /* Format identifier */
222   AnchorFormat1         format1[];
223   AnchorFormat2         format2[];
224   AnchorFormat3         format3[];
225   } u;
226 };
227 ASSERT_SIZE (Anchor, 2);
228
229
230 struct MarkRecord
231 {
232   friend struct MarkArray;
233
234   private:
235   USHORT        klass;                  /* Class defined for this mark */
236   OffsetTo<Anchor>
237                 markAnchor;             /* Offset to Anchor table--from
238                                          * beginning of MarkArray table */
239 };
240 ASSERT_SIZE (MarkRecord, 4);
241
242 struct MarkArray
243 {
244   inline unsigned int get_class (unsigned int index) const { return markRecord[index].klass; }
245   inline const Anchor& get_anchor (unsigned int index) const { return this+markRecord[index].markAnchor; }
246
247   private:
248   ArrayOf<MarkRecord>
249                 markRecord;     /* Array of MarkRecords--in Coverage order */
250 };
251 ASSERT_SIZE (MarkArray, 2);
252
253
254 /* Lookups */
255
256 struct SinglePosFormat1
257 {
258   friend struct SinglePos;
259
260   private:
261   inline bool apply (APPLY_ARG_DEF) const
262   {
263     unsigned int index = (this+coverage) (IN_CURGLYPH ());
264     if (HB_LIKELY (index == NOT_COVERED))
265       return false;
266
267     valueFormat.apply_value (layout, (const char *) this, values, CURPOSITION ());
268     return true;
269   }
270
271   private:
272   USHORT        format;                 /* Format identifier--format = 1 */
273   OffsetTo<Coverage>
274                 coverage;               /* Offset to Coverage table--from
275                                          * beginning of subtable */
276   ValueFormat   valueFormat;            /* Defines the types of data in the
277                                          * ValueRecord */
278   ValueRecord   values;                 /* Defines positioning
279                                          * value(s)--applied to all glyphs in
280                                          * the Coverage table */
281 };
282 ASSERT_SIZE (SinglePosFormat1, 6);
283
284 struct SinglePosFormat2
285 {
286   friend struct SinglePos;
287
288   private:
289   inline bool apply (APPLY_ARG_DEF) const
290   {
291     unsigned int index = (this+coverage) (IN_CURGLYPH ());
292     if (HB_LIKELY (index == NOT_COVERED))
293       return false;
294
295     if (HB_LIKELY (index >= valueCount))
296       return false;
297
298     valueFormat.apply_value (layout, (const char *) this,
299                              values + index * valueFormat.get_len (),
300                              CURPOSITION ());
301     return true;
302   }
303
304   private:
305   USHORT        format;                 /* Format identifier--format = 2 */
306   OffsetTo<Coverage>
307                 coverage;               /* Offset to Coverage table--from
308                                          * beginning of subtable */
309   ValueFormat   valueFormat;            /* Defines the types of data in the
310                                          * ValueRecord */
311   USHORT        valueCount;             /* Number of ValueRecords */
312   ValueRecord   values;                 /* Array of ValueRecords--positioning
313                                          * values applied to glyphs */
314 };
315 ASSERT_SIZE (SinglePosFormat2, 8);
316
317 struct SinglePos
318 {
319   friend struct PosLookupSubTable;
320
321   private:
322   inline bool apply (APPLY_ARG_DEF) const
323   {
324     switch (u.format) {
325     case 1: return u.format1->apply (APPLY_ARG);
326     case 2: return u.format2->apply (APPLY_ARG);
327     default:return false;
328     }
329   }
330
331   private:
332   union {
333   USHORT                format;         /* Format identifier */
334   SinglePosFormat1      format1[];
335   SinglePosFormat2      format2[];
336   } u;
337 };
338 ASSERT_SIZE (SinglePos, 2);
339
340
341 struct PairValueRecord
342 {
343   friend struct PairPosFormat1;
344
345   private:
346   GlyphID       secondGlyph;            /* GlyphID of second glyph in the
347                                          * pair--first glyph is listed in the
348                                          * Coverage table */
349   ValueRecord   values;                 /* Positioning data for the first glyph
350                                          * followed by for second glyph */
351 };
352 ASSERT_SIZE (PairValueRecord, 2);
353
354 struct PairSet
355 {
356   friend struct PairPosFormat1;
357
358   private:
359   USHORT        len;                    /* Number of PairValueRecords */
360   /* XXX */
361   PairValueRecord
362                 array[];                /* Array of PairValueRecords--ordered
363                                          * by GlyphID of the second glyph */
364 };
365 ASSERT_SIZE (PairSet, 2);
366
367 struct PairPosFormat1
368 {
369   friend struct PairPos;
370
371   private:
372   inline bool apply (APPLY_ARG_DEF) const
373   {
374     unsigned int end = MIN (buffer->in_length, buffer->in_pos + context_length);
375     if (HB_UNLIKELY (buffer->in_pos + 2 > end))
376       return false;
377
378     unsigned int index = (this+coverage) (IN_CURGLYPH ());
379     if (HB_LIKELY (index == NOT_COVERED))
380       return false;
381
382     unsigned int j = buffer->in_pos + 1;
383     while (!_hb_ot_layout_check_glyph_property (layout, IN_INFO (j), lookup_flag, &property))
384     {
385       if (HB_UNLIKELY (j == end))
386         return false;
387       j++;
388     }
389
390     const PairSet &pair_set = this+pairSet[index];
391
392     unsigned int len1 = valueFormat1.get_len ();
393     unsigned int len2 = valueFormat2.get_len ();
394     unsigned int record_len = 1 + len1 + len2;
395
396     unsigned int count = pair_set.len;
397     const PairValueRecord *record = pair_set.array;
398     for (unsigned int i = 0; i < count; i++)
399     {
400       if (IN_GLYPH (j) == record->secondGlyph)
401       {
402         valueFormat1.apply_value (layout, (const char *) this, record->values, CURPOSITION ());
403         valueFormat2.apply_value (layout, (const char *) this, record->values + len1, POSITION (j));
404         if (len2)
405           j++;
406         buffer->in_pos = j;
407         return true;
408       }
409       record += record_len;
410     }
411
412     return false;
413   }
414
415   private:
416   USHORT        format;                 /* Format identifier--format = 1 */
417   OffsetTo<Coverage>
418                 coverage;               /* Offset to Coverage table--from
419                                          * beginning of subtable */
420   ValueFormat   valueFormat1;           /* Defines the types of data in
421                                          * ValueRecord1--for the first glyph
422                                          * in the pair--may be zero (0) */
423   ValueFormat   valueFormat2;           /* Defines the types of data in
424                                          * ValueRecord2--for the second glyph
425                                          * in the pair--may be zero (0) */
426   OffsetArrayOf<PairSet>
427                 pairSet;                /* Array of PairSet tables
428                                          * ordered by Coverage Index */
429 };
430 ASSERT_SIZE (PairPosFormat1, 10);
431
432 struct PairPosFormat2
433 {
434   friend struct PairPos;
435
436   private:
437   inline bool apply (APPLY_ARG_DEF) const
438   {
439     unsigned int end = MIN (buffer->in_length, buffer->in_pos + context_length);
440     if (HB_UNLIKELY (buffer->in_pos + 2 > end))
441       return false;
442
443     unsigned int index = (this+coverage) (IN_CURGLYPH ());
444     if (HB_LIKELY (index == NOT_COVERED))
445       return false;
446
447     unsigned int j = buffer->in_pos + 1;
448     while (!_hb_ot_layout_check_glyph_property (layout, IN_INFO (j), lookup_flag, &property))
449     {
450       if (HB_UNLIKELY (j == end))
451         return false;
452       j++;
453     }
454
455     unsigned int len1 = valueFormat1.get_len ();
456     unsigned int len2 = valueFormat2.get_len ();
457     unsigned int record_len = len1 + len2;
458
459     unsigned int klass1 = (this+classDef1) (IN_CURGLYPH ());
460     unsigned int klass2 = (this+classDef2) (IN_GLYPH (j));
461     if (HB_UNLIKELY (klass1 >= class1Count || klass2 >= class2Count))
462       return false;
463
464     const Value *v = values + record_len * (klass1 * class2Count + klass2);
465     valueFormat1.apply_value (layout, (const char *) this, v, CURPOSITION ());
466     valueFormat2.apply_value (layout, (const char *) this, v + len1, POSITION (j));
467
468     if (len2)
469       j++;
470     buffer->in_pos = j;
471
472     return true;
473   }
474
475
476   private:
477   USHORT        format;                 /* Format identifier--format = 2 */
478   OffsetTo<Coverage>
479                 coverage;               /* Offset to Coverage table--from
480                                          * beginning of subtable */
481   ValueFormat   valueFormat1;           /* ValueRecord definition--for the
482                                          * first glyph of the pair--may be zero
483                                          * (0) */
484   ValueFormat   valueFormat2;           /* ValueRecord definition--for the
485                                          * second glyph of the pair--may be
486                                          * zero (0) */
487   OffsetTo<ClassDef>
488                 classDef1;              /* Offset to ClassDef table--from
489                                          * beginning of PairPos subtable--for
490                                          * the first glyph of the pair */
491   OffsetTo<ClassDef>
492                 classDef2;              /* Offset to ClassDef table--from
493                                          * beginning of PairPos subtable--for
494                                          * the second glyph of the pair */
495   USHORT        class1Count;            /* Number of classes in ClassDef1
496                                          * table--includes Class0 */
497   USHORT        class2Count;            /* Number of classes in ClassDef2
498                                          * table--includes Class0 */
499   ValueRecord   values;                 /* Matrix of value pairs:
500                                          * class1-major, class2-minor,
501                                          * Each entry has value1 and value2 */
502 };
503 ASSERT_SIZE (PairPosFormat2, 16);
504
505 struct PairPos
506 {
507   friend struct PosLookupSubTable;
508
509   private:
510   inline bool apply (APPLY_ARG_DEF) const
511   {
512     switch (u.format) {
513     case 1: return u.format1->apply (APPLY_ARG);
514     case 2: return u.format2->apply (APPLY_ARG);
515     default:return false;
516     }
517   }
518
519   private:
520   union {
521   USHORT                format;         /* Format identifier */
522   PairPosFormat1        format1[];
523   PairPosFormat2        format2[];
524   } u;
525 };
526 ASSERT_SIZE (PairPos, 2);
527
528
529 struct EntryExitRecord
530 {
531   OffsetTo<Anchor>
532                 entryAnchor;            /* Offset to EntryAnchor table--from
533                                          * beginning of CursivePos
534                                          * subtable--may be NULL */
535   OffsetTo<Anchor>
536                 exitAnchor;             /* Offset to ExitAnchor table--from
537                                          * beginning of CursivePos
538                                          * subtable--may be NULL */
539 };
540 ASSERT_SIZE (EntryExitRecord, 4);
541
542 struct CursivePosFormat1
543 {
544   friend struct CursivePos;
545
546   private:
547   inline bool apply (APPLY_ARG_DEF) const
548   {
549     /* Now comes the messiest part of the whole OpenType
550        specification.  At first glance, cursive connections seem easy
551        to understand, but there are pitfalls!  The reason is that
552        the specs don't mention how to compute the advance values
553        resp. glyph offsets.  I was told it would be an omission, to
554        be fixed in the next OpenType version...  Again many thanks to
555        Andrei Burago <andreib@microsoft.com> for clarifications.
556
557        Consider the following example:
558
559                         |  xadv1    |
560                          +---------+
561                          |         |
562                    +-----+--+ 1    |
563                    |     | .|      |
564                    |    0+--+------+
565                    |   2    |
566                    |        |
567                   0+--------+
568                   |  xadv2   |
569
570          glyph1: advance width = 12
571                  anchor point = (3,1)
572
573          glyph2: advance width = 11
574                  anchor point = (9,4)
575
576          LSB is 1 for both glyphs (so the boxes drawn above are glyph
577          bboxes).  Writing direction is R2L; `0' denotes the glyph's
578          coordinate origin.
579
580        Now the surprising part: The advance width of the *left* glyph
581        (resp. of the *bottom* glyph) will be modified, no matter
582        whether the writing direction is L2R or R2L (resp. T2B or
583        B2T)!  This assymetry is caused by the fact that the glyph's
584        coordinate origin is always the lower left corner for all
585        writing directions.
586
587        Continuing the above example, we can compute the new
588        (horizontal) advance width of glyph2 as
589
590          9 - 3 = 6  ,
591
592        and the new vertical offset of glyph2 as
593
594          1 - 4 = -3  .
595
596
597        Vertical writing direction is far more complicated:
598
599        a) Assuming that we recompute the advance height of the lower glyph:
600
601                                     --
602                          +---------+
603                 --       |         |
604                    +-----+--+ 1    | yadv1
605                    |     | .|      |
606              yadv2 |    0+--+------+        -- BSB1  --
607                    |   2    |       --      --        y_offset
608                    |        |
609      BSB2 --      0+--------+                        --
610           --    --
611
612          glyph1: advance height = 6
613                  anchor point = (3,1)
614
615          glyph2: advance height = 7
616                  anchor point = (9,4)
617
618          TSB is 1 for both glyphs; writing direction is T2B.
619
620
621            BSB1     = yadv1 - (TSB1 + ymax1)
622            BSB2     = yadv2 - (TSB2 + ymax2)
623            y_offset = y2 - y1
624
625          vertical advance width of glyph2
626            = y_offset + BSB2 - BSB1
627            = (y2 - y1) + (yadv2 - (TSB2 + ymax2)) - (yadv1 - (TSB1 + ymax1))
628            = y2 - y1 + yadv2 - TSB2 - ymax2 - (yadv1 - TSB1 - ymax1)
629            = y2 - y1 + yadv2 - TSB2 - ymax2 - yadv1 + TSB1 + ymax1
630
631
632        b) Assuming that we recompute the advance height of the upper glyph:
633
634                                     --      --
635                          +---------+        -- TSB1
636           --    --       |         |
637      TSB2 --       +-----+--+ 1    | yadv1   ymax1
638                    |     | .|      |
639              yadv2 |    0+--+------+        --       --
640       ymax2        |   2    |       --                y_offset
641                    |        |
642           --      0+--------+                        --
643                 --
644
645          glyph1: advance height = 6
646                  anchor point = (3,1)
647
648          glyph2: advance height = 7
649                  anchor point = (9,4)
650
651          TSB is 1 for both glyphs; writing direction is T2B.
652
653          y_offset = y2 - y1
654
655          vertical advance width of glyph2
656            = TSB1 + ymax1 + y_offset - (TSB2 + ymax2)
657            = TSB1 + ymax1 + y2 - y1 - TSB2 - ymax2
658
659
660        Comparing a) with b) shows that b) is easier to compute.  I'll wait
661        for a reply from Andrei to see what should really be implemented...
662
663        Since horizontal advance widths or vertical advance heights
664        can be used alone but not together, no ambiguity occurs.        */
665
666     struct hb_ot_layout_t::gpos_info_t *gpi = &layout->gpos_info;
667     hb_codepoint_t last_pos = gpi->last;
668     gpi->last = HB_OT_LAYOUT_GPOS_NO_LAST;
669
670     /* We don't handle mark glyphs here. */
671     if (property == HB_OT_LAYOUT_GLYPH_CLASS_MARK)
672       return false;
673
674     unsigned int index = (this+coverage) (IN_CURGLYPH ());
675     if (HB_LIKELY (index == NOT_COVERED))
676       return false;
677
678     const EntryExitRecord &record = entryExitRecord[index];
679
680     hb_position_t entry_x, entry_y, exit_x, exit_y;
681
682     if (last_pos == HB_OT_LAYOUT_GPOS_NO_LAST || !record.entryAnchor)
683       goto end;
684
685     (this+record.entryAnchor).get_anchor (layout, IN_CURGLYPH (), &entry_x, &entry_y);
686
687     if (gpi->r2l)
688     {
689       POSITION (buffer->in_pos)->x_advance   = entry_x - gpi->anchor_x;
690       POSITION (buffer->in_pos)->new_advance = TRUE;
691     }
692     else
693     {
694       POSITION (last_pos)->x_advance   = gpi->anchor_x - entry_x;
695       POSITION (last_pos)->new_advance = TRUE;
696     }
697
698     if  (lookup_flag & LookupFlag::RightToLeft)
699     {
700       POSITION (last_pos)->cursive_chain = last_pos - buffer->in_pos;
701       POSITION (last_pos)->y_pos = entry_y - gpi->anchor_y;
702     }
703     else
704     {
705       POSITION (buffer->in_pos)->cursive_chain = buffer->in_pos - last_pos;
706       POSITION (buffer->in_pos)->y_pos = gpi->anchor_y - entry_y;
707     }
708
709   end:
710     if (record.exitAnchor)
711     {
712       gpi->last = buffer->in_pos;
713       (this+record.exitAnchor).get_anchor (layout, IN_CURGLYPH (), &gpi->anchor_x, &gpi->anchor_y);
714     }
715
716     buffer->in_pos++;
717     return true;
718   }
719
720   private:
721   USHORT        format;                 /* Format identifier--format = 1 */
722   OffsetTo<Coverage>
723                 coverage;               /* Offset to Coverage table--from
724                                          * beginning of subtable */
725   ArrayOf<EntryExitRecord>
726                 entryExitRecord;        /* Array of EntryExit records--in
727                                          * Coverage Index order */
728 };
729 ASSERT_SIZE (CursivePosFormat1, 6);
730
731 struct CursivePos
732 {
733   friend struct PosLookupSubTable;
734
735   private:
736   inline bool apply (APPLY_ARG_DEF) const
737   {
738     switch (u.format) {
739     case 1: return u.format1->apply (APPLY_ARG);
740     default:return false;
741     }
742   }
743
744   private:
745   union {
746   USHORT                format;         /* Format identifier */
747   CursivePosFormat1     format1[];
748   } u;
749 };
750 ASSERT_SIZE (CursivePos, 2);
751
752
753 struct BaseArray
754 {
755   friend struct MarkBasePosFormat1;
756
757   private:
758   USHORT        len;                    /* Number of rows */
759   OffsetTo<Anchor>
760                 matrix[];               /* Matrix of offsets to Anchor tables--
761                                          * from beginning of BaseArray table--
762                                          * base-major--in order of
763                                          * BaseCoverage Index--, mark-minor--
764                                          * ordered by class--zero-based. */
765 };
766 ASSERT_SIZE (BaseArray, 2);
767
768 struct MarkBasePosFormat1
769 {
770   friend struct MarkBasePos;
771
772   private:
773   inline bool apply (APPLY_ARG_DEF) const
774   {
775     if  (lookup_flag & LookupFlag::IgnoreBaseGlyphs)
776       return false;
777
778     unsigned int mark_index = (this+markCoverage) (IN_CURGLYPH ());
779     if (HB_LIKELY (mark_index == NOT_COVERED))
780       return false;
781
782     /* now we search backwards for a non-mark glyph */
783     unsigned int count = buffer->in_pos;
784     unsigned int i = 1, j = count - 1;
785     while (i <= count)
786     {
787       property = _hb_ot_layout_get_glyph_property (layout, IN_GLYPH (j));
788       if (!(property == HB_OT_LAYOUT_GLYPH_CLASS_MARK || property & LookupFlag::MarkAttachmentType))
789         break;
790       i++, j--;
791     }
792     if (HB_UNLIKELY (i > buffer->in_pos))
793       return false;
794
795     /* The following assertion is too strong -- at least for mangal.ttf. */
796 #if 0
797     if (property != HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH)
798       return false;
799 #endif
800
801     unsigned int base_index = (this+baseCoverage) (IN_GLYPH (j));
802     if (base_index == NOT_COVERED)
803       return false;
804
805     const MarkArray& mark_array = this+markArray;
806     const BaseArray& base_array = this+baseArray;
807
808     unsigned int mark_class = mark_array.get_class (mark_index);
809     const Anchor& mark_anchor = mark_array.get_anchor (mark_index);
810
811     if (HB_UNLIKELY (mark_class >= classCount || base_index >= base_array.len))
812       return false;
813
814     hb_position_t mark_x, mark_y, base_x, base_y;
815
816     mark_anchor.get_anchor (layout, IN_CURGLYPH (), &mark_x, &mark_y);
817     unsigned int index = base_index * classCount + mark_class;
818     (&base_array+base_array.matrix[index]).get_anchor (layout, IN_GLYPH (j), &base_x, &base_y);
819
820     hb_glyph_position_t *o = POSITION (buffer->in_pos);
821     o->x_pos     = base_x - mark_x;
822     o->y_pos     = base_y - mark_y;
823     o->x_advance = 0;
824     o->y_advance = 0;
825     o->back      = i;
826
827     buffer->in_pos++;
828     return true;
829   }
830
831   private:
832   USHORT        format;                 /* Format identifier--format = 1 */
833   OffsetTo<Coverage>
834                 markCoverage;           /* Offset to MarkCoverage table--from
835                                          * beginning of MarkBasePos subtable */
836   OffsetTo<Coverage>
837                 baseCoverage;           /* Offset to BaseCoverage table--from
838                                          * beginning of MarkBasePos subtable */
839   USHORT        classCount;             /* Number of classes defined for marks */
840   OffsetTo<MarkArray>
841                 markArray;              /* Offset to MarkArray table--from
842                                          * beginning of MarkBasePos subtable */
843   OffsetTo<BaseArray>
844                 baseArray;              /* Offset to BaseArray table--from
845                                          * beginning of MarkBasePos subtable */
846 };
847 ASSERT_SIZE (MarkBasePosFormat1, 12);
848
849 struct MarkBasePos
850 {
851   friend struct PosLookupSubTable;
852
853   private:
854   inline bool apply (APPLY_ARG_DEF) const
855   {
856     switch (u.format) {
857     case 1: return u.format1->apply (APPLY_ARG);
858     default:return false;
859     }
860   }
861
862   private:
863   union {
864   USHORT                format;         /* Format identifier */
865   MarkBasePosFormat1    format1[];
866   } u;
867 };
868 ASSERT_SIZE (MarkBasePos, 2);
869
870
871 struct LigatureAttach
872 {
873   friend struct MarkLigPosFormat1;
874
875   private:
876   USHORT        len;                    /* Number of ComponentRecords in this
877                                          * ligature, ie. number of rows */
878   OffsetTo<Anchor>
879                 matrix[];               /* Matrix of offsets to Anchor tables--
880                                          * from beginning of LigatureAttach table--
881                                          * component-major--in order of
882                                          * writing direction--, mark-minor--
883                                          * ordered by class--zero-based. */
884 };
885 ASSERT_SIZE (LigatureAttach, 2);
886
887 typedef OffsetArrayOf<LigatureAttach> LigatureArray;
888                                         /* Array of LigatureAttach
889                                          * tables ordered by
890                                          * LigatureCoverage Index */
891 ASSERT_SIZE (LigatureArray, 2);
892
893 struct MarkLigPosFormat1
894 {
895   friend struct MarkLigPos;
896
897   private:
898   inline bool apply (APPLY_ARG_DEF) const
899   {
900     if  (lookup_flag & LookupFlag::IgnoreLigatures)
901       return false;
902
903     unsigned int mark_index = (this+markCoverage) (IN_CURGLYPH ());
904     if (HB_LIKELY (mark_index == NOT_COVERED))
905       return false;
906
907     /* now we search backwards for a non-mark glyph */
908     unsigned int count = buffer->in_pos;
909     unsigned int i = 1, j = count - 1;
910     while (i <= count)
911     {
912       property = _hb_ot_layout_get_glyph_property (layout, IN_GLYPH (j));
913       if (!(property == HB_OT_LAYOUT_GLYPH_CLASS_MARK || property & LookupFlag::MarkAttachmentType))
914         break;
915       i++, j--;
916     }
917     if (HB_UNLIKELY (i > buffer->in_pos))
918       return false;
919
920     /* The following assertion is too strong -- at least for mangal.ttf. */
921 #if 0
922     if (property != HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE)
923       return false;
924 #endif
925
926     unsigned int lig_index = (this+ligatureCoverage) (IN_GLYPH (j));
927     if (lig_index == NOT_COVERED)
928       return false;
929
930     const MarkArray& mark_array = this+markArray;
931     const LigatureArray& lig_array = this+ligatureArray;
932
933     unsigned int mark_class = mark_array.get_class (mark_index);
934     const Anchor& mark_anchor = mark_array.get_anchor (mark_index);
935
936     if (HB_UNLIKELY (mark_class >= classCount || lig_index >= lig_array.len))
937       return false;
938
939     const LigatureAttach& lig_attach = &lig_array+lig_array[lig_index];
940     count = lig_attach.len;
941     if (HB_UNLIKELY (!count))
942       return false;
943
944     unsigned int comp_index;
945     /* We must now check whether the ligature ID of the current mark glyph
946      * is identical to the ligature ID of the found ligature.  If yes, we
947      * can directly use the component index.  If not, we attach the mark
948      * glyph to the last component of the ligature. */
949     if (IN_LIGID (j) == IN_LIGID (buffer->in_pos))
950     {
951       comp_index = IN_COMPONENT (buffer->in_pos);
952       if (comp_index >= count)
953         comp_index = count - 1;
954     }
955     else
956       comp_index = count - 1;
957
958     hb_position_t mark_x, mark_y, lig_x, lig_y;
959
960     mark_anchor.get_anchor (layout, IN_CURGLYPH (), &mark_x, &mark_y);
961     unsigned int index = comp_index * classCount + mark_class;
962     (&lig_attach+lig_attach.matrix[index]).get_anchor (layout, IN_GLYPH (j), &lig_x, &lig_y);
963
964     hb_glyph_position_t *o = POSITION (buffer->in_pos);
965     o->x_pos     = lig_x - mark_x;
966     o->y_pos     = lig_y - mark_y;
967     o->x_advance = 0;
968     o->y_advance = 0;
969     o->back      = i;
970
971     buffer->in_pos++;
972     return true;
973   }
974
975   private:
976   USHORT        format;                 /* Format identifier--format = 1 */
977   OffsetTo<Coverage>
978                 markCoverage;           /* Offset to Mark Coverage table--from
979                                          * beginning of MarkLigPos subtable */
980   OffsetTo<Coverage>
981                 ligatureCoverage;       /* Offset to Ligature Coverage
982                                          * table--from beginning of MarkLigPos
983                                          * subtable */
984   USHORT        classCount;             /* Number of defined mark classes */
985   OffsetTo<MarkArray>
986                 markArray;              /* Offset to MarkArray table--from
987                                          * beginning of MarkLigPos subtable */
988   OffsetTo<LigatureArray>
989                 ligatureArray;          /* Offset to LigatureArray table--from
990                                          * beginning of MarkLigPos subtable */
991 };
992 ASSERT_SIZE (MarkLigPosFormat1, 12);
993
994 struct MarkLigPos
995 {
996   friend struct PosLookupSubTable;
997
998   private:
999   inline bool apply (APPLY_ARG_DEF) const
1000   {
1001     switch (u.format) {
1002     case 1: return u.format1->apply (APPLY_ARG);
1003     default:return false;
1004     }
1005   }
1006
1007   private:
1008   union {
1009   USHORT                format;         /* Format identifier */
1010   MarkLigPosFormat1     format1[];
1011   } u;
1012 };
1013 ASSERT_SIZE (MarkLigPos, 2);
1014
1015
1016 struct Mark2Array
1017 {
1018   friend struct MarkMarkPosFormat1;
1019
1020   private:
1021   USHORT        len;                    /* Number of rows */
1022   OffsetTo<Anchor>
1023                 matrix[];               /* Matrix of offsets to Anchor tables--
1024                                          * from beginning of Mark2Array table--
1025                                          * mark2-major--in order of
1026                                          * Mark2Coverage Index--, mark1-minor--
1027                                          * ordered by class--zero-based. */
1028 };
1029 ASSERT_SIZE (Mark2Array, 2);
1030
1031 struct MarkMarkPosFormat1
1032 {
1033   friend struct MarkMarkPos;
1034
1035   private:
1036   inline bool apply (APPLY_ARG_DEF) const
1037   {
1038     if  (lookup_flag & LookupFlag::IgnoreMarks)
1039       return false;
1040
1041     unsigned int mark1_index = (this+mark1Coverage) (IN_CURGLYPH ());
1042     if (HB_LIKELY (mark1_index == NOT_COVERED))
1043       return false;
1044
1045     /* now we search backwards for a suitable mark glyph until a non-mark glyph */
1046     unsigned int count = buffer->in_pos;
1047     unsigned int i = 1, j = count - 1;
1048     while (i <= count)
1049     {
1050       property = _hb_ot_layout_get_glyph_property (layout, IN_GLYPH (j));
1051       if (!(property == HB_OT_LAYOUT_GLYPH_CLASS_MARK || property & LookupFlag::MarkAttachmentType))
1052         return false;
1053       if (!(lookup_flag & LookupFlag::MarkAttachmentType) ||
1054            (lookup_flag & LookupFlag::MarkAttachmentType) == property)
1055         break;
1056       i++, j--;
1057     }
1058     if (HB_UNLIKELY (i > buffer->in_pos))
1059       return false;
1060
1061     unsigned int mark2_index = (this+mark2Coverage) (IN_GLYPH (j));
1062     if (mark2_index == NOT_COVERED)
1063       return false;
1064
1065     const MarkArray& mark1_array = this+mark1Array;
1066     const Mark2Array& mark2_array = this+mark2Array;
1067
1068     unsigned int mark1_class = mark1_array.get_class (mark1_index);
1069     const Anchor& mark1_anchor = mark1_array.get_anchor (mark1_index);
1070
1071     if (HB_UNLIKELY (mark1_class >= classCount || mark2_index >= mark2_array.len))
1072       return false;
1073
1074     hb_position_t mark1_x, mark1_y, mark2_x, mark2_y;
1075
1076     mark1_anchor.get_anchor (layout, IN_CURGLYPH (), &mark1_x, &mark1_y);
1077     unsigned int index = mark2_index * classCount + mark1_class;
1078     (&mark2_array+mark2_array.matrix[index]).get_anchor (layout, IN_GLYPH (j), &mark2_x, &mark2_y);
1079
1080     hb_glyph_position_t *o = POSITION (buffer->in_pos);
1081     o->x_pos     = mark2_x - mark1_x;
1082     o->y_pos     = mark2_y - mark1_y;
1083     o->x_advance = 0;
1084     o->y_advance = 0;
1085     o->back      = i;
1086
1087     buffer->in_pos++;
1088     return true;
1089   }
1090
1091   private:
1092   USHORT        format;                 /* Format identifier--format = 1 */
1093   OffsetTo<Coverage>
1094                 mark1Coverage;          /* Offset to Combining Mark1 Coverage
1095                                          * table--from beginning of MarkMarkPos
1096                                          * subtable */
1097   OffsetTo<Coverage>
1098                 mark2Coverage;          /* Offset to Combining Mark2 Coverage
1099                                          * table--from beginning of MarkMarkPos
1100                                          * subtable */
1101   USHORT        classCount;             /* Number of defined mark classes */
1102   OffsetTo<MarkArray>
1103                 mark1Array;             /* Offset to Mark1Array table--from
1104                                          * beginning of MarkMarkPos subtable */
1105   OffsetTo<Mark2Array>
1106                 mark2Array;             /* Offset to Mark2Array table--from
1107                                          * beginning of MarkMarkPos subtable */
1108 };
1109 ASSERT_SIZE (MarkMarkPosFormat1, 12);
1110
1111 struct MarkMarkPos
1112 {
1113   friend struct PosLookupSubTable;
1114
1115   private:
1116   inline bool apply (APPLY_ARG_DEF) const
1117   {
1118     switch (u.format) {
1119     case 1: return u.format1->apply (APPLY_ARG);
1120     default:return false;
1121     }
1122   }
1123
1124   private:
1125   union {
1126   USHORT                format;         /* Format identifier */
1127   MarkMarkPosFormat1    format1[];
1128   } u;
1129 };
1130 ASSERT_SIZE (MarkMarkPos, 2);
1131
1132
1133 static inline bool position_lookup (APPLY_ARG_DEF, unsigned int lookup_index);
1134
1135 struct ContextPos : Context
1136 {
1137   friend struct PosLookupSubTable;
1138
1139   private:
1140   inline bool apply (APPLY_ARG_DEF) const
1141   {
1142     return Context::apply (APPLY_ARG, position_lookup);
1143   }
1144 };
1145 ASSERT_SIZE (ContextPos, 2);
1146
1147 struct ChainContextPos : ChainContext
1148 {
1149   friend struct PosLookupSubTable;
1150
1151   private:
1152   inline bool apply (APPLY_ARG_DEF) const
1153   {
1154     return ChainContext::apply (APPLY_ARG, position_lookup);
1155   }
1156 };
1157 ASSERT_SIZE (ChainContextPos, 2);
1158
1159
1160 struct ExtensionPos : Extension
1161 {
1162   friend struct PosLookupSubTable;
1163
1164   private:
1165   inline bool apply (APPLY_ARG_DEF) const;
1166 };
1167 ASSERT_SIZE (ExtensionPos, 2);
1168
1169
1170
1171 /*
1172  * PosLookup
1173  */
1174
1175
1176 struct PosLookupSubTable
1177 {
1178   friend struct PosLookup;
1179
1180   enum {
1181     Single              = 1,
1182     Pair                = 2,
1183     Cursive             = 3,
1184     MarkBase            = 4,
1185     MarkLig             = 5,
1186     MarkMark            = 6,
1187     Context             = 7,
1188     ChainContext        = 8,
1189     Extension           = 9,
1190   };
1191
1192   bool apply (APPLY_ARG_DEF, unsigned int lookup_type) const
1193   {
1194     switch (lookup_type) {
1195     case Single:                return u.single->apply (APPLY_ARG);
1196     case Pair:                  return u.pair->apply (APPLY_ARG);
1197     case Cursive:               return u.cursive->apply (APPLY_ARG);
1198     case MarkBase:              return u.markBase->apply (APPLY_ARG);
1199     case MarkLig:               return u.markLig->apply (APPLY_ARG);
1200     case MarkMark:              return u.markMark->apply (APPLY_ARG);
1201     case Context:               return u.context->apply (APPLY_ARG);
1202     case ChainContext:          return u.chainContext->apply (APPLY_ARG);
1203     case Extension:             return u.extension->apply (APPLY_ARG);
1204     default:return false;
1205     }
1206   }
1207
1208   private:
1209   union {
1210   USHORT                format;
1211   SinglePos             single[];
1212   PairPos               pair[];
1213   CursivePos            cursive[];
1214   MarkBasePos           markBase[];
1215   MarkLigPos            markLig[];
1216   MarkMarkPos           markMark[];
1217   ContextPos            context[];
1218   ChainContextPos       chainContext[];
1219   ExtensionPos          extension[];
1220   } u;
1221 };
1222 ASSERT_SIZE (PosLookupSubTable, 2);
1223
1224
1225 struct PosLookup : Lookup
1226 {
1227   inline const PosLookupSubTable& get_subtable (unsigned int i) const
1228   {
1229     return (const PosLookupSubTable&) Lookup::get_subtable (i);
1230   }
1231
1232   /* Like get_type(), but looks through extension lookups.
1233    * Never returns Extension */
1234   inline unsigned int get_effective_type (void) const
1235   {
1236     unsigned int type = get_type ();
1237
1238     if (HB_UNLIKELY (type == PosLookupSubTable::Extension))
1239     {
1240       unsigned int count = get_subtable_count ();
1241       type = get_subtable(0).u.extension->get_type ();
1242       /* The spec says all subtables should have the same type.
1243        * This is specially important if one has a reverse type! */
1244       for (unsigned int i = 1; i < count; i++)
1245         if (get_subtable(i).u.extension->get_type () != type)
1246           return 0;
1247     }
1248
1249     return type;
1250   }
1251
1252   inline bool apply_once (hb_ot_layout_t *layout,
1253                           hb_buffer_t    *buffer,
1254                           unsigned int    context_length,
1255                           unsigned int    nesting_level_left) const
1256   {
1257     unsigned int lookup_type = get_type ();
1258     unsigned int lookup_flag = get_flag ();
1259     unsigned int property;
1260
1261     if (!_hb_ot_layout_check_glyph_property (layout, IN_CURINFO (), lookup_flag, &property))
1262       return false;
1263
1264     for (unsigned int i = 0; i < get_subtable_count (); i++)
1265       if (get_subtable (i).apply (APPLY_ARG, lookup_type))
1266         return true;
1267
1268     return false;
1269   }
1270
1271   bool apply_string (hb_ot_layout_t *layout,
1272                      hb_buffer_t    *buffer,
1273                      hb_ot_layout_feature_mask_t mask) const
1274   {
1275     bool ret = false;
1276
1277     if (HB_UNLIKELY (!buffer->in_length))
1278       return false;
1279
1280     layout->gpos_info.last = HB_OT_LAYOUT_GPOS_NO_LAST; /* no last valid glyph for cursive pos. */
1281
1282     buffer->in_pos = 0;
1283     while (buffer->in_pos < buffer->in_length)
1284     {
1285       bool done;
1286       if (~IN_PROPERTIES (buffer->in_pos) & mask)
1287       {
1288           done = apply_once (layout, buffer, NO_CONTEXT, MAX_NESTING_LEVEL);
1289           ret |= done;
1290       }
1291       else
1292       {
1293           done = false;
1294           /* Contrary to properties defined in GDEF, user-defined properties
1295              will always stop a possible cursive positioning.                */
1296           layout->gpos_info.last = HB_OT_LAYOUT_GPOS_NO_LAST;
1297       }
1298
1299       if (!done)
1300         buffer->in_pos++;
1301     }
1302
1303     return ret;
1304   }
1305 };
1306 ASSERT_SIZE (PosLookup, 6);
1307
1308
1309 /*
1310  * GPOS
1311  */
1312
1313 struct GPOS : GSUBGPOS
1314 {
1315   static const hb_tag_t Tag             = HB_TAG ('G','P','O','S');
1316
1317   static inline const GPOS& get_for_data (const char *data)
1318   {
1319     return (const GPOS&) GSUBGPOS::get_for_data (data);
1320   }
1321
1322   inline const PosLookup& get_lookup (unsigned int i) const
1323   {
1324     return (const PosLookup&) GSUBGPOS::get_lookup (i);
1325   }
1326
1327   inline bool position_lookup (hb_ot_layout_t *layout,
1328                                hb_buffer_t    *buffer,
1329                                unsigned int    lookup_index,
1330                                hb_ot_layout_feature_mask_t  mask) const
1331   {
1332     return get_lookup (lookup_index).apply_string (layout, buffer, mask);
1333   }
1334
1335 };
1336 ASSERT_SIZE (GPOS, 10);
1337
1338
1339 /* Out-of-class implementation for methods recursing */
1340
1341 inline bool ExtensionPos::apply (APPLY_ARG_DEF) const
1342 {
1343   unsigned int lookup_type = get_type ();
1344
1345   if (HB_UNLIKELY (lookup_type == PosLookupSubTable::Extension))
1346     return false;
1347
1348   return ((PosLookupSubTable&) get_subtable ()).apply (APPLY_ARG, lookup_type);
1349 }
1350
1351 static inline bool position_lookup (APPLY_ARG_DEF, unsigned int lookup_index)
1352 {
1353   const GPOS &gpos = *(layout->gpos);
1354   const PosLookup &l = gpos.get_lookup (lookup_index);
1355
1356   if (HB_UNLIKELY (nesting_level_left == 0))
1357     return false;
1358   nesting_level_left--;
1359
1360   if (HB_UNLIKELY (context_length < 1))
1361     return false;
1362
1363   return l.apply_once (layout, buffer, context_length, nesting_level_left);
1364 }
1365
1366
1367 #endif /* HB_OT_LAYOUT_GPOS_PRIVATE_H */