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; }