OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2009 Martin Hosken | |
3 * Copyright (C) 2009 SIL International | |
4 * | |
5 * This is part of HarfBuzz, a text shaping library. | |
6 * | |
7 * Permission is hereby granted, without written agreement and without | |
8 * license or royalty fees, to use, copy, modify, and distribute this | |
9 * software and its documentation for any purpose, provided that the | |
10 * above copyright notice and the following two paragraphs appear in | |
11 * all copies of this software. | |
12 * | |
13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR | |
14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES | |
15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN | |
16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH | |
17 * DAMAGE. | |
18 * | |
19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, | |
20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS | |
22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO | |
23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. | |
24 */ | |
25 | |
26 #include <graphite/GrClient.h> | |
27 #include <graphite/ITextSource.h> | |
28 #include <graphite/GrData.h> | |
29 #include <graphite/GrConstants.h> | |
30 #include <graphite/Segment.h> | |
31 #include "hb-buffer-private.hh" | |
32 #include "hb-font-private.h" | |
33 #include "hb-graphite.h" | |
34 #include <map> | |
35 | |
36 HB_BEGIN_DECLS | |
37 | |
38 | |
39 namespace TtfUtil | |
40 { | |
41 extern int FontAscent(const void *pOS2); | |
42 extern int FontDescent(const void *pOS2); | |
43 extern int DesignUnits(const void *pHead); | |
44 extern bool FontOs2Style(const void *pOS2, bool &fBold, bool &fItalic); | |
45 } | |
46 | |
47 typedef struct _featureSetting { | |
48 unsigned int id; | |
49 int value; | |
50 } featureSetting; | |
51 | |
52 class HbGrBufferTextSrc : public gr::ITextSource | |
53 { | |
54 public: | |
55 HbGrBufferTextSrc(hb_buffer_t *buff, hb_feature_t *feats, unsigned int num_fea
tures) | |
56 { | |
57 hb_feature_t *aFeat = feats; | |
58 featureSetting *aNewFeat; | |
59 | |
60 buffer = hb_buffer_reference(buff); | |
61 features = new featureSetting[num_features]; | |
62 nFeatures = num_features; | |
63 aNewFeat = features; | |
64 for (unsigned int i = 0; i < num_features; i++, aFeat++, aNewFeat++) | |
65 { | |
66 aNewFeat->id = aFeat->tag; | |
67 aNewFeat->value = aFeat->value; | |
68 } | |
69 }; | |
70 ~HbGrBufferTextSrc() { hb_buffer_destroy(buffer); delete[] features; }; | |
71 virtual gr::UtfType utfEncodingForm() { return gr::kutf32; }; | |
72 virtual size_t getLength() { return buffer->len; }; | |
73 virtual size_t fetch(gr::toffset ichMin, size_t cch, gr::utf32 * prgchBuffer) | |
74 { | |
75 assert(cch <= buffer->len); | |
76 if (cch > buffer->len) | |
77 return 0; | |
78 for (unsigned int i = ichMin; i < ichMin + cch; i++) | |
79 prgchBuffer[i - ichMin] = buffer->info[i].codepoint; | |
80 return (cch - ichMin); | |
81 }; | |
82 virtual size_t fetch(gr::toffset ichMin, size_t cch, gr::utf16 * prgchBuffer)
{ return 0 ;}; | |
83 virtual size_t fetch(gr::toffset ichMin, size_t cch, gr::utf8 * prgchBuffer) {
return 0; }; | |
84 virtual bool getRightToLeft(gr::toffset ich) | |
85 { return hb_buffer_get_direction(buffer) == HB_DIRECTION_RTL; }; | |
86 virtual unsigned int getDirectionDepth(gr::toffset ich) | |
87 { return hb_buffer_get_direction(buffer) == HB_DIRECTION_RTL ? 1 : 0; }; | |
88 virtual float getVerticalOffset(gr::toffset ich) { return 0; }; | |
89 virtual gr::isocode getLanguage(gr::toffset ich) | |
90 { | |
91 gr::isocode aLang; | |
92 char *p = (char *)(buffer->language); | |
93 int i; | |
94 for (i = 0; i < 4; i++) | |
95 { | |
96 if (p != NULL) | |
97 aLang.rgch[i] = *p; | |
98 else | |
99 aLang.rgch[i] = 0; | |
100 if (p && *p) | |
101 p++; | |
102 } | |
103 return aLang; | |
104 } | |
105 | |
106 virtual std::pair<gr::toffset, gr::toffset> propertyRange(gr::toffset ich) | |
107 { return std::pair<gr::toffset, gr::toffset>(0, buffer->len); }; | |
108 virtual size_t getFontFeatures(gr::toffset ich, gr::FeatureSetting * prgfset) | |
109 { | |
110 featureSetting *aFeat = features; | |
111 for (unsigned int i = 0; i < nFeatures; i++, aFeat++, prgfset++) | |
112 { | |
113 prgfset->id = aFeat->id; | |
114 prgfset->value = aFeat->value; | |
115 } | |
116 return nFeatures; | |
117 } | |
118 virtual bool sameSegment(gr::toffset ich1, gr::toffset ich2) {return true; }; | |
119 | |
120 private: | |
121 hb_buffer_t *buffer; | |
122 featureSetting *features; | |
123 unsigned int nFeatures; | |
124 }; | |
125 | |
126 class HbGrFont : public gr::Font | |
127 { | |
128 public: | |
129 HbGrFont(hb_font_t *font, hb_face_t *face) : gr::Font() | |
130 { m_font = hb_font_reference(font); m_face = hb_face_reference(face); initfont
(); }; | |
131 ~HbGrFont() | |
132 { | |
133 std::map<hb_tag_t,hb_blob_t *>::iterator p = m_blobs.begin(); | |
134 while (p != m_blobs.end()) | |
135 { hb_blob_destroy((p++)->second); } | |
136 hb_font_destroy(m_font); | |
137 hb_face_destroy(m_face); | |
138 }; | |
139 HbGrFont (const HbGrFont &font) : gr::Font(font) | |
140 { | |
141 *this = font; | |
142 m_blobs = std::map<hb_tag_t, hb_blob_t *>(font.m_blobs); | |
143 std::map<hb_tag_t,hb_blob_t *>::iterator p=m_blobs.begin(); | |
144 while (p != m_blobs.end()) { hb_blob_reference((*p++).second); } | |
145 hb_font_reference(m_font); | |
146 hb_face_reference(m_face); | |
147 }; | |
148 virtual HbGrFont *copyThis() { return new HbGrFont(*this); }; | |
149 virtual bool bold() { return m_bold; }; | |
150 virtual bool italic() { return m_italic; }; | |
151 virtual float ascent() { float asc; getFontMetrics(&asc, NULL, NULL); return a
sc; }; | |
152 virtual float descent() { float desc; getFontMetrics(NULL, &desc, NULL); retur
n desc; }; | |
153 virtual float height() | |
154 { float asc, desc; getFontMetrics(&asc, &desc, NULL); return (asc + desc); }; | |
155 virtual unsigned int getDPIx() { return m_font->x_ppem; }; | |
156 virtual unsigned int getDPIy() { return m_font->y_ppem; }; | |
157 virtual const void *getTable(gr::fontTableId32 tableID, size_t *pcbsize) | |
158 { | |
159 hb_blob_t *blob; | |
160 std::map<hb_tag_t,hb_blob_t *>::iterator p=m_blobs.find((hb_tag_t)tableID); | |
161 if (p == m_blobs.end()) | |
162 { | |
163 blob = hb_face_get_table(m_face, (hb_tag_t)tableID); | |
164 m_blobs[(hb_tag_t)tableID] = blob; | |
165 } | |
166 else | |
167 { blob = p->second; } | |
168 | |
169 const char *res = hb_blob_lock(blob); | |
170 if (pcbsize) | |
171 *pcbsize = hb_blob_get_length(blob); | |
172 hb_blob_unlock(blob); | |
173 return (const void *)res; | |
174 } | |
175 | |
176 virtual void getFontMetrics(float *pAscent, float *pDescent, float *pEmSquare) | |
177 { | |
178 if (pAscent) *pAscent = 1. * m_ascent * m_font->y_ppem / m_emsquare; | |
179 if (pDescent) *pDescent = 1. * m_descent * m_font->y_ppem / m_emsquare; | |
180 if (pEmSquare) *pEmSquare = m_font->x_scale; | |
181 } | |
182 virtual void getGlyphPoint(gr::gid16 glyphID, unsigned int pointNum, gr::Point
&pointReturn) | |
183 { | |
184 hb_position_t x, y; | |
185 hb_font_get_contour_point(m_font, m_face, pointNum, glyphID, &x, &y); | |
186 pointReturn.x = (float)x; | |
187 pointReturn.y = (float)y; | |
188 } | |
189 | |
190 virtual void getGlyphMetrics(gr::gid16 glyphID, gr::Rect &boundingBox, gr::Poi
nt &advances) | |
191 { | |
192 hb_glyph_metrics_t metrics; | |
193 hb_font_get_glyph_metrics(m_font, m_face, glyphID, &metrics); | |
194 boundingBox.top = (metrics.y_offset + metrics.height); | |
195 boundingBox.bottom = metrics.y_offset; | |
196 boundingBox.left = metrics.x_offset; | |
197 boundingBox.right = (metrics.x_offset + metrics.width); | |
198 advances.x = metrics.x_advance; | |
199 advances.y = metrics.y_advance; | |
200 // fprintf (stderr, "%d: (%d, %d, %d, %d)+(%d, %d)\n", glyphID, metrics.x_off
set, metrics.y_offset, metrics.width, metrics.height, metrics.x_advance, metrics
.y_advance); | |
201 } | |
202 | |
203 private: | |
204 HB_INTERNAL void initfont(); | |
205 | |
206 hb_font_t *m_font; | |
207 hb_face_t *m_face; | |
208 float m_ascent; | |
209 float m_descent; | |
210 float m_emsquare; | |
211 bool m_bold; | |
212 bool m_italic; | |
213 std::map<hb_tag_t, hb_blob_t *> m_blobs; | |
214 }; | |
215 | |
216 void HbGrFont::initfont() | |
217 { | |
218 const void *pOS2 = getTable(gr::kttiOs2, NULL); | |
219 const void *pHead = getTable(gr::kttiHead, NULL); | |
220 TtfUtil::FontOs2Style(pOS2, m_bold, m_italic); | |
221 m_ascent = static_cast<float>(TtfUtil::FontAscent(pOS2)); | |
222 m_descent = static_cast<float>(TtfUtil::FontDescent(pOS2)); | |
223 m_emsquare = static_cast<float>(TtfUtil::DesignUnits(pHead)); | |
224 } | |
225 | |
226 void | |
227 hb_graphite_shape (hb_font_t *font, | |
228 hb_face_t *face, | |
229 hb_buffer_t *buffer, | |
230 hb_feature_t *features, | |
231 unsigned int num_features) | |
232 { | |
233 /* create text source */ | |
234 HbGrBufferTextSrc textSrc(buffer, features, num_features); | |
235 | |
236 /* create grfont */ | |
237 HbGrFont grfont(font, face); | |
238 | |
239 /* create segment */ | |
240 int *firsts; | |
241 bool *flags; | |
242 int numChars; | |
243 int numGlyphs; | |
244 gr::LayoutEnvironment layout; | |
245 std::pair<gr::GlyphIterator, gr::GlyphIterator>glyph_range; | |
246 gr::GlyphIterator iGlyph; | |
247 hb_codepoint_t *glyph_infos, *pGlyph; | |
248 hb_glyph_position_t *pPosition; | |
249 int cGlyph = 0; | |
250 int cChar = 0; | |
251 | |
252 layout.setStartOfLine(0); | |
253 layout.setEndOfLine(0); | |
254 layout.setDumbFallback(true); | |
255 layout.setJustifier(NULL); | |
256 layout.setRightToLeft(false); | |
257 | |
258 gr::RangeSegment pSegment(&grfont, &textSrc, &layout, (gr::toffset)0, | |
259 static_cast<gr::toffset>(buffer->len), (gr::Segment *)NULL); | |
260 | |
261 /* fill in buffer from segment */ | |
262 _hb_buffer_clear_output(buffer); | |
263 pSegment.getUniscribeClusters(NULL, 0, &numChars, NULL, 0, &numGlyphs); | |
264 firsts = new int[numChars]; | |
265 flags = new bool[numGlyphs]; | |
266 glyph_infos = new hb_codepoint_t[numGlyphs]; | |
267 hb_buffer_ensure(buffer, numGlyphs); | |
268 pSegment.getUniscribeClusters(firsts, numChars, NULL, flags, numGlyphs, NULL); | |
269 glyph_range = pSegment.glyphs(); | |
270 for (pGlyph = glyph_infos, iGlyph = glyph_range.first; iGlyph != glyph_range.s
econd; | |
271 iGlyph++, pGlyph++) | |
272 { *pGlyph = iGlyph->glyphID(); } | |
273 | |
274 while (cGlyph < numGlyphs) | |
275 { | |
276 if (flags[cGlyph]) | |
277 { | |
278 int oldcChar = cChar++; | |
279 int oldcGlyph = cGlyph++; | |
280 while (cChar < numChars && firsts[cChar] == firsts[oldcChar]) cChar++; | |
281 while (cGlyph < numGlyphs && !flags[cGlyph]) cGlyph++; | |
282 _hb_buffer_add_output_glyphs(buffer, cChar - oldcChar, cGlyph - oldcGlyp
h, | |
283 glyph_infos + oldcGlyph, 0xFFFF, 0xFFFF); | |
284 } | |
285 else | |
286 { cGlyph++; } /* This should never happen */ | |
287 } | |
288 | |
289 float curradvx = 0., curradvy = 0.; | |
290 for (pPosition = hb_buffer_get_glyph_positions(buffer), iGlyph = glyph_range.f
irst; | |
291 iGlyph != glyph_range.second; pPosition++, iGlyph++) | |
292 { | |
293 pPosition->x_offset = iGlyph->origin() - curradvx; | |
294 pPosition->y_offset = iGlyph->yOffset() - curradvy; | |
295 pPosition->x_advance = pPosition->x_offset + iGlyph->advanceWidth(); | |
296 pPosition->y_advance = pPosition->y_offset + iGlyph->advanceHeight(); | |
297 if (pPosition->x_advance < 0 && iGlyph->logicalIndex() != iGlyph->attachedCl
usterBase()->logicalIndex()) | |
298 pPosition->x_advance = 0; | |
299 curradvx += pPosition->x_advance; | |
300 curradvy += pPosition->y_advance; | |
301 // fprintf(stderr, "%d@(%f, %f)+(%f, %f)\n", iGlyph->glyphID(), iGlyph->origi
n(), iGlyph->yOffset(), iGlyph->advanceWidth(), iGlyph->advanceHeight()); | |
302 } | |
303 | |
304 delete[] glyph_infos; | |
305 delete[] firsts; | |
306 delete[] flags; | |
307 } | |
308 | |
309 | |
310 HB_END_DECLS | |
OLD | NEW |