parent
3ba6818ba9
commit
305ba86715
5 changed files with 386 additions and 0 deletions
@ -0,0 +1,308 @@ |
||||
/*
|
||||
* Copyright (C) 2009, Martin Hosken |
||||
* Copyright (C) 2009, SIL International |
||||
* |
||||
* This is part of HarfBuzz, a text shaping library. |
||||
* |
||||
* Permission is hereby granted, without written agreement and without |
||||
* license or royalty fees, to use, copy, modify, and distribute this |
||||
* software and its documentation for any purpose, provided that the |
||||
* above copyright notice and the following two paragraphs appear in |
||||
* all copies of this software. |
||||
* |
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR |
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES |
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN |
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
||||
* DAMAGE. |
||||
* |
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, |
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS |
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO |
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
||||
*/ |
||||
|
||||
#include <graphite/GrClient.h> |
||||
#include <graphite/ITextSource.h> |
||||
#include <graphite/GrData.h> |
||||
#include <graphite/GrConstants.h> |
||||
#include <graphite/Segment.h> |
||||
#include "hb-buffer-private.hh" |
||||
#include "hb-font-private.hh" |
||||
#include "hb-graphite.h" |
||||
#include <map> |
||||
|
||||
namespace TtfUtil |
||||
{ |
||||
extern int FontAscent(const void *pOS2); |
||||
extern int FontDescent(const void *pOS2); |
||||
extern int DesignUnits(const void *pHead); |
||||
extern bool FontOs2Style(const void *pOS2, bool &fBold, bool &fItalic); |
||||
} |
||||
|
||||
typedef struct _featureSetting { |
||||
unsigned int id; |
||||
int value; |
||||
} featureSetting; |
||||
|
||||
class GrBufferTextSrc : public gr::ITextSource |
||||
{ |
||||
public: |
||||
GrBufferTextSrc(hb_buffer_t *buff, hb_feature_t *feats, unsigned int num_features) |
||||
{ |
||||
int i; |
||||
hb_feature_t *aFeat = feats; |
||||
featureSetting *aNewFeat; |
||||
|
||||
buffer = hb_buffer_reference(buff); |
||||
features = new featureSetting[num_features]; |
||||
nFeatures = num_features; |
||||
aNewFeat = features; |
||||
for (i = 0; i < num_features; i++, aFeat++, aNewFeat++) |
||||
{ |
||||
aNewFeat->id = aFeat->tag; |
||||
aNewFeat->value = aFeat->value; |
||||
} |
||||
}; |
||||
~GrBufferTextSrc() { hb_buffer_destroy(buffer); delete[] features; }; |
||||
virtual gr::UtfType utfEncodingForm() { return gr::kutf32; }; |
||||
virtual size_t getLength() { return buffer->len; }; |
||||
virtual size_t fetch(gr::toffset ichMin, size_t cch, gr::utf32 * prgchBuffer) |
||||
{ |
||||
int i; |
||||
|
||||
assert(cch <= buffer->len); |
||||
if (cch > buffer->len) |
||||
return 0; |
||||
for (i = ichMin; i < ichMin + cch; i++) |
||||
prgchBuffer[i - ichMin] = buffer->info[i].codepoint; |
||||
return (cch - ichMin); |
||||
}; |
||||
virtual size_t fetch(gr::toffset ichMin, size_t cch, gr::utf16 * prgchBuffer) { return 0 ;}; |
||||
virtual size_t fetch(gr::toffset ichMin, size_t cch, gr::utf8 * prgchBuffer) { return 0; }; |
||||
virtual bool getRightToLeft(gr::toffset ich) |
||||
{ return hb_buffer_get_direction(buffer) == HB_DIRECTION_RTL; }; |
||||
virtual unsigned int getDirectionDepth(gr::toffset ich) |
||||
{ return hb_buffer_get_direction(buffer) == HB_DIRECTION_RTL ? 1 : 0; }; |
||||
virtual float getVerticalOffset(gr::toffset ich) { return 0; }; |
||||
virtual gr::isocode getLanguage(gr::toffset ich) |
||||
{ |
||||
gr::isocode aLang; |
||||
char *p = (char *)(buffer->language); |
||||
int i; |
||||
for (i = 0; i < 4; i++) |
||||
{ |
||||
if (p != NULL) |
||||
aLang.rgch[i] = *p; |
||||
else |
||||
aLang.rgch[i] = 0; |
||||
if (p && *p) |
||||
p++; |
||||
} |
||||
return aLang; |
||||
} |
||||
|
||||
virtual std::pair<gr::toffset, gr::toffset> propertyRange(gr::toffset ich) |
||||
{ return std::pair<gr::toffset, gr::toffset>(0, buffer->len); }; |
||||
virtual size_t getFontFeatures(gr::toffset ich, gr::FeatureSetting * prgfset) |
||||
{ |
||||
int i; |
||||
featureSetting *aFeat = features; |
||||
for (i = 0; i < nFeatures; i++, aFeat++, prgfset++) |
||||
{ |
||||
prgfset->id = aFeat->id; |
||||
prgfset->value = aFeat->value; |
||||
} |
||||
return nFeatures; |
||||
} |
||||
virtual bool sameSegment(gr::toffset ich1, gr::toffset ich2) {return true; }; |
||||
|
||||
private: |
||||
hb_buffer_t *buffer; |
||||
featureSetting *features; |
||||
unsigned int nFeatures; |
||||
}; |
||||
|
||||
class GrHbFont : public gr::Font |
||||
{ |
||||
public: |
||||
GrHbFont(hb_font_t *font, hb_face_t *face) : gr::Font() |
||||
{ m_font = hb_font_reference(font); m_face = hb_face_reference(face); initfont(); }; |
||||
~GrHbFont() |
||||
{ |
||||
std::map<hb_tag_t,hb_blob_t *>::iterator p = m_blobs.begin(); |
||||
while (p != m_blobs.end()) |
||||
{ hb_blob_destroy((p++)->second); } |
||||
hb_font_destroy(m_font); |
||||
hb_face_destroy(m_face); |
||||
}; |
||||
GrHbFont (const GrHbFont &font) : gr::Font(font) |
||||
{ |
||||
*this = font; |
||||
m_blobs = std::map<hb_tag_t, hb_blob_t *>(font.m_blobs); |
||||
std::map<hb_tag_t,hb_blob_t *>::iterator p=m_blobs.begin(); |
||||
while (p != m_blobs.end()) { hb_blob_reference((*p++).second); } |
||||
hb_font_reference(m_font); |
||||
hb_face_reference(m_face); |
||||
}; |
||||
virtual GrHbFont *copyThis() { return new GrHbFont(*this); }; |
||||
virtual bool bold() { return m_bold; }; |
||||
virtual bool italic() { return m_italic; }; |
||||
virtual float ascent() { float asc; getFontMetrics(&asc, NULL, NULL); return asc; }; |
||||
virtual float descent() { float desc; getFontMetrics(NULL, &desc, NULL); return desc; }; |
||||
virtual float height() |
||||
{ float asc, desc; getFontMetrics(&asc, &desc, NULL); return (asc + desc); }; |
||||
virtual unsigned int getDPIx() { return m_font->x_ppem; }; |
||||
virtual unsigned int getDPIy() { return m_font->y_ppem; }; |
||||
virtual const void *getTable(gr::fontTableId32 tableID, size_t *pcbsize) |
||||
{ |
||||
hb_blob_t *blob; |
||||
std::map<hb_tag_t,hb_blob_t *>::iterator p=m_blobs.find((hb_tag_t)tableID); |
||||
if (p == m_blobs.end()) |
||||
{ |
||||
blob = hb_face_get_table(m_face, (hb_tag_t)tableID); |
||||
m_blobs[(hb_tag_t)tableID] = blob; |
||||
} |
||||
else |
||||
{ blob = p->second; } |
||||
|
||||
const char *res = hb_blob_lock(blob); |
||||
if (pcbsize) |
||||
*pcbsize = hb_blob_get_length(blob); |
||||
hb_blob_unlock(blob); |
||||
return (const void *)res; |
||||
} |
||||
|
||||
virtual void getFontMetrics(float *pAscent, float *pDescent, float *pEmSquare) |
||||
{ |
||||
if (pAscent) *pAscent = 1. * m_ascent * m_font->y_ppem / m_emsquare; |
||||
if (pDescent) *pDescent = 1. * m_descent * m_font->y_ppem / m_emsquare; |
||||
if (pEmSquare) *pEmSquare = m_font->x_scale; |
||||
} |
||||
virtual void getGlyphPoint(gr::gid16 glyphID, unsigned int pointNum, gr::Point &pointReturn) |
||||
{ |
||||
hb_position_t x, y; |
||||
hb_font_get_contour_point(m_font, m_face, pointNum, glyphID, &x, &y); |
||||
pointReturn.x = (float)x; |
||||
pointReturn.y = (float)y; |
||||
} |
||||
|
||||
virtual void getGlyphMetrics(gr::gid16 glyphID, gr::Rect &boundingBox, gr::Point &advances) |
||||
{ |
||||
hb_glyph_metrics_t metrics; |
||||
hb_font_get_glyph_metrics(m_font, m_face, glyphID, &metrics); |
||||
boundingBox.top = (metrics.y_offset + metrics.height); |
||||
boundingBox.bottom = metrics.y_offset; |
||||
boundingBox.left = metrics.x_offset; |
||||
boundingBox.right = (metrics.x_offset + metrics.width); |
||||
advances.x = metrics.x_advance; |
||||
advances.y = metrics.y_advance; |
||||
// 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);
|
||||
} |
||||
|
||||
private: |
||||
void initfont(); |
||||
|
||||
hb_font_t *m_font; |
||||
hb_face_t *m_face; |
||||
float m_ascent; |
||||
float m_descent; |
||||
float m_emsquare; |
||||
bool m_bold; |
||||
bool m_italic; |
||||
std::map<hb_tag_t, hb_blob_t *> m_blobs; |
||||
}; |
||||
|
||||
void GrHbFont::initfont() |
||||
{ |
||||
const void *pOS2 = getTable(gr::kttiOs2, NULL); |
||||
const void *pHead = getTable(gr::kttiHead, NULL); |
||||
TtfUtil::FontOs2Style(pOS2, m_bold, m_italic); |
||||
m_ascent = static_cast<float>(TtfUtil::FontAscent(pOS2)); |
||||
m_descent = static_cast<float>(TtfUtil::FontDescent(pOS2)); |
||||
m_emsquare = static_cast<float>(TtfUtil::DesignUnits(pHead)); |
||||
} |
||||
|
||||
void |
||||
hb_graphite_shape (hb_font_t *font, |
||||
hb_face_t *face, |
||||
hb_buffer_t *buffer, |
||||
hb_feature_t *features, |
||||
unsigned int num_features) |
||||
{ |
||||
/* create text source */ |
||||
GrBufferTextSrc textSrc(buffer, features, num_features); |
||||
|
||||
/* create grfont */ |
||||
GrHbFont grfont(font, face); |
||||
|
||||
/* create segment */ |
||||
int *firsts; |
||||
bool *flags; |
||||
int numChars; |
||||
int numGlyphs; |
||||
gr::LayoutEnvironment layout; |
||||
std::pair<gr::GlyphIterator, gr::GlyphIterator>glyph_range; |
||||
gr::GlyphIterator iGlyph; |
||||
hb_codepoint_t *glyph_infos, *pGlyph; |
||||
hb_glyph_position_t *pPosition; |
||||
int cGlyph = 0; |
||||
int cChar = 0; |
||||
|
||||
layout.setStartOfLine(0); |
||||
layout.setEndOfLine(0); |
||||
layout.setDumbFallback(true); |
||||
layout.setJustifier(NULL); |
||||
layout.setRightToLeft(false); |
||||
|
||||
gr::RangeSegment pSegment(&grfont, &textSrc, &layout, (gr::toffset)0, |
||||
static_cast<gr::toffset>(buffer->len), (gr::Segment *)NULL); |
||||
|
||||
/* fill in buffer from segment */ |
||||
_hb_buffer_clear_output(buffer); |
||||
pSegment.getUniscribeClusters(NULL, 0, &numChars, NULL, 0, &numGlyphs); |
||||
firsts = new int[numChars]; |
||||
flags = new bool[numGlyphs]; |
||||
glyph_infos = new hb_codepoint_t[numGlyphs]; |
||||
hb_buffer_ensure(buffer, numGlyphs); |
||||
pSegment.getUniscribeClusters(firsts, numChars, NULL, flags, numGlyphs, NULL); |
||||
glyph_range = pSegment.glyphs(); |
||||
for (pGlyph = glyph_infos, iGlyph = glyph_range.first; iGlyph != glyph_range.second; |
||||
iGlyph++, pGlyph++) |
||||
{ *pGlyph = iGlyph->glyphID(); } |
||||
|
||||
while (cGlyph < numGlyphs) |
||||
{ |
||||
if (flags[cGlyph]) |
||||
{ |
||||
int oldcChar = cChar++; |
||||
int oldcGlyph = cGlyph++; |
||||
while (cChar < numChars && firsts[cChar] == firsts[oldcChar]) cChar++; |
||||
while (cGlyph < numGlyphs && !flags[cGlyph]) cGlyph++; |
||||
_hb_buffer_add_output_glyphs(buffer, cChar - oldcChar, cGlyph - oldcGlyph, |
||||
glyph_infos + oldcGlyph, 0xFFFF, 0xFFFF); |
||||
} |
||||
else |
||||
{ cGlyph++; } /* This should never happen */ |
||||
} |
||||
|
||||
float curradvx = 0., curradvy = 0.; |
||||
for (pPosition = hb_buffer_get_glyph_positions(buffer), iGlyph = glyph_range.first; |
||||
iGlyph != glyph_range.second; pPosition++, iGlyph++) |
||||
{ |
||||
pPosition->x_offset = iGlyph->origin() - curradvx; |
||||
pPosition->y_offset = iGlyph->yOffset() - curradvy; |
||||
pPosition->x_advance = pPosition->x_offset + iGlyph->advanceWidth(); |
||||
pPosition->y_advance = pPosition->y_offset + iGlyph->advanceHeight(); |
||||
// if (pPosition->x_advance < 0)
|
||||
// pPosition->x_advance = 0;
|
||||
curradvx += pPosition->x_advance; |
||||
curradvy += pPosition->y_advance; |
||||
// fprintf(stderr, "%d@(%f, %f)+(%f, %f)\n", iGlyph->glyphID(), iGlyph->origin(), iGlyph->yOffset(), iGlyph->advanceWidth(), iGlyph->advanceHeight());
|
||||
} |
||||
|
||||
delete[] glyph_infos; |
||||
delete[] firsts; |
||||
delete[] flags; |
||||
} |
@ -0,0 +1,46 @@ |
||||
/*
|
||||
* Copyright (C) 2009, Martin Hosken |
||||
* Copyright (C) 2009, SIL International |
||||
* |
||||
* This is part of HarfBuzz, a text shaping library. |
||||
* |
||||
* Permission is hereby granted, without written agreement and without |
||||
* license or royalty fees, to use, copy, modify, and distribute this |
||||
* software and its documentation for any purpose, provided that the |
||||
* above copyright notice and the following two paragraphs appear in |
||||
* all copies of this software. |
||||
* |
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR |
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES |
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN |
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
||||
* DAMAGE. |
||||
* |
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, |
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS |
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO |
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
||||
* |
||||
* Red Hat Author(s): Behdad Esfahbod |
||||
*/ |
||||
|
||||
#ifndef HB_GRAPHITE_H |
||||
#define HB_GRAPHITE_H |
||||
|
||||
#include "hb-shape.h" |
||||
|
||||
|
||||
HB_BEGIN_DECLS |
||||
|
||||
#define HB_GRAPHITE_TAG_Silf HB_TAG('S','i','l','f') |
||||
|
||||
void hb_graphite_shape (hb_font_t *font, |
||||
hb_face_t *face, |
||||
hb_buffer_t *buffer, |
||||
hb_feature_t *features, |
||||
unsigned int num_features); |
||||
|
||||
HB_END_DECLS |
||||
|
||||
#endif /* HB_GRAPHITE_H */ |
Loading…
Reference in new issue