X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali-toolkit%2Finternal%2Ftext%2Flayouts%2Flayout-engine.cpp;h=7bbf2cca4d54aa9bea9f8514622e1b63364681e3;hb=refs%2Fchanges%2F63%2F284863%2F3;hp=695d950a69e59f5e966f3f1e49e767b34728b129;hpb=b13abf6bf040c3af7b683c9d326d304bdb5f52cc;p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git diff --git a/dali-toolkit/internal/text/layouts/layout-engine.cpp b/dali-toolkit/internal/text/layouts/layout-engine.cpp index 695d950..7bbf2cc 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,12 +38,20 @@ namespace Toolkit { namespace Text { -float GetLineHeight(const LineRun lineRun) +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. - return lineRun.ascender - lineRun.descender + lineRun.lineSpacing; + // 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 @@ -50,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) { @@ -86,7 +97,8 @@ struct LineLayout glyphIndexInSecondHalfLine{0u}, characterIndexInSecondHalfLine{0u}, numberOfGlyphsInSecondHalfLine{0u}, - numberOfCharactersInSecondHalfLine{0u} + numberOfCharactersInSecondHalfLine{0u}, + relativeLineSize{1.0f} { } @@ -109,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. @@ -129,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 @@ -153,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; } /** @@ -185,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); } /** @@ -250,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. @@ -278,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); @@ -299,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); @@ -316,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; @@ -345,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) { @@ -405,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) { @@ -593,6 +667,7 @@ struct Engine::Impl * @param[out] lineLayout The line layout. * @param[in] completelyFill Whether to completely fill the line ( even if the last word exceeds the boundaries ). * @param[in] ellipsisPosition Where is the location the text elide + * @param[in] hiddenInputEnabled Whether the hidden input is enabled. */ void GetLineLayoutForBox(const Parameters& parameters, LayoutBidiParameters& bidiParameters, @@ -600,7 +675,8 @@ struct Engine::Impl bool completelyFill, DevelText::EllipsisPosition::Type ellipsisPosition, bool enforceEllipsisInSingleLine, - bool elideTextEnabled) + bool elideTextEnabled, + bool hiddenInputEnabled) { DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->GetLineLayoutForBox\n"); DALI_LOG_INFO(gLogFilter, Debug::Verbose, " initial glyph index : %d\n", lineLayout.glyphIndex); @@ -639,13 +715,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); @@ -660,6 +747,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); @@ -680,11 +769,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; @@ -736,10 +828,14 @@ struct Engine::Impl const float previousTmpLength = tmpLineLayout.length; const float previousTmpWhiteSpaceLengthEndOfLine = tmpLineLayout.whiteSpaceLengthEndOfLine; - if(isWhiteSpace) + // The calculated text size is used in atlas renderer. + // When the text is all white space, partial render issue occurs because the width is 0. + // To avoid issue, do not remove the white space size in hidden input mode. + if(isWhiteSpace && !hiddenInputEnabled) { // 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 { @@ -777,11 +873,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, @@ -813,7 +912,7 @@ struct Engine::Impl tmpLineLayout.numberOfGlyphs -= numberOfGLyphsInGroup; } - if(isRemovedGlyphWhiteSpace) + if(isRemovedGlyphWhiteSpace && !hiddenInputEnabled) { tmpLineLayout.penX -= glyphMetrics.advance; tmpLineLayout.length -= glyphMetrics.advance; @@ -1008,16 +1107,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) { @@ -1025,16 +1122,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); } } @@ -1043,11 +1138,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); @@ -1057,20 +1150,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) @@ -1079,20 +1166,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); @@ -1103,59 +1184,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); } /** @@ -1202,6 +1252,7 @@ struct Engine::Impl * @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 + * @param[in] isHiddenInputEnabled Whether the hidden input is enabled. * @param[in] ellipsisPosition Where is the location the text elide * * return Whether the line is ellipsized. @@ -1215,21 +1266,31 @@ struct Engine::Impl Length& numberOfLines, float penY, bool& isAutoScrollEnabled, + bool isAutoScrollMaxTextureExceeded, + bool isHiddenInputEnabled, 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. @@ -1256,7 +1317,8 @@ struct Engine::Impl true, ellipsisPosition, enforceEllipsisInSingleLine, - true); + true, + isHiddenInputEnabled); if(ellipsisPosition == DevelText::EllipsisPosition::START && !isMultiline) { @@ -1281,7 +1343,16 @@ struct Engine::Impl layoutSize.width = layoutParameters.boundingBox.width; if(layoutSize.height < Math::MACHINE_EPSILON_1000) { - layoutSize.height += GetLineHeight(*lineRun); + 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; @@ -1377,10 +1448,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) @@ -1388,7 +1456,7 @@ struct Engine::Impl layoutSize.width = lineRun.width; } - layoutSize.height += GetLineHeight(lineRun); + layoutSize.height += GetLineHeight(lineRun, isLastLine); } /** @@ -1434,12 +1502,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 += GetLineHeight(lineRun); + layoutSize.height += GetLineHeight(lineRun, true); } /** @@ -1456,14 +1525,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 += GetLineHeight(line); + layoutSize.height += GetLineHeight(line, isLastLine); } } @@ -1496,10 +1566,57 @@ 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, + bool isHiddenInputEnabled, DevelText::EllipsisPosition::Type ellipsisPosition) { DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->LayoutText\n"); @@ -1514,7 +1631,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) { @@ -1574,7 +1692,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; @@ -1678,13 +1796,18 @@ 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, false, ellipsisPosition, false, - elideTextEnabled); + elideTextEnabled, + isHiddenInputEnabled); DALI_LOG_INFO(gLogFilter, Debug::Verbose, " glyph index %d\n", layout.glyphIndex); DALI_LOG_INFO(gLogFilter, Debug::Verbose, " character index %d\n", layout.characterIndex); @@ -1692,6 +1815,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. @@ -1726,6 +1857,8 @@ struct Engine::Impl numberOfLines, penY, isAutoScrollEnabled, + isAutoScrollMaxTextureExceeded, + isHiddenInputEnabled, ellipsisPosition, false); } @@ -1744,6 +1877,8 @@ struct Engine::Impl numberOfLines, penY, isAutoScrollEnabled, + isAutoScrollMaxTextureExceeded, + isHiddenInputEnabled, ellipsisPosition, true); } @@ -1835,14 +1970,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; @@ -1867,7 +1995,6 @@ struct Engine::Impl linesBuffer[lineIndex].ellipsis = false; } numberOfLines--; - lineIndex++; } linesBuffer[0u].ellipsis = true; } @@ -2102,6 +2229,7 @@ struct Engine::Impl float mDefaultLineSize; IntrusivePtr mMetrics; + float mRelativeLineSize; }; Engine::Engine() @@ -2145,12 +2273,16 @@ bool Engine::LayoutText(Parameters& layoutParameters, Size& layoutSize, bool elideTextEnabled, bool& isAutoScrollEnabled, + bool isAutoScrollMaxTextureExceeded, + bool isHiddenInputEnabled, DevelText::EllipsisPosition::Type ellipsisPosition) { return mImpl->LayoutText(layoutParameters, layoutSize, elideTextEnabled, isAutoScrollEnabled, + isAutoScrollMaxTextureExceeded, + isHiddenInputEnabled, ellipsisPosition); } @@ -2193,6 +2325,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