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 (likely (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 (likely (c->check_struct (this)));
69   }
70 
71   ActionSubrecordHeader
72 		header;
73   HBFixed	lowerLimit;	/* If the distance factor is less than this value,
74 				 * then the ligature is decomposed. */
75   HBFixed	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   HBGlyphID	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 (likely (c->check_struct (this)));
116   }
117 
118   protected:
119   ActionSubrecordHeader
120 		header;
121   HBFixed	substThreshold; /* Distance growth factor (in ems) at which
122 				 * this glyph is replaced and the growth factor
123 				 * recalculated. */
124   HBGlyphID	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   HBGlyphID	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 (likely (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   HBFixed	minimumLimit;	/* The lowest value for the ductility axis tha
150 				 * still yields an acceptable appearance. Normally
151 				 * this will be 1.0. */
152   HBFixed	noStretchValue; /* This is the default value that corresponds to
153 				 * no change in appearance. Normally, this will
154 				 * be 1.0. */
155   HBFixed	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 (likely (c->check_struct (this)));
167   }
168 
169   protected:
170   ActionSubrecordHeader
171 		header;
172   HBUINT16	flags;		/* Currently unused; set to 0. */
173   HBGlyphID	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 
189     switch (u.header.actionType)
190     {
191     case 0:  return_trace (u.decompositionAction.sanitize (c));
192     case 1:  return_trace (u.unconditionalAddGlyphAction.sanitize (c));
193     case 2:  return_trace (u.conditionalAddGlyphAction.sanitize (c));
194     // case 3: return_trace (u.stretchGlyphAction.sanitize (c));
195     case 4:  return_trace (u.decompositionAction.sanitize (c));
196     case 5:  return_trace (u.decompositionAction.sanitize (c));
197     default: return_trace (true);
198     }
199   }
200 
201   protected:
202   union	{
203   ActionSubrecordHeader		header;
204   DecompositionAction		decompositionAction;
205   UnconditionalAddGlyphAction	unconditionalAddGlyphAction;
206   ConditionalAddGlyphAction	conditionalAddGlyphAction;
207   /* StretchGlyphAction stretchGlyphAction; -- Not supported by CoreText */
208   DuctileGlyphAction		ductileGlyphAction;
209   RepeatedAddGlyphAction	repeatedAddGlyphAction;
210   } u;				/* Data. The format of this data depends on
211 				 * the value of the actionType field. */
212   public:
213   DEFINE_SIZE_UNION (6, header);
214 };
215 
216 struct PostcompensationActionChain
217 {
sanitizeAAT::PostcompensationActionChain218   bool sanitize (hb_sanitize_context_t *c) const
219   {
220     TRACE_SANITIZE (this);
221     if (unlikely (!c->check_struct (this)))
222       return_trace (false);
223 
224     unsigned int offset = min_size;
225     for (unsigned int i = 0; i < count; i++)
226     {
227       const ActionSubrecord& subrecord = StructAtOffset<ActionSubrecord> (this, offset);
228       if (unlikely (!subrecord.sanitize (c))) return_trace (false);
229       offset += subrecord.get_length ();
230     }
231 
232     return_trace (true);
233   }
234 
235   protected:
236   HBUINT32	count;
237 
238   public:
239   DEFINE_SIZE_STATIC (4);
240 };
241 
242 struct JustWidthDeltaEntry
243 {
244   enum Flags
245   {
246     Reserved1		=0xE000,/* Reserved. You should set these bits to zero. */
247     UnlimiteGap		=0x1000,/* The glyph can take unlimited gap. When this
248 				 * glyph participates in the justification process,
249 				 * it and any other glyphs on the line having this
250 				 * bit set absorb all the remaining gap. */
251     Reserved2		=0x0FF0,/* Reserved. You should set these bits to zero. */
252     Priority		=0x000F /* The justification priority of the glyph. */
253   };
254 
255   enum Priority
256   {
257     Kashida		= 0,	/* Kashida priority. This is the highest priority
258 				 * during justification. */
259     Whitespace		= 1,	/* Whitespace priority. Any whitespace glyphs (as
260 				 * identified in the glyph properties table) will
261 				 * get this priority. */
262     InterCharacter	= 2,	/* Inter-character priority. Give this to any
263 				 * remaining glyphs. */
264     NullPriority	= 3	/* Null priority. You should set this priority for
265 				 * glyphs that only participate in justification
266 				 * after the above priorities. Normally all glyphs
267 				 * have one of the previous three values. If you
268 				 * don't want a glyph to participate in justification,
269 				 * and you don't want to set its factors to zero,
270 				 * you may instead assign it to the null priority. */
271   };
272 
273   protected:
274   HBFixed	beforeGrowLimit;/* The ratio by which the advance width of the
275 				 * glyph is permitted to grow on the left or top side. */
276   HBFixed	beforeShrinkLimit;
277 				/* The ratio by which the advance width of the
278 				 * glyph is permitted to shrink on the left or top side. */
279   HBFixed	afterGrowLimit;	/* The ratio by which the advance width of the glyph
280 				 * is permitted to shrink on the left or top side. */
281   HBFixed	afterShrinkLimit;
282 				/* The ratio by which the advance width of the glyph
283 				 * is at most permitted to shrink on the right or
284 				 * bottom side. */
285   HBUINT16	growFlags;	/* Flags controlling the grow case. */
286   HBUINT16	shrinkFlags;	/* Flags controlling the shrink case. */
287 
288   public:
289   DEFINE_SIZE_STATIC (20);
290 };
291 
292 struct WidthDeltaPair
293 {
sanitizeAAT::WidthDeltaPair294   bool sanitize (hb_sanitize_context_t *c) const
295   {
296     TRACE_SANITIZE (this);
297     return_trace (likely (c->check_struct (this)));
298   }
299 
300   protected:
301   HBUINT32	justClass;	/* The justification category associated
302 				 * with the wdRecord field. Only 7 bits of
303 				 * this field are used. (The other bits are
304 				 * used as padding to guarantee longword
305 				 * alignment of the following record). */
306   JustWidthDeltaEntry
307 		wdRecord;	/* The actual width delta record. */
308 
309   public:
310   DEFINE_SIZE_STATIC (24);
311 };
312 
313 typedef OT::Array32Of<WidthDeltaPair> WidthDeltaCluster;
314 
315 struct JustificationCategory
316 {
317   typedef void EntryData;
318 
319   enum Flags
320   {
321     SetMark		=0x8000,/* If set, make the current glyph the marked
322 				 * glyph. */
323     DontAdvance		=0x4000,/* If set, don't advance to the next glyph before
324 				 * going to the new state. */
325     MarkCategory	=0x3F80,/* The justification category for the marked
326 				 * glyph if nonzero. */
327     CurrentCategory	=0x007F /* The justification category for the current
328 				 * glyph if nonzero. */
329   };
330 
sanitizeAAT::JustificationCategory331   bool sanitize (hb_sanitize_context_t *c, const void *base) const
332   {
333     TRACE_SANITIZE (this);
334     return_trace (likely (c->check_struct (this) &&
335 			  morphHeader.sanitize (c) &&
336 			  stHeader.sanitize (c)));
337   }
338 
339   protected:
340   ChainSubtable<ObsoleteTypes>
341 		morphHeader;	/* Metamorphosis-style subtable header. */
342   StateTable<ObsoleteTypes, EntryData>
343 		stHeader;	/* The justification insertion state table header */
344   public:
345   DEFINE_SIZE_STATIC (30);
346 };
347 
348 struct JustificationHeader
349 {
sanitizeAAT::JustificationHeader350   bool sanitize (hb_sanitize_context_t *c, const void *base) const
351   {
352     TRACE_SANITIZE (this);
353     return_trace (likely (c->check_struct (this) &&
354 			  justClassTable.sanitize (c, base, base) &&
355 			  wdcTable.sanitize (c, base) &&
356 			  pcTable.sanitize (c, base) &&
357 			  lookupTable.sanitize (c, base)));
358   }
359 
360   protected:
361   Offset16To<JustificationCategory>
362 		justClassTable;	/* Offset to the justification category state table. */
363   Offset16To<WidthDeltaCluster>
364 		wdcTable;	/* Offset from start of justification table to start
365 				 * of the subtable containing the width delta factors
366 				 * for the glyphs in your font.
367 				 *
368 				 * The width delta clusters table. */
369   Offset16To<PostcompensationActionChain>
370 		pcTable;	/* Offset from start of justification table to start
371 				 * of postcompensation subtable (set to zero if none).
372 				 *
373 				 * The postcompensation subtable, if present in the font. */
374   Lookup<Offset16To<WidthDeltaCluster>>
375 		lookupTable;	/* Lookup table associating glyphs with width delta
376 				 * clusters. See the description of Width Delta Clusters
377 				 * table for details on how to interpret the lookup values. */
378 
379   public:
380   DEFINE_SIZE_MIN (8);
381 };
382 
383 struct just
384 {
385   static constexpr hb_tag_t tableTag = HB_AAT_TAG_just;
386 
sanitizeAAT::just387   bool sanitize (hb_sanitize_context_t *c) const
388   {
389     TRACE_SANITIZE (this);
390 
391     return_trace (likely (c->check_struct (this) &&
392 			  version.major == 1 &&
393 			  horizData.sanitize (c, this, this) &&
394 			  vertData.sanitize (c, this, this)));
395   }
396 
397   protected:
398   FixedVersion<>version;	/* Version of the justification table
399 				 * (0x00010000u for version 1.0). */
400   HBUINT16	format;		/* Format of the justification table (set to 0). */
401   Offset16To<JustificationHeader>
402 		horizData;	/* Byte offset from the start of the justification table
403 				 * to the header for tables that contain justification
404 				 * information for horizontal text.
405 				 * If you are not including this information,
406 				 * store 0. */
407   Offset16To<JustificationHeader>
408 		vertData;	/* ditto, vertical */
409 
410   public:
411   DEFINE_SIZE_STATIC (10);
412 };
413 
414 } /* namespace AAT */
415 
416 
417 #endif /* HB_AAT_LAYOUT_JUST_TABLE_HH */
418