3 Copyright 2010, SIL International
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.
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.
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.
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.
27 #include "inc/UtfCodec.h"
32 #include "inc/Segment.h"
33 #include "graphite2/Font.h"
34 #include "inc/CharInfo.h"
35 #include "inc/debug.h"
38 #include "inc/CmapCache.h"
39 #include "inc/Collider.h"
40 #include "graphite2/Segment.h"
43 using namespace graphite2
;
45 Segment::Segment(size_t numchars
, const Face
* face
, uint32 script
, int textDir
)
47 m_freeJustifies(NULL
),
48 m_charinfo(new CharInfo
[numchars
]),
51 m_silf(face
->chooseSilf(script
)),
54 m_bufSize(numchars
+ 10),
55 m_numGlyphs(numchars
),
56 m_numCharinfo(numchars
),
59 m_flags(((m_silf
->flags() & 0x20) != 0) << 1),
60 m_passBits(m_silf
->aPassBits() ? -1 : 0)
63 m_bufSize
= log_binary(numchars
)+1;
68 for (SlotRope::iterator i
= m_slots
.begin(); i
!= m_slots
.end(); ++i
)
70 for (AttributeRope::iterator i
= m_userAttrs
.begin(); i
!= m_userAttrs
.end(); ++i
)
72 for (JustifyRope::iterator i
= m_justifies
.begin(); i
!= m_justifies
.end(); ++i
)
78 void Segment::appendSlot(int id
, int cid
, int gid
, int iFeats
, size_t coffset
)
80 Slot
*aSlot
= newSlot();
83 m_charinfo
[id
].init(cid
);
84 m_charinfo
[id
].feats(iFeats
);
85 m_charinfo
[id
].base(coffset
);
86 const GlyphFace
* theGlyph
= m_face
->glyphs().glyphSafe(gid
);
87 m_charinfo
[id
].breakWeight(theGlyph
? theGlyph
->attrs()[m_silf
->aBreak()] : 0);
90 aSlot
->setGlyph(this, gid
, theGlyph
);
94 if (m_last
) m_last
->next(aSlot
);
97 if (!m_first
) m_first
= aSlot
;
98 if (theGlyph
&& m_silf
->aPassBits())
99 m_passBits
&= theGlyph
->attrs()[m_silf
->aPassBits()]
100 | (m_silf
->numPasses() > 16 ? (theGlyph
->attrs()[m_silf
->aPassBits() + 1] << 16) : 0);
103 Slot
*Segment::newSlot()
107 // check that the segment doesn't grow indefinintely
108 if (m_numGlyphs
> m_numCharinfo
* MAX_SEG_GROWTH_FACTOR
)
110 int numUser
= m_silf
->numUser();
111 #if !defined GRAPHITE2_NTRACING
112 if (m_face
->logger()) ++numUser
;
114 Slot
*newSlots
= grzeroalloc
<Slot
>(m_bufSize
);
115 int16
*newAttrs
= grzeroalloc
<int16
>(m_bufSize
* numUser
);
116 if (!newSlots
|| !newAttrs
)
122 for (size_t i
= 0; i
< m_bufSize
; i
++)
124 ::new (newSlots
+ i
) Slot(newAttrs
+ i
* numUser
);
125 newSlots
[i
].next(newSlots
+ i
+ 1);
127 newSlots
[m_bufSize
- 1].next(NULL
);
128 newSlots
[0].next(NULL
);
129 m_slots
.push_back(newSlots
);
130 m_userAttrs
.push_back(newAttrs
);
131 m_freeSlots
= (m_bufSize
> 1)? newSlots
+ 1 : NULL
;
134 Slot
*res
= m_freeSlots
;
135 m_freeSlots
= m_freeSlots
->next();
140 void Segment::freeSlot(Slot
*aSlot
)
142 if (aSlot
== nullptr) return;
143 if (m_last
== aSlot
) m_last
= aSlot
->prev();
144 if (m_first
== aSlot
) m_first
= aSlot
->next();
145 if (aSlot
->attachedTo())
146 aSlot
->attachedTo()->removeChild(aSlot
);
147 while (aSlot
->firstChild())
149 if (aSlot
->firstChild()->attachedTo() == aSlot
)
151 aSlot
->firstChild()->attachTo(nullptr);
152 aSlot
->removeChild(aSlot
->firstChild());
155 aSlot
->firstChild(nullptr);
157 // reset the slot incase it is reused
158 ::new (aSlot
) Slot(aSlot
->userAttrs());
159 memset(aSlot
->userAttrs(), 0, m_silf
->numUser() * sizeof(int16
));
160 // Update generation counter for debug
161 #if !defined GRAPHITE2_NTRACING
162 if (m_face
->logger())
163 ++aSlot
->userAttrs()[m_silf
->numUser()];
165 // update next pointer
167 aSlot
->next(nullptr);
169 aSlot
->next(m_freeSlots
);
173 SlotJustify
*Segment::newJustify()
175 if (!m_freeJustifies
)
177 const size_t justSize
= SlotJustify::size_of(m_silf
->numJustLevels());
178 byte
*justs
= grzeroalloc
<byte
>(justSize
* m_bufSize
);
179 if (!justs
) return NULL
;
180 for (ptrdiff_t i
= m_bufSize
- 2; i
>= 0; --i
)
182 SlotJustify
*p
= reinterpret_cast<SlotJustify
*>(justs
+ justSize
* i
);
183 SlotJustify
*next
= reinterpret_cast<SlotJustify
*>(justs
+ justSize
* (i
+ 1));
186 m_freeJustifies
= (SlotJustify
*)justs
;
187 m_justifies
.push_back(m_freeJustifies
);
189 SlotJustify
*res
= m_freeJustifies
;
190 m_freeJustifies
= m_freeJustifies
->next
;
195 void Segment::freeJustify(SlotJustify
*aJustify
)
197 int numJust
= m_silf
->numJustLevels();
198 if (m_silf
->numJustLevels() <= 0) numJust
= 1;
199 aJustify
->next
= m_freeJustifies
;
200 memset(aJustify
->values
, 0, numJust
*SlotJustify::NUMJUSTPARAMS
*sizeof(int16
));
201 m_freeJustifies
= aJustify
;
204 // reverse the slots but keep diacritics in their same position after their bases
205 void Segment::reverseSlots()
207 m_dir
= m_dir
^ 64; // invert the reverse flag
208 if (m_first
== m_last
) return; // skip 0 or 1 glyph runs
211 Slot
*curr
= m_first
;
216 while (curr
&& getSlotBidiClass(curr
) == 16)
219 tfirst
= curr
->prev();
224 if (getSlotBidiClass(curr
) == 16)
226 Slot
*d
= curr
->next();
227 while (d
&& getSlotBidiClass(d
) == 16)
230 d
= d
? d
->prev() : m_last
;
231 Slot
*p
= out
->next(); // one after the diacritics. out can't be null
241 else // will always fire first time round the loop
259 void Segment::linkClusters(Slot
*s
, Slot
* end
)
263 for (; s
!= end
&& !s
->isBase(); s
= s
->next());
268 for (; s
!= end
; s
= s
->next())
270 if (!s
->isBase()) continue;
278 for (; s
!= end
; s
= s
->next())
280 if (!s
->isBase()) continue;
288 Position
Segment::positionSlots(const Font
*font
, Slot
* iStart
, Slot
* iEnd
, bool isRtl
, bool isFinal
)
290 Position
currpos(0., 0.);
291 float clusterMin
= 0.;
293 bool reorder
= (currdir() != isRtl
);
303 if (!iStart
) iStart
= m_first
;
304 if (!iEnd
) iEnd
= m_last
;
306 if (!iStart
|| !iEnd
) // only true for empty segments
311 for (Slot
* s
= iEnd
, * const end
= iStart
->prev(); s
&& s
!= end
; s
= s
->prev())
314 currpos
= s
->finalise(this, font
, currpos
, bbox
, 0, clusterMin
= currpos
.x
, isRtl
, isFinal
);
319 for (Slot
* s
= iStart
, * const end
= iEnd
->next(); s
&& s
!= end
; s
= s
->next())
322 currpos
= s
->finalise(this, font
, currpos
, bbox
, 0, clusterMin
= currpos
.x
, isRtl
, isFinal
);
331 void Segment::associateChars(int offset
, size_t numChars
)
335 for (c
= m_charinfo
+ offset
, cend
= m_charinfo
+ offset
+ numChars
; c
!= cend
; ++c
)
340 for (Slot
* s
= m_first
; s
; s
->index(i
++), s
= s
->next())
345 for (const int after
= s
->after(); j
<= after
; ++j
)
348 if (c
->before() == -1 || i
< c
->before()) c
->before(i
);
349 if (c
->after() < i
) c
->after(i
);
352 for (Slot
*s
= m_first
; s
; s
= s
->next())
355 for (a
= s
->after() + 1; a
< offset
+ int(numChars
) && charinfo(a
)->after() < 0; ++a
)
356 { charinfo(a
)->after(s
->index()); }
360 for (a
= s
->before() - 1; a
>= offset
&& charinfo(a
)->before() < 0; --a
)
361 { charinfo(a
)->before(s
->index()); }
368 template <typename utf_iter
>
369 inline void process_utf_data(Segment
& seg
, const Face
& face
, const int fid
, utf_iter c
, size_t n_chars
)
371 const Cmap
& cmap
= face
.cmap();
374 const typename
utf_iter::codeunit_type
* const base
= c
;
375 for (; n_chars
; --n_chars
, ++c
, ++slotid
)
377 const uint32 usv
= *c
;
378 uint16 gid
= cmap
[usv
];
379 if (!gid
) gid
= face
.findPseudo(usv
);
380 seg
.appendSlot(slotid
, usv
, gid
, fid
, c
- base
);
385 bool Segment::read_text(const Face
*face
, const Features
* pFeats
/*must not be NULL*/, gr_encform enc
, const void* pStart
, size_t nChars
)
389 if (!m_charinfo
) return false;
391 // utf iterator is self recovering so we don't care about the error state of the iterator.
394 case gr_utf8
: process_utf_data(*this, *face
, addFeatures(*pFeats
), utf8::const_iterator(pStart
), nChars
); break;
395 case gr_utf16
: process_utf_data(*this, *face
, addFeatures(*pFeats
), utf16::const_iterator(pStart
), nChars
); break;
396 case gr_utf32
: process_utf_data(*this, *face
, addFeatures(*pFeats
), utf32::const_iterator(pStart
), nChars
); break;
401 void Segment::doMirror(uint16 aMirror
)
404 for (s
= m_first
; s
; s
= s
->next())
406 unsigned short g
= glyphAttr(s
->gid(), aMirror
);
407 if (g
&& (!(dir() & 4) || !glyphAttr(s
->gid(), aMirror
+ 1)))
408 s
->setGlyph(this, g
);
412 bool Segment::initCollisions()
414 m_collisions
= grzeroalloc
<SlotCollision
>(slotCount());
415 if (!m_collisions
) return false;
417 for (Slot
*p
= m_first
; p
; p
= p
->next())
418 if (p
->index() < slotCount())
419 ::new (collisionInfo(p
)) SlotCollision(this, p
);