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