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 ArrayOf<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::LArrayOf<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 OffsetTo<JustificationCategory> 362 justClassTable; /* Offset to the justification category state table. */ 363 OffsetTo<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 OffsetTo<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<OffsetTo<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 OffsetTo<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 OffsetTo<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