Always allocate new ligature id
[framework/uifw/harfbuzz.git] / src / hb-graphite.cc
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_features)
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 asc; };
152   virtual float descent() { float desc; getFontMetrics(NULL, &desc, NULL); return 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::Point &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_offset, 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.second;
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 - oldcGlyph,
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.first;
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->attachedClusterBase()->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->origin(), 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