De-C++ where possible
[apps/core/preloaded/video-player.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 namespace TtfUtil
37 {
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);
42 }
43
44 typedef struct _featureSetting {
45     unsigned int id;
46     int value;
47 } featureSetting;
48
49 class HbGrBufferTextSrc : public gr::ITextSource
50 {
51 public:
52   HbGrBufferTextSrc(hb_buffer_t *buff, hb_feature_t *feats, unsigned int num_features)
53   {
54     hb_feature_t *aFeat = feats;
55     featureSetting *aNewFeat;
56
57     buffer = hb_buffer_reference(buff);
58     features = new featureSetting[num_features];
59     nFeatures = num_features;
60     aNewFeat = features;
61     for (unsigned int i = 0; i < num_features; i++, aFeat++, aNewFeat++)
62     {
63         aNewFeat->id = aFeat->tag;
64         aNewFeat->value = aFeat->value;
65     }
66   };
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)
71   {
72     assert(cch <= buffer->len);
73     if (cch > buffer->len)
74       return 0;
75     for (unsigned int i = ichMin; i < ichMin + cch; i++)
76       prgchBuffer[i - ichMin] = buffer->info[i].codepoint;
77     return (cch - ichMin);
78   };
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)
87   {
88     gr::isocode aLang;
89     char *p = (char *)(buffer->language);
90     int i;
91     for (i = 0; i < 4; i++)
92     {
93       if (p != NULL)
94         aLang.rgch[i] = *p;
95       else
96         aLang.rgch[i] = 0;
97       if (p && *p)
98         p++;
99     }
100     return aLang;
101   }
102
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)
106   {
107     featureSetting *aFeat = features;
108     for (unsigned int i = 0; i < nFeatures; i++, aFeat++, prgfset++)
109     {
110       prgfset->id = aFeat->id;
111       prgfset->value = aFeat->value;
112     }
113     return nFeatures;
114   }
115   virtual bool sameSegment(gr::toffset ich1, gr::toffset ich2) {return true; };
116
117 private:
118   hb_buffer_t   *buffer;
119   featureSetting   *features;
120   unsigned int nFeatures;
121 };
122
123 class HbGrFont : public gr::Font
124 {
125 public:
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(); };
128   ~HbGrFont()
129   {
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);
135   };
136   HbGrFont (const HbGrFont &font) : gr::Font(font)
137   {
138     *this = 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);
144   };
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)
155   {
156     hb_blob_t *blob;
157     std::map<hb_tag_t,hb_blob_t *>::iterator p=m_blobs.find((hb_tag_t)tableID);
158     if (p == m_blobs.end())
159     {
160       blob = hb_face_get_table(m_face, (hb_tag_t)tableID);
161       m_blobs[(hb_tag_t)tableID] = blob;
162     }
163     else
164     { blob = p->second; }
165
166     const char *res = hb_blob_lock(blob);
167     if (pcbsize)
168       *pcbsize = hb_blob_get_length(blob);
169     hb_blob_unlock(blob);
170     return (const void *)res;
171   }
172
173   virtual void getFontMetrics(float *pAscent, float *pDescent, float *pEmSquare)
174   {
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;
178   }
179   virtual void getGlyphPoint(gr::gid16 glyphID, unsigned int pointNum, gr::Point &pointReturn)
180   {
181     hb_position_t x, y;
182     hb_font_get_contour_point(m_font, m_face, pointNum, glyphID, &x, &y);
183     pointReturn.x = (float)x;
184     pointReturn.y = (float)y;
185   }
186
187   virtual void getGlyphMetrics(gr::gid16 glyphID, gr::Rect &boundingBox, gr::Point &advances)
188   {
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);
198   }
199
200 private:
201   HB_INTERNAL void initfont();
202
203   hb_font_t *m_font;
204   hb_face_t *m_face;
205   float m_ascent;
206   float m_descent;
207   float m_emsquare;
208   bool m_bold;
209   bool m_italic;
210   std::map<hb_tag_t, hb_blob_t *> m_blobs;
211 };
212
213 void HbGrFont::initfont()
214 {
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));
221 }
222
223 void
224 hb_graphite_shape (hb_font_t    *font,
225                    hb_face_t    *face,
226                    hb_buffer_t  *buffer,
227                    hb_feature_t *features,
228                    unsigned int  num_features)
229 {
230   /* create text source */
231   HbGrBufferTextSrc   textSrc(buffer, features, num_features);
232
233   /* create grfont */
234   HbGrFont          grfont(font, face);
235
236   /* create segment */
237   int *firsts;
238   bool *flags;
239   int numChars;
240   int numGlyphs;
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;
246   int cGlyph = 0;
247   int cChar = 0;
248
249   layout.setStartOfLine(0);
250   layout.setEndOfLine(0);
251   layout.setDumbFallback(true);
252   layout.setJustifier(NULL);
253   layout.setRightToLeft(false);
254
255   gr::RangeSegment pSegment(&grfont, &textSrc, &layout, (gr::toffset)0,
256         static_cast<gr::toffset>(buffer->len), (gr::Segment *)NULL);
257
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;
268         iGlyph++, pGlyph++)
269   { *pGlyph = iGlyph->glyphID(); }
270
271   while (cGlyph < numGlyphs)
272   {
273     if (flags[cGlyph])
274     {
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);
281     }
282     else
283     { cGlyph++; }   /* This should never happen */
284   }
285
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++)
289   {
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());
299   }
300
301   delete[] glyph_infos;
302   delete[] firsts;
303   delete[] flags;
304 }