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