Slot.cpp (19139B)
1 /* GRAPHITE2 LICENSING 2 3 Copyright 2010, SIL International 4 All rights reserved. 5 6 This library is free software; you can redistribute it and/or modify 7 it under the terms of the GNU Lesser General Public License as published 8 by the Free Software Foundation; either version 2.1 of License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 Lesser General Public License for more details. 15 16 You should also have received a copy of the GNU Lesser General Public 17 License along with this library in the file named "LICENSE". 18 If not, write to the Free Software Foundation, 51 Franklin Street, 19 Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 20 internet at http://www.fsf.org/licenses/lgpl.html. 21 22 Alternatively, the contents of this file may be used under the terms of the 23 Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public 24 License, as published by the Free Software Foundation, either version 2 25 of the License or (at your option) any later version. 26 */ 27 #include "inc/Segment.h" 28 #include "inc/Slot.h" 29 #include "inc/Silf.h" 30 #include "inc/CharInfo.h" 31 #include "inc/Rule.h" 32 #include "inc/Collider.h" 33 34 35 using namespace graphite2; 36 37 Slot::Slot(int16 *user_attrs) : 38 m_next(NULL), m_prev(NULL), 39 m_glyphid(0), m_realglyphid(0), m_original(0), m_before(0), m_after(0), 40 m_index(0), m_parent(NULL), m_child(NULL), m_sibling(NULL), 41 m_position(0, 0), m_shift(0, 0), m_advance(0, 0), 42 m_attach(0, 0), m_with(0, 0), m_just(0.), 43 m_flags(0), m_attLevel(0), m_bidiCls(-1), m_bidiLevel(0), 44 m_userAttr(user_attrs), m_justs(NULL) 45 { 46 } 47 48 // take care, this does not copy any of the GrSlot pointer fields 49 void Slot::set(const Slot & orig, int charOffset, size_t sizeAttr, size_t justLevels, size_t numChars) 50 { 51 // leave m_next and m_prev unchanged 52 m_glyphid = orig.m_glyphid; 53 m_realglyphid = orig.m_realglyphid; 54 m_original = orig.m_original + charOffset; 55 if (charOffset + int(orig.m_before) < 0) 56 m_before = 0; 57 else 58 m_before = orig.m_before + charOffset; 59 if (charOffset <= 0 && orig.m_after + charOffset >= numChars) 60 m_after = int(numChars) - 1; 61 else 62 m_after = orig.m_after + charOffset; 63 m_parent = NULL; 64 m_child = NULL; 65 m_sibling = NULL; 66 m_position = orig.m_position; 67 m_shift = orig.m_shift; 68 m_advance = orig.m_advance; 69 m_attach = orig.m_attach; 70 m_with = orig.m_with; 71 m_flags = orig.m_flags; 72 m_attLevel = orig.m_attLevel; 73 m_bidiCls = orig.m_bidiCls; 74 m_bidiLevel = orig.m_bidiLevel; 75 if (m_userAttr && orig.m_userAttr) 76 memcpy(m_userAttr, orig.m_userAttr, sizeAttr * sizeof(*m_userAttr)); 77 if (m_justs && orig.m_justs) 78 memcpy(m_justs, orig.m_justs, SlotJustify::size_of(justLevels)); 79 } 80 81 void Slot::update(int /*numGrSlots*/, int numCharInfo, Position &relpos) 82 { 83 m_before += numCharInfo; 84 m_after += numCharInfo; 85 m_position = m_position + relpos; 86 } 87 88 Position Slot::finalise(const Segment *seg, const Font *font, Position & base, Rect & bbox, uint8 attrLevel, float & clusterMin, bool rtl, bool isFinal, int depth) 89 { 90 SlotCollision *coll = NULL; 91 if (depth > 100 || (attrLevel && m_attLevel > attrLevel)) return Position(0, 0); 92 float scale = font ? font->scale() : 1.0f; 93 Position shift(m_shift.x * (rtl * -2 + 1) + m_just, m_shift.y); 94 float tAdvance = m_advance.x + m_just; 95 if (isFinal && (coll = seg->collisionInfo(this))) 96 { 97 const Position &collshift = coll->offset(); 98 if (!(coll->flags() & SlotCollision::COLL_KERN) || rtl) 99 shift = shift + collshift; 100 } 101 const GlyphFace * glyphFace = seg->getFace()->glyphs().glyphSafe(glyph()); 102 if (font) 103 { 104 scale = font->scale(); 105 shift *= scale; 106 if (font->isHinted() && glyphFace) 107 tAdvance = (m_advance.x - glyphFace->theAdvance().x + m_just) * scale + font->advance(glyph()); 108 else 109 tAdvance *= scale; 110 } 111 Position res; 112 113 m_position = base + shift; 114 if (!m_parent) 115 { 116 res = base + Position(tAdvance, m_advance.y * scale); 117 clusterMin = m_position.x; 118 } 119 else 120 { 121 float tAdv; 122 m_position += (m_attach - m_with) * scale; 123 tAdv = m_advance.x >= 0.5f ? m_position.x + tAdvance - shift.x : 0.f; 124 res = Position(tAdv, 0); 125 if ((m_advance.x >= 0.5f || m_position.x < 0) && m_position.x < clusterMin) clusterMin = m_position.x; 126 } 127 128 if (glyphFace) 129 { 130 Rect ourBbox = glyphFace->theBBox() * scale + m_position; 131 bbox = bbox.widen(ourBbox); 132 } 133 134 if (m_child && m_child != this && m_child->attachedTo() == this) 135 { 136 Position tRes = m_child->finalise(seg, font, m_position, bbox, attrLevel, clusterMin, rtl, isFinal, depth + 1); 137 if ((!m_parent || m_advance.x >= 0.5f) && tRes.x > res.x) res = tRes; 138 } 139 140 if (m_parent && m_sibling && m_sibling != this && m_sibling->attachedTo() == m_parent) 141 { 142 Position tRes = m_sibling->finalise(seg, font, base, bbox, attrLevel, clusterMin, rtl, isFinal, depth + 1); 143 if (tRes.x > res.x) res = tRes; 144 } 145 146 if (!m_parent && clusterMin < base.x) 147 { 148 Position adj = Position(m_position.x - clusterMin, 0.); 149 res += adj; 150 m_position += adj; 151 if (m_child) m_child->floodShift(adj); 152 } 153 return res; 154 } 155 156 int32 Slot::clusterMetric(const Segment *seg, uint8 metric, uint8 attrLevel, bool rtl) 157 { 158 Position base; 159 if (glyph() >= seg->getFace()->glyphs().numGlyphs()) 160 return 0; 161 Rect bbox = seg->theGlyphBBoxTemporary(glyph()); 162 float clusterMin = 0.; 163 Position res = finalise(seg, NULL, base, bbox, attrLevel, clusterMin, rtl, false); 164 165 switch (metrics(metric)) 166 { 167 case kgmetLsb : 168 return int32(bbox.bl.x); 169 case kgmetRsb : 170 return int32(res.x - bbox.tr.x); 171 case kgmetBbTop : 172 return int32(bbox.tr.y); 173 case kgmetBbBottom : 174 return int32(bbox.bl.y); 175 case kgmetBbLeft : 176 return int32(bbox.bl.x); 177 case kgmetBbRight : 178 return int32(bbox.tr.x); 179 case kgmetBbWidth : 180 return int32(bbox.tr.x - bbox.bl.x); 181 case kgmetBbHeight : 182 return int32(bbox.tr.y - bbox.bl.y); 183 case kgmetAdvWidth : 184 return int32(res.x); 185 case kgmetAdvHeight : 186 return int32(res.y); 187 default : 188 return 0; 189 } 190 } 191 192 #define SLOTGETCOLATTR(x) { SlotCollision *c = seg->collisionInfo(this); return c ? int(c-> x) : 0; } 193 194 int Slot::getAttr(const Segment *seg, attrCode ind, uint8 subindex) const 195 { 196 if (ind >= gr_slatJStretch && ind < gr_slatJStretch + 20 && ind != gr_slatJWidth) 197 { 198 int indx = ind - gr_slatJStretch; 199 return getJustify(seg, indx / 5, indx % 5); 200 } 201 202 switch (ind) 203 { 204 case gr_slatAdvX : return int(m_advance.x); 205 case gr_slatAdvY : return int(m_advance.y); 206 case gr_slatAttTo : return m_parent ? 1 : 0; 207 case gr_slatAttX : return int(m_attach.x); 208 case gr_slatAttY : return int(m_attach.y); 209 case gr_slatAttXOff : 210 case gr_slatAttYOff : return 0; 211 case gr_slatAttWithX : return int(m_with.x); 212 case gr_slatAttWithY : return int(m_with.y); 213 case gr_slatAttWithXOff: 214 case gr_slatAttWithYOff:return 0; 215 case gr_slatAttLevel : return m_attLevel; 216 case gr_slatBreak : return seg->charinfo(m_original)->breakWeight(); 217 case gr_slatCompRef : return 0; 218 case gr_slatDir : return seg->dir() & 1; 219 case gr_slatInsert : return isInsertBefore(); 220 case gr_slatPosX : return int(m_position.x); // but need to calculate it 221 case gr_slatPosY : return int(m_position.y); 222 case gr_slatShiftX : return int(m_shift.x); 223 case gr_slatShiftY : return int(m_shift.y); 224 case gr_slatMeasureSol: return -1; // err what's this? 225 case gr_slatMeasureEol: return -1; 226 case gr_slatJWidth: return int(m_just); 227 case gr_slatUserDefnV1: subindex = 0; GR_FALLTHROUGH; 228 // no break 229 case gr_slatUserDefn : return subindex < seg->numAttrs() ? m_userAttr[subindex] : 0; 230 case gr_slatSegSplit : return seg->charinfo(m_original)->flags() & 3; 231 case gr_slatBidiLevel: return m_bidiLevel; 232 case gr_slatColFlags : { SlotCollision *c = seg->collisionInfo(this); return c ? c->flags() : 0; } 233 case gr_slatColLimitblx:SLOTGETCOLATTR(limit().bl.x) 234 case gr_slatColLimitbly:SLOTGETCOLATTR(limit().bl.y) 235 case gr_slatColLimittrx:SLOTGETCOLATTR(limit().tr.x) 236 case gr_slatColLimittry:SLOTGETCOLATTR(limit().tr.y) 237 case gr_slatColShiftx : SLOTGETCOLATTR(offset().x) 238 case gr_slatColShifty : SLOTGETCOLATTR(offset().y) 239 case gr_slatColMargin : SLOTGETCOLATTR(margin()) 240 case gr_slatColMarginWt:SLOTGETCOLATTR(marginWt()) 241 case gr_slatColExclGlyph:SLOTGETCOLATTR(exclGlyph()) 242 case gr_slatColExclOffx:SLOTGETCOLATTR(exclOffset().x) 243 case gr_slatColExclOffy:SLOTGETCOLATTR(exclOffset().y) 244 case gr_slatSeqClass : SLOTGETCOLATTR(seqClass()) 245 case gr_slatSeqProxClass:SLOTGETCOLATTR(seqProxClass()) 246 case gr_slatSeqOrder : SLOTGETCOLATTR(seqOrder()) 247 case gr_slatSeqAboveXoff:SLOTGETCOLATTR(seqAboveXoff()) 248 case gr_slatSeqAboveWt: SLOTGETCOLATTR(seqAboveWt()) 249 case gr_slatSeqBelowXlim:SLOTGETCOLATTR(seqBelowXlim()) 250 case gr_slatSeqBelowWt: SLOTGETCOLATTR(seqBelowWt()) 251 case gr_slatSeqValignHt:SLOTGETCOLATTR(seqValignHt()) 252 case gr_slatSeqValignWt:SLOTGETCOLATTR(seqValignWt()) 253 default : return 0; 254 } 255 } 256 257 #define SLOTCOLSETATTR(x) { \ 258 SlotCollision *c = seg->collisionInfo(this); \ 259 if (c) { c-> x ; c->setFlags(c->flags() & ~SlotCollision::COLL_KNOWN); } \ 260 break; } 261 #define SLOTCOLSETCOMPLEXATTR(t, y, x) { \ 262 SlotCollision *c = seg->collisionInfo(this); \ 263 if (c) { \ 264 const t &s = c-> y; \ 265 c-> x ; c->setFlags(c->flags() & ~SlotCollision::COLL_KNOWN); } \ 266 break; } 267 268 void Slot::setAttr(Segment *seg, attrCode ind, uint8 subindex, int16 value, const SlotMap & map) 269 { 270 if (ind == gr_slatUserDefnV1) 271 { 272 ind = gr_slatUserDefn; 273 subindex = 0; 274 if (seg->numAttrs() == 0) 275 return; 276 } 277 else if (ind >= gr_slatJStretch && ind < gr_slatJStretch + 20 && ind != gr_slatJWidth) 278 { 279 int indx = ind - gr_slatJStretch; 280 return setJustify(seg, indx / 5, indx % 5, value); 281 } 282 283 switch (ind) 284 { 285 case gr_slatAdvX : m_advance.x = value; break; 286 case gr_slatAdvY : m_advance.y = value; break; 287 case gr_slatAttTo : 288 { 289 const uint16 idx = uint16(value); 290 if (idx < map.size() && map[idx]) 291 { 292 Slot *other = map[idx]; 293 if (other == this || other == m_parent || other->isCopied()) break; 294 if (m_parent) { m_parent->removeChild(this); attachTo(NULL); } 295 Slot *pOther = other; 296 int count = 0; 297 bool foundOther = false; 298 while (pOther) 299 { 300 ++count; 301 if (pOther == this) foundOther = true; 302 pOther = pOther->attachedTo(); 303 } 304 for (pOther = m_child; pOther; pOther = pOther->m_child) 305 ++count; 306 for (pOther = m_sibling; pOther; pOther = pOther->m_sibling) 307 ++count; 308 if (count < 100 && !foundOther && other->child(this)) 309 { 310 attachTo(other); 311 if ((map.dir() != 0) ^ (idx > subindex)) 312 m_with = Position(advance(), 0); 313 else // normal match to previous root 314 m_attach = Position(other->advance(), 0); 315 } 316 } 317 break; 318 } 319 case gr_slatAttX : m_attach.x = value; break; 320 case gr_slatAttY : m_attach.y = value; break; 321 case gr_slatAttXOff : 322 case gr_slatAttYOff : break; 323 case gr_slatAttWithX : m_with.x = value; break; 324 case gr_slatAttWithY : m_with.y = value; break; 325 case gr_slatAttWithXOff : 326 case gr_slatAttWithYOff : break; 327 case gr_slatAttLevel : 328 m_attLevel = byte(value); 329 break; 330 case gr_slatBreak : 331 seg->charinfo(m_original)->breakWeight(value); 332 break; 333 case gr_slatCompRef : break; // not sure what to do here 334 case gr_slatDir : break; 335 case gr_slatInsert : 336 markInsertBefore(value? true : false); 337 break; 338 case gr_slatPosX : break; // can't set these here 339 case gr_slatPosY : break; 340 case gr_slatShiftX : m_shift.x = value; break; 341 case gr_slatShiftY : m_shift.y = value; break; 342 case gr_slatMeasureSol : break; 343 case gr_slatMeasureEol : break; 344 case gr_slatJWidth : just(value); break; 345 case gr_slatSegSplit : seg->charinfo(m_original)->addflags(value & 3); break; 346 case gr_slatUserDefn : m_userAttr[subindex] = value; break; 347 case gr_slatColFlags : { 348 SlotCollision *c = seg->collisionInfo(this); 349 if (c) 350 c->setFlags(value); 351 break; } 352 case gr_slatColLimitblx : SLOTCOLSETCOMPLEXATTR(Rect, limit(), setLimit(Rect(Position(value, s.bl.y), s.tr))) 353 case gr_slatColLimitbly : SLOTCOLSETCOMPLEXATTR(Rect, limit(), setLimit(Rect(Position(s.bl.x, value), s.tr))) 354 case gr_slatColLimittrx : SLOTCOLSETCOMPLEXATTR(Rect, limit(), setLimit(Rect(s.bl, Position(value, s.tr.y)))) 355 case gr_slatColLimittry : SLOTCOLSETCOMPLEXATTR(Rect, limit(), setLimit(Rect(s.bl, Position(s.tr.x, value)))) 356 case gr_slatColMargin : SLOTCOLSETATTR(setMargin(value)) 357 case gr_slatColMarginWt : SLOTCOLSETATTR(setMarginWt(value)) 358 case gr_slatColExclGlyph : SLOTCOLSETATTR(setExclGlyph(value)) 359 case gr_slatColExclOffx : SLOTCOLSETCOMPLEXATTR(Position, exclOffset(), setExclOffset(Position(value, s.y))) 360 case gr_slatColExclOffy : SLOTCOLSETCOMPLEXATTR(Position, exclOffset(), setExclOffset(Position(s.x, value))) 361 case gr_slatSeqClass : SLOTCOLSETATTR(setSeqClass(value)) 362 case gr_slatSeqProxClass : SLOTCOLSETATTR(setSeqProxClass(value)) 363 case gr_slatSeqOrder : SLOTCOLSETATTR(setSeqOrder(value)) 364 case gr_slatSeqAboveXoff : SLOTCOLSETATTR(setSeqAboveXoff(value)) 365 case gr_slatSeqAboveWt : SLOTCOLSETATTR(setSeqAboveWt(value)) 366 case gr_slatSeqBelowXlim : SLOTCOLSETATTR(setSeqBelowXlim(value)) 367 case gr_slatSeqBelowWt : SLOTCOLSETATTR(setSeqBelowWt(value)) 368 case gr_slatSeqValignHt : SLOTCOLSETATTR(setSeqValignHt(value)) 369 case gr_slatSeqValignWt : SLOTCOLSETATTR(setSeqValignWt(value)) 370 default : 371 break; 372 } 373 } 374 375 int Slot::getJustify(const Segment *seg, uint8 level, uint8 subindex) const 376 { 377 if (level && level >= seg->silf()->numJustLevels()) return 0; 378 379 if (m_justs) 380 return m_justs->values[level * SlotJustify::NUMJUSTPARAMS + subindex]; 381 382 if (level >= seg->silf()->numJustLevels()) return 0; 383 Justinfo *jAttrs = seg->silf()->justAttrs() + level; 384 385 switch (subindex) { 386 case 0 : return seg->glyphAttr(gid(), jAttrs->attrStretch()); 387 case 1 : return seg->glyphAttr(gid(), jAttrs->attrShrink()); 388 case 2 : return seg->glyphAttr(gid(), jAttrs->attrStep()); 389 case 3 : return seg->glyphAttr(gid(), jAttrs->attrWeight()); 390 case 4 : return 0; // not been set yet, so clearly 0 391 default: return 0; 392 } 393 } 394 395 void Slot::setJustify(Segment *seg, uint8 level, uint8 subindex, int16 value) 396 { 397 if (level && level >= seg->silf()->numJustLevels()) return; 398 if (!m_justs) 399 { 400 SlotJustify *j = seg->newJustify(); 401 if (!j) return; 402 j->LoadSlot(this, seg); 403 m_justs = j; 404 } 405 m_justs->values[level * SlotJustify::NUMJUSTPARAMS + subindex] = value; 406 } 407 408 bool Slot::child(Slot *ap) 409 { 410 if (this == ap) return false; 411 else if (ap == m_child) return true; 412 else if (!m_child) 413 m_child = ap; 414 else 415 return m_child->sibling(ap); 416 return true; 417 } 418 419 bool Slot::sibling(Slot *ap) 420 { 421 if (this == ap) return false; 422 else if (ap == m_sibling) return true; 423 else if (!m_sibling || !ap) 424 m_sibling = ap; 425 else 426 return m_sibling->sibling(ap); 427 return true; 428 } 429 430 bool Slot::removeChild(Slot *ap) 431 { 432 if (this == ap || !m_child || !ap) return false; 433 else if (ap == m_child) 434 { 435 Slot *nSibling = m_child->nextSibling(); 436 m_child->nextSibling(NULL); 437 m_child = nSibling; 438 return true; 439 } 440 for (Slot *p = m_child; p; p = p->m_sibling) 441 { 442 if (p->m_sibling && p->m_sibling == ap) 443 { 444 p->m_sibling = p->m_sibling->m_sibling; 445 ap->nextSibling(NULL); 446 return true; 447 } 448 } 449 return false; 450 } 451 452 void Slot::setGlyph(Segment *seg, uint16 glyphid, const GlyphFace * theGlyph) 453 { 454 m_glyphid = glyphid; 455 m_bidiCls = -1; 456 if (!theGlyph) 457 { 458 theGlyph = seg->getFace()->glyphs().glyphSafe(glyphid); 459 if (!theGlyph) 460 { 461 m_realglyphid = 0; 462 m_advance = Position(0.,0.); 463 return; 464 } 465 } 466 m_realglyphid = theGlyph->attrs()[seg->silf()->aPseudo()]; 467 if (m_realglyphid > seg->getFace()->glyphs().numGlyphs()) 468 m_realglyphid = 0; 469 const GlyphFace *aGlyph = theGlyph; 470 if (m_realglyphid) 471 { 472 aGlyph = seg->getFace()->glyphs().glyphSafe(m_realglyphid); 473 if (!aGlyph) aGlyph = theGlyph; 474 } 475 m_advance = Position(aGlyph->theAdvance().x, 0.); 476 if (seg->silf()->aPassBits()) 477 { 478 seg->mergePassBits(uint8(theGlyph->attrs()[seg->silf()->aPassBits()])); 479 if (seg->silf()->numPasses() > 16) 480 seg->mergePassBits(theGlyph->attrs()[seg->silf()->aPassBits()+1] << 16); 481 } 482 } 483 484 void Slot::floodShift(Position adj, int depth) 485 { 486 if (depth > 100) 487 return; 488 m_position += adj; 489 if (m_child) m_child->floodShift(adj, depth + 1); 490 if (m_sibling) m_sibling->floodShift(adj, depth + 1); 491 } 492 493 void SlotJustify::LoadSlot(const Slot *s, const Segment *seg) 494 { 495 for (int i = seg->silf()->numJustLevels() - 1; i >= 0; --i) 496 { 497 Justinfo *justs = seg->silf()->justAttrs() + i; 498 int16 *v = values + i * NUMJUSTPARAMS; 499 v[0] = seg->glyphAttr(s->gid(), justs->attrStretch()); 500 v[1] = seg->glyphAttr(s->gid(), justs->attrShrink()); 501 v[2] = seg->glyphAttr(s->gid(), justs->attrStep()); 502 v[3] = seg->glyphAttr(s->gid(), justs->attrWeight()); 503 } 504 } 505 506 Slot * Slot::nextInCluster(const Slot *s) const 507 { 508 Slot *base; 509 if (s->firstChild()) 510 return s->firstChild(); 511 else if (s->nextSibling()) 512 return s->nextSibling(); 513 while ((base = s->attachedTo())) 514 { 515 // if (base->firstChild() == s && base->nextSibling()) 516 if (base->nextSibling()) 517 return base->nextSibling(); 518 s = base; 519 } 520 return NULL; 521 } 522 523 bool Slot::isChildOf(const Slot *base) const 524 { 525 for (Slot *p = m_parent; p; p = p->m_parent) 526 if (p == base) 527 return true; 528 return false; 529 }