| /* | |
| * 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; | |
| F16DOT16 lowerLimit; /* If the distance factor is less than this value, | |
| * then the ligature is decomposed. */ | |
| F16DOT16 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; | |
| F16DOT16 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. */ | |
| F16DOT16 minimumLimit; /* The lowest value for the ductility axis that | |
| * still yields an acceptable appearance. Normally | |
| * this will be 1.0. */ | |
| F16DOT16 noStretchValue; /* This is the default value that corresponds to | |
| * no change in appearance. Normally, this will | |
| * be 1.0. */ | |
| F16DOT16 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); | |
| hb_barrier (); | |
| switch (u.header.actionType) | |
| { | |
| case 0: hb_barrier (); return_trace (u.decompositionAction.sanitize (c)); | |
| case 1: hb_barrier (); return_trace (u.unconditionalAddGlyphAction.sanitize (c)); | |
| case 2: hb_barrier (); return_trace (u.conditionalAddGlyphAction.sanitize (c)); | |
| // case 3: hb_barrier (); return_trace (u.stretchGlyphAction.sanitize (c)); | |
| case 4: hb_barrier (); return_trace (u.decompositionAction.sanitize (c)); | |
| case 5: hb_barrier (); 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); | |
| hb_barrier (); | |
| 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: | |
| F16DOT16 beforeGrowLimit;/* The ratio by which the advance width of the | |
| * glyph is permitted to grow on the left or top side. */ | |
| F16DOT16 beforeShrinkLimit; | |
| /* The ratio by which the advance width of the | |
| * glyph is permitted to shrink on the left or top side. */ | |
| F16DOT16 afterGrowLimit; /* The ratio by which the advance width of the glyph | |
| * is permitted to shrink on the left or top side. */ | |
| F16DOT16 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) && | |
| hb_barrier () && | |
| 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 */ |