本文整理汇总了C++中TextRun::expansion方法的典型用法代码示例。如果您正苦于以下问题:C++ TextRun::expansion方法的具体用法?C++ TextRun::expansion怎么用?C++ TextRun::expansion使用的例子?那么恭喜您, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在类TextRun
的用法示例。
在下文中一共展示了TextRun::expansion方法的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C++代码示例。
示例1: UniscribeHelper
UniscribeHelperTextRun::UniscribeHelperTextRun(const TextRun& run,
const Font& font)
: UniscribeHelper(0, run.length(), run.rtl(),
font.primaryFont()->platformData().hfont(),
font.primaryFont()->platformData().scriptCache(),
font.primaryFont()->platformData().scriptFontProperties(),
font.primaryFont()->spaceGlyph())
, m_font(&font)
, m_fontIndex(0)
{
if (run.is8Bit()) {
m_stringFor8BitRun = String::make16BitFrom8BitSource(run.characters8(), run.length());
setInput(m_stringFor8BitRun.characters16());
} else {
setInput(run.characters16());
}
setDirectionalOverride(run.directionalOverride());
setLetterSpacing(font.letterSpacing());
setSpaceWidth(font.spaceWidth());
setWordSpacing(font.wordSpacing());
setAscent(font.fontMetrics().ascent());
setRangeProperties(font.fontDescription().featureSettings());
init();
// Expansion is the amount to add to make justification happen. This
// should be done after Init() so all the runs are already measured.
if (run.expansion() > 0)
justify(run.expansion());
}
示例2: drawComplexText
void Font::drawComplexText(GraphicsContext* gc, const TextRun& run,
const FloatPoint& point, int from, int to) const
{
if (!run.length())
return;
SkCanvas* canvas = gc->platformContext()->canvas();
TextDrawingModeFlags textMode = gc->platformContext()->getTextDrawingMode();
bool fill = textMode & TextModeFill;
bool stroke = (textMode & TextModeStroke)
&& gc->platformContext()->getStrokeStyle() != NoStroke
&& gc->platformContext()->getStrokeThickness() > 0;
if (!fill && !stroke)
return;
SkPaint strokePaint, fillPaint;
if (fill) {
gc->platformContext()->setupPaintForFilling(&fillPaint);
setupForTextPainting(&fillPaint, gc->fillColor().rgb());
}
if (stroke) {
gc->platformContext()->setupPaintForStroking(&strokePaint, 0, 0);
setupForTextPainting(&strokePaint, gc->strokeColor().rgb());
}
ComplexTextController controller(run, point.x(), point.y(), this);
controller.setWordSpacingAdjustment(wordSpacing());
controller.setLetterSpacingAdjustment(letterSpacing());
controller.setPadding(run.expansion());
if (run.rtl()) {
// FIXME: this causes us to shape the text twice -- once to compute the width and then again
// below when actually rendering. Change ComplexTextController to match platform/mac and
// platform/chromium/win by having it store the shaped runs, so we can reuse the results.
controller.reset(point.x() + controller.widthOfFullRun());
// We need to set the padding again because ComplexTextController layout consumed the value.
// Fixing the above problem would help here too.
controller.setPadding(run.expansion());
}
while (controller.nextScriptRun()) {
if (fill) {
controller.fontPlatformDataForScriptRun()->setupPaint(&fillPaint);
adjustTextRenderMode(&fillPaint, gc->platformContext());
canvas->drawPosText(controller.glyphs(), controller.length() << 1, controller.positions(), fillPaint);
}
if (stroke) {
controller.fontPlatformDataForScriptRun()->setupPaint(&strokePaint);
adjustTextRenderMode(&strokePaint, gc->platformContext());
canvas->drawPosText(controller.glyphs(), controller.length() << 1, controller.positions(), strokePaint);
}
}
}
示例3: offsetForPositionForComplexText
// Return the code point index for the given |x| offset into the text run.
int Font::offsetForPositionForComplexText(const TextRun& run, float xFloat,
bool includePartialGlyphs) const
{
// FIXME: This truncation is not a problem for HTML, but only affects SVG, which passes floating-point numbers
// to Font::offsetForPosition(). Bug http://webkit.org/b/40673 tracks fixing this problem.
int targetX = static_cast<int>(xFloat);
// (Mac code ignores includePartialGlyphs, and they don't know what it's
// supposed to do, so we just ignore it as well.)
ComplexTextController controller(run, 0, 0, this);
controller.setWordSpacingAdjustment(wordSpacing());
controller.setLetterSpacingAdjustment(letterSpacing());
controller.setPadding(run.expansion());
if (run.rtl()) {
// See FIXME in drawComplexText.
controller.reset(controller.widthOfFullRun());
controller.setPadding(run.expansion());
}
unsigned basePosition = 0;
int x = controller.offsetX();
while (controller.nextScriptRun()) {
int nextX = controller.offsetX();
if (std::min(x, nextX) <= targetX && targetX <= std::max(x, nextX)) {
// The x value in question is within this script run.
const int glyphIndex = glyphIndexForXPositionInScriptRun(controller, targetX);
// Now that we have a glyph index, we have to turn that into a
// code-point index. Because of ligatures, several code-points may
// have gone into a single glyph. We iterate over the clusters log
// and find the first code-point which contributed to the glyph.
// Some shapers (i.e. Khmer) will produce cluster logs which report
// that /no/ code points contributed to certain glyphs. Because of
// this, we take any code point which contributed to the glyph in
// question, or any subsequent glyph. If we run off the end, then
// we take the last code point.
const unsigned short* log = controller.logClusters();
for (unsigned j = 0; j < controller.numCodePoints(); ++j) {
if (log[j] >= glyphIndex)
return basePosition + j;
}
return basePosition + controller.numCodePoints() - 1;
}
basePosition += controller.numCodePoints();
}
return basePosition;
}
示例4: selectionRectForComplexText
// Return the rectangle for selecting the given range of code-points in the TextRun.
FloatRect Font::selectionRectForComplexText(const TextRun& run,
const FloatPoint& point, int height,
int from, int to) const
{
int fromX = -1, toX = -1;
ComplexTextController controller(run, 0, 0, this);
controller.setWordSpacingAdjustment(wordSpacing());
controller.setLetterSpacingAdjustment(letterSpacing());
controller.setPadding(run.expansion());
if (run.rtl()) {
// See FIXME in drawComplexText.
controller.reset(controller.widthOfFullRun());
controller.setPadding(run.expansion());
}
// Iterate through the script runs in logical order, searching for the run covering the positions of interest.
while (controller.nextScriptRun() && (fromX == -1 || toX == -1)) {
if (fromX == -1 && from >= 0 && static_cast<unsigned>(from) < controller.numCodePoints()) {
// |from| is within this script run. So we index the clusters log to
// find which glyph this code-point contributed to and find its x
// position.
int glyph = controller.logClusters()[from];
fromX = controller.positions()[glyph].x();
if (controller.rtl())
fromX += truncateFixedPointToInteger(controller.advances()[glyph]);
} else
from -= controller.numCodePoints();
if (toX == -1 && to >= 0 && static_cast<unsigned>(to) < controller.numCodePoints()) {
int glyph = controller.logClusters()[to];
toX = controller.positions()[glyph].x();
if (controller.rtl())
toX += truncateFixedPointToInteger(controller.advances()[glyph]);
} else
to -= controller.numCodePoints();
}
// The position in question might be just after the text.
if (fromX == -1)
fromX = controller.offsetX();
if (toX == -1)
toX = controller.offsetX();
ASSERT(fromX != -1 && toX != -1);
if (fromX < toX)
return FloatRect(point.x() + fromX, point.y(), toX - fromX, height);
return FloatRect(point.x() + toX, point.y(), fromX - toX, height);
}
示例5: setupLayout
static QTextLine setupLayout(QTextLayout* layout, const TextRun& style)
{
int flags = style.rtl() ? Qt::TextForceRightToLeft : Qt::TextForceLeftToRight;
if (style.expansion())
flags |= Qt::TextJustificationForced;
layout->setFlags(flags);
layout->beginLayout();
QTextLine line = layout->createLine();
line.setLineWidth(INT_MAX/256);
if (style.expansion())
line.setLineWidth(line.naturalTextWidth() + style.expansion());
layout->endLayout();
return line;
}
示例6: resetControlAndState
// FIXME: Rearchitect this to be more like WidthIterator in Font.cpp. Have an advance() method
// that does stuff in that method instead of doing everything in the constructor. Have advance()
// take the GlyphBuffer as an arg so that we don't have to populate the glyph buffer when
// measuring.
UniscribeController::UniscribeController(const Font* font, const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts)
: m_font(*font)
, m_run(run)
, m_fallbackFonts(fallbackFonts)
, m_minGlyphBoundingBoxX(numeric_limits<float>::max())
, m_maxGlyphBoundingBoxX(numeric_limits<float>::min())
, m_minGlyphBoundingBoxY(numeric_limits<float>::max())
, m_maxGlyphBoundingBoxY(numeric_limits<float>::min())
, m_end(run.length())
, m_currentCharacter(0)
, m_runWidthSoFar(0)
, m_padding(run.expansion())
, m_computingOffsetPosition(false)
, m_includePartialGlyphs(false)
, m_offsetX(0)
, m_offsetPosition(0)
{
if (!m_padding)
m_padPerSpace = 0;
else {
float numSpaces = 0;
for (int s = 0; s < m_run.length(); s++) {
if (Font::treatAsSpace(m_run[s]))
numSpaces++;
}
if (numSpaces == 0)
m_padPerSpace = 0;
else
m_padPerSpace = m_padding / numSpaces;
}
// Null out our uniscribe structs
resetControlAndState();
}
示例7: floatWidthForComplexText
float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* /* fallbackFonts */, GlyphOverflow* /* glyphOverflow */) const
{
ComplexTextController controller(run, 0, 0, this);
controller.setWordSpacingAdjustment(wordSpacing());
controller.setLetterSpacingAdjustment(letterSpacing());
controller.setPadding(run.expansion());
return controller.widthOfFullRun();
}
示例8: floatWidthForComplexText
float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>*, GlyphOverflow*) const
{
if (!primaryFont()->platformData().size())
return 0;
if (!run.length())
return 0;
if (run.length() == 1 && treatAsSpace(run[0]))
return QFontMetrics(font()).width(space) + run.expansion();
String sanitized = Font::normalizeSpaces(run.characters(), run.length());
QString string = fromRawDataWithoutRef(sanitized);
int w = QFontMetrics(font()).width(string);
// WebKit expects us to ignore word spacing on the first character (as opposed to what Qt does)
if (treatAsSpace(run[0]))
w -= m_wordSpacing;
return w + run.expansion();
}
示例9: UniscribeHelper
UniscribeHelperTextRun::UniscribeHelperTextRun(const TextRun& run,
const Font& font)
: UniscribeHelper(run.characters(), run.length(), run.rtl(),
font.primaryFont()->platformData().hfont(),
font.primaryFont()->platformData().scriptCache(),
font.primaryFont()->platformData().scriptFontProperties(),
font.primaryFont()->spaceGlyph())
, m_font(&font)
, m_fontIndex(0)
{
setDirectionalOverride(run.directionalOverride());
setLetterSpacing(font.letterSpacing());
setSpaceWidth(font.spaceWidth());
setWordSpacing(font.wordSpacing());
setAscent(font.fontMetrics().ascent());
init();
// Expansion is the amount to add to make justification happen. This
// should be done after Init() so all the runs are already measured.
if (run.expansion() > 0)
justify(run.expansion());
}
示例10: drawComplexText
void Font::drawComplexText(GraphicsContext* gc, TextRun const& run,
FloatPoint const& point, int, int) const
{
if (!run.length())
return;
int mode = gc->textDrawingMode();
bool fill = mode & TextModeFill;
bool stroke = mode & TextModeStroke;
if (!fill && !stroke)
return;
SkPaint fillPaint, strokePaint;
if (fill)
setupFill(&fillPaint, gc, primaryFont());
if (stroke)
setupStroke(&strokePaint, gc, primaryFont());
SkCanvas* canvas = gc->platformContext()->recordingCanvas();
bool haveMultipleLayers = isCanvasMultiLayered(canvas);
TextRunWalker walker(run, point.x(), point.y(), this);
walker.setWordAndLetterSpacing(wordSpacing(), letterSpacing());
walker.setPadding(run.expansion());
while (walker.nextScriptRun()) {
if (fill) {
walker.fontPlatformDataForScriptRun()->setupPaint(&fillPaint);
adjustTextRenderMode(&fillPaint, haveMultipleLayers);
canvas->drawPosText(walker.glyphs(), walker.length() << 1,
walker.positions(), fillPaint);
}
if (stroke) {
walker.fontPlatformDataForScriptRun()->setupPaint(&strokePaint);
adjustTextRenderMode(&strokePaint, haveMultipleLayers);
canvas->drawPosText(walker.glyphs(), walker.length() << 1,
walker.positions(), strokePaint);
}
}
gc->platformContext()->endRecording();
}
示例11: ASSERT
ShapeResultSpacing::ShapeResultSpacing(const TextRun& run,
const FontDescription& fontDescription)
: m_textRun(run)
, m_letterSpacing(fontDescription.letterSpacing())
, m_wordSpacing(fontDescription.wordSpacing())
, m_expansion(run.expansion())
, m_expansionPerOpportunity(0)
, m_expansionOpportunityCount(0)
, m_textJustify(TextJustify::TextJustifyAuto)
, m_hasSpacing(false)
, m_normalizeSpace(run.normalizeSpace())
, m_allowTabs(run.allowTabs())
, m_isAfterExpansion(false)
, m_isVerticalOffset(fontDescription.isVerticalAnyUpright())
{
if (m_textRun.spacingDisabled())
return;
if (!m_letterSpacing && !m_wordSpacing && !m_expansion)
return;
m_hasSpacing = true;
if (!m_expansion)
return;
// Setup for justifications (expansions.)
m_textJustify = run.getTextJustify();
m_isAfterExpansion = !run.allowsLeadingExpansion();
bool isAfterExpansion = m_isAfterExpansion;
m_expansionOpportunityCount = Character::expansionOpportunityCount(run,
isAfterExpansion);
if (isAfterExpansion && !run.allowsTrailingExpansion()) {
ASSERT(m_expansionOpportunityCount > 0);
--m_expansionOpportunityCount;
}
if (m_expansionOpportunityCount)
m_expansionPerOpportunity = m_expansion / m_expansionOpportunityCount;
}
示例12: codePath
Font::CodePath Font::codePath(const TextRun& run) const
{
if (s_codePath != Auto)
return s_codePath;
#if ENABLE(SVG_FONTS)
if (run.renderingContext())
return Simple;
#endif
#if PLATFORM(QT) && !HAVE(QRAWFONT)
if (run.expansion() || run.rtl() || isSmallCaps() || wordSpacing() || letterSpacing())
return Complex;
#endif
if (m_fontDescription.featureSettings() && m_fontDescription.featureSettings()->size() > 0)
return Complex;
CodePath result = Simple;
// Start from 0 since drawing and highlighting also measure the characters before run->from
// FIXME: Should use a UnicodeSet in ports where ICU is used. Note that we
// can't simply use UnicodeCharacter Property/class because some characters
// are not 'combining', but still need to go to the complex path.
// Alternatively, we may as well consider binary search over a sorted
// list of ranges.
for (int i = 0; i < run.length(); i++) {
const UChar c = run[i];
if (c < 0x2E5) // U+02E5 through U+02E9 (Modifier Letters : Tone letters)
continue;
if (c <= 0x2E9)
return Complex;
if (c < 0x300) // U+0300 through U+036F Combining diacritical marks
continue;
if (c <= 0x36F)
return Complex;
if (c < 0x0591 || c == 0x05BE) // U+0591 through U+05CF excluding U+05BE Hebrew combining marks, Hebrew punctuation Paseq, Sof Pasuq and Nun Hafukha
continue;
if (c <= 0x05CF)
return Complex;
// U+0600 through U+109F Arabic, Syriac, Thaana, NKo, Samaritan, Mandaic,
// Devanagari, Bengali, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannada,
// Malayalam, Sinhala, Thai, Lao, Tibetan, Myanmar
if (c < 0x0600)
continue;
if (c <= 0x109F)
return Complex;
// U+1100 through U+11FF Hangul Jamo (only Ancient Korean should be left here if you precompose;
// Modern Korean will be precomposed as a result of step A)
if (c < 0x1100)
continue;
if (c <= 0x11FF)
return Complex;
if (c < 0x135D) // U+135D through U+135F Ethiopic combining marks
continue;
if (c <= 0x135F)
return Complex;
if (c < 0x1700) // U+1780 through U+18AF Tagalog, Hanunoo, Buhid, Taghanwa,Khmer, Mongolian
continue;
if (c <= 0x18AF)
return Complex;
if (c < 0x1900) // U+1900 through U+194F Limbu (Unicode 4.0)
continue;
if (c <= 0x194F)
return Complex;
if (c < 0x1980) // U+1980 through U+19DF New Tai Lue
continue;
if (c <= 0x19DF)
return Complex;
if (c < 0x1A00) // U+1A00 through U+1CFF Buginese, Tai Tham, Balinese, Batak, Lepcha, Vedic
continue;
if (c <= 0x1CFF)
return Complex;
if (c < 0x1DC0) // U+1DC0 through U+1DFF Comining diacritical mark supplement
continue;
if (c <= 0x1DFF)
return Complex;
// U+1E00 through U+2000 characters with diacritics and stacked diacritics
if (c <= 0x2000) {
result = SimpleWithGlyphOverflow;
continue;
}
if (c < 0x20D0) // U+20D0 through U+20FF Combining marks for symbols
continue;
if (c <= 0x20FF)
return Complex;
if (c < 0x2CEF) // U+2CEF through U+2CF1 Combining marks for Coptic
//.........这里部分代码省略.........
示例13: codePath
Font::CodePath Font::codePath(const TextRun& run) const
{
if (s_codePath != Auto)
return s_codePath;
#if PLATFORM(QT)
if (run.expansion() || run.rtl() || isSmallCaps() || wordSpacing() || letterSpacing())
return Complex;
#endif
CodePath result = Simple;
// Start from 0 since drawing and highlighting also measure the characters before run->from
for (int i = 0; i < run.length(); i++) {
const UChar c = run[i];
if (c < 0x300) // U+0300 through U+036F Combining diacritical marks
continue;
if (c <= 0x36F)
return Complex;
if (c < 0x0591 || c == 0x05BE) // U+0591 through U+05CF excluding U+05BE Hebrew combining marks, Hebrew punctuation Paseq, Sof Pasuq and Nun Hafukha
continue;
if (c <= 0x05CF)
return Complex;
if (c < 0x0600) // U+0600 through U+1059 Arabic, Syriac, Thaana, Devanagari, Bengali, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannada, Malayalam, Sinhala, Thai, Lao, Tibetan, Myanmar
continue;
if (c <= 0x1059)
return Complex;
if (c < 0x1100) // U+1100 through U+11FF Hangul Jamo (only Ancient Korean should be left here if you precompose; Modern Korean will be precomposed as a result of step A)
continue;
if (c <= 0x11FF)
return Complex;
if (c < 0x1780) // U+1780 through U+18AF Khmer, Mongolian
continue;
if (c <= 0x18AF)
return Complex;
if (c < 0x1900) // U+1900 through U+194F Limbu (Unicode 4.0)
continue;
if (c <= 0x194F)
return Complex;
if (c < 0x1E00) // U+1E00 through U+2000 characters with diacritics and stacked diacritics
continue;
if (c <= 0x2000) {
result = SimpleWithGlyphOverflow;
continue;
}
if (c < 0x20D0) // U+20D0 through U+20FF Combining marks for symbols
continue;
if (c <= 0x20FF)
return Complex;
if (c < 0xFE20) // U+FE20 through U+FE2F Combining half marks
continue;
if (c <= 0xFE2F)
return Complex;
}
#if ENABLE(SAMSUNG_WEBKIT_PERFORMANCE_PATCH)
// SAMSUNG CHANGE : Webkit Performance Patch Merge + r94303
if (run.length() > 1 && typesettingFeatures())
#else
if (typesettingFeatures())
// SAMSUNG CHANGE : Webkit Performance Patch Merge -
#endif
return Complex;
return result;
}
示例14: drawTextCommon
static void drawTextCommon(GraphicsContext* ctx, const TextRun& run, const FloatPoint& point, int from, int to, const QFont& font, bool isComplexText)
{
if (to < 0)
to = run.length();
QPainter *p = ctx->platformContext();
QPen textFillPen;
if (ctx->textDrawingMode() & TextModeFill)
textFillPen = fillPenForContext(ctx);
QPen textStrokePen;
if (ctx->textDrawingMode() & TextModeStroke)
textStrokePen = strokePenForContext(ctx);
String sanitized = Font::normalizeSpaces(run.characters(), run.length());
QString string = fromRawDataWithoutRef(sanitized);
QPointF pt(point.x(), point.y());
if (from > 0 || to < run.length()) {
if (isComplexText) {
QTextLayout layout(string, font);
QTextLine line = setupLayout(&layout, run);
float x1 = line.cursorToX(from);
float x2 = line.cursorToX(to);
if (x2 < x1)
qSwap(x1, x2);
QFontMetrics fm(font);
int ascent = fm.ascent();
QRectF boundingRect(point.x() + x1, point.y() - ascent, x2 - x1, fm.height());
QRectF clip = boundingRect;
ContextShadow* ctxShadow = ctx->contextShadow();
if (ctxShadow->m_type != ContextShadow::NoShadow) {
qreal dx1 = 0, dx2 = 0, dy1 = 0, dy2 = 0;
if (ctxShadow->offset().x() > 0)
dx2 = ctxShadow->offset().x();
else
dx1 = -ctxShadow->offset().x();
if (ctxShadow->offset().y() > 0)
dy2 = ctxShadow->offset().y();
else
dy1 = -ctxShadow->offset().y();
// expand the clip rect to include the text shadow as well
clip.adjust(dx1, dx2, dy1, dy2);
clip.adjust(-ctxShadow->m_blurDistance, -ctxShadow->m_blurDistance, ctxShadow->m_blurDistance, ctxShadow->m_blurDistance);
}
p->save();
p->setClipRect(clip.toRect(), Qt::IntersectClip);
pt.setY(pt.y() - ascent);
if (ctxShadow->m_type != ContextShadow::NoShadow) {
ContextShadow* ctxShadow = ctx->contextShadow();
if (!ctxShadow->mustUseContextShadow(ctx)) {
p->save();
p->setPen(ctxShadow->m_color);
p->translate(ctxShadow->offset());
line.draw(p, pt);
p->restore();
} else {
QPainter* shadowPainter = ctxShadow->beginShadowLayer(ctx, boundingRect);
if (shadowPainter) {
// Since it will be blurred anyway, we don't care about render hints.
shadowPainter->setFont(p->font());
shadowPainter->setPen(ctxShadow->m_color);
line.draw(shadowPainter, pt);
ctxShadow->endShadowLayer(ctx);
}
}
}
p->setPen(textFillPen);
line.draw(p, pt);
p->restore();
return;
}
int skipWidth = QFontMetrics(font).width(string, from, Qt::TextBypassShaping);
pt.setX(pt.x() + skipWidth);
string = fromRawDataWithoutRef(sanitized, from, to - from);
}
p->setFont(font);
int flags = run.rtl() ? Qt::TextForceRightToLeft : Qt::TextForceLeftToRight;
if (!isComplexText && !(ctx->textDrawingMode() & TextModeStroke))
flags |= Qt::TextBypassShaping;
QPainterPath textStrokePath;
if (ctx->textDrawingMode() & TextModeStroke)
textStrokePath.addText(pt, font, string);
ContextShadow* ctxShadow = ctx->contextShadow();
if (ctxShadow->m_type != ContextShadow::NoShadow) {
if (ctx->textDrawingMode() & TextModeFill) {
if (ctxShadow->m_type != ContextShadow::BlurShadow) {
p->save();
p->setPen(ctxShadow->m_color);
p->translate(ctxShadow->offset());
p->drawText(pt, string, flags, run.expansion());
//.........这里部分代码省略.........
示例15: generateComponents
static int generateComponents(TextRunComponents* components, const Font &font, const TextRun &run)
{
int letterSpacing = font.letterSpacing();
int wordSpacing = font.wordSpacing();
int padding = run.expansion();
int numSpaces = 0;
if (padding) {
for (int i = 0; i < run.length(); i++)
if (Font::treatAsSpace(run[i]))
++numSpaces;
}
int offset = 0;
if (letterSpacing) {
// need to draw every letter on it's own
int start = 0;
if (Font::treatAsSpace(run[0])) {
int add = 0;
if (numSpaces) {
add = padding/numSpaces;
padding -= add;
--numSpaces;
}
components->append(TextRunComponent(1, font, offset));
offset += add + letterSpacing + components->last().m_width;
start = 1;
}
for (int i = 1; i < run.length(); ++i) {
UChar ch = run[i];
if (U16_IS_LEAD(ch) && U16_IS_TRAIL(run[i-1]))
ch = U16_GET_SUPPLEMENTARY(ch, run[i-1]);
if (U16_IS_TRAIL(ch) || U_GET_GC_MASK(ch) & U_GC_MN_MASK)
continue;
if (Font::treatAsSpace(run[i])) {
int add = 0;
if (i - start > 0) {
components->append(TextRunComponent(run.characters16() + start, i - start,
run, font, offset));
offset += components->last().m_width + letterSpacing;
}
if (numSpaces) {
add = padding/numSpaces;
padding -= add;
--numSpaces;
}
components->append(TextRunComponent(1, font, offset));
offset += wordSpacing + add + components->last().m_width + letterSpacing;
start = i + 1;
continue;
}
if (i - start > 0) {
components->append(TextRunComponent(run.characters16() + start, i - start,
run,
font, offset));
offset += components->last().m_width + letterSpacing;
}
start = i;
}
if (run.length() - start > 0) {
components->append(TextRunComponent(run.characters16() + start, run.length() - start,
run,
font, offset));
offset += components->last().m_width;
}
offset += letterSpacing;
} else {
int start = 0;
for (int i = 0; i < run.length(); ++i) {
if (Font::treatAsSpace(run[i])) {
if (i - start > 0) {
components->append(TextRunComponent(run.characters16() + start, i - start,
run,
font, offset));
offset += components->last().m_width;
}
int add = 0;
if (numSpaces) {
add = padding/numSpaces;
padding -= add;
--numSpaces;
}
components->append(TextRunComponent(1, font, offset));
offset += add + components->last().m_width;
if (i)
offset += wordSpacing;
start = i + 1;
}
}
if (run.length() - start > 0) {
components->append(TextRunComponent(run.characters16() + start, run.length() - start,
run,
font, offset));
offset += components->last().m_width;
}
}
return offset;
}