1 /*  GRAPHITE2 LICENSING
2 
3     Copyright 2012, 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 #pragma once
28 
29 
30 #include "graphite2/Font.h"
31 #include "inc/Main.h"
32 #include "inc/Position.h"
33 #include "inc/GlyphFace.h"
34 
35 namespace graphite2 {
36 
37 class Face;
38 class FeatureVal;
39 class Segment;
40 
41 
42 struct SlantBox
43 {
44     static const SlantBox empty;
45 
46 //    SlantBox(float psi = 0., float pdi = 0., float psa = 0., float pda = 0.) : si(psi), di(pdi), sa(psa), da(pda) {};
widthSlantBox47     float width() const { return sa - si; }
heightSlantBox48     float height() const { return da - di; }
49     float si; // min
50     float di; // min
51     float sa; // max
52     float da; // max
53 };
54 
55 
56 struct BBox
57 {
xiBBox58     BBox(float pxi = 0, float pyi = 0., float pxa = 0., float pya = 0.) : xi(pxi), yi(pyi), xa(pxa), ya(pya) {};
widthBBox59     float width() const { return xa - xi; }
heightBBox60     float height() const { return ya - yi; }
61     float xi; // min
62     float yi; // min
63     float xa; // max
64     float ya; // max
65 };
66 
67 
68 class GlyphBox
69 {
70     GlyphBox(const GlyphBox &);
71     GlyphBox & operator = (const GlyphBox &);
72 
73 public:
GlyphBox(uint8 numsubs,unsigned short bitmap,Rect * slanted)74     GlyphBox(uint8 numsubs, unsigned short bitmap, Rect *slanted) : _num(numsubs), _bitmap(bitmap), _slant(*slanted) {};
75 
addSubBox(int subindex,int boundary,Rect * val)76     void addSubBox(int subindex, int boundary, Rect *val) { _subs[subindex * 2 + boundary] = *val; }
subVal(int subindex,int boundary)77     Rect &subVal(int subindex, int boundary) { return _subs[subindex * 2 + boundary]; }
slant()78     const Rect &slant() const { return _slant; }
num()79     uint8 num() const { return _num; }
subs()80     const Rect *subs() const { return _subs; }
81 
82 private:
83     uint8   _num;
84     unsigned short  _bitmap;
85     Rect    _slant;
86     Rect    _subs[1];
87 };
88 
89 class GlyphCache
90 {
91     class Loader;
92 
93     GlyphCache(const GlyphCache&);
94     GlyphCache& operator=(const GlyphCache&);
95 
96 public:
97     GlyphCache(const Face & face, const uint32 face_options);
98     ~GlyphCache();
99 
100     unsigned short  numGlyphs() const throw();
101     unsigned short  numAttrs() const throw();
102     unsigned short  unitsPerEm() const throw();
103 
104     const GlyphFace *glyph(unsigned short glyphid) const;      //result may be changed by subsequent call with a different glyphid
105     const GlyphFace *glyphSafe(unsigned short glyphid) const;
106     float            getBoundingMetric(unsigned short glyphid, uint8 metric) const;
107     uint8            numSubBounds(unsigned short glyphid) const;
108     float            getSubBoundingMetric(unsigned short glyphid, uint8 subindex, uint8 metric) const;
slant(unsigned short glyphid)109     const Rect &     slant(unsigned short glyphid) const { return _boxes[glyphid] ? _boxes[glyphid]->slant() : _empty_slant_box; }
110     const SlantBox & getBoundingSlantBox(unsigned short glyphid) const;
111     const BBox &     getBoundingBBox(unsigned short glyphid) const;
112     const SlantBox & getSubBoundingSlantBox(unsigned short glyphid, uint8 subindex) const;
113     const BBox &     getSubBoundingBBox(unsigned short glyphid, uint8 subindex) const;
114     bool             check(unsigned short glyphid) const;
hasBoxes()115     bool             hasBoxes() const { return _boxes != 0; }
116 
117     CLASS_NEW_DELETE;
118 
119 private:
120     const Rect            _empty_slant_box;
121     const Loader        * _glyph_loader;
122     const GlyphFace *   * _glyphs;
123     GlyphBox        *   * _boxes;
124     unsigned short        _num_glyphs,
125                           _num_attrs,
126                           _upem;
127 };
128 
129 inline
numGlyphs()130 unsigned short GlyphCache::numGlyphs() const throw()
131 {
132     return _num_glyphs;
133 }
134 
135 inline
numAttrs()136 unsigned short GlyphCache::numAttrs() const throw()
137 {
138     return _num_attrs;
139 }
140 
141 inline
unitsPerEm()142 unsigned short  GlyphCache::unitsPerEm() const throw()
143 {
144     return _upem;
145 }
146 
147 inline
check(unsigned short glyphid)148 bool GlyphCache::check(unsigned short glyphid) const
149 {
150     return _boxes && glyphid < _num_glyphs;
151 }
152 
153 inline
glyphSafe(unsigned short glyphid)154 const GlyphFace *GlyphCache::glyphSafe(unsigned short glyphid) const
155 {
156     return glyphid < _num_glyphs ? glyph(glyphid) : NULL;
157 }
158 
159 inline
getBoundingMetric(unsigned short glyphid,uint8 metric)160 float GlyphCache::getBoundingMetric(unsigned short glyphid, uint8 metric) const
161 {
162     if (glyphid >= _num_glyphs) return 0.;
163     switch (metric) {
164         case 0: return (float)(glyph(glyphid)->theBBox().bl.x);                          // x_min
165         case 1: return (float)(glyph(glyphid)->theBBox().bl.y);                          // y_min
166         case 2: return (float)(glyph(glyphid)->theBBox().tr.x);                          // x_max
167         case 3: return (float)(glyph(glyphid)->theBBox().tr.y);                          // y_max
168         case 4: return (float)(_boxes[glyphid] ? _boxes[glyphid]->slant().bl.x : 0.f);    // sum_min
169         case 5: return (float)(_boxes[glyphid] ? _boxes[glyphid]->slant().bl.y : 0.f);    // diff_min
170         case 6: return (float)(_boxes[glyphid] ? _boxes[glyphid]->slant().tr.x : 0.f);    // sum_max
171         case 7: return (float)(_boxes[glyphid] ? _boxes[glyphid]->slant().tr.y : 0.f);    // diff_max
172         default: return 0.;
173     }
174 }
175 
getBoundingSlantBox(unsigned short glyphid)176 inline const SlantBox &GlyphCache::getBoundingSlantBox(unsigned short glyphid) const
177 {
178     return _boxes[glyphid] ? *(SlantBox *)(&(_boxes[glyphid]->slant())) : SlantBox::empty;
179 }
180 
getBoundingBBox(unsigned short glyphid)181 inline const BBox &GlyphCache::getBoundingBBox(unsigned short glyphid) const
182 {
183     return *(BBox *)(&(glyph(glyphid)->theBBox()));
184 }
185 
186 inline
getSubBoundingMetric(unsigned short glyphid,uint8 subindex,uint8 metric)187 float GlyphCache::getSubBoundingMetric(unsigned short glyphid, uint8 subindex, uint8 metric) const
188 {
189     GlyphBox *b = _boxes[glyphid];
190     if (b == NULL || subindex >= b->num()) return 0;
191 
192     switch (metric) {
193         case 0: return b->subVal(subindex, 0).bl.x;
194         case 1: return b->subVal(subindex, 0).bl.y;
195         case 2: return b->subVal(subindex, 0).tr.x;
196         case 3: return b->subVal(subindex, 0).tr.y;
197         case 4: return b->subVal(subindex, 1).bl.x;
198         case 5: return b->subVal(subindex, 1).bl.y;
199         case 6: return b->subVal(subindex, 1).tr.x;
200         case 7: return b->subVal(subindex, 1).tr.y;
201         default: return 0.;
202     }
203 }
204 
getSubBoundingSlantBox(unsigned short glyphid,uint8 subindex)205 inline const SlantBox &GlyphCache::getSubBoundingSlantBox(unsigned short glyphid, uint8 subindex) const
206 {
207     GlyphBox *b = _boxes[glyphid];
208     return *(SlantBox *)(b->subs() + 2 * subindex + 1);
209 }
210 
getSubBoundingBBox(unsigned short glyphid,uint8 subindex)211 inline const BBox &GlyphCache::getSubBoundingBBox(unsigned short glyphid, uint8 subindex) const
212 {
213     GlyphBox *b = _boxes[glyphid];
214     return *(BBox *)(b->subs() + 2 * subindex);
215 }
216 
217 inline
numSubBounds(unsigned short glyphid)218 uint8 GlyphCache::numSubBounds(unsigned short glyphid) const
219 {
220     return _boxes[glyphid] ? _boxes[glyphid]->num() : 0;
221 }
222 
223 } // namespace graphite2
224