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 |