xref: /aosp_15_r20/external/harfbuzz_ng/src/hb-aat-layout-just-table.hh (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
1 /*
2  * Copyright © 2018  Ebrahim Byagowi
3  *
4  *  This is part of HarfBuzz, a text shaping 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 
25 #ifndef HB_AAT_LAYOUT_JUST_TABLE_HH
26 #define HB_AAT_LAYOUT_JUST_TABLE_HH
27 
28 #include "hb-aat-layout-common.hh"
29 #include "hb-ot-layout.hh"
30 #include "hb-open-type.hh"
31 
32 #include "hb-aat-layout-morx-table.hh"
33 
34 /*
35  * just -- Justification
36  * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6just.html
37  */
38 #define HB_AAT_TAG_just HB_TAG('j','u','s','t')
39 
40 
41 namespace AAT {
42 
43 using namespace OT;
44 
45 
46 struct ActionSubrecordHeader
47 {
sanitizeAAT::ActionSubrecordHeader48   bool sanitize (hb_sanitize_context_t *c) const
49   {
50     TRACE_SANITIZE (this);
51     return_trace (c->check_struct (this));
52   }
53 
54   HBUINT16	actionClass;	/* The JustClass value associated with this
55 				 * ActionSubrecord. */
56   HBUINT16	actionType;	/* The type of postcompensation action. */
57   HBUINT16	actionLength;	/* Length of this ActionSubrecord record, which
58 				 * must be a multiple of 4. */
59   public:
60   DEFINE_SIZE_STATIC (6);
61 };
62 
63 struct DecompositionAction
64 {
sanitizeAAT::DecompositionAction65   bool sanitize (hb_sanitize_context_t *c) const
66   {
67     TRACE_SANITIZE (this);
68     return_trace (c->check_struct (this));
69   }
70 
71   ActionSubrecordHeader
72 		header;
73   F16DOT16	lowerLimit;	/* If the distance factor is less than this value,
74 				 * then the ligature is decomposed. */
75   F16DOT16	upperLimit;	/* If the distance factor is greater than this value,
76 				 * then the ligature is decomposed. */
77   HBUINT16	order;		/* Numerical order in which this ligature will
78 				 * be decomposed; you may want infrequent ligatures
79 				 * to decompose before more frequent ones. The ligatures
80 				 * on the line of text will decompose in increasing
81 				 * value of this field. */
82   Array16Of<HBUINT16>
83 		decomposedglyphs;
84 				/* Number of 16-bit glyph indexes that follow;
85 				 * the ligature will be decomposed into these glyphs.
86 				 *
87 				 * Array of decomposed glyphs. */
88   public:
89   DEFINE_SIZE_ARRAY (18, decomposedglyphs);
90 };
91 
92 struct UnconditionalAddGlyphAction
93 {
sanitizeAAT::UnconditionalAddGlyphAction94   bool sanitize (hb_sanitize_context_t *c) const
95   {
96     TRACE_SANITIZE (this);
97     return_trace (c->check_struct (this));
98   }
99 
100   protected:
101   ActionSubrecordHeader
102 		header;
103   HBGlyphID16	addGlyph;	/* Glyph that should be added if the distance factor
104 				 * is growing. */
105 
106   public:
107   DEFINE_SIZE_STATIC (8);
108 };
109 
110 struct ConditionalAddGlyphAction
111 {
sanitizeAAT::ConditionalAddGlyphAction112   bool sanitize (hb_sanitize_context_t *c) const
113   {
114     TRACE_SANITIZE (this);
115     return_trace (c->check_struct (this));
116   }
117 
118   protected:
119   ActionSubrecordHeader
120 		header;
121   F16DOT16	substThreshold; /* Distance growth factor (in ems) at which
122 				 * this glyph is replaced and the growth factor
123 				 * recalculated. */
124   HBGlyphID16	addGlyph;	/* Glyph to be added as kashida. If this value is
125 				 * 0xFFFF, no extra glyph will be added. Note that
126 				 * generally when a glyph is added, justification
127 				 * will need to be redone. */
128   HBGlyphID16	substGlyph;	/* Glyph to be substituted for this glyph if the
129 				 * growth factor equals or exceeds the value of
130 				 * substThreshold. */
131   public:
132   DEFINE_SIZE_STATIC (14);
133 };
134 
135 struct DuctileGlyphAction
136 {
sanitizeAAT::DuctileGlyphAction137   bool sanitize (hb_sanitize_context_t *c) const
138   {
139     TRACE_SANITIZE (this);
140     return_trace (c->check_struct (this));
141   }
142 
143   protected:
144   ActionSubrecordHeader
145 		header;
146   HBUINT32	variationAxis;	/* The 4-byte tag identifying the ductile axis.
147 				 * This would normally be 0x64756374 ('duct'),
148 				 * but you may use any axis the font contains. */
149   F16DOT16	minimumLimit;	/* The lowest value for the ductility axis that
150 				 * still yields an acceptable appearance. Normally
151 				 * this will be 1.0. */
152   F16DOT16	noStretchValue; /* This is the default value that corresponds to
153 				 * no change in appearance. Normally, this will
154 				 * be 1.0. */
155   F16DOT16	maximumLimit;	/* The highest value for the ductility axis that
156 				 * still yields an acceptable appearance. */
157   public:
158   DEFINE_SIZE_STATIC (22);
159 };
160 
161 struct RepeatedAddGlyphAction
162 {
sanitizeAAT::RepeatedAddGlyphAction163   bool sanitize (hb_sanitize_context_t *c) const
164   {
165     TRACE_SANITIZE (this);
166     return_trace (c->check_struct (this));
167   }
168 
169   protected:
170   ActionSubrecordHeader
171 		header;
172   HBUINT16	flags;		/* Currently unused; set to 0. */
173   HBGlyphID16	glyph;		/* Glyph that should be added if the distance factor
174 				 * is growing. */
175   public:
176   DEFINE_SIZE_STATIC (10);
177 };
178 
179 struct ActionSubrecord
180 {
get_lengthAAT::ActionSubrecord181   unsigned int get_length () const { return u.header.actionLength; }
182 
sanitizeAAT::ActionSubrecord183   bool sanitize (hb_sanitize_context_t *c) const
184   {
185     TRACE_SANITIZE (this);
186     if (unlikely (!c->check_struct (this)))
187       return_trace (false);
188     hb_barrier ();
189 
190     switch (u.header.actionType)
191     {
192     case 0: hb_barrier ();  return_trace (u.decompositionAction.sanitize (c));
193     case 1: hb_barrier ();  return_trace (u.unconditionalAddGlyphAction.sanitize (c));
194     case 2: hb_barrier ();  return_trace (u.conditionalAddGlyphAction.sanitize (c));
195     // case 3: hb_barrier (); return_trace (u.stretchGlyphAction.sanitize (c));
196     case 4: hb_barrier ();  return_trace (u.decompositionAction.sanitize (c));
197     case 5: hb_barrier ();  return_trace (u.decompositionAction.sanitize (c));
198     default: return_trace (true);
199     }
200   }
201 
202   protected:
203   union	{
204   ActionSubrecordHeader		header;
205   DecompositionAction		decompositionAction;
206   UnconditionalAddGlyphAction	unconditionalAddGlyphAction;
207   ConditionalAddGlyphAction	conditionalAddGlyphAction;
208   /* StretchGlyphAction stretchGlyphAction; -- Not supported by CoreText */
209   DuctileGlyphAction		ductileGlyphAction;
210   RepeatedAddGlyphAction	repeatedAddGlyphAction;
211   } u;				/* Data. The format of this data depends on
212 				 * the value of the actionType field. */
213   public:
214   DEFINE_SIZE_UNION (6, header);
215 };
216 
217 struct PostcompensationActionChain
218 {
sanitizeAAT::PostcompensationActionChain219   bool sanitize (hb_sanitize_context_t *c) const
220   {
221     TRACE_SANITIZE (this);
222     if (unlikely (!c->check_struct (this)))
223       return_trace (false);
224     hb_barrier ();
225 
226     unsigned int offset = min_size;
227     for (unsigned int i = 0; i < count; i++)
228     {
229       const ActionSubrecord& subrecord = StructAtOffset<ActionSubrecord> (this, offset);
230       if (unlikely (!subrecord.sanitize (c))) return_trace (false);
231       offset += subrecord.get_length ();
232     }
233 
234     return_trace (true);
235   }
236 
237   protected:
238   HBUINT32	count;
239 
240   public:
241   DEFINE_SIZE_STATIC (4);
242 };
243 
244 struct JustWidthDeltaEntry
245 {
246   enum Flags
247   {
248     Reserved1		=0xE000,/* Reserved. You should set these bits to zero. */
249     UnlimiteGap		=0x1000,/* The glyph can take unlimited gap. When this
250 				 * glyph participates in the justification process,
251 				 * it and any other glyphs on the line having this
252 				 * bit set absorb all the remaining gap. */
253     Reserved2		=0x0FF0,/* Reserved. You should set these bits to zero. */
254     Priority		=0x000F /* The justification priority of the glyph. */
255   };
256 
257   enum Priority
258   {
259     Kashida		= 0,	/* Kashida priority. This is the highest priority
260 				 * during justification. */
261     Whitespace		= 1,	/* Whitespace priority. Any whitespace glyphs (as
262 				 * identified in the glyph properties table) will
263 				 * get this priority. */
264     InterCharacter	= 2,	/* Inter-character priority. Give this to any
265 				 * remaining glyphs. */
266     NullPriority	= 3	/* Null priority. You should set this priority for
267 				 * glyphs that only participate in justification
268 				 * after the above priorities. Normally all glyphs
269 				 * have one of the previous three values. If you
270 				 * don't want a glyph to participate in justification,
271 				 * and you don't want to set its factors to zero,
272 				 * you may instead assign it to the null priority. */
273   };
274 
275   protected:
276   F16DOT16	beforeGrowLimit;/* The ratio by which the advance width of the
277 				 * glyph is permitted to grow on the left or top side. */
278   F16DOT16	beforeShrinkLimit;
279 				/* The ratio by which the advance width of the
280 				 * glyph is permitted to shrink on the left or top side. */
281   F16DOT16	afterGrowLimit;	/* The ratio by which the advance width of the glyph
282 				 * is permitted to shrink on the left or top side. */
283   F16DOT16	afterShrinkLimit;
284 				/* The ratio by which the advance width of the glyph
285 				 * is at most permitted to shrink on the right or
286 				 * bottom side. */
287   HBUINT16	growFlags;	/* Flags controlling the grow case. */
288   HBUINT16	shrinkFlags;	/* Flags controlling the shrink case. */
289 
290   public:
291   DEFINE_SIZE_STATIC (20);
292 };
293 
294 struct WidthDeltaPair
295 {
sanitizeAAT::WidthDeltaPair296   bool sanitize (hb_sanitize_context_t *c) const
297   {
298     TRACE_SANITIZE (this);
299     return_trace (c->check_struct (this));
300   }
301 
302   protected:
303   HBUINT32	justClass;	/* The justification category associated
304 				 * with the wdRecord field. Only 7 bits of
305 				 * this field are used. (The other bits are
306 				 * used as padding to guarantee longword
307 				 * alignment of the following record). */
308   JustWidthDeltaEntry
309 		wdRecord;	/* The actual width delta record. */
310 
311   public:
312   DEFINE_SIZE_STATIC (24);
313 };
314 
315 typedef OT::Array32Of<WidthDeltaPair> WidthDeltaCluster;
316 
317 struct JustificationCategory
318 {
319   typedef void EntryData;
320 
321   enum Flags
322   {
323     SetMark		=0x8000,/* If set, make the current glyph the marked
324 				 * glyph. */
325     DontAdvance		=0x4000,/* If set, don't advance to the next glyph before
326 				 * going to the new state. */
327     MarkCategory	=0x3F80,/* The justification category for the marked
328 				 * glyph if nonzero. */
329     CurrentCategory	=0x007F /* The justification category for the current
330 				 * glyph if nonzero. */
331   };
332 
sanitizeAAT::JustificationCategory333   bool sanitize (hb_sanitize_context_t *c, const void *base) const
334   {
335     TRACE_SANITIZE (this);
336     return_trace (likely (c->check_struct (this) &&
337 			  morphHeader.sanitize (c) &&
338 			  stHeader.sanitize (c)));
339   }
340 
341   protected:
342   ChainSubtable<ObsoleteTypes>
343 		morphHeader;	/* Metamorphosis-style subtable header. */
344   StateTable<ObsoleteTypes, EntryData>
345 		stHeader;	/* The justification insertion state table header */
346   public:
347   DEFINE_SIZE_STATIC (30);
348 };
349 
350 struct JustificationHeader
351 {
sanitizeAAT::JustificationHeader352   bool sanitize (hb_sanitize_context_t *c, const void *base) const
353   {
354     TRACE_SANITIZE (this);
355     return_trace (likely (c->check_struct (this) &&
356 			  justClassTable.sanitize (c, base, base) &&
357 			  wdcTable.sanitize (c, base) &&
358 			  pcTable.sanitize (c, base) &&
359 			  lookupTable.sanitize (c, base)));
360   }
361 
362   protected:
363   Offset16To<JustificationCategory>
364 		justClassTable;	/* Offset to the justification category state table. */
365   Offset16To<WidthDeltaCluster>
366 		wdcTable;	/* Offset from start of justification table to start
367 				 * of the subtable containing the width delta factors
368 				 * for the glyphs in your font.
369 				 *
370 				 * The width delta clusters table. */
371   Offset16To<PostcompensationActionChain>
372 		pcTable;	/* Offset from start of justification table to start
373 				 * of postcompensation subtable (set to zero if none).
374 				 *
375 				 * The postcompensation subtable, if present in the font. */
376   Lookup<Offset16To<WidthDeltaCluster>>
377 		lookupTable;	/* Lookup table associating glyphs with width delta
378 				 * clusters. See the description of Width Delta Clusters
379 				 * table for details on how to interpret the lookup values. */
380 
381   public:
382   DEFINE_SIZE_MIN (8);
383 };
384 
385 struct just
386 {
387   static constexpr hb_tag_t tableTag = HB_AAT_TAG_just;
388 
sanitizeAAT::just389   bool sanitize (hb_sanitize_context_t *c) const
390   {
391     TRACE_SANITIZE (this);
392 
393     return_trace (likely (c->check_struct (this) &&
394 			  hb_barrier () &&
395 			  version.major == 1 &&
396 			  horizData.sanitize (c, this, this) &&
397 			  vertData.sanitize (c, this, this)));
398   }
399 
400   protected:
401   FixedVersion<>version;	/* Version of the justification table
402 				 * (0x00010000u for version 1.0). */
403   HBUINT16	format;		/* Format of the justification table (set to 0). */
404   Offset16To<JustificationHeader>
405 		horizData;	/* Byte offset from the start of the justification table
406 				 * to the header for tables that contain justification
407 				 * information for horizontal text.
408 				 * If you are not including this information,
409 				 * store 0. */
410   Offset16To<JustificationHeader>
411 		vertData;	/* ditto, vertical */
412 
413   public:
414   DEFINE_SIZE_STATIC (10);
415 };
416 
417 } /* namespace AAT */
418 
419 
420 #endif /* HB_AAT_LAYOUT_JUST_TABLE_HH */
421