Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/harfbuzz/src/OT/Layout/GPOS/CursivePosFormat1.hh @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 1 #ifndef OT_LAYOUT_GPOS_CURSIVEPOSFORMAT1_HH | |
| 2 #define OT_LAYOUT_GPOS_CURSIVEPOSFORMAT1_HH | |
| 3 | |
| 4 #include "Anchor.hh" | |
| 5 | |
| 6 namespace OT { | |
| 7 namespace Layout { | |
| 8 namespace GPOS_impl { | |
| 9 | |
| 10 struct EntryExitRecord | |
| 11 { | |
| 12 friend struct CursivePosFormat1; | |
| 13 | |
| 14 bool sanitize (hb_sanitize_context_t *c, const void *base) const | |
| 15 { | |
| 16 TRACE_SANITIZE (this); | |
| 17 return_trace (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base)); | |
| 18 } | |
| 19 | |
| 20 void collect_variation_indices (hb_collect_variation_indices_context_t *c, | |
| 21 const void *src_base) const | |
| 22 { | |
| 23 (src_base+entryAnchor).collect_variation_indices (c); | |
| 24 (src_base+exitAnchor).collect_variation_indices (c); | |
| 25 } | |
| 26 | |
| 27 EntryExitRecord* subset (hb_subset_context_t *c, | |
| 28 const void *src_base) const | |
| 29 { | |
| 30 TRACE_SERIALIZE (this); | |
| 31 auto *out = c->serializer->embed (this); | |
| 32 if (unlikely (!out)) return_trace (nullptr); | |
| 33 | |
| 34 out->entryAnchor.serialize_subset (c, entryAnchor, src_base); | |
| 35 out->exitAnchor.serialize_subset (c, exitAnchor, src_base); | |
| 36 return_trace (out); | |
| 37 } | |
| 38 | |
| 39 protected: | |
| 40 Offset16To<Anchor> | |
| 41 entryAnchor; /* Offset to EntryAnchor table--from | |
| 42 * beginning of CursivePos | |
| 43 * subtable--may be NULL */ | |
| 44 Offset16To<Anchor> | |
| 45 exitAnchor; /* Offset to ExitAnchor table--from | |
| 46 * beginning of CursivePos | |
| 47 * subtable--may be NULL */ | |
| 48 public: | |
| 49 DEFINE_SIZE_STATIC (4); | |
| 50 }; | |
| 51 | |
| 52 static void | |
| 53 reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent) { | |
| 54 int chain = pos[i].attach_chain(), type = pos[i].attach_type(); | |
| 55 if (likely (!chain || 0 == (type & ATTACH_TYPE_CURSIVE))) | |
| 56 return; | |
| 57 | |
| 58 pos[i].attach_chain() = 0; | |
| 59 | |
| 60 unsigned int j = (int) i + chain; | |
| 61 | |
| 62 /* Stop if we see new parent in the chain. */ | |
| 63 if (j == new_parent) | |
| 64 return; | |
| 65 | |
| 66 reverse_cursive_minor_offset (pos, j, direction, new_parent); | |
| 67 | |
| 68 if (HB_DIRECTION_IS_HORIZONTAL (direction)) | |
| 69 pos[j].y_offset = -pos[i].y_offset; | |
| 70 else | |
| 71 pos[j].x_offset = -pos[i].x_offset; | |
| 72 | |
| 73 pos[j].attach_chain() = -chain; | |
| 74 pos[j].attach_type() = type; | |
| 75 } | |
| 76 | |
| 77 | |
| 78 struct CursivePosFormat1 | |
| 79 { | |
| 80 protected: | |
| 81 HBUINT16 format; /* Format identifier--format = 1 */ | |
| 82 Offset16To<Coverage> | |
| 83 coverage; /* Offset to Coverage table--from | |
| 84 * beginning of subtable */ | |
| 85 Array16Of<EntryExitRecord> | |
| 86 entryExitRecord; /* Array of EntryExit records--in | |
| 87 * Coverage Index order */ | |
| 88 public: | |
| 89 DEFINE_SIZE_ARRAY (6, entryExitRecord); | |
| 90 | |
| 91 bool sanitize (hb_sanitize_context_t *c) const | |
| 92 { | |
| 93 TRACE_SANITIZE (this); | |
| 94 return_trace (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this)); | |
| 95 } | |
| 96 | |
| 97 bool intersects (const hb_set_t *glyphs) const | |
| 98 { return (this+coverage).intersects (glyphs); } | |
| 99 | |
| 100 void closure_lookups (hb_closure_lookups_context_t *c) const {} | |
| 101 | |
| 102 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const | |
| 103 { | |
| 104 + hb_zip (this+coverage, entryExitRecord) | |
| 105 | hb_filter (c->glyph_set, hb_first) | |
| 106 | hb_map (hb_second) | |
| 107 | hb_apply ([&] (const EntryExitRecord& record) { record.collect_variation_indices (c, this); }) | |
| 108 ; | |
| 109 } | |
| 110 | |
| 111 void collect_glyphs (hb_collect_glyphs_context_t *c) const | |
| 112 { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; } | |
| 113 | |
| 114 const Coverage &get_coverage () const { return this+coverage; } | |
| 115 | |
| 116 bool apply (hb_ot_apply_context_t *c) const | |
| 117 { | |
| 118 TRACE_APPLY (this); | |
| 119 hb_buffer_t *buffer = c->buffer; | |
| 120 | |
| 121 const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage (buffer->cur().codepoint)]; | |
| 122 if (!this_record.entryAnchor) return_trace (false); | |
| 123 | |
| 124 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; | |
| 125 skippy_iter.reset (buffer->idx, 1); | |
| 126 unsigned unsafe_from; | |
| 127 if (!skippy_iter.prev (&unsafe_from)) | |
| 128 { | |
| 129 buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1); | |
| 130 return_trace (false); | |
| 131 } | |
| 132 | |
| 133 const EntryExitRecord &prev_record = entryExitRecord[(this+coverage).get_coverage (buffer->info[skippy_iter.idx].codepoint)]; | |
| 134 if (!prev_record.exitAnchor) | |
| 135 { | |
| 136 buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); | |
| 137 return_trace (false); | |
| 138 } | |
| 139 | |
| 140 unsigned int i = skippy_iter.idx; | |
| 141 unsigned int j = buffer->idx; | |
| 142 | |
| 143 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) | |
| 144 { | |
| 145 c->buffer->message (c->font, | |
| 146 "cursive attaching glyph at %d to glyph at %d", | |
| 147 i, j); | |
| 148 } | |
| 149 | |
| 150 buffer->unsafe_to_break (i, j + 1); | |
| 151 float entry_x, entry_y, exit_x, exit_y; | |
| 152 (this+prev_record.exitAnchor).get_anchor (c, buffer->info[i].codepoint, &exit_x, &exit_y); | |
| 153 (this+this_record.entryAnchor).get_anchor (c, buffer->info[j].codepoint, &entry_x, &entry_y); | |
| 154 | |
| 155 hb_glyph_position_t *pos = buffer->pos; | |
| 156 | |
| 157 hb_position_t d; | |
| 158 /* Main-direction adjustment */ | |
| 159 switch (c->direction) { | |
| 160 case HB_DIRECTION_LTR: | |
| 161 pos[i].x_advance = roundf (exit_x) + pos[i].x_offset; | |
| 162 | |
| 163 d = roundf (entry_x) + pos[j].x_offset; | |
| 164 pos[j].x_advance -= d; | |
| 165 pos[j].x_offset -= d; | |
| 166 break; | |
| 167 case HB_DIRECTION_RTL: | |
| 168 d = roundf (exit_x) + pos[i].x_offset; | |
| 169 pos[i].x_advance -= d; | |
| 170 pos[i].x_offset -= d; | |
| 171 | |
| 172 pos[j].x_advance = roundf (entry_x) + pos[j].x_offset; | |
| 173 break; | |
| 174 case HB_DIRECTION_TTB: | |
| 175 pos[i].y_advance = roundf (exit_y) + pos[i].y_offset; | |
| 176 | |
| 177 d = roundf (entry_y) + pos[j].y_offset; | |
| 178 pos[j].y_advance -= d; | |
| 179 pos[j].y_offset -= d; | |
| 180 break; | |
| 181 case HB_DIRECTION_BTT: | |
| 182 d = roundf (exit_y) + pos[i].y_offset; | |
| 183 pos[i].y_advance -= d; | |
| 184 pos[i].y_offset -= d; | |
| 185 | |
| 186 pos[j].y_advance = roundf (entry_y); | |
| 187 break; | |
| 188 case HB_DIRECTION_INVALID: | |
| 189 default: | |
| 190 break; | |
| 191 } | |
| 192 | |
| 193 /* Cross-direction adjustment */ | |
| 194 | |
| 195 /* We attach child to parent (think graph theory and rooted trees whereas | |
| 196 * the root stays on baseline and each node aligns itself against its | |
| 197 * parent. | |
| 198 * | |
| 199 * Optimize things for the case of RightToLeft, as that's most common in | |
| 200 * Arabic. */ | |
| 201 unsigned int child = i; | |
| 202 unsigned int parent = j; | |
| 203 hb_position_t x_offset = entry_x - exit_x; | |
| 204 hb_position_t y_offset = entry_y - exit_y; | |
| 205 if (!(c->lookup_props & LookupFlag::RightToLeft)) | |
| 206 { | |
| 207 unsigned int k = child; | |
| 208 child = parent; | |
| 209 parent = k; | |
| 210 x_offset = -x_offset; | |
| 211 y_offset = -y_offset; | |
| 212 } | |
| 213 | |
| 214 /* If child was already connected to someone else, walk through its old | |
| 215 * chain and reverse the link direction, such that the whole tree of its | |
| 216 * previous connection now attaches to new parent. Watch out for case | |
| 217 * where new parent is on the path from old chain... | |
| 218 */ | |
| 219 reverse_cursive_minor_offset (pos, child, c->direction, parent); | |
| 220 | |
| 221 pos[child].attach_type() = ATTACH_TYPE_CURSIVE; | |
| 222 pos[child].attach_chain() = (int) parent - (int) child; | |
| 223 buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT; | |
| 224 if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction))) | |
| 225 pos[child].y_offset = y_offset; | |
| 226 else | |
| 227 pos[child].x_offset = x_offset; | |
| 228 | |
| 229 /* If parent was attached to child, separate them. | |
| 230 * https://github.com/harfbuzz/harfbuzz/issues/2469 | |
| 231 */ | |
| 232 if (unlikely (pos[parent].attach_chain() == -pos[child].attach_chain())) | |
| 233 { | |
| 234 pos[parent].attach_chain() = 0; | |
| 235 if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction))) | |
| 236 pos[parent].y_offset = 0; | |
| 237 else | |
| 238 pos[parent].x_offset = 0; | |
| 239 } | |
| 240 | |
| 241 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) | |
| 242 { | |
| 243 c->buffer->message (c->font, | |
| 244 "cursive attached glyph at %d to glyph at %d", | |
| 245 i, j); | |
| 246 } | |
| 247 | |
| 248 buffer->idx++; | |
| 249 return_trace (true); | |
| 250 } | |
| 251 | |
| 252 template <typename Iterator, | |
| 253 hb_requires (hb_is_iterator (Iterator))> | |
| 254 void serialize (hb_subset_context_t *c, | |
| 255 Iterator it, | |
| 256 const void *src_base) | |
| 257 { | |
| 258 if (unlikely (!c->serializer->extend_min ((*this)))) return; | |
| 259 this->format = 1; | |
| 260 this->entryExitRecord.len = it.len (); | |
| 261 | |
| 262 for (const EntryExitRecord& entry_record : + it | |
| 263 | hb_map (hb_second)) | |
| 264 entry_record.subset (c, src_base); | |
| 265 | |
| 266 auto glyphs = | |
| 267 + it | |
| 268 | hb_map_retains_sorting (hb_first) | |
| 269 ; | |
| 270 | |
| 271 coverage.serialize_serialize (c->serializer, glyphs); | |
| 272 } | |
| 273 | |
| 274 bool subset (hb_subset_context_t *c) const | |
| 275 { | |
| 276 TRACE_SUBSET (this); | |
| 277 const hb_set_t &glyphset = *c->plan->glyphset_gsub (); | |
| 278 const hb_map_t &glyph_map = *c->plan->glyph_map; | |
| 279 | |
| 280 auto *out = c->serializer->start_embed (*this); | |
| 281 if (unlikely (!out)) return_trace (false); | |
| 282 | |
| 283 auto it = | |
| 284 + hb_zip (this+coverage, entryExitRecord) | |
| 285 | hb_filter (glyphset, hb_first) | |
| 286 | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const EntryExitRecord&> p) -> hb_pair_t<hb_codepoint_t, const EntryExitRecord&> | |
| 287 { return hb_pair (glyph_map[p.first], p.second);}) | |
| 288 ; | |
| 289 | |
| 290 bool ret = bool (it); | |
| 291 out->serialize (c, it, this); | |
| 292 return_trace (ret); | |
| 293 } | |
| 294 }; | |
| 295 | |
| 296 | |
| 297 } | |
| 298 } | |
| 299 } | |
| 300 | |
| 301 #endif /* OT_LAYOUT_GPOS_CURSIVEPOSFORMAT1_HH */ |
