void setGlyphXPositions(bool isRTL)
    {
        double position = 0;
        // logClustersIndex indexes logClusters for the first (or last when
        // RTL) codepoint of the current glyph.  Each time we advance a glyph,
        // we skip over all the codepoints that contributed to the current
        // glyph.
        unsigned logClustersIndex = isRTL ? m_item.num_glyphs - 1 : 0;

        for (int iter = 0; iter < m_item.num_glyphs; ++iter) {
            // Glyphs are stored in logical order, but for layout purposes we
            // always go left to right.
            int i = isRTL ? m_item.num_glyphs - iter - 1 : iter;

            m_glyphs16[i] = m_item.glyphs[i];
            double offsetX = truncateFixedPointToInteger(m_item.offsets[i].x);
            m_xPositions[i] = m_offsetX + position + offsetX;

            double advance = truncateFixedPointToInteger(m_item.advances[i]);
            // The first half of the conjuction works around the case where
            // output glyphs aren't associated with any codepoints by the
            // clusters log.
            if (logClustersIndex < m_item.item.length
                && isWordBreak(m_item.item.pos + logClustersIndex, isRTL)) {
                advance += m_wordSpacingAdjustment;

                if (m_padding > 0) {
                    unsigned toPad = roundf(m_padPerWordBreak + m_padError);
                    m_padError += m_padPerWordBreak - toPad;

                    if (m_padding < toPad)
                        toPad = m_padding;
                    m_padding -= toPad;
                    advance += toPad;
                }
            }

            // We would like to add m_letterSpacing after each cluster, but I
            // don't know where the cluster information is. This is typically
            // fine for Roman languages, but breaks more complex languages
            // terribly.
            // advance += m_letterSpacing;

            if (isRTL) {
                while (logClustersIndex > 0 && logClusters()[logClustersIndex] == i)
                    logClustersIndex--;
            } else {
                while (logClustersIndex < m_item.item.length && logClusters()[logClustersIndex] == i)
                    logClustersIndex++;
            }

            position += advance;
        }

        m_pixelWidth = position;
        m_offsetX += m_pixelWidth;
    }
void QTextEngine::shape( int item ) const
{
    assert( item < items.size() );
    QScriptItem &si = items[item];

    if ( si.num_glyphs )
	return;

    QFont::Script script = (QFont::Script)si.analysis.script;
    si.glyph_data_offset = used;

    if ( !si.fontEngine )
	si.fontEngine = fnt->engineForScript( script );
    si.fontEngine->ref();

	si.ascent = si.fontEngine->ascent();
	si.descent = si.fontEngine->descent();
    si.num_glyphs = 0;

    if ( si.fontEngine && si.fontEngine != (QFontEngine*)-1 ) {
        QShaperItem shaper_item;
        shaper_item.script = si.analysis.script;
        shaper_item.string = &string;
        shaper_item.from = si.position;
        shaper_item.length = length(item);
        shaper_item.font = si.fontEngine;
        shaper_item.num_glyphs = QMAX(int(num_glyphs - used), shaper_item.length);
        shaper_item.flags = si.analysis.bidiLevel % 2 ? RightToLeft : 0;

        while (1) {
//         qDebug("    . num_glyphs=%d, used=%d, item.num_glyphs=%d", num_glyphs, used, shaper_item.num_glyphs);
            ensureSpace(shaper_item.num_glyphs);
            shaper_item.num_glyphs = num_glyphs - used;
//          qDebug("    .. num_glyphs=%d, used=%d, item.num_glyphs=%d", num_glyphs, used, shaper_item.num_glyphs);
            shaper_item.glyphs = glyphs(&si);
            shaper_item.advances = advances(&si);
            shaper_item.offsets = offsets(&si);
            shaper_item.attributes = glyphAttributes(&si);
            shaper_item.log_clusters = logClusters(&si);
            if (scriptEngines[shaper_item.script].shape(&shaper_item))
                break;
        }

        si.num_glyphs = shaper_item.num_glyphs;
    }
    ((QTextEngine *)this)->used += si.num_glyphs;

    si.width = 0;
    advance_t *advances = this->advances( &si );
    advance_t *end = advances + si.num_glyphs;
    while ( advances < end )
	si.width += *(advances++);

    return;
}
void ComplexTextController::setGlyphXPositions(bool isRTL)
{
    const double rtlFlip = isRTL ? -1 : 1;
    double position = 0;

    // logClustersIndex indexes logClusters for the first codepoint of the current glyph.
    // Each time we advance a glyph, we skip over all the codepoints that contributed to the current glyph.
    int logClustersIndex = 0;

    // Iterate through the glyphs in logical order, flipping for RTL where necessary.
    // Glyphs are positioned starting from m_offsetX; in RTL mode they go leftwards from there.
    for (size_t i = 0; i < m_item.num_glyphs; ++i) {
        while (static_cast<unsigned>(logClustersIndex) < m_item.item.length && logClusters()[logClustersIndex] < i)
            logClustersIndex++;

        // If the current glyph is just after a space, add in the word spacing.
        position += determineWordBreakSpacing(logClustersIndex);

        m_glyphs16[i] = m_item.glyphs[i];
        double offsetX = truncateFixedPointToInteger(m_item.offsets[i].x);
        double advance = truncateFixedPointToInteger(m_item.advances[i]);
        if (isRTL)
            offsetX -= advance;

        m_xPositions[i] = m_offsetX + (position * rtlFlip) + offsetX;

        if (m_currentFontData->isZeroWidthSpaceGlyph(m_glyphs16[i]))
            continue;

        // At the end of each cluster, add in the letter spacing.
        if (i + 1 == m_item.num_glyphs || m_item.attributes[i + 1].clusterStart)
            position += m_letterSpacing;

        position += advance;
    }
    m_pixelWidth = std::max(position, 0.0);
    m_offsetX += m_pixelWidth * rtlFlip;
}
void QTextEngine::shapeTextMac(int item) const
{
    QScriptItem &si = layoutData->items[item];

    si.glyph_data_offset = layoutData->used;

    QFontEngine *font = fontEngine(si, &si.ascent, &si.descent, &si.leading);
    if (font->type() != QFontEngine::Multi) {
        shapeTextWithHarfbuzz(item);
        return;
    }
    
#ifndef QT_MAC_USE_COCOA
    QFontEngineMacMulti *fe = static_cast<QFontEngineMacMulti *>(font);
#else
    QCoreTextFontEngineMulti *fe = static_cast<QCoreTextFontEngineMulti *>(font);
#endif
    QTextEngine::ShaperFlags flags;
    if (si.analysis.bidiLevel % 2)
        flags |= RightToLeft;
    if (option.useDesignMetrics())
	flags |= DesignMetrics;

    attributes(); // pre-initialize char attributes

    const int len = length(item);
    int num_glyphs = length(item);
    const QChar *str = layoutData->string.unicode() + si.position;
    ushort upperCased[256];
    if (si.analysis.flags == QScriptAnalysis::SmallCaps || si.analysis.flags == QScriptAnalysis::Uppercase
            || si.analysis.flags == QScriptAnalysis::Lowercase) {
        ushort *uc = upperCased;
        if (len > 256)
            uc = new ushort[len];
        for (int i = 0; i < len; ++i) {
            if(si.analysis.flags == QScriptAnalysis::Lowercase)
                uc[i] = str[i].toLower().unicode();
            else
                uc[i] = str[i].toUpper().unicode();
        }
        str = reinterpret_cast<const QChar *>(uc);
    }

    ensureSpace(num_glyphs);
    num_glyphs = layoutData->glyphLayout.numGlyphs - layoutData->used;

    QGlyphLayout g = availableGlyphs(&si);
    g.numGlyphs = num_glyphs;
    unsigned short *log_clusters = logClusters(&si);

    bool stringToCMapFailed = false;
    if (!fe->stringToCMap(str, len, &g, &num_glyphs, flags, log_clusters, attributes())) {
        ensureSpace(num_glyphs);
        stringToCMapFailed = fe->stringToCMap(str, len, &g, &num_glyphs, flags, log_clusters,
                                              attributes());
    }

    if (!stringToCMapFailed) {
        heuristicSetGlyphAttributes(str, len, &g, log_clusters, num_glyphs);

        si.num_glyphs = num_glyphs;

        layoutData->used += si.num_glyphs;

        QGlyphLayout g = shapedGlyphs(&si);

        if (si.analysis.script == QUnicodeTables::Arabic) {
            QVarLengthArray<QArabicProperties> props(len + 2);
            QArabicProperties *properties = props.data();
            int f = si.position;
            int l = len;
            if (f > 0) {
                --f;
                ++l;
                ++properties;
            }
            if (f + l < layoutData->string.length()) {
                ++l;
            }
            qt_getArabicProperties((const unsigned short *)(layoutData->string.unicode()+f), l, props.data());

            unsigned short *log_clusters = logClusters(&si);

            for (int i = 0; i < len; ++i) {
                int gpos = log_clusters[i];
                g.attributes[gpos].justification = properties[i].justification;
            }
        }
    }

    const ushort *uc = reinterpret_cast<const ushort *>(str);

    if ((si.analysis.flags == QScriptAnalysis::SmallCaps || si.analysis.flags == QScriptAnalysis::Uppercase
         || si.analysis.flags == QScriptAnalysis::Lowercase)
        && uc != upperCased)
        delete [] uc;
}