| /* | 
 |  * Copyright © 2018  Ebrahim Byagowi | 
 |  * | 
 |  *  This is part of HarfBuzz, a text shaping library. | 
 |  * | 
 |  * Permission is hereby granted, without written agreement and without | 
 |  * license or royalty fees, to use, copy, modify, and distribute this | 
 |  * software and its documentation for any purpose, provided that the | 
 |  * above copyright notice and the following two paragraphs appear in | 
 |  * all copies of this software. | 
 |  * | 
 |  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR | 
 |  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES | 
 |  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN | 
 |  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH | 
 |  * DAMAGE. | 
 |  * | 
 |  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, | 
 |  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND | 
 |  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS | 
 |  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO | 
 |  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. | 
 |  */ | 
 |  | 
 | #ifndef HB_AAT_LAYOUT_JUST_TABLE_HH | 
 | #define HB_AAT_LAYOUT_JUST_TABLE_HH | 
 |  | 
 | #include "hb-aat-layout-common.hh" | 
 | #include "hb-ot-layout.hh" | 
 | #include "hb-open-type.hh" | 
 |  | 
 | #include "hb-aat-layout-morx-table.hh" | 
 |  | 
 | /* | 
 |  * just -- Justification | 
 |  * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6just.html | 
 |  */ | 
 | #define HB_AAT_TAG_just HB_TAG('j','u','s','t') | 
 |  | 
 |  | 
 | namespace AAT { | 
 |  | 
 | using namespace OT; | 
 |  | 
 |  | 
 | struct ActionSubrecordHeader | 
 | { | 
 |   bool sanitize (hb_sanitize_context_t *c) const | 
 |   { | 
 |     TRACE_SANITIZE (this); | 
 |     return_trace (c->check_struct (this)); | 
 |   } | 
 |  | 
 |   HBUINT16	actionClass;	/* The JustClass value associated with this | 
 | 				 * ActionSubrecord. */ | 
 |   HBUINT16	actionType;	/* The type of postcompensation action. */ | 
 |   HBUINT16	actionLength;	/* Length of this ActionSubrecord record, which | 
 | 				 * must be a multiple of 4. */ | 
 |   public: | 
 |   DEFINE_SIZE_STATIC (6); | 
 | }; | 
 |  | 
 | struct DecompositionAction | 
 | { | 
 |   bool sanitize (hb_sanitize_context_t *c) const | 
 |   { | 
 |     TRACE_SANITIZE (this); | 
 |     return_trace (c->check_struct (this)); | 
 |   } | 
 |  | 
 |   ActionSubrecordHeader | 
 | 		header; | 
 |   HBFixed	lowerLimit;	/* If the distance factor is less than this value, | 
 | 				 * then the ligature is decomposed. */ | 
 |   HBFixed	upperLimit;	/* If the distance factor is greater than this value, | 
 | 				 * then the ligature is decomposed. */ | 
 |   HBUINT16	order;		/* Numerical order in which this ligature will | 
 | 				 * be decomposed; you may want infrequent ligatures | 
 | 				 * to decompose before more frequent ones. The ligatures | 
 | 				 * on the line of text will decompose in increasing | 
 | 				 * value of this field. */ | 
 |   Array16Of<HBUINT16> | 
 | 		decomposedglyphs; | 
 | 				/* Number of 16-bit glyph indexes that follow; | 
 | 				 * the ligature will be decomposed into these glyphs. | 
 | 				 * | 
 | 				 * Array of decomposed glyphs. */ | 
 |   public: | 
 |   DEFINE_SIZE_ARRAY (18, decomposedglyphs); | 
 | }; | 
 |  | 
 | struct UnconditionalAddGlyphAction | 
 | { | 
 |   bool sanitize (hb_sanitize_context_t *c) const | 
 |   { | 
 |     TRACE_SANITIZE (this); | 
 |     return_trace (c->check_struct (this)); | 
 |   } | 
 |  | 
 |   protected: | 
 |   ActionSubrecordHeader | 
 | 		header; | 
 |   HBGlyphID16	addGlyph;	/* Glyph that should be added if the distance factor | 
 | 				 * is growing. */ | 
 |  | 
 |   public: | 
 |   DEFINE_SIZE_STATIC (8); | 
 | }; | 
 |  | 
 | struct ConditionalAddGlyphAction | 
 | { | 
 |   bool sanitize (hb_sanitize_context_t *c) const | 
 |   { | 
 |     TRACE_SANITIZE (this); | 
 |     return_trace (c->check_struct (this)); | 
 |   } | 
 |  | 
 |   protected: | 
 |   ActionSubrecordHeader | 
 | 		header; | 
 |   HBFixed	substThreshold; /* Distance growth factor (in ems) at which | 
 | 				 * this glyph is replaced and the growth factor | 
 | 				 * recalculated. */ | 
 |   HBGlyphID16	addGlyph;	/* Glyph to be added as kashida. If this value is | 
 | 				 * 0xFFFF, no extra glyph will be added. Note that | 
 | 				 * generally when a glyph is added, justification | 
 | 				 * will need to be redone. */ | 
 |   HBGlyphID16	substGlyph;	/* Glyph to be substituted for this glyph if the | 
 | 				 * growth factor equals or exceeds the value of | 
 | 				 * substThreshold. */ | 
 |   public: | 
 |   DEFINE_SIZE_STATIC (14); | 
 | }; | 
 |  | 
 | struct DuctileGlyphAction | 
 | { | 
 |   bool sanitize (hb_sanitize_context_t *c) const | 
 |   { | 
 |     TRACE_SANITIZE (this); | 
 |     return_trace (c->check_struct (this)); | 
 |   } | 
 |  | 
 |   protected: | 
 |   ActionSubrecordHeader | 
 | 		header; | 
 |   HBUINT32	variationAxis;	/* The 4-byte tag identifying the ductile axis. | 
 | 				 * This would normally be 0x64756374 ('duct'), | 
 | 				 * but you may use any axis the font contains. */ | 
 |   HBFixed	minimumLimit;	/* The lowest value for the ductility axis that | 
 | 				 * still yields an acceptable appearance. Normally | 
 | 				 * this will be 1.0. */ | 
 |   HBFixed	noStretchValue; /* This is the default value that corresponds to | 
 | 				 * no change in appearance. Normally, this will | 
 | 				 * be 1.0. */ | 
 |   HBFixed	maximumLimit;	/* The highest value for the ductility axis that | 
 | 				 * still yields an acceptable appearance. */ | 
 |   public: | 
 |   DEFINE_SIZE_STATIC (22); | 
 | }; | 
 |  | 
 | struct RepeatedAddGlyphAction | 
 | { | 
 |   bool sanitize (hb_sanitize_context_t *c) const | 
 |   { | 
 |     TRACE_SANITIZE (this); | 
 |     return_trace (c->check_struct (this)); | 
 |   } | 
 |  | 
 |   protected: | 
 |   ActionSubrecordHeader | 
 | 		header; | 
 |   HBUINT16	flags;		/* Currently unused; set to 0. */ | 
 |   HBGlyphID16	glyph;		/* Glyph that should be added if the distance factor | 
 | 				 * is growing. */ | 
 |   public: | 
 |   DEFINE_SIZE_STATIC (10); | 
 | }; | 
 |  | 
 | struct ActionSubrecord | 
 | { | 
 |   unsigned int get_length () const { return u.header.actionLength; } | 
 |  | 
 |   bool sanitize (hb_sanitize_context_t *c) const | 
 |   { | 
 |     TRACE_SANITIZE (this); | 
 |     if (unlikely (!c->check_struct (this))) | 
 |       return_trace (false); | 
 |  | 
 |     switch (u.header.actionType) | 
 |     { | 
 |     case 0:  return_trace (u.decompositionAction.sanitize (c)); | 
 |     case 1:  return_trace (u.unconditionalAddGlyphAction.sanitize (c)); | 
 |     case 2:  return_trace (u.conditionalAddGlyphAction.sanitize (c)); | 
 |     // case 3: return_trace (u.stretchGlyphAction.sanitize (c)); | 
 |     case 4:  return_trace (u.decompositionAction.sanitize (c)); | 
 |     case 5:  return_trace (u.decompositionAction.sanitize (c)); | 
 |     default: return_trace (true); | 
 |     } | 
 |   } | 
 |  | 
 |   protected: | 
 |   union	{ | 
 |   ActionSubrecordHeader		header; | 
 |   DecompositionAction		decompositionAction; | 
 |   UnconditionalAddGlyphAction	unconditionalAddGlyphAction; | 
 |   ConditionalAddGlyphAction	conditionalAddGlyphAction; | 
 |   /* StretchGlyphAction stretchGlyphAction; -- Not supported by CoreText */ | 
 |   DuctileGlyphAction		ductileGlyphAction; | 
 |   RepeatedAddGlyphAction	repeatedAddGlyphAction; | 
 |   } u;				/* Data. The format of this data depends on | 
 | 				 * the value of the actionType field. */ | 
 |   public: | 
 |   DEFINE_SIZE_UNION (6, header); | 
 | }; | 
 |  | 
 | struct PostcompensationActionChain | 
 | { | 
 |   bool sanitize (hb_sanitize_context_t *c) const | 
 |   { | 
 |     TRACE_SANITIZE (this); | 
 |     if (unlikely (!c->check_struct (this))) | 
 |       return_trace (false); | 
 |  | 
 |     unsigned int offset = min_size; | 
 |     for (unsigned int i = 0; i < count; i++) | 
 |     { | 
 |       const ActionSubrecord& subrecord = StructAtOffset<ActionSubrecord> (this, offset); | 
 |       if (unlikely (!subrecord.sanitize (c))) return_trace (false); | 
 |       offset += subrecord.get_length (); | 
 |     } | 
 |  | 
 |     return_trace (true); | 
 |   } | 
 |  | 
 |   protected: | 
 |   HBUINT32	count; | 
 |  | 
 |   public: | 
 |   DEFINE_SIZE_STATIC (4); | 
 | }; | 
 |  | 
 | struct JustWidthDeltaEntry | 
 | { | 
 |   enum Flags | 
 |   { | 
 |     Reserved1		=0xE000,/* Reserved. You should set these bits to zero. */ | 
 |     UnlimiteGap		=0x1000,/* The glyph can take unlimited gap. When this | 
 | 				 * glyph participates in the justification process, | 
 | 				 * it and any other glyphs on the line having this | 
 | 				 * bit set absorb all the remaining gap. */ | 
 |     Reserved2		=0x0FF0,/* Reserved. You should set these bits to zero. */ | 
 |     Priority		=0x000F /* The justification priority of the glyph. */ | 
 |   }; | 
 |  | 
 |   enum Priority | 
 |   { | 
 |     Kashida		= 0,	/* Kashida priority. This is the highest priority | 
 | 				 * during justification. */ | 
 |     Whitespace		= 1,	/* Whitespace priority. Any whitespace glyphs (as | 
 | 				 * identified in the glyph properties table) will | 
 | 				 * get this priority. */ | 
 |     InterCharacter	= 2,	/* Inter-character priority. Give this to any | 
 | 				 * remaining glyphs. */ | 
 |     NullPriority	= 3	/* Null priority. You should set this priority for | 
 | 				 * glyphs that only participate in justification | 
 | 				 * after the above priorities. Normally all glyphs | 
 | 				 * have one of the previous three values. If you | 
 | 				 * don't want a glyph to participate in justification, | 
 | 				 * and you don't want to set its factors to zero, | 
 | 				 * you may instead assign it to the null priority. */ | 
 |   }; | 
 |  | 
 |   protected: | 
 |   HBFixed	beforeGrowLimit;/* The ratio by which the advance width of the | 
 | 				 * glyph is permitted to grow on the left or top side. */ | 
 |   HBFixed	beforeShrinkLimit; | 
 | 				/* The ratio by which the advance width of the | 
 | 				 * glyph is permitted to shrink on the left or top side. */ | 
 |   HBFixed	afterGrowLimit;	/* The ratio by which the advance width of the glyph | 
 | 				 * is permitted to shrink on the left or top side. */ | 
 |   HBFixed	afterShrinkLimit; | 
 | 				/* The ratio by which the advance width of the glyph | 
 | 				 * is at most permitted to shrink on the right or | 
 | 				 * bottom side. */ | 
 |   HBUINT16	growFlags;	/* Flags controlling the grow case. */ | 
 |   HBUINT16	shrinkFlags;	/* Flags controlling the shrink case. */ | 
 |  | 
 |   public: | 
 |   DEFINE_SIZE_STATIC (20); | 
 | }; | 
 |  | 
 | struct WidthDeltaPair | 
 | { | 
 |   bool sanitize (hb_sanitize_context_t *c) const | 
 |   { | 
 |     TRACE_SANITIZE (this); | 
 |     return_trace (c->check_struct (this)); | 
 |   } | 
 |  | 
 |   protected: | 
 |   HBUINT32	justClass;	/* The justification category associated | 
 | 				 * with the wdRecord field. Only 7 bits of | 
 | 				 * this field are used. (The other bits are | 
 | 				 * used as padding to guarantee longword | 
 | 				 * alignment of the following record). */ | 
 |   JustWidthDeltaEntry | 
 | 		wdRecord;	/* The actual width delta record. */ | 
 |  | 
 |   public: | 
 |   DEFINE_SIZE_STATIC (24); | 
 | }; | 
 |  | 
 | typedef OT::Array32Of<WidthDeltaPair> WidthDeltaCluster; | 
 |  | 
 | struct JustificationCategory | 
 | { | 
 |   typedef void EntryData; | 
 |  | 
 |   enum Flags | 
 |   { | 
 |     SetMark		=0x8000,/* If set, make the current glyph the marked | 
 | 				 * glyph. */ | 
 |     DontAdvance		=0x4000,/* If set, don't advance to the next glyph before | 
 | 				 * going to the new state. */ | 
 |     MarkCategory	=0x3F80,/* The justification category for the marked | 
 | 				 * glyph if nonzero. */ | 
 |     CurrentCategory	=0x007F /* The justification category for the current | 
 | 				 * glyph if nonzero. */ | 
 |   }; | 
 |  | 
 |   bool sanitize (hb_sanitize_context_t *c, const void *base) const | 
 |   { | 
 |     TRACE_SANITIZE (this); | 
 |     return_trace (likely (c->check_struct (this) && | 
 | 			  morphHeader.sanitize (c) && | 
 | 			  stHeader.sanitize (c))); | 
 |   } | 
 |  | 
 |   protected: | 
 |   ChainSubtable<ObsoleteTypes> | 
 | 		morphHeader;	/* Metamorphosis-style subtable header. */ | 
 |   StateTable<ObsoleteTypes, EntryData> | 
 | 		stHeader;	/* The justification insertion state table header */ | 
 |   public: | 
 |   DEFINE_SIZE_STATIC (30); | 
 | }; | 
 |  | 
 | struct JustificationHeader | 
 | { | 
 |   bool sanitize (hb_sanitize_context_t *c, const void *base) const | 
 |   { | 
 |     TRACE_SANITIZE (this); | 
 |     return_trace (likely (c->check_struct (this) && | 
 | 			  justClassTable.sanitize (c, base, base) && | 
 | 			  wdcTable.sanitize (c, base) && | 
 | 			  pcTable.sanitize (c, base) && | 
 | 			  lookupTable.sanitize (c, base))); | 
 |   } | 
 |  | 
 |   protected: | 
 |   Offset16To<JustificationCategory> | 
 | 		justClassTable;	/* Offset to the justification category state table. */ | 
 |   Offset16To<WidthDeltaCluster> | 
 | 		wdcTable;	/* Offset from start of justification table to start | 
 | 				 * of the subtable containing the width delta factors | 
 | 				 * for the glyphs in your font. | 
 | 				 * | 
 | 				 * The width delta clusters table. */ | 
 |   Offset16To<PostcompensationActionChain> | 
 | 		pcTable;	/* Offset from start of justification table to start | 
 | 				 * of postcompensation subtable (set to zero if none). | 
 | 				 * | 
 | 				 * The postcompensation subtable, if present in the font. */ | 
 |   Lookup<Offset16To<WidthDeltaCluster>> | 
 | 		lookupTable;	/* Lookup table associating glyphs with width delta | 
 | 				 * clusters. See the description of Width Delta Clusters | 
 | 				 * table for details on how to interpret the lookup values. */ | 
 |  | 
 |   public: | 
 |   DEFINE_SIZE_MIN (8); | 
 | }; | 
 |  | 
 | struct just | 
 | { | 
 |   static constexpr hb_tag_t tableTag = HB_AAT_TAG_just; | 
 |  | 
 |   bool sanitize (hb_sanitize_context_t *c) const | 
 |   { | 
 |     TRACE_SANITIZE (this); | 
 |  | 
 |     return_trace (likely (c->check_struct (this) && | 
 | 			  version.major == 1 && | 
 | 			  horizData.sanitize (c, this, this) && | 
 | 			  vertData.sanitize (c, this, this))); | 
 |   } | 
 |  | 
 |   protected: | 
 |   FixedVersion<>version;	/* Version of the justification table | 
 | 				 * (0x00010000u for version 1.0). */ | 
 |   HBUINT16	format;		/* Format of the justification table (set to 0). */ | 
 |   Offset16To<JustificationHeader> | 
 | 		horizData;	/* Byte offset from the start of the justification table | 
 | 				 * to the header for tables that contain justification | 
 | 				 * information for horizontal text. | 
 | 				 * If you are not including this information, | 
 | 				 * store 0. */ | 
 |   Offset16To<JustificationHeader> | 
 | 		vertData;	/* ditto, vertical */ | 
 |  | 
 |   public: | 
 |   DEFINE_SIZE_STATIC (10); | 
 | }; | 
 |  | 
 | } /* namespace AAT */ | 
 |  | 
 |  | 
 | #endif /* HB_AAT_LAYOUT_JUST_TABLE_HH */ |