/**
 * 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;
}
Exemple #2
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);
}
Exemple #3
0
    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);
        }
    }
Exemple #5
0
/**
    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);
    }
}
Exemple #7
0
QT_BEGIN_NAMESPACE

HB_Bool qShapeItem(HB_ShaperItem *item)
{
    return HB_ShapeItem(item);
}
Exemple #8
0
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;
}