|
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 |
|
33 |
|
34 using namespace graphite2; |
|
35 |
|
36 Slot::Slot() : |
|
37 m_next(NULL), m_prev(NULL), |
|
38 m_glyphid(0), m_realglyphid(0), m_original(0), m_before(0), m_after(0), |
|
39 m_index(0), m_parent(NULL), m_child(NULL), m_sibling(NULL), |
|
40 m_position(0, 0), m_shift(0, 0), m_advance(0, 0), |
|
41 m_attach(0, 0), m_with(0, 0), m_just(0.), |
|
42 m_flags(0), m_attLevel(0), m_bidiCls(-1), m_bidiLevel(0), m_justs(NULL) |
|
43 // Do not set m_userAttr since it is set *before* new is called since this |
|
44 // is used as a positional new to reset the GrSlot |
|
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 numUserAttr, 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 = 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, numUserAttr * 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) |
|
89 { |
|
90 if (attrLevel && m_attLevel > attrLevel) return Position(0, 0); |
|
91 float scale = 1.0; |
|
92 Position shift(m_shift.x * ((seg->dir() & 1) * -2 + 1) + m_just, m_shift.y); |
|
93 float tAdvance = m_advance.x + m_just; |
|
94 const GlyphFace * glyphFace = seg->getFace()->glyphs().glyphSafe(glyph()); |
|
95 if (font) |
|
96 { |
|
97 scale = font->scale(); |
|
98 shift *= scale; |
|
99 if (font->isHinted() && glyphFace) |
|
100 tAdvance = (m_advance.x - glyphFace->theAdvance().x + m_just) * scale + font->advance(m_glyphid); |
|
101 else |
|
102 tAdvance *= scale; |
|
103 } |
|
104 Position res; |
|
105 |
|
106 m_position = base + shift; |
|
107 if (!m_parent) |
|
108 { |
|
109 res = base + Position(tAdvance, m_advance.y * scale); |
|
110 clusterMin = base.x; |
|
111 } |
|
112 else |
|
113 { |
|
114 float tAdv; |
|
115 m_position += (m_attach - m_with) * scale; |
|
116 tAdv = m_advance.x >= 0.5 ? m_position.x + tAdvance - shift.x : 0.f; |
|
117 res = Position(tAdv, 0); |
|
118 if ((m_advance.x >= 0.5 || m_position.x < 0) && m_position.x < clusterMin) clusterMin = m_position.x; |
|
119 } |
|
120 |
|
121 if (glyphFace) |
|
122 { |
|
123 Rect ourBbox = glyphFace->theBBox() * scale + m_position; |
|
124 bbox = bbox.widen(ourBbox); |
|
125 } |
|
126 |
|
127 if (m_child && m_child != this && m_child->attachedTo() == this) |
|
128 { |
|
129 Position tRes = m_child->finalise(seg, font, m_position, bbox, attrLevel, clusterMin); |
|
130 if ((!m_parent || m_advance.x >= 0.5) && tRes.x > res.x) res = tRes; |
|
131 } |
|
132 |
|
133 if (m_parent && m_sibling && m_sibling != this && m_sibling->attachedTo() == m_parent) |
|
134 { |
|
135 Position tRes = m_sibling->finalise(seg, font, base, bbox, attrLevel, clusterMin); |
|
136 if (tRes.x > res.x) res = tRes; |
|
137 } |
|
138 |
|
139 if (!m_parent && clusterMin < base.x) |
|
140 { |
|
141 Position adj = Position(base.x - clusterMin, 0.); |
|
142 res += adj; |
|
143 m_position += adj; |
|
144 if (m_child) m_child->floodShift(adj); |
|
145 } |
|
146 return res; |
|
147 } |
|
148 |
|
149 int32 Slot::clusterMetric(const Segment *seg, uint8 metric, uint8 attrLevel) |
|
150 { |
|
151 Position base; |
|
152 Rect bbox = seg->theGlyphBBoxTemporary(glyph()); |
|
153 float clusterMin = 0.; |
|
154 Position res = finalise(seg, NULL, base, bbox, attrLevel, clusterMin); |
|
155 |
|
156 switch (metrics(metric)) |
|
157 { |
|
158 case kgmetLsb : |
|
159 return static_cast<uint32>(bbox.bl.x); |
|
160 case kgmetRsb : |
|
161 return static_cast<uint32>(res.x - bbox.tr.x); |
|
162 case kgmetBbTop : |
|
163 return static_cast<uint32>(bbox.tr.y); |
|
164 case kgmetBbBottom : |
|
165 return static_cast<uint32>(bbox.bl.y); |
|
166 case kgmetBbLeft : |
|
167 return static_cast<uint32>(bbox.bl.x); |
|
168 case kgmetBbRight : |
|
169 return static_cast<uint32>(bbox.tr.x); |
|
170 case kgmetBbWidth : |
|
171 return static_cast<uint32>(bbox.tr.x - bbox.bl.x); |
|
172 case kgmetBbHeight : |
|
173 return static_cast<uint32>(bbox.tr.y - bbox.bl.y); |
|
174 case kgmetAdvWidth : |
|
175 return static_cast<uint32>(res.x); |
|
176 case kgmetAdvHeight : |
|
177 return static_cast<uint32>(res.y); |
|
178 default : |
|
179 return 0; |
|
180 } |
|
181 } |
|
182 |
|
183 int Slot::getAttr(const Segment *seg, attrCode ind, uint8 subindex) const |
|
184 { |
|
185 if (!this) return 0; |
|
186 if (ind == gr_slatUserDefnV1) |
|
187 { |
|
188 ind = gr_slatUserDefn; |
|
189 subindex = 0; |
|
190 } |
|
191 else if (ind >= gr_slatJStretch && ind < gr_slatJStretch + 20 && ind != gr_slatJWidth) |
|
192 { |
|
193 int indx = ind - gr_slatJStretch; |
|
194 return getJustify(seg, indx / 5, indx % 5); |
|
195 } |
|
196 |
|
197 switch (ind) |
|
198 { |
|
199 case gr_slatAdvX : return int(m_advance.x); |
|
200 case gr_slatAdvY : return int(m_advance.y); |
|
201 case gr_slatAttTo : return m_parent ? 1 : 0; |
|
202 case gr_slatAttX : return int(m_attach.x); |
|
203 case gr_slatAttY : return int(m_attach.y); |
|
204 case gr_slatAttXOff : |
|
205 case gr_slatAttYOff : return 0; |
|
206 case gr_slatAttWithX : return int(m_with.x); |
|
207 case gr_slatAttWithY : return int(m_with.y); |
|
208 case gr_slatAttWithXOff: |
|
209 case gr_slatAttWithYOff:return 0; |
|
210 case gr_slatAttLevel : return m_attLevel; |
|
211 case gr_slatBreak : return seg->charinfo(m_original)->breakWeight(); |
|
212 case gr_slatCompRef : return 0; |
|
213 case gr_slatDir : if (m_bidiCls == -1) |
|
214 const_cast<Slot *>(this)->setBidiClass(seg->glyphAttr(gid(), seg->silf()->aBidi())); |
|
215 return m_bidiCls; |
|
216 case gr_slatInsert : return isInsertBefore(); |
|
217 case gr_slatPosX : return int(m_position.x); // but need to calculate it |
|
218 case gr_slatPosY : return int(m_position.y); |
|
219 case gr_slatShiftX : return int(m_shift.x); |
|
220 case gr_slatShiftY : return int(m_shift.y); |
|
221 case gr_slatMeasureSol: return -1; // err what's this? |
|
222 case gr_slatMeasureEol: return -1; |
|
223 case gr_slatJWidth: return int(m_just); |
|
224 case gr_slatUserDefn : return m_userAttr[subindex]; |
|
225 case gr_slatSegSplit : return seg->charinfo(m_original)->flags() & 3; |
|
226 case gr_slatBidiLevel: return m_bidiLevel; |
|
227 default : return 0; |
|
228 } |
|
229 } |
|
230 |
|
231 void Slot::setAttr(Segment *seg, attrCode ind, uint8 subindex, int16 value, const SlotMap & map) |
|
232 { |
|
233 if (!this) return; |
|
234 if (ind == gr_slatUserDefnV1) |
|
235 { |
|
236 ind = gr_slatUserDefn; |
|
237 subindex = 0; |
|
238 } |
|
239 else if (ind >= gr_slatJStretch && ind < gr_slatJStretch + 20 && ind != gr_slatJWidth) |
|
240 { |
|
241 int indx = ind - gr_slatJStretch; |
|
242 return setJustify(seg, indx / 5, indx % 5, value); |
|
243 } |
|
244 |
|
245 switch (ind) |
|
246 { |
|
247 case gr_slatAdvX : m_advance.x = value; break; |
|
248 case gr_slatAdvY : m_advance.y = value; break; |
|
249 case gr_slatAttTo : |
|
250 { |
|
251 const uint16 idx = uint16(value); |
|
252 if (idx < map.size() && map[idx]) |
|
253 { |
|
254 Slot *other = map[idx]; |
|
255 if (other == this) break; |
|
256 if (m_parent) m_parent->removeChild(this); |
|
257 if (other->child(this)) |
|
258 { |
|
259 attachTo(other); |
|
260 if (((seg->dir() & 1) != 0) ^ (idx > subindex)) |
|
261 m_with = Position(advance(), 0); |
|
262 else // normal match to previous root |
|
263 m_attach = Position(other->advance(), 0); |
|
264 } |
|
265 } |
|
266 break; |
|
267 } |
|
268 case gr_slatAttX : m_attach.x = value; break; |
|
269 case gr_slatAttY : m_attach.y = value; break; |
|
270 case gr_slatAttXOff : |
|
271 case gr_slatAttYOff : break; |
|
272 case gr_slatAttWithX : m_with.x = value; break; |
|
273 case gr_slatAttWithY : m_with.y = value; break; |
|
274 case gr_slatAttWithXOff : |
|
275 case gr_slatAttWithYOff : break; |
|
276 case gr_slatAttLevel : |
|
277 m_attLevel = byte(value); |
|
278 break; |
|
279 case gr_slatBreak : |
|
280 seg->charinfo(m_original)->breakWeight(value); |
|
281 break; |
|
282 case gr_slatCompRef : break; // not sure what to do here |
|
283 case gr_slatDir : m_bidiCls = value; break; |
|
284 case gr_slatInsert : |
|
285 markInsertBefore(value? true : false); |
|
286 break; |
|
287 case gr_slatPosX : break; // can't set these here |
|
288 case gr_slatPosY : break; |
|
289 case gr_slatShiftX : m_shift.x = value; break; |
|
290 case gr_slatShiftY : m_shift.y = value; break; |
|
291 case gr_slatMeasureSol : break; |
|
292 case gr_slatMeasureEol : break; |
|
293 case gr_slatJWidth : just(value); break; |
|
294 case gr_slatSegSplit : seg->charinfo(m_original)->addflags(value & 3); break; |
|
295 case gr_slatUserDefn : m_userAttr[subindex] = value; break; |
|
296 default : |
|
297 break; |
|
298 } |
|
299 } |
|
300 |
|
301 int Slot::getJustify(const Segment *seg, uint8 level, uint8 subindex) const |
|
302 { |
|
303 if (level && level >= seg->silf()->numJustLevels()) return 0; |
|
304 |
|
305 if (m_justs) |
|
306 return m_justs->values[level * SlotJustify::NUMJUSTPARAMS + subindex]; |
|
307 |
|
308 if (level >= seg->silf()->numJustLevels()) return 0; |
|
309 Justinfo *jAttrs = seg->silf()->justAttrs() + level; |
|
310 |
|
311 switch (subindex) { |
|
312 case 0 : return seg->glyphAttr(gid(), jAttrs->attrStretch()); |
|
313 case 1 : return seg->glyphAttr(gid(), jAttrs->attrShrink()); |
|
314 case 2 : return seg->glyphAttr(gid(), jAttrs->attrStep()); |
|
315 case 3 : return seg->glyphAttr(gid(), jAttrs->attrWeight()); |
|
316 case 4 : return 0; // not been set yet, so clearly 0 |
|
317 default: return 0; |
|
318 } |
|
319 } |
|
320 |
|
321 void Slot::setJustify(Segment *seg, uint8 level, uint8 subindex, int16 value) |
|
322 { |
|
323 if (level && level >= seg->silf()->numJustLevels()) return; |
|
324 if (!m_justs) |
|
325 { |
|
326 SlotJustify *j = seg->newJustify(); |
|
327 if (!j) return; |
|
328 j->LoadSlot(this, seg); |
|
329 m_justs = j; |
|
330 } |
|
331 m_justs->values[level * SlotJustify::NUMJUSTPARAMS + subindex] = value; |
|
332 } |
|
333 |
|
334 bool Slot::child(Slot *ap) |
|
335 { |
|
336 if (this == ap) return false; |
|
337 else if (ap == m_child) return true; |
|
338 else if (!m_child) |
|
339 m_child = ap; |
|
340 else |
|
341 return m_child->sibling(ap); |
|
342 return true; |
|
343 } |
|
344 |
|
345 bool Slot::sibling(Slot *ap) |
|
346 { |
|
347 if (this == ap) return false; |
|
348 else if (ap == m_sibling) return true; |
|
349 else if (!m_sibling || !ap) |
|
350 m_sibling = ap; |
|
351 else |
|
352 return m_sibling->sibling(ap); |
|
353 return true; |
|
354 } |
|
355 |
|
356 bool Slot::removeChild(Slot *ap) |
|
357 { |
|
358 if (this == ap || !m_child) return false; |
|
359 else if (ap == m_child) |
|
360 { |
|
361 Slot *nSibling = m_child->nextSibling(); |
|
362 m_child->sibling(NULL); |
|
363 m_child = nSibling; |
|
364 return true; |
|
365 } |
|
366 else |
|
367 return m_child->removeSibling(ap); |
|
368 return true; |
|
369 } |
|
370 |
|
371 bool Slot::removeSibling(Slot *ap) |
|
372 { |
|
373 if (this == ap || !m_sibling) return false; |
|
374 else if (ap == m_sibling) |
|
375 { |
|
376 m_sibling = m_sibling->nextSibling(); |
|
377 return true; |
|
378 } |
|
379 else |
|
380 return m_sibling->removeSibling(ap); |
|
381 return true; |
|
382 } |
|
383 |
|
384 void Slot::setGlyph(Segment *seg, uint16 glyphid, const GlyphFace * theGlyph) |
|
385 { |
|
386 m_glyphid = glyphid; |
|
387 if (!theGlyph) |
|
388 { |
|
389 theGlyph = seg->getFace()->glyphs().glyphSafe(glyphid); |
|
390 if (!theGlyph) |
|
391 { |
|
392 m_realglyphid = 0; |
|
393 m_advance = Position(0.,0.); |
|
394 return; |
|
395 } |
|
396 } |
|
397 m_realglyphid = theGlyph->attrs()[seg->silf()->aPseudo()]; |
|
398 const GlyphFace *aGlyph = theGlyph; |
|
399 if (m_realglyphid) |
|
400 { |
|
401 aGlyph = seg->getFace()->glyphs().glyphSafe(m_realglyphid); |
|
402 if (!aGlyph) aGlyph = theGlyph; |
|
403 } |
|
404 m_advance = Position(aGlyph->theAdvance().x, 0.); |
|
405 if (seg->silf()->aPassBits()) |
|
406 seg->mergePassBits(theGlyph->attrs()[seg->silf()->aPassBits()]); |
|
407 } |
|
408 |
|
409 void Slot::floodShift(Position adj) |
|
410 { |
|
411 m_position += adj; |
|
412 if (m_child) m_child->floodShift(adj); |
|
413 if (m_sibling) m_sibling->floodShift(adj); |
|
414 } |
|
415 |
|
416 void SlotJustify::LoadSlot(const Slot *s, const Segment *seg) |
|
417 { |
|
418 for (int i = seg->silf()->numJustLevels() - 1; i >= 0; --i) |
|
419 { |
|
420 Justinfo *justs = seg->silf()->justAttrs() + i; |
|
421 int16 *v = values + i * NUMJUSTPARAMS; |
|
422 v[0] = seg->glyphAttr(s->gid(), justs->attrStretch()); |
|
423 v[1] = seg->glyphAttr(s->gid(), justs->attrShrink()); |
|
424 v[2] = seg->glyphAttr(s->gid(), justs->attrStep()); |
|
425 v[3] = seg->glyphAttr(s->gid(), justs->attrWeight()); |
|
426 } |
|
427 } |