michael@0: /* GRAPHITE2 LICENSING michael@0: michael@0: Copyright 2010, SIL International michael@0: All rights reserved. michael@0: michael@0: This library is free software; you can redistribute it and/or modify michael@0: it under the terms of the GNU Lesser General Public License as published michael@0: by the Free Software Foundation; either version 2.1 of License, or michael@0: (at your option) any later version. michael@0: michael@0: This program is distributed in the hope that it will be useful, michael@0: but WITHOUT ANY WARRANTY; without even the implied warranty of michael@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU michael@0: Lesser General Public License for more details. michael@0: michael@0: You should also have received a copy of the GNU Lesser General Public michael@0: License along with this library in the file named "LICENSE". michael@0: If not, write to the Free Software Foundation, 51 Franklin Street, michael@0: Suite 500, Boston, MA 02110-1335, USA or visit their web page on the michael@0: internet at http://www.fsf.org/licenses/lgpl.html. michael@0: michael@0: Alternatively, the contents of this file may be used under the terms of the michael@0: Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public michael@0: License, as published by the Free Software Foundation, either version 2 michael@0: of the License or (at your option) any later version. michael@0: */ michael@0: #pragma once michael@0: michael@0: #include "inc/Main.h" michael@0: michael@0: #include michael@0: michael@0: #include "inc/CharInfo.h" michael@0: #include "inc/Face.h" michael@0: #include "inc/FeatureVal.h" michael@0: #include "inc/GlyphCache.h" michael@0: #include "inc/GlyphFace.h" michael@0: //#include "inc/Silf.h" michael@0: #include "inc/Slot.h" michael@0: #include "inc/Position.h" michael@0: #include "inc/List.h" michael@0: #include "inc/Bidi.h" michael@0: michael@0: #define MAX_SEG_GROWTH_FACTOR 256 michael@0: michael@0: namespace graphite2 { michael@0: michael@0: typedef Vector FeatureList; michael@0: typedef Vector SlotRope; michael@0: typedef Vector AttributeRope; michael@0: typedef Vector JustifyRope; michael@0: michael@0: #ifndef GRAPHITE2_NSEGCACHE michael@0: class SegmentScopeState; michael@0: #endif michael@0: class Font; michael@0: class Segment; michael@0: class Silf; michael@0: michael@0: enum SpliceParam { michael@0: /** sub-Segments longer than this are not cached michael@0: * (in Unicode code points) */ michael@0: eMaxSpliceSize = 96 michael@0: }; michael@0: michael@0: enum justFlags { michael@0: gr_justStartInline = 1, michael@0: gr_justEndInline = 2 michael@0: }; michael@0: michael@0: class SegmentScopeState michael@0: { michael@0: private: michael@0: friend class Segment; michael@0: Slot * realFirstSlot; michael@0: Slot * slotBeforeScope; michael@0: Slot * slotAfterScope; michael@0: Slot * realLastSlot; michael@0: size_t numGlyphsOutsideScope; michael@0: }; michael@0: michael@0: class Segment michael@0: { michael@0: // Prevent copying of any kind. michael@0: Segment(const Segment&); michael@0: Segment& operator=(const Segment&); michael@0: michael@0: public: michael@0: unsigned int slotCount() const { return m_numGlyphs; } //one slot per glyph michael@0: void extendLength(int num) { m_numGlyphs += num; } michael@0: Position advance() const { return m_advance; } michael@0: bool runGraphite() { if (m_silf) return m_face->runGraphite(this, m_silf); else return true;}; michael@0: void chooseSilf(uint32 script) { m_silf = m_face->chooseSilf(script); } michael@0: const Silf *silf() const { return m_silf; } michael@0: unsigned int charInfoCount() const { return m_numCharinfo; } michael@0: const CharInfo *charinfo(unsigned int index) const { return index < m_numCharinfo ? m_charinfo + index : NULL; } michael@0: CharInfo *charinfo(unsigned int index) { return index < m_numCharinfo ? m_charinfo + index : NULL; } michael@0: int8 dir() const { return m_dir; } michael@0: michael@0: Segment(unsigned int numchars, const Face* face, uint32 script, int dir); michael@0: ~Segment(); michael@0: #ifndef GRAPHITE2_NSEGCACHE michael@0: SegmentScopeState setScope(Slot * firstSlot, Slot * lastSlot, size_t subLength); michael@0: void removeScope(SegmentScopeState & state); michael@0: void append(const Segment &other); michael@0: void splice(size_t offset, size_t length, Slot * const startSlot, michael@0: Slot * endSlot, const Slot * srcSlot, michael@0: const size_t numGlyphs); michael@0: #endif michael@0: Slot *first() { return m_first; } michael@0: void first(Slot *p) { m_first = p; } michael@0: Slot *last() { return m_last; } michael@0: void last(Slot *p) { m_last = p; } michael@0: void appendSlot(int i, int cid, int gid, int fid, size_t coffset); michael@0: Slot *newSlot(); michael@0: void freeSlot(Slot *); michael@0: SlotJustify *newJustify(); michael@0: void freeJustify(SlotJustify *aJustify); michael@0: Position positionSlots(const Font *font, Slot *first=0, Slot *last=0); michael@0: void associateChars(int offset, int num); michael@0: void linkClusters(Slot *first, Slot *last); michael@0: uint16 getClassGlyph(uint16 cid, uint16 offset) const { return m_silf->getClassGlyph(cid, offset); } michael@0: uint16 findClassIndex(uint16 cid, uint16 gid) const { return m_silf->findClassIndex(cid, gid); } michael@0: int addFeatures(const Features& feats) { m_feats.push_back(feats); return m_feats.size() - 1; } michael@0: uint32 getFeature(int index, uint8 findex) const { const FeatureRef* pFR=m_face->theSill().theFeatureMap().featureRef(findex); if (!pFR) return 0; else return pFR->getFeatureVal(m_feats[index]); } michael@0: void dir(int8 val) { m_dir = val; } michael@0: unsigned int passBits() const { return m_passBits; } michael@0: void mergePassBits(const unsigned int val) { m_passBits &= val; } michael@0: int16 glyphAttr(uint16 gid, uint16 gattr) const { const GlyphFace * p = m_face->glyphs().glyphSafe(gid); return p ? p->attrs()[gattr] : 0; } michael@0: int32 getGlyphMetric(Slot *iSlot, uint8 metric, uint8 attrLevel) const; michael@0: float glyphAdvance(uint16 gid) const { return m_face->glyphs().glyph(gid)->theAdvance().x; } michael@0: const Rect &theGlyphBBoxTemporary(uint16 gid) const { return m_face->glyphs().glyph(gid)->theBBox(); } //warning value may become invalid when another glyph is accessed michael@0: Slot *findRoot(Slot *is) const { return is->attachedTo() ? findRoot(is->attachedTo()) : is; } michael@0: int numAttrs() const { return m_silf->numUser(); } michael@0: int defaultOriginal() const { return m_defaultOriginal; } michael@0: const Face * getFace() const { return m_face; } michael@0: const Features & getFeatures(unsigned int /*charIndex*/) { assert(m_feats.size() == 1); return m_feats[0]; } michael@0: void bidiPass(uint8 aBidi, int paradir, uint8 aMirror); michael@0: Slot *addLineEnd(Slot *nSlot); michael@0: void delLineEnd(Slot *s); michael@0: bool hasJustification() const { return m_justifies.size() != 0; } michael@0: michael@0: bool isWhitespace(const int cid) const; michael@0: michael@0: CLASS_NEW_DELETE michael@0: michael@0: public: //only used by: GrSegment* makeAndInitialize(const GrFont *font, const GrFace *face, uint32 script, const FeaturesHandle& pFeats/*must not be IsNull*/, encform enc, const void* pStart, size_t nChars, int dir); michael@0: bool read_text(const Face *face, const Features* pFeats/*must not be NULL*/, gr_encform enc, const void*pStart, size_t nChars); michael@0: void prepare_pos(const Font *font); michael@0: void finalise(const Font *font); michael@0: float justify(Slot *pSlot, const Font *font, float width, enum justFlags flags, Slot *pFirst, Slot *pLast); michael@0: michael@0: private: michael@0: Position m_advance; // whole segment advance michael@0: SlotRope m_slots; // Vector of slot buffers michael@0: AttributeRope m_userAttrs; // Vector of userAttrs buffers michael@0: JustifyRope m_justifies; // Slot justification info buffers michael@0: FeatureList m_feats; // feature settings referenced by charinfos in this segment michael@0: Slot * m_freeSlots; // linked list of free slots michael@0: SlotJustify * m_freeJustifies; // Slot justification blocks free list michael@0: CharInfo * m_charinfo; // character info, one per input character michael@0: const Face * m_face; // GrFace michael@0: const Silf * m_silf; michael@0: Slot * m_first; // first slot in segment michael@0: Slot * m_last; // last slot in segment michael@0: unsigned int m_bufSize, // how big a buffer to create when need more slots michael@0: m_numGlyphs, michael@0: m_numCharinfo, // size of the array and number of input characters michael@0: m_passBits; // if bit set then skip pass michael@0: int m_defaultOriginal; // number of whitespace chars in the string michael@0: int8 m_dir; michael@0: }; michael@0: michael@0: michael@0: michael@0: inline michael@0: void Segment::finalise(const Font *font) michael@0: { michael@0: if (!m_first) return; michael@0: michael@0: m_advance = positionSlots(font); michael@0: associateChars(0, m_numCharinfo); michael@0: linkClusters(m_first, m_last); michael@0: } michael@0: michael@0: inline michael@0: int32 Segment::getGlyphMetric(Slot *iSlot, uint8 metric, uint8 attrLevel) const { michael@0: if (attrLevel > 0) michael@0: { michael@0: Slot *is = findRoot(iSlot); michael@0: return is->clusterMetric(this, metric, attrLevel); michael@0: } michael@0: else michael@0: return m_face->getGlyphMetric(iSlot->gid(), metric); michael@0: } michael@0: michael@0: inline michael@0: bool Segment::isWhitespace(const int cid) const michael@0: { michael@0: return ((cid >= 0x0009) * (cid <= 0x000D) michael@0: + (cid == 0x0020) michael@0: + (cid == 0x0085) michael@0: + (cid == 0x00A0) michael@0: + (cid == 0x1680) michael@0: + (cid == 0x180E) michael@0: + (cid >= 0x2000) * (cid <= 0x200A) michael@0: + (cid == 0x2028) michael@0: + (cid == 0x2029) michael@0: + (cid == 0x202F) michael@0: + (cid == 0x205F) michael@0: + (cid == 0x3000)) != 0; michael@0: } michael@0: michael@0: //inline michael@0: //bool Segment::isWhitespace(const int cid) const michael@0: //{ michael@0: // switch (cid >> 8) michael@0: // { michael@0: // case 0x00: michael@0: // switch (cid) michael@0: // { michael@0: // case 0x09: michael@0: // case 0x0A: michael@0: // case 0x0B: michael@0: // case 0x0C: michael@0: // case 0x0D: michael@0: // case 0x20: michael@0: // return true; michael@0: // default: michael@0: // break; michael@0: // } michael@0: // break; michael@0: // case 0x16: michael@0: // return cid == 0x1680; michael@0: // break; michael@0: // case 0x18: michael@0: // return cid == 0x180E; michael@0: // break; michael@0: // case 0x20: michael@0: // switch (cid) michael@0: // { michael@0: // case 0x00: michael@0: // case 0x01: michael@0: // case 0x02: michael@0: // case 0x03: michael@0: // case 0x04: michael@0: // case 0x05: michael@0: // case 0x06: michael@0: // case 0x07: michael@0: // case 0x08: michael@0: // case 0x09: michael@0: // case 0x0A: michael@0: // case 0x28: michael@0: // case 0x29: michael@0: // case 0x2F: michael@0: // case 0x5F: michael@0: // return true michael@0: // default: michael@0: // break; michael@0: // } michael@0: // break; michael@0: // case 0x30: michael@0: // return cid == 0x3000; michael@0: // break; michael@0: // } michael@0: // michael@0: // return false; michael@0: //} michael@0: michael@0: } // namespace graphite2 michael@0: michael@0: struct gr_segment : public graphite2::Segment {}; michael@0: