extraWidth( 0.f ),
wsLengthEndOfLine( 0.f ),
ascender( 0.f ),
- descender( MAX_FLOAT )
+ descender( MAX_FLOAT ),
+ lineSpacing( 0.f )
{}
~LineLayout()
float wsLengthEndOfLine; ///< The length of the white spaces at the end of the line.
float ascender; ///< The maximum ascender of all fonts in the line.
float descender; ///< The minimum descender of all fonts in the line.
+ float lineSpacing; ///< The line spacing
};
struct Engine::Impl
Impl()
: mLayout( Layout::Engine::SINGLE_LINE_BOX ),
mCursorWidth( CURSOR_WIDTH ),
- mDefaultLineSpacing( LINE_SPACING )
+ mDefaultLineSpacing( LINE_SPACING ),
+ mPreviousCharacterExtraWidth( 0.0f )
{
}
{
lineLayout.descender = fontMetrics.descender;
}
+
+ // set the line spacing
+ lineLayout.lineSpacing = mDefaultLineSpacing;
}
/**
// Get the line break info for the current character.
const LineBreakInfo lineBreakInfo = hasCharacters ? *( parameters.lineBreakInfoBuffer + characterLastIndex ) : TextAbstraction::LINE_NO_BREAK;
- // Get the word break info for the current character.
- const WordBreakInfo wordBreakInfo = *( parameters.wordBreakInfoBuffer + characterLastIndex );
-
// Increase the number of characters.
tmpLineLayout.numberOfCharacters += charactersPerGlyph;
const float extraWidth = glyphMetrics.xBearing + glyphMetrics.width - glyphMetrics.advance;
tmpExtraWidth = ( 0.f < extraWidth ) ? extraWidth : 0.f;
+ tmpExtraWidth = std::max( mPreviousCharacterExtraWidth - glyphMetrics.advance, tmpExtraWidth );
}
}
else
const float extraWidth = glyphMetrics.xBearing + glyphMetrics.width - glyphMetrics.advance;
tmpExtraWidth = ( 0.f < extraWidth ) ? extraWidth : 0.f;
+ tmpExtraWidth = std::max( mPreviousCharacterExtraWidth - glyphMetrics.advance, tmpExtraWidth );
}
else // LTR
{
const float extraWidth = glyphMetrics.xBearing + glyphMetrics.width - glyphMetrics.advance;
tmpExtraWidth = ( 0.f < extraWidth ) ? extraWidth : 0.f;
+ tmpExtraWidth = std::max( mPreviousCharacterExtraWidth - glyphMetrics.advance, tmpExtraWidth );
}
}
}
tmpLineLayout.wsLengthEndOfLine = 0.f;
}
+ // If calculation is end but wsLengthEndOfLine is exist, it means end of text is space.
+ // Merge remained length.
+ if ( !parameters.ignoreSpaceAfterText && glyphIndex == lastGlyphOfParagraphPlusOne-1 && tmpLineLayout.wsLengthEndOfLine > 0 )
+ {
+ tmpLineLayout.length += tmpLineLayout.wsLengthEndOfLine;
+ tmpLineLayout.wsLengthEndOfLine = 0u;
+ }
+
+ // Save the current extra width to compare with the next one
+ mPreviousCharacterExtraWidth = tmpExtraWidth;
+
// Check if the accumulated length fits in the width of the box.
- if( ( completelyFill || isMultiline ) && !isWhiteSpace &&
+ if( ( completelyFill || isMultiline ) && !(parameters.ignoreSpaceAfterText && isWhiteSpace) &&
( tmpExtraBearing + lineLayout.length + lineLayout.wsLengthEndOfLine + tmpLineLayout.length + tmpExtraWidth > parameters.boundingBox.width ) )
{
// Current word does not fit in the box's width.
}
if( isMultiline &&
- ( TextAbstraction::WORD_BREAK == wordBreakInfo ) )
+ ( TextAbstraction::LINE_ALLOW_BREAK == lineBreakInfo ) )
{
oneWordLaidOut = isWordLaidOut;
DALI_LOG_INFO( gLogFilter, Debug::Verbose, " One word laid-out\n" );
* @param[in,out] numberOfLines The number of laid-out lines.
* @param[in] penY The vertical layout position.
* @param[in] currentParagraphDirection The current paragraph's direction.
+ * @param[in,out] isAutoScrollEnabled If the isAutoScrollEnabled is true and the height of the text exceeds the boundaries of the control the text is elided and the isAutoScrollEnabled is set to false to disable the autoscroll
*
* return Whether the line is ellipsized.
*/
Vector2* glyphPositionsBuffer,
Length& numberOfLines,
float penY,
- CharacterDirection currentParagraphDirection )
+ CharacterDirection currentParagraphDirection,
+ bool& isAutoScrollEnabled )
{
- const bool ellipsis = ( ( penY - layout.descender > layoutParameters.boundingBox.height ) ||
- ( ( mLayout == SINGLE_LINE_BOX ) &&
- ( layout.extraBearing + layout.length + layout.extraWidth > layoutParameters.boundingBox.width ) ) );
+ const bool ellipsis = isAutoScrollEnabled ? ( penY - layout.descender > layoutParameters.boundingBox.height ) :
+ ( ( penY - layout.descender > layoutParameters.boundingBox.height ) ||
+ ( ( mLayout == SINGLE_LINE_BOX ) &&
+ ( layout.extraBearing + layout.length + layout.extraWidth > layoutParameters.boundingBox.width ) ) );
if( ellipsis )
{
+ isAutoScrollEnabled = false;
// Do not layout more lines if ellipsis is enabled.
// The last line needs to be completely filled with characters.
// Get the last line and layout it again with the 'completelyFill' flag to true.
lineRun = linesBuffer + ( numberOfLines - 1u );
- penY -= layout.ascender - lineRun->descender;
+ penY -= layout.ascender - lineRun->descender + lineRun->lineSpacing;
ellipsisLayout.glyphIndex = lineRun->glyphRun.glyphIndex;
}
layoutSize.width = layoutParameters.boundingBox.width;
if( layoutSize.height < Math::MACHINE_EPSILON_1000 )
{
- layoutSize.height += ( lineRun->ascender + -lineRun->descender );
+ layoutSize.height += ( lineRun->ascender + -lineRun->descender ) + lineRun->lineSpacing;
}
SetGlyphPositions( layoutParameters.glyphsBuffer + lineRun->glyphRun.glyphIndex,
lineRun.glyphRun.numberOfGlyphs = layout.numberOfGlyphs;
lineRun.characterRun.characterIndex = layout.characterIndex;
lineRun.characterRun.numberOfCharacters = layout.numberOfCharacters;
+ lineRun.lineSpacing = mDefaultLineSpacing;
+
if( isLastLine && !layoutParameters.isLastNewParagraph )
{
const float width = layout.extraBearing + layout.length + layout.extraWidth + layout.wsLengthEndOfLine;
layoutSize.width = lineRun.width;
}
- layoutSize.height += ( lineRun.ascender + -lineRun.descender );
+ layoutSize.height += ( lineRun.ascender + -lineRun.descender ) + lineRun.lineSpacing;
}
/**
lineRun.alignmentOffset = 0.f;
lineRun.direction = !RTL;
lineRun.ellipsis = false;
+ lineRun.lineSpacing = mDefaultLineSpacing;
- layoutSize.height += ( lineRun.ascender + -lineRun.descender );
+ layoutSize.height += ( lineRun.ascender + -lineRun.descender ) + lineRun.lineSpacing;
}
/**
layoutSize.width = line.width;
}
- layoutSize.height += ( line.ascender + -line.descender );
+ layoutSize.height += ( line.ascender + -line.descender ) + line.lineSpacing;
}
}
Vector<Vector2>& glyphPositions,
Vector<LineRun>& lines,
Size& layoutSize,
- bool elideTextEnabled )
+ bool elideTextEnabled,
+ bool& isAutoScrollEnabled )
{
DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->LayoutText\n" );
DALI_LOG_INFO( gLogFilter, Debug::Verbose, " box size %f, %f\n", layoutParameters.boundingBox.width, layoutParameters.boundingBox.height );
glyphPositionsBuffer,
numberOfLines,
penY,
- currentParagraphDirection );
+ currentParagraphDirection,
+ isAutoScrollEnabled );
}
if( ellipsis )
glyphPositionsBuffer + index - layoutParameters.startGlyphIndex );
// Updates the vertical pen's position.
- penY += -layout.descender;
+ penY += -layout.descender + layout.lineSpacing + mDefaultLineSpacing;
// Increase the glyph index.
index = nextIndex;
Length numberOfCharacters,
Text::HorizontalAlignment::Type horizontalAlignment,
Vector<LineRun>& lines,
- float& alignmentOffset )
+ float& alignmentOffset,
+ Dali::LayoutDirection::Type layoutDirection,
+ bool matchSystemLanguageDirection )
{
const CharacterIndex lastCharacterPlusOne = startIndex + numberOfCharacters;
// the box width, line length, and the paragraph's direction.
CalculateHorizontalAlignment( size.width,
horizontalAlignment,
- line );
+ line,
+ layoutDirection,
+ matchSystemLanguageDirection );
// Updates the alignment offset.
alignmentOffset = std::min( alignmentOffset, line.alignmentOffset );
void CalculateHorizontalAlignment( float boxWidth,
HorizontalAlignment::Type horizontalAlignment,
- LineRun& line )
+ LineRun& line,
+ Dali::LayoutDirection::Type layoutDirection,
+ bool matchSystemLanguageDirection )
{
line.alignmentOffset = 0.f;
- const bool isRTL = RTL == line.direction;
+ const bool isLineRTL = RTL == line.direction;
+ // Whether to swap the alignment.
+ // Swap if the line is RTL and is not required to match the direction of the system's language or if it's required to match the direction of the system's language and it's RTL.
+ bool isLayoutRTL = isLineRTL;
float lineLength = line.width;
- HorizontalAlignment::Type alignment = horizontalAlignment;
- if( isRTL )
+ // match align for system language direction
+ if( matchSystemLanguageDirection )
{
// Swap the alignment type if the line is right to left.
- switch( alignment )
- {
- case HorizontalAlignment::BEGIN:
- {
- alignment = HorizontalAlignment::END;
- break;
- }
- case HorizontalAlignment::CENTER:
- {
- // Nothing to do.
- break;
- }
- case HorizontalAlignment::END:
- {
- alignment = HorizontalAlignment::BEGIN;
- break;
- }
- }
+ isLayoutRTL = layoutDirection == LayoutDirection::RIGHT_TO_LEFT;
}
-
// Calculate the horizontal line offset.
- switch( alignment )
+ switch( horizontalAlignment )
{
case HorizontalAlignment::BEGIN:
{
- line.alignmentOffset = 0.f;
+ if( isLayoutRTL )
+ {
+ if( isLineRTL )
+ {
+ lineLength += line.extraLength;
+ }
- if( isRTL )
+ line.alignmentOffset = boxWidth - lineLength;
+ }
+ else
{
- // 'Remove' the white spaces at the end of the line (which are at the beginning in visual order)
- line.alignmentOffset -= line.extraLength;
+ line.alignmentOffset = 0.f;
+
+ if( isLineRTL )
+ {
+ // 'Remove' the white spaces at the end of the line (which are at the beginning in visual order)
+ line.alignmentOffset -= line.extraLength;
+ }
}
break;
}
{
line.alignmentOffset = 0.5f * ( boxWidth - lineLength );
- if( isRTL )
+ if( isLineRTL )
{
line.alignmentOffset -= line.extraLength;
}
}
case HorizontalAlignment::END:
{
- if( isRTL )
+ if( isLayoutRTL )
{
- lineLength += line.extraLength;
+ line.alignmentOffset = 0.f;
+
+ if( isLineRTL )
+ {
+ // 'Remove' the white spaces at the end of the line (which are at the beginning in visual order)
+ line.alignmentOffset -= line.extraLength;
+ }
}
+ else
+ {
+ if( isLineRTL )
+ {
+ lineLength += line.extraLength;
+ }
- line.alignmentOffset = boxWidth - lineLength;
+ line.alignmentOffset = boxWidth - lineLength;
+ }
break;
}
}
line.alignmentOffset = 0.f;
line.direction = !RTL;
line.ellipsis = false;
+ line.lineSpacing = mDefaultLineSpacing;
}
Type mLayout;
float mCursorWidth;
float mDefaultLineSpacing;
+ float mPreviousCharacterExtraWidth;
IntrusivePtr<Metrics> mMetrics;
};
Vector<Vector2>& glyphPositions,
Vector<LineRun>& lines,
Size& layoutSize,
- bool elideTextEnabled )
+ bool elideTextEnabled,
+ bool& isAutoScrollEnabled )
{
return mImpl->LayoutText( layoutParameters,
glyphPositions,
lines,
layoutSize,
- elideTextEnabled );
+ elideTextEnabled,
+ isAutoScrollEnabled );
}
void Engine::ReLayoutRightToLeftLines( const Parameters& layoutParameters,
Length numberOfCharacters,
Text::HorizontalAlignment::Type horizontalAlignment,
Vector<LineRun>& lines,
- float& alignmentOffset )
+ float& alignmentOffset,
+ Dali::LayoutDirection::Type layoutDirection,
+ bool matchSystemLanguageDirection )
{
mImpl->Align( size,
startIndex,
numberOfCharacters,
horizontalAlignment,
lines,
- alignmentOffset );
+ alignmentOffset,
+ layoutDirection,
+ matchSystemLanguageDirection );
}
void Engine::SetDefaultLineSpacing( float lineSpacing )