/** * takes a utf16 string and runs Harfbuzz to create a list of glyphs * * @param aContext void context * @param aUtf16String the utf16 string * @param aHarfBuzz structure containing Harfbuzz stuff * @return error */ static int Utf16_To_Harfbuzz( void *aContext, uint16_t *aUtf16String, int nChars, HarfBuzz_t *aHarfBuzz ) { ft_Context_t *ftContext = FT_CONTEXT( aContext ); HB_FontRec hbFont; HB_Face hbFace = NULL; HB_ShaperItem hbShaperItem; memset( aHarfBuzz->str, 0, sizeof( aHarfBuzz->str ) ); memset( aHarfBuzz->out_glyphs, 0, sizeof( aHarfBuzz->out_glyphs ) ); memset( aHarfBuzz->out_attrs, 0, sizeof( aHarfBuzz->out_attrs ) ); memset( aHarfBuzz->out_advs, 0, sizeof( aHarfBuzz->out_advs ) ); memset( aHarfBuzz->out_offsets, 0, sizeof( aHarfBuzz->out_offsets ) ); memset( aHarfBuzz->out_logClusters, 0, sizeof( aHarfBuzz->out_logClusters ) ); memset( &hbFont, 0, sizeof( HB_FontRec ) ); memset( &hbFace, 0, sizeof( HB_Face ) ); hbFace = HB_NewFace( ftContext->m_face, hb_freetype_table_sfnt_get ); memcpy( aHarfBuzz->str, aUtf16String, nChars * sizeof( uint16_t ) ); aHarfBuzz->n_Chars = nChars; assert( ftContext->m_face != NULL ); hbFont.klass = &hb_freetype_class; hbFont.userData = ftContext->m_face; hbFont.x_ppem = ftContext->m_face->size->metrics.x_ppem; hbFont.y_ppem = ftContext->m_face->size->metrics.y_ppem; hbFont.x_scale = ftContext->m_face->size->metrics.x_scale; hbFont.y_scale = ftContext->m_face->size->metrics.y_scale; memset( &hbShaperItem, 0, sizeof( HB_ShaperItem ) ); hbShaperItem.kerning_applied = FALSE; hbShaperItem.string = ( HB_UChar16 * )aHarfBuzz->str; hbShaperItem.stringLength = nChars; hbShaperItem.item.bidiLevel = 0; hbShaperItem.item.script = HB_Script_Arabic; hbShaperItem.item.pos = 0; hbShaperItem.item.length = hbShaperItem.stringLength; hbShaperItem.shaperFlags = 0; hbShaperItem.font = &hbFont; hbShaperItem.face = hbFace; hbShaperItem.glyphIndicesPresent = FALSE; hbShaperItem.initialGlyphCount = 0; hbShaperItem.glyphs = aHarfBuzz->out_glyphs; hbShaperItem.attributes = aHarfBuzz->out_attrs; hbShaperItem.advances = aHarfBuzz->out_advs; hbShaperItem.offsets = aHarfBuzz->out_offsets; hbShaperItem.log_clusters = aHarfBuzz->out_logClusters; hbShaperItem.num_glyphs = MAX_CHARS; HB_ShapeItem( &hbShaperItem ); HB_FreeFace( hbFace ); return 0; }
Shaper::Shaper(FT_Face face, HB_Script script, const QString &str) { HB_Face hbFace = HB_NewFace(face, hb_getSFntTable); hbFont.klass = &hb_fontClass; hbFont.userData = face; hbFont.x_ppem = face->size->metrics.x_ppem; hbFont.y_ppem = face->size->metrics.y_ppem; hbFont.x_scale = face->size->metrics.x_scale; hbFont.y_scale = face->size->metrics.y_scale; shaper_item.kerning_applied = false; shaper_item.string = reinterpret_cast<const HB_UChar16 *>(str.constData()); shaper_item.stringLength = str.length(); shaper_item.item.script = script; shaper_item.item.pos = 0; shaper_item.item.length = shaper_item.stringLength; shaper_item.item.bidiLevel = 0; // ### shaper_item.shaperFlags = 0; shaper_item.font = &hbFont; shaper_item.face = hbFace; shaper_item.num_glyphs = shaper_item.item.length; shaper_item.glyphIndicesPresent = false; shaper_item.initialGlyphCount = 0; while (1) { hb_glyphs.resize(shaper_item.num_glyphs); hb_attributes.resize(shaper_item.num_glyphs); hb_advances.resize(shaper_item.num_glyphs); hb_offsets.resize(shaper_item.num_glyphs); hb_logClusters.resize(shaper_item.num_glyphs); memset(hb_glyphs.data(), 0, hb_glyphs.size() * sizeof(HB_Glyph)); memset(hb_attributes.data(), 0, hb_attributes.size() * sizeof(HB_GlyphAttributes)); memset(hb_advances.data(), 0, hb_advances.size() * sizeof(HB_Fixed)); memset(hb_offsets.data(), 0, hb_offsets.size() * sizeof(HB_FixedPoint)); shaper_item.glyphs = hb_glyphs.data(); shaper_item.attributes = hb_attributes.data(); shaper_item.advances = hb_advances.data(); shaper_item.offsets = hb_offsets.data(); shaper_item.log_clusters = hb_logClusters.data(); if (HB_ShapeItem(&shaper_item)) break; } HB_FreeFace(hbFace); }
bool shapeGlyphs() { for (;;) { m_item.num_glyphs = m_maxGlyphs; HB_ShapeItem(&m_item); if (m_item.num_glyphs < m_maxGlyphs) break; // We overflowed our arrays. Resize and retry. if (!expandGlyphArrays()) return false; } return true; }
void shapeGlyphs() { for (;;) { if (HB_ShapeItem(&m_item)) break; // We overflowed our arrays. Resize and retry. // HB_ShapeItem fills in m_item.num_glyphs with the needed size. deleteGlyphArrays(); // The |+ 1| here is a workaround for a bug in Harfbuzz: the Khmer // shaper (at least) can fail because of insufficient glyph buffers // and request 0 additional glyphs: throwing us into an infinite // loop. createGlyphArrays(m_item.num_glyphs + 1); } }
/** Do the shaping for this string. Assume str is an item, i.e. same script across the entire string */ ShaperOutput ShaperItemInfo::shapeItem(QString str) { if(str.length() == 0) return ShaperOutput(); QVector<uint> ustr = str.toUcs4(); //XXX let stringScript work with utf16 shaper_item.string = str.utf16(); shaper_item.stringLength = str.length(); shaper_item.item.script = stringScript(ustr, 0); shaper_item.item.pos = 0; shaper_item.item.length = str.length(); HB_ShapeItem(&shaper_item); return ShaperOutput(&shaper_item); }
void ComplexTextController::shapeGlyphs() { // HB_ShapeItem() resets m_item.num_glyphs. If the previous call to // HB_ShapeItem() used less space than was available, the capacity of // the array may be larger than the current value of m_item.num_glyphs. // So, we need to reset the num_glyphs to the capacity of the array. m_item.num_glyphs = m_glyphsArrayCapacity; resetGlyphArrays(); while (!HB_ShapeItem(&m_item)) { // We overflowed our arrays. Resize and retry. // HB_ShapeItem fills in m_item.num_glyphs with the needed size. deleteGlyphArrays(); // The |+ 1| here is a workaround for a bug in Harfbuzz: the Khmer // shaper (at least) can fail because of insufficient glyph buffers // and request 0 additional glyphs: throwing us into an infinite // loop. createGlyphArrays(m_item.num_glyphs + 1); } }
QT_BEGIN_NAMESPACE HB_Bool qShapeItem(HB_ShaperItem *item) { return HB_ShapeItem(item); }
QList< RenderedGlyph > FMShaper::doShape(QString string, bool ltr) { qDebug() << "FMShaper::doShape("<<string<<","<<ltr<<")"; if(!faceisset) setFont(); QMap<unsigned int, unsigned short> glyphToChar; // ugly and wrong, but shaper doesnt preserve any data about glyph generation. foreach(QChar c, string) { glyphToChar[FT_Get_Char_Index(anchorFace, c.unicode())] = c.unicode(); } m.kerning_applied = false; m.string = reinterpret_cast<const HB_UChar16 *> ( string.constData() ); m.stringLength = string.length(); m.item.pos = 0; m.item.bidiLevel = 0; m.shaperFlags = HB_ShaperFlag_UseDesignMetrics; m.initialGlyphCount = m.num_glyphs = m.item.length = m.stringLength; m.glyphIndicesPresent = false; int neededspace = m.num_glyphs ; QVarLengthArray<HB_Glyph> hb_glyphs(neededspace); QVarLengthArray<HB_GlyphAttributes> hb_attributes(neededspace); QVarLengthArray<HB_Fixed> hb_advances(neededspace); QVarLengthArray<HB_FixedPoint> hb_offsets(neededspace); QVarLengthArray<unsigned short> hb_logClusters(neededspace); HB_Bool result = false; int iter = 0; while ( !result ) { neededspace = m.num_glyphs ; hb_glyphs.resize(neededspace); hb_attributes.resize(neededspace); hb_advances.resize(neededspace); hb_offsets.resize(neededspace); hb_logClusters.resize(neededspace); memset(hb_glyphs.data(), 0, hb_glyphs.size() * sizeof(HB_Glyph)); memset(hb_attributes.data(), 0, hb_attributes.size() * sizeof(HB_GlyphAttributes)); memset(hb_advances.data(), 0, hb_advances.size() * sizeof(HB_Fixed)); memset(hb_offsets.data(), 0, hb_offsets.size() * sizeof(HB_FixedPoint)); memset(hb_logClusters.data(), 0, hb_logClusters.size() * sizeof(unsigned short)); m.glyphs = hb_glyphs.data(); m.attributes = hb_attributes.data(); m.advances = hb_advances.data(); m.offsets = hb_offsets.data(); m.log_clusters = hb_logClusters.data(); qDebug() << "----------------------------------------------item allocated------------"; result = HB_ShapeItem ( &m ); qDebug() << "----------------------------------------------ShapeItem run"<<++iter<<" - "<< (result ? "has " : "wants ") << m.num_glyphs <<" glyphs-"; } QList<RenderedGlyph> renderedString; int base = 0; int baseCorrection = 0; QString dbgS; for(int gIndex = 0; gIndex < m.num_glyphs; ++gIndex) { HB_GlyphAttributes attr = m.attributes[gIndex]; // qDebug()<< "ATTR("<< m.glyphs[gIndex] // << ") combiningClass = " << attr.combiningClass // << "; clusterStart =" << attr.clusterStart // << "; mark = "<< attr.mark; if(m.attributes[gIndex].clusterStart ) { base = gIndex; baseCorrection = 0; } // if(m.attributes[gIndex].mark ) else { // qDebug() << "catch a mark"; // for(int b=base; b < gIndex; ++b) { // baseCorrection = renderedString[base].xadvance; } } RenderedGlyph gl; gl.glyph = m.glyphs[gIndex]; gl.xadvance = /*ltr ? */( double ) ( m.advances[gIndex]) /*:( double ) ( -m.advances[gIndex])*/ ; gl.yadvance = 0.0; gl.xoffset = /*ltr ?*/ ( m.offsets[gIndex].x - baseCorrection ) /*: ( baseCorrection - m.offsets[gIndex].x )*/; gl.yoffset = m.offsets[gIndex].y ; gl.log = m.log_clusters[gIndex]; // gl.lChar = string.at(m.log_clusters[gIndex]).unicode(); gl.lChar = glyphToChar[ m.glyphs[m.log_clusters[gIndex]] ]; renderedString << gl; // if(gl.log == 32) // qDebug()<<"SPACE"<<gl.glyph<<gl.xadvance<<gl.xoffset<<gl.log; // dbgS += "["+ QString::number(gIndex)+ " ; " + QString::number(gl.log)+ " ; " +( (gl.log > 32) ? QString(QChar(gl.log)) : "--")+"] "; // dbgS += QChar(gl.log); // dbgS += "[" + QString::number(gl.lChar) + "]"; dbgS += "["+QString::number(gIndex)+ ";" +QString(QChar(gl.lChar))+"]"; } // qDebug() << "EndOf FMShaper::doShape("<<string<<","<<ltr<<")"; qDebug() <<"LOGS:"<<dbgS; return renderedString; }