X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=blobdiff_plain;f=dali-toolkit%2Finternal%2Ftext%2Flayouts%2Flayout-engine.cpp;h=39af47ce85a4a56eb4bfe19d9ae570306f919354;hp=b27f6349ca64ed687b15d30156f970c815874202;hb=c427acac5f2616578c05987c99e7b430c9ab0137;hpb=b0faad981257720e1a5fb15af45647f30b669adf diff --git a/dali-toolkit/internal/text/layouts/layout-engine.cpp b/dali-toolkit/internal/text/layouts/layout-engine.cpp index b27f634..39af47c 100644 --- a/dali-toolkit/internal/text/layouts/layout-engine.cpp +++ b/dali-toolkit/internal/text/layouts/layout-engine.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,7 +28,9 @@ #include #include #include +#include #include +#include namespace Dali { @@ -36,6 +38,20 @@ namespace Toolkit { namespace Text { +float GetLineHeight(const LineRun lineRun, bool isLastLine) +{ + // The line height is the addition of the line ascender, the line descender and the line spacing. + // However, the line descender has a negative value, hence the subtraction. + // In case this is the only/last line then line spacing should be ignored. + float lineHeight = lineRun.ascender - lineRun.descender; + + if(!isLastLine || lineRun.lineSpacing > 0) + { + lineHeight += lineRun.lineSpacing; + } + return lineHeight; +} + namespace Layout { namespace @@ -44,12 +60,13 @@ namespace Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_LAYOUT"); #endif -const float MAX_FLOAT = std::numeric_limits::max(); -const CharacterDirection LTR = false; -const CharacterDirection RTL = !LTR; -const float LINE_SPACING = 0.f; -const float MIN_LINE_SIZE = 0.f; -const Character HYPHEN_UNICODE = 0x002D; +const float MAX_FLOAT = std::numeric_limits::max(); +const CharacterDirection LTR = false; +const CharacterDirection RTL = !LTR; +const float LINE_SPACING = 0.f; +const float MIN_LINE_SIZE = 0.f; +const Character HYPHEN_UNICODE = 0x002D; +const float RELATIVE_LINE_SIZE = 1.f; inline bool isEmptyLineAtLast(const Vector& lines, const Vector::Iterator& line) { @@ -80,7 +97,8 @@ struct LineLayout glyphIndexInSecondHalfLine{0u}, characterIndexInSecondHalfLine{0u}, numberOfGlyphsInSecondHalfLine{0u}, - numberOfCharactersInSecondHalfLine{0u} + numberOfCharactersInSecondHalfLine{0u}, + relativeLineSize{1.0f} { } @@ -103,6 +121,7 @@ struct LineLayout characterIndexInSecondHalfLine = 0u; numberOfGlyphsInSecondHalfLine = 0u; numberOfCharactersInSecondHalfLine = 0u; + relativeLineSize = 1.0f; } GlyphIndex glyphIndex; ///< Index of the first glyph to be laid-out. @@ -123,6 +142,8 @@ struct LineLayout CharacterIndex characterIndexInSecondHalfLine; ///< Index of the first character to be laid-out for the second half of line. Length numberOfGlyphsInSecondHalfLine; ///< The number of glyph which fit in one line for the second half of line. Length numberOfCharactersInSecondHalfLine; ///< The number of characters which fit in one line for the second half of line. + + float relativeLineSize; ///< The relative line size to be applied for this line. }; struct LayoutBidiParameters @@ -147,8 +168,53 @@ struct Engine::Impl : mLayout{Layout::Engine::SINGLE_LINE_BOX}, mCursorWidth{0.f}, mDefaultLineSpacing{LINE_SPACING}, - mDefaultLineSize{MIN_LINE_SIZE} + mDefaultLineSize{MIN_LINE_SIZE}, + mRelativeLineSize{RELATIVE_LINE_SIZE} + { + } + + /** + * @brief get the line spacing. + * + * @param[in] textSize The text size. + * @param[in] relativeLineSize The relative line size to be applied. + * @return the line spacing value. + */ + float GetLineSpacing(float textSize, float relativeLineSize) { + float lineSpacing; + float relTextSize; + + // Sets the line size + lineSpacing = mDefaultLineSize - textSize; + lineSpacing = lineSpacing < 0.f ? 0.f : lineSpacing; + + // Add the line spacing + lineSpacing += mDefaultLineSpacing; + + //subtract line spcaing if relativeLineSize < 1 & larger than min height + relTextSize = textSize * relativeLineSize; + if(relTextSize > mDefaultLineSize) + { + if(relativeLineSize < 1) + { + //subtract the difference (always will be positive) + lineSpacing -= (textSize - relTextSize); + } + else + { + //reverse the addition in the top. + if(mDefaultLineSize > textSize) + { + lineSpacing -= mDefaultLineSize - textSize; + } + + //add difference instead + lineSpacing += relTextSize - textSize; + } + } + + return lineSpacing; } /** @@ -179,12 +245,7 @@ struct Engine::Impl // Sets the minimum descender. lineLayout.descender = std::min(lineLayout.descender, fontMetrics.descender); - // Sets the line size - lineLayout.lineSpacing = mDefaultLineSize - (lineLayout.ascender + -lineLayout.descender); - lineLayout.lineSpacing = lineLayout.lineSpacing < 0.f ? 0.f : lineLayout.lineSpacing; - - // Add the line spacing - lineLayout.lineSpacing += mDefaultLineSpacing; + lineLayout.lineSpacing = GetLineSpacing(lineLayout.ascender + -lineLayout.descender, lineLayout.relativeLineSize); } /** @@ -244,10 +305,16 @@ struct Engine::Impl const float outlineWidth = static_cast(parameters.textModel->GetOutlineWidth()); const GlyphIndex lastGlyphOfParagraphPlusOne = parameters.startGlyphIndex + parameters.numberOfGlyphs; + const float modelCharacterSpacing = parameters.textModel->mVisualModel->GetCharacterSpacing(); + + // Get the character-spacing runs. + const Vector& characterSpacingGlyphRuns = parameters.textModel->mVisualModel->GetCharacterSpacingGlyphRuns(); CharacterIndex characterLogicalIndex = 0u; CharacterIndex characterVisualIndex = 0u; + float calculatedAdvance = 0.f; + // If there are characters in the second half of Line then the first visual index mapped from visualToLogicalMapSecondHalf // Otherwise maps the first visual index from visualToLogicalMap. // This is to initialize the first visual index. @@ -272,7 +339,9 @@ struct Engine::Impl { const GlyphInfo& glyphInfo = *(glyphsBuffer + *(charactersToGlyphsBuffer + characterVisualIndex)); - whiteSpaceLengthEndOfLine += glyphInfo.advance; + const float characterSpacing = GetGlyphCharacterSpacing(characterVisualIndex, characterSpacingGlyphRuns, modelCharacterSpacing); + calculatedAdvance = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, glyphInfo.advance); + whiteSpaceLengthEndOfLine += calculatedAdvance; ++characterLogicalIndex; characterVisualIndex = bidirectionalLineInfo.characterRunForSecondHalfLine.characterIndex + *(bidirectionalLineInfo.visualToLogicalMapSecondHalf + characterLogicalIndex); @@ -293,7 +362,9 @@ struct Engine::Impl { const GlyphInfo& glyphInfo = *(glyphsBuffer + *(charactersToGlyphsBuffer + characterVisualIndex)); - whiteSpaceLengthEndOfLine += glyphInfo.advance; + const float characterSpacing = GetGlyphCharacterSpacing(characterVisualIndex, characterSpacingGlyphRuns, modelCharacterSpacing); + calculatedAdvance = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, glyphInfo.advance); + whiteSpaceLengthEndOfLine += calculatedAdvance; ++characterLogicalIndex; characterVisualIndex = bidirectionalLineInfo.characterRun.characterIndex + *(bidirectionalLineInfo.visualToLogicalMap + characterLogicalIndex); @@ -310,11 +381,14 @@ struct Engine::Impl charactersPerGlyphBuffer); GlyphMetrics glyphMetrics; + const float characterSpacing = GetGlyphCharacterSpacing(glyphIndex, characterSpacingGlyphRuns, modelCharacterSpacing); + calculatedAdvance = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, (*(glyphsBuffer + glyphIndex)).advance); GetGlyphsMetrics(glyphIndex, numberOfGLyphsInGroup, glyphMetrics, glyphsBuffer, - mMetrics); + mMetrics, + calculatedAdvance); float penX = -glyphMetrics.xBearing + mCursorWidth + outlineWidth; @@ -339,11 +413,14 @@ struct Engine::Impl characterLogicalIndex += *(charactersPerGlyphBuffer + glyphIndex + numberOfGLyphsInGroup - 1u); GlyphMetrics glyphMetrics; + const float characterSpacing = GetGlyphCharacterSpacing(glyphIndex, characterSpacingGlyphRuns, modelCharacterSpacing); + calculatedAdvance = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, (*(glyphsBuffer + glyphIndex)).advance); GetGlyphsMetrics(glyphIndex, numberOfGLyphsInGroup, glyphMetrics, glyphsBuffer, - mMetrics); + mMetrics, + calculatedAdvance); if(isWhiteSpace) { @@ -399,11 +476,14 @@ struct Engine::Impl characterLogicalIndex += *(charactersPerGlyphBuffer + glyphIndex + numberOfGLyphsInGroup - 1u); GlyphMetrics glyphMetrics; + const float characterSpacing = GetGlyphCharacterSpacing(glyphIndex, characterSpacingGlyphRuns, modelCharacterSpacing); + calculatedAdvance = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, (*(glyphsBuffer + glyphIndex)).advance); GetGlyphsMetrics(glyphIndex, numberOfGLyphsInGroup, glyphMetrics, glyphsBuffer, - mMetrics); + mMetrics, + calculatedAdvance); if(isWhiteSpace) { @@ -633,13 +713,24 @@ struct Engine::Impl float widthFirstHalf = ((ellipsisPosition != DevelText::EllipsisPosition::MIDDLE) ? targetWidth : targetWidth - std::floor(targetWidth / 2)); bool isSecondHalf = false; + // Character Spacing + const float modelCharacterSpacing = parameters.textModel->mVisualModel->GetCharacterSpacing(); + float calculatedAdvance = 0.f; + Vector& glyphToCharacterMap = parameters.textModel->mVisualModel->mGlyphsToCharacters; + const CharacterIndex* glyphToCharacterMapBuffer = glyphToCharacterMap.Begin(); + + // Get the character-spacing runs. + const Vector& characterSpacingGlyphRuns = parameters.textModel->mVisualModel->GetCharacterSpacingGlyphRuns(); GlyphMetrics glyphMetrics; + const float characterSpacing = GetGlyphCharacterSpacing(lineLayout.glyphIndex, characterSpacingGlyphRuns, modelCharacterSpacing); + calculatedAdvance = GetCalculatedAdvance(*(textBuffer + (*(glyphToCharacterMapBuffer + lineLayout.glyphIndex))), characterSpacing, (*(glyphsBuffer + lineLayout.glyphIndex)).advance); GetGlyphsMetrics(lineLayout.glyphIndex, numberOfGLyphsInGroup, glyphMetrics, glyphsBuffer, - mMetrics); + mMetrics, + calculatedAdvance); // Set the direction of the first character of the line. lineLayout.characterIndex = *(glyphsToCharactersBuffer + lineLayout.glyphIndex); @@ -654,6 +745,8 @@ struct Engine::Impl // It needs to add as well space for the cursor if the text is in edit mode and extra space in case the text is outlined. tmpLineLayout.penX = -glyphMetrics.xBearing + mCursorWidth + outlineWidth; + tmpLineLayout.relativeLineSize = lineLayout.relativeLineSize; + // Calculate the line height if there is no characters. FontId lastFontId = glyphMetrics.fontId; UpdateLineHeight(glyphMetrics, tmpLineLayout); @@ -674,11 +767,14 @@ struct Engine::Impl charactersPerGlyphBuffer); GlyphMetrics glyphMetrics; + const float characterSpacing = GetGlyphCharacterSpacing(glyphIndex, characterSpacingGlyphRuns, modelCharacterSpacing); + calculatedAdvance = GetCalculatedAdvance(*(textBuffer + (*(glyphToCharacterMapBuffer + glyphIndex))), characterSpacing, (*(glyphsBuffer + glyphIndex)).advance); GetGlyphsMetrics(glyphIndex, numberOfGLyphsInGroup, glyphMetrics, glyphsBuffer, - mMetrics); + mMetrics, + calculatedAdvance); const bool isLastGlyph = glyphIndex + numberOfGLyphsInGroup == totalNumberOfGlyphs; @@ -733,7 +829,8 @@ struct Engine::Impl if(isWhiteSpace) { // Add the length to the length of white spaces at the end of the line. - tmpLineLayout.whiteSpaceLengthEndOfLine += glyphMetrics.advance; // The advance is used as the width is always zero for the white spaces. + tmpLineLayout.whiteSpaceLengthEndOfLine += glyphMetrics.advance; + // The advance is used as the width is always zero for the white spaces. } else { @@ -771,11 +868,14 @@ struct Engine::Impl while(tmpLineLayout.length + tmpLineLayout.whiteSpaceLengthEndOfLine > targetWidth && glyphIndexToRemove < glyphIndex) { GlyphMetrics glyphMetrics; + const float characterSpacing = GetGlyphCharacterSpacing(glyphIndexToRemove, characterSpacingGlyphRuns, modelCharacterSpacing); + calculatedAdvance = GetCalculatedAdvance(*(textBuffer + (*(glyphToCharacterMapBuffer + glyphIndexToRemove))), characterSpacing, (*(glyphsBuffer + glyphIndexToRemove)).advance); GetGlyphsMetrics(glyphIndexToRemove, numberOfGLyphsInGroup, glyphMetrics, glyphsBuffer, - mMetrics); + mMetrics, + calculatedAdvance); const Length numberOfGLyphsInGroup = GetNumberOfGlyphsOfGroup(glyphIndexToRemove, lastGlyphOfParagraphPlusOne, @@ -1002,16 +1102,14 @@ struct Engine::Impl const GlyphInfo& glyph = *(glyphsBuffer + startIndexForGlyph); float penX = -glyph.xBearing + mCursorWidth + outlineWidth; // - for(GlyphIndex i = 0u; i < numberOfGlyphs; ++i) - { - const GlyphInfo& glyph = *(glyphsBuffer + startIndexForGlyph + i); - Vector2& position = *(glyphPositionsBuffer + startIndexForGlyphPositions + i); - - position.x = penX + glyph.xBearing; - position.y = -glyph.yBearing; - - penX += (glyph.advance + interGlyphExtraAdvance); - } + CalculateGlyphPositionsLTR(layoutParameters.textModel->mVisualModel, + layoutParameters.textModel->mLogicalModel, + interGlyphExtraAdvance, + numberOfGlyphs, + startIndexForGlyph, // startIndexForGlyph is the index of the first glyph in the line + startIndexForGlyphPositions, + glyphPositionsBuffer, + penX); if(layout.isSplitToTwoHalves) { @@ -1019,16 +1117,14 @@ struct Engine::Impl const Length numberOfGlyphsInSecondHalfLine = layout.numberOfGlyphsInSecondHalfLine; const GlyphIndex startIndexForGlyphPositionsnSecondHalf = layout.glyphIndexInSecondHalfLine - layoutParameters.startGlyphIndex; - for(GlyphIndex i = 0u; i < numberOfGlyphsInSecondHalfLine; ++i) - { - const GlyphInfo& glyph = *(glyphsBuffer + startIndexForGlyphInSecondHalf + i); - Vector2& position = *(glyphPositionsBuffer + startIndexForGlyphPositionsnSecondHalf + i); - - position.x = penX + glyph.xBearing; - position.y = -glyph.yBearing; - - penX += (glyph.advance + interGlyphExtraAdvance); - } + CalculateGlyphPositionsLTR(layoutParameters.textModel->mVisualModel, + layoutParameters.textModel->mLogicalModel, + interGlyphExtraAdvance, + numberOfGlyphsInSecondHalfLine, + startIndexForGlyphInSecondHalf, // startIndexForGlyph is the index of the first glyph in the line + startIndexForGlyphPositionsnSecondHalf, + glyphPositionsBuffer, + penX); } } @@ -1037,11 +1133,9 @@ struct Engine::Impl LayoutBidiParameters& layoutBidiParameters, const LineLayout& layout) { - const Character* const textBuffer = layoutParameters.textModel->mLogicalModel->mText.Begin(); const BidirectionalLineInfoRun& bidiLine = layoutParameters.textModel->mLogicalModel->mBidirectionalLineInfo[layoutBidiParameters.bidiLineIndex]; const GlyphInfo* const glyphsBuffer = layoutParameters.textModel->mVisualModel->mGlyphs.Begin(); const GlyphIndex* const charactersToGlyphsBuffer = layoutParameters.textModel->mVisualModel->mCharactersToGlyph.Begin(); - const Length* const glyphsPerCharacterBuffer = layoutParameters.textModel->mVisualModel->mGlyphsPerCharacter.Begin(); CharacterIndex characterLogicalIndex = 0u; CharacterIndex characterVisualIndex = bidiLine.characterRunForSecondHalfLine.characterIndex + *(bidiLine.visualToLogicalMapSecondHalf + characterLogicalIndex); @@ -1051,20 +1145,14 @@ struct Engine::Impl if(layout.isSplitToTwoHalves) { - while(TextAbstraction::IsWhiteSpace(*(textBuffer + characterVisualIndex))) - { - const GlyphIndex glyphIndex = *(charactersToGlyphsBuffer + characterVisualIndex); - const GlyphInfo& glyph = *(glyphsBuffer + glyphIndex); - - Vector2& position = *(glyphPositionsBuffer + glyphIndex - layoutParameters.startGlyphIndex); - position.x = penX; - position.y = -glyph.yBearing; - - penX += glyph.advance; - - ++characterLogicalIndex; - characterVisualIndex = bidiLine.characterRun.characterIndex + *(bidiLine.visualToLogicalMap + characterLogicalIndex); - } + CalculateGlyphPositionsRTL(layoutParameters.textModel->mVisualModel, + layoutParameters.textModel->mLogicalModel, + layoutBidiParameters.bidiLineIndex, + layoutParameters.startGlyphIndex, + glyphPositionsBuffer, + characterVisualIndex, + characterLogicalIndex, + penX); } if(characterLogicalIndex == bidiLine.characterRunForSecondHalfLine.numberOfCharacters) @@ -1073,20 +1161,14 @@ struct Engine::Impl characterLogicalIndex = 0u; characterVisualIndex = bidiLine.characterRun.characterIndex + *(bidiLine.visualToLogicalMap + characterLogicalIndex); - while(TextAbstraction::IsWhiteSpace(*(textBuffer + characterVisualIndex))) - { - const GlyphIndex glyphIndex = *(charactersToGlyphsBuffer + characterVisualIndex); - const GlyphInfo& glyph = *(glyphsBuffer + glyphIndex); - - Vector2& position = *(glyphPositionsBuffer + glyphIndex - layoutParameters.startGlyphIndex); - position.x = penX; - position.y = -glyph.yBearing; - - penX += glyph.advance; - - ++characterLogicalIndex; - characterVisualIndex = bidiLine.characterRun.characterIndex + *(bidiLine.visualToLogicalMap + characterLogicalIndex); - } + CalculateGlyphPositionsRTL(layoutParameters.textModel->mVisualModel, + layoutParameters.textModel->mLogicalModel, + layoutBidiParameters.bidiLineIndex, + layoutParameters.startGlyphIndex, + glyphPositionsBuffer, + characterVisualIndex, + characterLogicalIndex, + penX); } const GlyphIndex glyphIndex = *(charactersToGlyphsBuffer + characterVisualIndex); @@ -1097,59 +1179,28 @@ struct Engine::Impl // Traverses the characters of the right to left paragraph. if(layout.isSplitToTwoHalves && !extendedToSecondHalf) { - for(; characterLogicalIndex < bidiLine.characterRunForSecondHalfLine.numberOfCharacters; - ++characterLogicalIndex) - { - // Convert the character in the logical order into the character in the visual order. - const CharacterIndex characterVisualIndex = bidiLine.characterRunForSecondHalfLine.characterIndex + *(bidiLine.visualToLogicalMapSecondHalf + characterLogicalIndex); - - // Get the number of glyphs of the character. - const Length numberOfGlyphs = *(glyphsPerCharacterBuffer + characterVisualIndex); - - for(GlyphIndex index = 0u; index < numberOfGlyphs; ++index) - { - // Convert the character in the visual order into the glyph in the visual order. - const GlyphIndex glyphIndex = *(charactersToGlyphsBuffer + characterVisualIndex) + index; - - DALI_ASSERT_DEBUG(glyphIndex < layoutParameters.textModel->mVisualModel->mGlyphs.Count()); - - const GlyphInfo& glyph = *(glyphsBuffer + glyphIndex); - Vector2& position = *(glyphPositionsBuffer + glyphIndex - layoutParameters.startGlyphIndex); - - position.x = penX + glyph.xBearing; - position.y = -glyph.yBearing; - - penX += (glyph.advance + layoutParameters.interGlyphExtraAdvance); - } - } + TraversesCharactersForGlyphPositionsRTL(layoutParameters.textModel->mVisualModel, + layoutParameters.textModel->mLogicalModel->mText.Begin(), + layoutParameters.startGlyphIndex, + layoutParameters.interGlyphExtraAdvance, + bidiLine.characterRunForSecondHalfLine, + bidiLine.visualToLogicalMapSecondHalf, + glyphPositionsBuffer, + characterLogicalIndex, + penX); } characterLogicalIndex = extendedToSecondHalf ? characterLogicalIndex : 0u; - for(; characterLogicalIndex < bidiLine.characterRun.numberOfCharacters; - ++characterLogicalIndex) - { - // Convert the character in the logical order into the character in the visual order. - const CharacterIndex characterVisualIndex = bidiLine.characterRun.characterIndex + *(bidiLine.visualToLogicalMap + characterLogicalIndex); - - // Get the number of glyphs of the character. - const Length numberOfGlyphs = *(glyphsPerCharacterBuffer + characterVisualIndex); - - for(GlyphIndex index = 0u; index < numberOfGlyphs; ++index) - { - // Convert the character in the visual order into the glyph in the visual order. - const GlyphIndex glyphIndex = *(charactersToGlyphsBuffer + characterVisualIndex) + index; - DALI_ASSERT_DEBUG(glyphIndex < layoutParameters.textModel->mVisualModel->mGlyphs.Count()); - - const GlyphInfo& glyph = *(glyphsBuffer + glyphIndex); - Vector2& position = *(glyphPositionsBuffer + glyphIndex - layoutParameters.startGlyphIndex); - - position.x = penX + glyph.xBearing; - position.y = -glyph.yBearing; - - penX += (glyph.advance + layoutParameters.interGlyphExtraAdvance); - } - } + TraversesCharactersForGlyphPositionsRTL(layoutParameters.textModel->mVisualModel, + layoutParameters.textModel->mLogicalModel->mText.Begin(), + layoutParameters.startGlyphIndex, + layoutParameters.interGlyphExtraAdvance, + bidiLine.characterRun, + bidiLine.visualToLogicalMap, + glyphPositionsBuffer, + characterLogicalIndex, + penX); } /** @@ -1209,21 +1260,30 @@ struct Engine::Impl Length& numberOfLines, float penY, bool& isAutoScrollEnabled, + bool isAutoScrollMaxTextureExceeded, DevelText::EllipsisPosition::Type ellipsisPosition, bool enforceEllipsisInSingleLine) { - const bool ellipsis = enforceEllipsisInSingleLine || (isAutoScrollEnabled ? (penY - layout.descender > layoutParameters.boundingBox.height) : ((penY - layout.descender > layoutParameters.boundingBox.height) || ((mLayout == SINGLE_LINE_BOX) && (layout.length > layoutParameters.boundingBox.width)))); + const bool ellipsis = enforceEllipsisInSingleLine || (isAutoScrollEnabled ? isAutoScrollMaxTextureExceeded : ((penY - layout.descender > layoutParameters.boundingBox.height) || ((mLayout == SINGLE_LINE_BOX) && (layout.length > layoutParameters.boundingBox.width)))); const bool isMultiline = !enforceEllipsisInSingleLine && (mLayout == MULTI_LINE_BOX); if(ellipsis && (ellipsisPosition == DevelText::EllipsisPosition::END || !isMultiline)) { - isAutoScrollEnabled = false; - // Do not layout more lines if ellipsis is enabled. + if(penY - layout.descender > layoutParameters.boundingBox.height) + { + // Even if auto scroll is enabled and text is bigger than max texture size, + // if the the height is small, auto scroll should not work. + isAutoScrollEnabled = false; + } + // Do not layout more lines if ellipsis is enabled. // The last line needs to be completely filled with characters. // Part of a word may be used. LineRun* lineRun = nullptr; LineLayout ellipsisLayout; + + ellipsisLayout.relativeLineSize = layout.relativeLineSize; + if(0u != numberOfLines) { // Get the last line and layout it again with the 'completelyFill' flag to true. @@ -1275,7 +1335,16 @@ struct Engine::Impl layoutSize.width = layoutParameters.boundingBox.width; if(layoutSize.height < Math::MACHINE_EPSILON_1000) { - layoutSize.height += (lineRun->ascender + -lineRun->descender) + lineRun->lineSpacing; + layoutSize.height += GetLineHeight(*lineRun, true); + } + else + { + //when we apply ellipsis, the last line should not take negative linespacing into account for layoutSize.height calculation + //usually we don't includ it in normal cases using GetLineHeight() + if(lineRun->lineSpacing < 0) + { + layoutSize.height -= lineRun->lineSpacing; + } } const Vector& bidirectionalLinesInfo = layoutParameters.textModel->mLogicalModel->mBidirectionalLineInfo; @@ -1371,10 +1440,7 @@ struct Engine::Impl lineRun.direction = layout.direction; lineRun.ellipsis = false; - lineRun.lineSpacing = mDefaultLineSize - (lineRun.ascender + -lineRun.descender); - lineRun.lineSpacing = lineRun.lineSpacing < 0.f ? 0.f : lineRun.lineSpacing; - - lineRun.lineSpacing += mDefaultLineSpacing; + lineRun.lineSpacing = GetLineSpacing(lineRun.ascender + -lineRun.descender, layout.relativeLineSize); // Update the actual size. if(lineRun.width > layoutSize.width) @@ -1382,7 +1448,7 @@ struct Engine::Impl layoutSize.width = lineRun.width; } - layoutSize.height += (lineRun.ascender + -lineRun.descender) + lineRun.lineSpacing; + layoutSize.height += GetLineHeight(lineRun, isLastLine); } /** @@ -1428,12 +1494,13 @@ struct Engine::Impl lineRun.direction = LTR; lineRun.ellipsis = false; - lineRun.lineSpacing = mDefaultLineSize - (lineRun.ascender + -lineRun.descender); - lineRun.lineSpacing = lineRun.lineSpacing < 0.f ? 0.f : lineRun.lineSpacing; + BoundedParagraphRun currentParagraphRun; + LineLayout tempLineLayout; + (GetBoundedParagraph(layoutParameters.textModel->GetBoundedParagraphRuns(), characterIndex, currentParagraphRun) ? SetRelativeLineSize(¤tParagraphRun, tempLineLayout) : SetRelativeLineSize(nullptr, tempLineLayout)); - lineRun.lineSpacing += mDefaultLineSpacing; + lineRun.lineSpacing = GetLineSpacing(lineRun.ascender + -lineRun.descender, tempLineLayout.relativeLineSize); - layoutSize.height += (lineRun.ascender + -lineRun.descender) + lineRun.lineSpacing; + layoutSize.height += GetLineHeight(lineRun, true); } /** @@ -1450,14 +1517,15 @@ struct Engine::Impl it != endIt; ++it) { - const LineRun& line = *it; + const LineRun& line = *it; + bool isLastLine = (it + 1 == endIt); if(line.width > layoutSize.width) { layoutSize.width = line.width; } - layoutSize.height += (line.ascender + -line.descender) + line.lineSpacing; + layoutSize.height += GetLineHeight(line, isLastLine); } } @@ -1490,10 +1558,56 @@ struct Engine::Impl } } + /** + * @brief Sets the relative line size for the LineLayout + * + * @param[in] currentParagraphRun Contains the bounded paragraph for this line layout. + * @param[in,out] lineLayout The line layout to be updated. + */ + void SetRelativeLineSize(BoundedParagraphRun* currentParagraphRun, LineLayout& lineLayout) + { + lineLayout.relativeLineSize = mRelativeLineSize; + + if(currentParagraphRun != nullptr && currentParagraphRun->relativeLineSizeDefined) + { + lineLayout.relativeLineSize = currentParagraphRun->relativeLineSize; + } + } + + /** + * @brief Get the bounded paragraph for the characterIndex if exists. + * + * @param[in] boundedParagraphRuns The bounded paragraph list to search in. + * @param[in] characterIndex The character index to get bounded paragraph for. + * @param[out] currentParagraphRun Contains the bounded paragraph if found for the characterIndex. + * + * @return returns true if a bounded paragraph was found. + */ + bool GetBoundedParagraph(const Vector boundedParagraphRuns, CharacterIndex characterIndex, BoundedParagraphRun& currentParagraphRun) + { + for(Vector::Iterator it = boundedParagraphRuns.Begin(), + endIt = boundedParagraphRuns.End(); + it != endIt; + ++it) + { + BoundedParagraphRun& tempParagraphRun = *it; + + if(characterIndex >= tempParagraphRun.characterRun.characterIndex && + characterIndex < (tempParagraphRun.characterRun.characterIndex + tempParagraphRun.characterRun.numberOfCharacters)) + { + currentParagraphRun = tempParagraphRun; + return true; + } + } + + return false; + } + bool LayoutText(Parameters& layoutParameters, Size& layoutSize, bool elideTextEnabled, bool& isAutoScrollEnabled, + bool isAutoScrollMaxTextureExceeded, DevelText::EllipsisPosition::Type ellipsisPosition) { DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->LayoutText\n"); @@ -1508,7 +1622,8 @@ struct Engine::Impl layoutParameters.textModel->mVisualModel->SetFirstMiddleIndexOfElidedGlyphs(0u); layoutParameters.textModel->mVisualModel->SetSecondMiddleIndexOfElidedGlyphs(0u); - Vector& lines = layoutParameters.textModel->mVisualModel->mLines; + Vector& lines = layoutParameters.textModel->mVisualModel->mLines; + const Vector& boundedParagraphRuns = layoutParameters.textModel->GetBoundedParagraphRuns(); if(0u == layoutParameters.numberOfGlyphs) { @@ -1568,7 +1683,7 @@ struct Engine::Impl // Retrieve BiDi info. const bool hasBidiParagraphs = !layoutParameters.textModel->mLogicalModel->mBidirectionalParagraphInfo.Empty(); - const CharacterIndex* const glyphsToCharactersBuffer = hasBidiParagraphs ? layoutParameters.textModel->mVisualModel->mGlyphsToCharacters.Begin() : nullptr; + const CharacterIndex* const glyphsToCharactersBuffer = layoutParameters.textModel->mVisualModel->mGlyphsToCharacters.Begin(); const Vector& bidirectionalParagraphsInfo = layoutParameters.textModel->mLogicalModel->mBidirectionalParagraphInfo; const Vector& bidirectionalLinesInfo = layoutParameters.textModel->mLogicalModel->mBidirectionalLineInfo; @@ -1672,6 +1787,10 @@ struct Engine::Impl LineLayout layout; layout.direction = layoutBidiParameters.paragraphDirection; layout.glyphIndex = index; + + BoundedParagraphRun currentParagraphRun; + (GetBoundedParagraph(boundedParagraphRuns, *(glyphsToCharactersBuffer + index), currentParagraphRun) ? SetRelativeLineSize(¤tParagraphRun, layout) : SetRelativeLineSize(nullptr, layout)); + GetLineLayoutForBox(layoutParameters, layoutBidiParameters, layout, @@ -1686,6 +1805,14 @@ struct Engine::Impl DALI_LOG_INFO(gLogFilter, Debug::Verbose, " number of characters %d\n", layout.numberOfCharacters); DALI_LOG_INFO(gLogFilter, Debug::Verbose, " length %f\n", layout.length); + CharacterIndex lastCharacterInParagraph = currentParagraphRun.characterRun.characterIndex + currentParagraphRun.characterRun.numberOfCharacters - 1; + + //check if this is the last line in paragraph, if false we should use the default relative line size (the one set using the property) + if(lastCharacterInParagraph >= layout.characterIndex && lastCharacterInParagraph < layout.characterIndex + layout.numberOfCharacters) + { + layout.relativeLineSize = mRelativeLineSize; + } + if(0u == layout.numberOfGlyphs + layout.numberOfGlyphsInSecondHalfLine) { // The width is too small and no characters are laid-out. @@ -1720,6 +1847,7 @@ struct Engine::Impl numberOfLines, penY, isAutoScrollEnabled, + isAutoScrollMaxTextureExceeded, ellipsisPosition, false); } @@ -1738,6 +1866,7 @@ struct Engine::Impl numberOfLines, penY, isAutoScrollEnabled, + isAutoScrollMaxTextureExceeded, ellipsisPosition, true); } @@ -1829,14 +1958,7 @@ struct Engine::Impl } // Updates the vertical pen's position. - penY += -layout.descender + layout.lineSpacing + mDefaultLineSpacing; - // If there is a defaultLineSize, updates the pen's position. - if(mDefaultLineSize > 0.f) - { - float lineSpacing = mDefaultLineSize - (layout.ascender + -layout.descender); - lineSpacing = lineSpacing < 0.f ? 0.f : lineSpacing; - penY += lineSpacing; - } + penY += -layout.descender + layout.lineSpacing + GetLineSpacing(layout.ascender + -layout.descender, layout.relativeLineSize); // Increase the glyph index. index = nextIndex; @@ -1861,7 +1983,6 @@ struct Engine::Impl linesBuffer[lineIndex].ellipsis = false; } numberOfLines--; - lineIndex++; } linesBuffer[0u].ellipsis = true; } @@ -2096,6 +2217,7 @@ struct Engine::Impl float mDefaultLineSize; IntrusivePtr mMetrics; + float mRelativeLineSize; }; Engine::Engine() @@ -2139,12 +2261,14 @@ bool Engine::LayoutText(Parameters& layoutParameters, Size& layoutSize, bool elideTextEnabled, bool& isAutoScrollEnabled, + bool isAutoScrollMaxTextureExceeded, DevelText::EllipsisPosition::Type ellipsisPosition) { return mImpl->LayoutText(layoutParameters, layoutSize, elideTextEnabled, isAutoScrollEnabled, + isAutoScrollMaxTextureExceeded, ellipsisPosition); } @@ -2187,6 +2311,16 @@ float Engine::GetDefaultLineSize() const return mImpl->mDefaultLineSize; } +void Engine::SetRelativeLineSize(float relativeLineSize) +{ + mImpl->mRelativeLineSize = relativeLineSize; +} + +float Engine::GetRelativeLineSize() const +{ + return mImpl->mRelativeLineSize; +} + } // namespace Layout } // namespace Text