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=8c8ea9424cfd7b9a418562c89ca5b526ce0d8e19;hb=c427acac5f2616578c05987c99e7b430c9ab0137;hpb=a4a06c5a4c6c02861972d1ea9029c64d60bed192 diff --git a/dali-toolkit/internal/text/layouts/layout-engine.cpp b/dali-toolkit/internal/text/layouts/layout-engine.cpp index 8c8ea94..39af47c 100644 --- a/dali-toolkit/internal/text/layouts/layout-engine.cpp +++ b/dali-toolkit/internal/text/layouts/layout-engine.cpp @@ -30,6 +30,7 @@ #include #include #include +#include namespace Dali { @@ -37,11 +38,18 @@ 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 @@ -89,7 +97,8 @@ struct LineLayout glyphIndexInSecondHalfLine{0u}, characterIndexInSecondHalfLine{0u}, numberOfGlyphsInSecondHalfLine{0u}, - numberOfCharactersInSecondHalfLine{0u} + numberOfCharactersInSecondHalfLine{0u}, + relativeLineSize{1.0f} { } @@ -112,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. @@ -132,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 @@ -165,9 +177,10 @@ struct Engine::Impl * @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 GetLineSpacing(float textSize, float relativeLineSize) { float lineSpacing; float relTextSize; @@ -180,10 +193,10 @@ struct Engine::Impl lineSpacing += mDefaultLineSpacing; //subtract line spcaing if relativeLineSize < 1 & larger than min height - relTextSize = textSize * mRelativeLineSize; + relTextSize = textSize * relativeLineSize; if(relTextSize > mDefaultLineSize) { - if(mRelativeLineSize < 1) + if(relativeLineSize < 1) { //subtract the difference (always will be positive) lineSpacing -= (textSize - relTextSize); @@ -232,7 +245,7 @@ struct Engine::Impl // Sets the minimum descender. lineLayout.descender = std::min(lineLayout.descender, fontMetrics.descender); - lineLayout.lineSpacing = GetLineSpacing(lineLayout.ascender + -lineLayout.descender); + lineLayout.lineSpacing = GetLineSpacing(lineLayout.ascender + -lineLayout.descender, lineLayout.relativeLineSize); } /** @@ -292,7 +305,10 @@ struct Engine::Impl const float outlineWidth = static_cast(parameters.textModel->GetOutlineWidth()); const GlyphIndex lastGlyphOfParagraphPlusOne = parameters.startGlyphIndex + parameters.numberOfGlyphs; - const float characterSpacing = parameters.textModel->mVisualModel->GetCharacterSpacing(); + 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; @@ -323,7 +339,8 @@ struct Engine::Impl { const GlyphInfo& glyphInfo = *(glyphsBuffer + *(charactersToGlyphsBuffer + characterVisualIndex)); - calculatedAdvance = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, glyphInfo.advance); + const float characterSpacing = GetGlyphCharacterSpacing(characterVisualIndex, characterSpacingGlyphRuns, modelCharacterSpacing); + calculatedAdvance = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, glyphInfo.advance); whiteSpaceLengthEndOfLine += calculatedAdvance; ++characterLogicalIndex; @@ -345,7 +362,8 @@ struct Engine::Impl { const GlyphInfo& glyphInfo = *(glyphsBuffer + *(charactersToGlyphsBuffer + characterVisualIndex)); - calculatedAdvance = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, glyphInfo.advance); + const float characterSpacing = GetGlyphCharacterSpacing(characterVisualIndex, characterSpacingGlyphRuns, modelCharacterSpacing); + calculatedAdvance = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, glyphInfo.advance); whiteSpaceLengthEndOfLine += calculatedAdvance; ++characterLogicalIndex; @@ -363,7 +381,8 @@ struct Engine::Impl charactersPerGlyphBuffer); GlyphMetrics glyphMetrics; - calculatedAdvance = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, (*(glyphsBuffer + glyphIndex)).advance); + const float characterSpacing = GetGlyphCharacterSpacing(glyphIndex, characterSpacingGlyphRuns, modelCharacterSpacing); + calculatedAdvance = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, (*(glyphsBuffer + glyphIndex)).advance); GetGlyphsMetrics(glyphIndex, numberOfGLyphsInGroup, glyphMetrics, @@ -394,7 +413,8 @@ struct Engine::Impl characterLogicalIndex += *(charactersPerGlyphBuffer + glyphIndex + numberOfGLyphsInGroup - 1u); GlyphMetrics glyphMetrics; - calculatedAdvance = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, (*(glyphsBuffer + glyphIndex)).advance); + const float characterSpacing = GetGlyphCharacterSpacing(glyphIndex, characterSpacingGlyphRuns, modelCharacterSpacing); + calculatedAdvance = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, (*(glyphsBuffer + glyphIndex)).advance); GetGlyphsMetrics(glyphIndex, numberOfGLyphsInGroup, glyphMetrics, @@ -456,7 +476,8 @@ struct Engine::Impl characterLogicalIndex += *(charactersPerGlyphBuffer + glyphIndex + numberOfGLyphsInGroup - 1u); GlyphMetrics glyphMetrics; - calculatedAdvance = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, (*(glyphsBuffer + glyphIndex)).advance); + const float characterSpacing = GetGlyphCharacterSpacing(glyphIndex, characterSpacingGlyphRuns, modelCharacterSpacing); + calculatedAdvance = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, (*(glyphsBuffer + glyphIndex)).advance); GetGlyphsMetrics(glyphIndex, numberOfGLyphsInGroup, glyphMetrics, @@ -693,13 +714,17 @@ struct Engine::Impl bool isSecondHalf = false; // Character Spacing - const float characterSpacing = parameters.textModel->mVisualModel->GetCharacterSpacing(); + 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; - calculatedAdvance = GetCalculatedAdvance(*(textBuffer + (*(glyphToCharacterMapBuffer + lineLayout.glyphIndex))), characterSpacing, (*(glyphsBuffer + lineLayout.glyphIndex)).advance); + const float characterSpacing = GetGlyphCharacterSpacing(lineLayout.glyphIndex, characterSpacingGlyphRuns, modelCharacterSpacing); + calculatedAdvance = GetCalculatedAdvance(*(textBuffer + (*(glyphToCharacterMapBuffer + lineLayout.glyphIndex))), characterSpacing, (*(glyphsBuffer + lineLayout.glyphIndex)).advance); GetGlyphsMetrics(lineLayout.glyphIndex, numberOfGLyphsInGroup, glyphMetrics, @@ -720,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); @@ -740,7 +767,8 @@ struct Engine::Impl charactersPerGlyphBuffer); GlyphMetrics glyphMetrics; - calculatedAdvance = GetCalculatedAdvance(*(textBuffer + (*(glyphToCharacterMapBuffer + glyphIndex))), characterSpacing, (*(glyphsBuffer + glyphIndex)).advance); + const float characterSpacing = GetGlyphCharacterSpacing(glyphIndex, characterSpacingGlyphRuns, modelCharacterSpacing); + calculatedAdvance = GetCalculatedAdvance(*(textBuffer + (*(glyphToCharacterMapBuffer + glyphIndex))), characterSpacing, (*(glyphsBuffer + glyphIndex)).advance); GetGlyphsMetrics(glyphIndex, numberOfGLyphsInGroup, glyphMetrics, @@ -840,7 +868,8 @@ struct Engine::Impl while(tmpLineLayout.length + tmpLineLayout.whiteSpaceLengthEndOfLine > targetWidth && glyphIndexToRemove < glyphIndex) { GlyphMetrics glyphMetrics; - calculatedAdvance = GetCalculatedAdvance(*(textBuffer + (*(glyphToCharacterMapBuffer + glyphIndexToRemove))), characterSpacing, (*(glyphsBuffer + glyphIndexToRemove)).advance); + const float characterSpacing = GetGlyphCharacterSpacing(glyphIndexToRemove, characterSpacingGlyphRuns, modelCharacterSpacing); + calculatedAdvance = GetCalculatedAdvance(*(textBuffer + (*(glyphToCharacterMapBuffer + glyphIndexToRemove))), characterSpacing, (*(glyphsBuffer + glyphIndexToRemove)).advance); GetGlyphsMetrics(glyphIndexToRemove, numberOfGLyphsInGroup, glyphMetrics, @@ -1231,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. @@ -1297,7 +1335,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; @@ -1393,7 +1440,7 @@ struct Engine::Impl lineRun.direction = layout.direction; lineRun.ellipsis = false; - lineRun.lineSpacing = GetLineSpacing(lineRun.ascender + -lineRun.descender); + lineRun.lineSpacing = GetLineSpacing(lineRun.ascender + -lineRun.descender, layout.relativeLineSize); // Update the actual size. if(lineRun.width > layoutSize.width) @@ -1401,7 +1448,7 @@ struct Engine::Impl layoutSize.width = lineRun.width; } - layoutSize.height += GetLineHeight(lineRun); + layoutSize.height += GetLineHeight(lineRun, isLastLine); } /** @@ -1447,9 +1494,13 @@ struct Engine::Impl lineRun.direction = LTR; lineRun.ellipsis = false; - lineRun.lineSpacing = GetLineSpacing(lineRun.ascender + -lineRun.descender); + BoundedParagraphRun currentParagraphRun; + LineLayout tempLineLayout; + (GetBoundedParagraph(layoutParameters.textModel->GetBoundedParagraphRuns(), characterIndex, currentParagraphRun) ? SetRelativeLineSize(¤tParagraphRun, tempLineLayout) : SetRelativeLineSize(nullptr, tempLineLayout)); + + lineRun.lineSpacing = GetLineSpacing(lineRun.ascender + -lineRun.descender, tempLineLayout.relativeLineSize); - layoutSize.height += GetLineHeight(lineRun); + layoutSize.height += GetLineHeight(lineRun, true); } /** @@ -1466,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 += GetLineHeight(line); + layoutSize.height += GetLineHeight(line, isLastLine); } } @@ -1506,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"); @@ -1524,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) { @@ -1584,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; @@ -1688,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, @@ -1702,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. @@ -1736,6 +1847,7 @@ struct Engine::Impl numberOfLines, penY, isAutoScrollEnabled, + isAutoScrollMaxTextureExceeded, ellipsisPosition, false); } @@ -1754,6 +1866,7 @@ struct Engine::Impl numberOfLines, penY, isAutoScrollEnabled, + isAutoScrollMaxTextureExceeded, ellipsisPosition, true); } @@ -1845,7 +1958,7 @@ struct Engine::Impl } // Updates the vertical pen's position. - penY += -layout.descender + layout.lineSpacing + GetLineSpacing(layout.ascender + -layout.descender); + penY += -layout.descender + layout.lineSpacing + GetLineSpacing(layout.ascender + -layout.descender, layout.relativeLineSize); // Increase the glyph index. index = nextIndex; @@ -2148,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); }