blob: d745c1143171c68bd5ea273860645e1011fb9976 [file] [log] [blame]
/*
* 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 (likely (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 (likely (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 (likely (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 (likely (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 tha
* 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 (likely (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 (likely (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 */