2 * Copyright (C) 2009, Martin Hosken
3 * Copyright (C) 2009, SIL International
5 * This is part of HarfBuzz, a text shaping library.
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.
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
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.
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"
38 extern int FontAscent(const void *pOS2);
39 extern int FontDescent(const void *pOS2);
40 extern int DesignUnits(const void *pHead);
41 extern bool FontOs2Style(const void *pOS2, bool &fBold, bool &fItalic);
44 typedef struct _featureSetting {
49 class HbGrBufferTextSrc : public gr::ITextSource
52 HbGrBufferTextSrc(hb_buffer_t *buff, hb_feature_t *feats, unsigned int num_features)
54 hb_feature_t *aFeat = feats;
55 featureSetting *aNewFeat;
57 buffer = hb_buffer_reference(buff);
58 features = new featureSetting[num_features];
59 nFeatures = num_features;
61 for (unsigned int i = 0; i < num_features; i++, aFeat++, aNewFeat++)
63 aNewFeat->id = aFeat->tag;
64 aNewFeat->value = aFeat->value;
67 ~HbGrBufferTextSrc() { hb_buffer_destroy(buffer); delete[] features; };
68 virtual gr::UtfType utfEncodingForm() { return gr::kutf32; };
69 virtual size_t getLength() { return buffer->len; };
70 virtual size_t fetch(gr::toffset ichMin, size_t cch, gr::utf32 * prgchBuffer)
72 assert(cch <= buffer->len);
73 if (cch > buffer->len)
75 for (unsigned int i = ichMin; i < ichMin + cch; i++)
76 prgchBuffer[i - ichMin] = buffer->info[i].codepoint;
77 return (cch - ichMin);
79 virtual size_t fetch(gr::toffset ichMin, size_t cch, gr::utf16 * prgchBuffer) { return 0 ;};
80 virtual size_t fetch(gr::toffset ichMin, size_t cch, gr::utf8 * prgchBuffer) { return 0; };
81 virtual bool getRightToLeft(gr::toffset ich)
82 { return hb_buffer_get_direction(buffer) == HB_DIRECTION_RTL; };
83 virtual unsigned int getDirectionDepth(gr::toffset ich)
84 { return hb_buffer_get_direction(buffer) == HB_DIRECTION_RTL ? 1 : 0; };
85 virtual float getVerticalOffset(gr::toffset ich) { return 0; };
86 virtual gr::isocode getLanguage(gr::toffset ich)
89 char *p = (char *)(buffer->language);
91 for (i = 0; i < 4; i++)
103 virtual std::pair<gr::toffset, gr::toffset> propertyRange(gr::toffset ich)
104 { return std::pair<gr::toffset, gr::toffset>(0, buffer->len); };
105 virtual size_t getFontFeatures(gr::toffset ich, gr::FeatureSetting * prgfset)
107 featureSetting *aFeat = features;
108 for (unsigned int i = 0; i < nFeatures; i++, aFeat++, prgfset++)
110 prgfset->id = aFeat->id;
111 prgfset->value = aFeat->value;
115 virtual bool sameSegment(gr::toffset ich1, gr::toffset ich2) {return true; };
119 featureSetting *features;
120 unsigned int nFeatures;
123 class HbGrFont : public gr::Font
126 HbGrFont(hb_font_t *font, hb_face_t *face) : gr::Font()
127 { m_font = hb_font_reference(font); m_face = hb_face_reference(face); initfont(); };
130 std::map<hb_tag_t,hb_blob_t *>::iterator p = m_blobs.begin();
131 while (p != m_blobs.end())
132 { hb_blob_destroy((p++)->second); }
133 hb_font_destroy(m_font);
134 hb_face_destroy(m_face);
136 HbGrFont (const HbGrFont &font) : gr::Font(font)
139 m_blobs = std::map<hb_tag_t, hb_blob_t *>(font.m_blobs);
140 std::map<hb_tag_t,hb_blob_t *>::iterator p=m_blobs.begin();
141 while (p != m_blobs.end()) { hb_blob_reference((*p++).second); }
142 hb_font_reference(m_font);
143 hb_face_reference(m_face);
145 virtual HbGrFont *copyThis() { return new HbGrFont(*this); };
146 virtual bool bold() { return m_bold; };
147 virtual bool italic() { return m_italic; };
148 virtual float ascent() { float asc; getFontMetrics(&asc, NULL, NULL); return asc; };
149 virtual float descent() { float desc; getFontMetrics(NULL, &desc, NULL); return desc; };
150 virtual float height()
151 { float asc, desc; getFontMetrics(&asc, &desc, NULL); return (asc + desc); };
152 virtual unsigned int getDPIx() { return m_font->x_ppem; };
153 virtual unsigned int getDPIy() { return m_font->y_ppem; };
154 virtual const void *getTable(gr::fontTableId32 tableID, size_t *pcbsize)
157 std::map<hb_tag_t,hb_blob_t *>::iterator p=m_blobs.find((hb_tag_t)tableID);
158 if (p == m_blobs.end())
160 blob = hb_face_get_table(m_face, (hb_tag_t)tableID);
161 m_blobs[(hb_tag_t)tableID] = blob;
164 { blob = p->second; }
166 const char *res = hb_blob_lock(blob);
168 *pcbsize = hb_blob_get_length(blob);
169 hb_blob_unlock(blob);
170 return (const void *)res;
173 virtual void getFontMetrics(float *pAscent, float *pDescent, float *pEmSquare)
175 if (pAscent) *pAscent = 1. * m_ascent * m_font->y_ppem / m_emsquare;
176 if (pDescent) *pDescent = 1. * m_descent * m_font->y_ppem / m_emsquare;
177 if (pEmSquare) *pEmSquare = m_font->x_scale;
179 virtual void getGlyphPoint(gr::gid16 glyphID, unsigned int pointNum, gr::Point &pointReturn)
182 hb_font_get_contour_point(m_font, m_face, pointNum, glyphID, &x, &y);
183 pointReturn.x = (float)x;
184 pointReturn.y = (float)y;
187 virtual void getGlyphMetrics(gr::gid16 glyphID, gr::Rect &boundingBox, gr::Point &advances)
189 hb_glyph_metrics_t metrics;
190 hb_font_get_glyph_metrics(m_font, m_face, glyphID, &metrics);
191 boundingBox.top = (metrics.y_offset + metrics.height);
192 boundingBox.bottom = metrics.y_offset;
193 boundingBox.left = metrics.x_offset;
194 boundingBox.right = (metrics.x_offset + metrics.width);
195 advances.x = metrics.x_advance;
196 advances.y = metrics.y_advance;
197 // fprintf (stderr, "%d: (%d, %d, %d, %d)+(%d, %d)\n", glyphID, metrics.x_offset, metrics.y_offset, metrics.width, metrics.height, metrics.x_advance, metrics.y_advance);
201 HB_INTERNAL void initfont();
210 std::map<hb_tag_t, hb_blob_t *> m_blobs;
213 void HbGrFont::initfont()
215 const void *pOS2 = getTable(gr::kttiOs2, NULL);
216 const void *pHead = getTable(gr::kttiHead, NULL);
217 TtfUtil::FontOs2Style(pOS2, m_bold, m_italic);
218 m_ascent = static_cast<float>(TtfUtil::FontAscent(pOS2));
219 m_descent = static_cast<float>(TtfUtil::FontDescent(pOS2));
220 m_emsquare = static_cast<float>(TtfUtil::DesignUnits(pHead));
224 hb_graphite_shape (hb_font_t *font,
227 hb_feature_t *features,
228 unsigned int num_features)
230 /* create text source */
231 HbGrBufferTextSrc textSrc(buffer, features, num_features);
234 HbGrFont grfont(font, face);
241 gr::LayoutEnvironment layout;
242 std::pair<gr::GlyphIterator, gr::GlyphIterator>glyph_range;
243 gr::GlyphIterator iGlyph;
244 hb_codepoint_t *glyph_infos, *pGlyph;
245 hb_glyph_position_t *pPosition;
249 layout.setStartOfLine(0);
250 layout.setEndOfLine(0);
251 layout.setDumbFallback(true);
252 layout.setJustifier(NULL);
253 layout.setRightToLeft(false);
255 gr::RangeSegment pSegment(&grfont, &textSrc, &layout, (gr::toffset)0,
256 static_cast<gr::toffset>(buffer->len), (gr::Segment *)NULL);
258 /* fill in buffer from segment */
259 _hb_buffer_clear_output(buffer);
260 pSegment.getUniscribeClusters(NULL, 0, &numChars, NULL, 0, &numGlyphs);
261 firsts = new int[numChars];
262 flags = new bool[numGlyphs];
263 glyph_infos = new hb_codepoint_t[numGlyphs];
264 hb_buffer_ensure(buffer, numGlyphs);
265 pSegment.getUniscribeClusters(firsts, numChars, NULL, flags, numGlyphs, NULL);
266 glyph_range = pSegment.glyphs();
267 for (pGlyph = glyph_infos, iGlyph = glyph_range.first; iGlyph != glyph_range.second;
269 { *pGlyph = iGlyph->glyphID(); }
271 while (cGlyph < numGlyphs)
275 int oldcChar = cChar++;
276 int oldcGlyph = cGlyph++;
277 while (cChar < numChars && firsts[cChar] == firsts[oldcChar]) cChar++;
278 while (cGlyph < numGlyphs && !flags[cGlyph]) cGlyph++;
279 _hb_buffer_add_output_glyphs(buffer, cChar - oldcChar, cGlyph - oldcGlyph,
280 glyph_infos + oldcGlyph, 0xFFFF, 0xFFFF);
283 { cGlyph++; } /* This should never happen */
286 float curradvx = 0., curradvy = 0.;
287 for (pPosition = hb_buffer_get_glyph_positions(buffer), iGlyph = glyph_range.first;
288 iGlyph != glyph_range.second; pPosition++, iGlyph++)
290 pPosition->x_offset = iGlyph->origin() - curradvx;
291 pPosition->y_offset = iGlyph->yOffset() - curradvy;
292 pPosition->x_advance = pPosition->x_offset + iGlyph->advanceWidth();
293 pPosition->y_advance = pPosition->y_offset + iGlyph->advanceHeight();
294 if (pPosition->x_advance < 0 && iGlyph->logicalIndex() != iGlyph->attachedClusterBase()->logicalIndex())
295 pPosition->x_advance = 0;
296 curradvx += pPosition->x_advance;
297 curradvy += pPosition->y_advance;
298 // fprintf(stderr, "%d@(%f, %f)+(%f, %f)\n", iGlyph->glyphID(), iGlyph->origin(), iGlyph->yOffset(), iGlyph->advanceWidth(), iGlyph->advanceHeight());
301 delete[] glyph_infos;