X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=blobdiff_plain;f=dali-toolkit%2Finternal%2Ftext%2Frendering%2Fview-model.cpp;h=0c4aeb3e00c4fcf38e7b6cf9e9e7b7de263c25ca;hp=4ad0b14d60f3c3ca6553f2e6e7aafb3be9c06b9f;hb=HEAD;hpb=1bf8666355ccc3b6ca6dde1cf4be9f0bc6e35875 diff --git a/dali-toolkit/internal/text/rendering/view-model.cpp b/dali-toolkit/internal/text/rendering/view-model.cpp index 4ad0b14..3799fc9 100644 --- a/dali-toolkit/internal/text/rendering/view-model.cpp +++ b/dali-toolkit/internal/text/rendering/view-model.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2023 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. @@ -23,6 +23,7 @@ #include // INTERNAL INCLUDES +#include #include namespace Dali @@ -35,7 +36,11 @@ ViewModel::ViewModel(const ModelInterface* const model) : mModel(model), mElidedGlyphs(), mElidedLayout(), - mIsTextElided(false) + mIsTextElided(false), + mStartIndexOfElidedGlyphs(0u), + mEndIndexOfElidedGlyphs(0u), + mFirstMiddleIndexOfElidedGlyphs(0u), + mSecondMiddleIndexOfElidedGlyphs(0u) { } @@ -73,6 +78,11 @@ DevelText::VerticalLineAlignment::Type ViewModel::GetVerticalLineAlignment() con return mModel->GetVerticalLineAlignment(); } +DevelText::EllipsisPosition::Type ViewModel::GetEllipsisPosition() const +{ + return mModel->GetEllipsisPosition(); +} + bool ViewModel::IsTextElideEnabled() const { return mModel->IsTextElideEnabled(); @@ -83,7 +93,7 @@ Length ViewModel::GetNumberOfLines() const return mModel->GetNumberOfLines(); } -const LineRun* const ViewModel::GetLines() const +const LineRun* ViewModel::GetLines() const { return mModel->GetLines(); } @@ -93,11 +103,16 @@ Length ViewModel::GetNumberOfScripts() const return mModel->GetNumberOfScripts(); } -const ScriptRun* const ViewModel::GetScriptRuns() const +const ScriptRun* ViewModel::GetScriptRuns() const { return mModel->GetScriptRuns(); } +Length ViewModel::GetNumberOfCharacters() const +{ + return mModel->GetNumberOfCharacters(); +} + Length ViewModel::GetNumberOfGlyphs() const { if(mIsTextElided && mModel->IsTextElideEnabled()) @@ -112,7 +127,47 @@ Length ViewModel::GetNumberOfGlyphs() const return 0u; } -const GlyphInfo* const ViewModel::GetGlyphs() const +GlyphIndex ViewModel::GetStartIndexOfElidedGlyphs() const +{ + if(mIsTextElided && mModel->IsTextElideEnabled()) + { + return mStartIndexOfElidedGlyphs; + } + + return mModel->GetStartIndexOfElidedGlyphs(); +} + +GlyphIndex ViewModel::GetEndIndexOfElidedGlyphs() const +{ + if(mIsTextElided && mModel->IsTextElideEnabled()) + { + return mEndIndexOfElidedGlyphs; + } + + return mModel->GetEndIndexOfElidedGlyphs(); +} + +GlyphIndex ViewModel::GetFirstMiddleIndexOfElidedGlyphs() const +{ + if(mIsTextElided && mModel->IsTextElideEnabled()) + { + return mFirstMiddleIndexOfElidedGlyphs; + } + + return mModel->GetFirstMiddleIndexOfElidedGlyphs(); +} + +GlyphIndex ViewModel::GetSecondMiddleIndexOfElidedGlyphs() const +{ + if(mIsTextElided && mModel->IsTextElideEnabled()) + { + return mSecondMiddleIndexOfElidedGlyphs; + } + + return mModel->GetSecondMiddleIndexOfElidedGlyphs(); +} + +const GlyphInfo* ViewModel::GetGlyphs() const { if(mIsTextElided && mModel->IsTextElideEnabled()) { @@ -126,7 +181,7 @@ const GlyphInfo* const ViewModel::GetGlyphs() const return NULL; } -const Vector2* const ViewModel::GetLayout() const +const Vector2* ViewModel::GetLayout() const { if(mIsTextElided && mModel->IsTextElideEnabled()) { @@ -140,27 +195,27 @@ const Vector2* const ViewModel::GetLayout() const return NULL; } -const Vector4* const ViewModel::GetColors() const +const Vector4* ViewModel::GetColors() const { return mModel->GetColors(); } -const ColorIndex* const ViewModel::GetColorIndices() const +const ColorIndex* ViewModel::GetColorIndices() const { return mModel->GetColorIndices(); } -const Vector4* const ViewModel::GetBackgroundColors() const +const Vector4* ViewModel::GetBackgroundColors() const { return mModel->GetBackgroundColors(); } -const ColorIndex* const ViewModel::GetBackgroundColorIndices() const +const ColorIndex* ViewModel::GetBackgroundColorIndices() const { return mModel->GetBackgroundColorIndices(); } -bool const ViewModel::IsMarkupBackgroundColorSet() const +bool ViewModel::IsMarkupBackgroundColorSet() const { return mModel->IsMarkupBackgroundColorSet(); } @@ -195,17 +250,37 @@ bool ViewModel::IsUnderlineEnabled() const return mModel->IsUnderlineEnabled(); } +bool ViewModel::IsMarkupUnderlineSet() const +{ + return mModel->IsMarkupUnderlineSet(); +} + float ViewModel::GetUnderlineHeight() const { return mModel->GetUnderlineHeight(); } +Text::Underline::Type ViewModel::GetUnderlineType() const +{ + return mModel->GetUnderlineType(); +} + +float ViewModel::GetDashedUnderlineWidth() const +{ + return mModel->GetDashedUnderlineWidth(); +} + +float ViewModel::GetDashedUnderlineGap() const +{ + return mModel->GetDashedUnderlineGap(); +} + Length ViewModel::GetNumberOfUnderlineRuns() const { return mModel->GetNumberOfUnderlineRuns(); } -void ViewModel::GetUnderlineRuns(GlyphRun* underlineRuns, UnderlineRunIndex index, Length numberOfRuns) const +void ViewModel::GetUnderlineRuns(UnderlinedGlyphRun* underlineRuns, UnderlineRunIndex index, Length numberOfRuns) const { mModel->GetUnderlineRuns(underlineRuns, index, numberOfRuns); } @@ -235,6 +310,11 @@ bool ViewModel::IsMarkupProcessorEnabled() const return mModel->IsMarkupProcessorEnabled(); } +bool ViewModel::IsSpannedTextPlaced() const +{ + return mModel->IsSpannedTextPlaced(); +} + const GlyphInfo* ViewModel::GetHyphens() const { return mModel->GetHyphens(); @@ -250,164 +330,435 @@ Length ViewModel::GetHyphensCount() const return mModel->GetHyphensCount(); } +float ViewModel::GetCharacterSpacing() const +{ + return mModel->GetCharacterSpacing(); +} + +const Character* ViewModel::GetTextBuffer() const +{ + return mModel->GetTextBuffer(); +} + +const Vector& ViewModel::GetGlyphsToCharacters() const +{ + return mModel->GetGlyphsToCharacters(); +} + void ViewModel::ElideGlyphs() { - mIsTextElided = false; + mIsTextElided = false; + mStartIndexOfElidedGlyphs = mFirstMiddleIndexOfElidedGlyphs = mSecondMiddleIndexOfElidedGlyphs = 0; + mEndIndexOfElidedGlyphs = mModel->GetNumberOfGlyphs() - 1u; + + auto ellipsisPosition = GetEllipsisPosition(); + auto characterSpacing = GetCharacterSpacing(); + const Character* textBuffer = GetTextBuffer(); + const Vector& glyphToCharacterMap = GetGlyphsToCharacters(); + const CharacterIndex* glyphToCharacterMapBuffer = glyphToCharacterMap.Begin(); + float calculatedAdvance = 0.f; - if(mModel->IsTextElideEnabled()) + if(IsTextElideEnabled()) { const Length numberOfLines = mModel->GetNumberOfLines(); if(0u != numberOfLines) { const LineRun* const lines = mModel->GetLines(); - const LineRun& lastLine = *(lines + (numberOfLines - 1u)); - const Length numberOfLaidOutGlyphs = lastLine.glyphRun.glyphIndex + lastLine.glyphRun.numberOfGlyphs; + //Get line of ellipsis + const LineRun* ellipsisLine = nullptr; + const LineRun* ellipsisNextLine = nullptr; + + for(Length lineIndex = 0; lineIndex < numberOfLines; lineIndex++) + { + const LineRun* line = (lines + lineIndex); + if(line->ellipsis) + { + ellipsisLine = line; + if(lineIndex < numberOfLines - 1u) + { + ellipsisNextLine = (lines + lineIndex + 1u); + } + break; + } + } - if(lastLine.ellipsis && (0u != numberOfLaidOutGlyphs)) + // Check if there is a line contains Ellipsis. + // Then find total number of glyphs and total number of laid out glyphs. + // Check where to set Ellipsis glyph in line. + // Determine index of Ellipsis glyph and how many glyphs should be replaced by Ellipsis glyph, according to width of Ellipsis glyph. + if(ellipsisLine != nullptr) { - mIsTextElided = true; - TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get(); + // Total number of glyphs. + const Length numberOfGlyphs = mModel->GetNumberOfGlyphs(); + // Total number of laid out glyphs. + Length numberOfActualLaidOutGlyphs = 0u; - const GlyphInfo* const glyphs = mModel->GetGlyphs(); - const Vector2* const positions = mModel->GetLayout(); + // Accumulate laid out glyphs for each line to find total number of laid out glyphs. + for(Length lineIndex = 0u; lineIndex < numberOfLines; lineIndex++) + { + numberOfActualLaidOutGlyphs += lines[lineIndex].glyphRun.numberOfGlyphs + lines[lineIndex].glyphRunSecondHalf.numberOfGlyphs; + } - // Copy the glyphs to be elided. - mElidedGlyphs.Resize(numberOfLaidOutGlyphs); - mElidedLayout.Resize(numberOfLaidOutGlyphs); + // Make sure there are laid out glyphs. + if(0u != numberOfActualLaidOutGlyphs) + { + // There are elided glyphs. + mIsTextElided = true; + TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get(); - GlyphInfo* elidedGlyphsBuffer = mElidedGlyphs.Begin(); - Vector2* elidedPositionsBuffer = mElidedLayout.Begin(); + // Retrieve the whole glyphs and their positions. + const GlyphInfo* const glyphs = mModel->GetGlyphs(); + const Vector2* const positions = mModel->GetLayout(); - memcpy(elidedGlyphsBuffer, glyphs, numberOfLaidOutGlyphs * sizeof(GlyphInfo)); - memcpy(elidedPositionsBuffer, positions, numberOfLaidOutGlyphs * sizeof(Vector2)); + // Copy the glyphs to be elided. + mElidedGlyphs.Resize(numberOfGlyphs); + mElidedLayout.Resize(numberOfGlyphs); + GlyphInfo* elidedGlyphsBuffer = mElidedGlyphs.Begin(); + Vector2* elidedPositionsBuffer = mElidedLayout.Begin(); - const Size& controlSize = mModel->GetControlSize(); + memcpy(elidedGlyphsBuffer, glyphs, numberOfGlyphs * sizeof(GlyphInfo)); + memcpy(elidedPositionsBuffer, positions, numberOfGlyphs * sizeof(Vector2)); - if((1u == numberOfLines) && - (lastLine.ascender - lastLine.descender > controlSize.height)) - { - // Get the first glyph which is going to be replaced and the ellipsis glyph. - GlyphInfo& glyphToRemove = *elidedGlyphsBuffer; - const GlyphInfo& ellipsisGlyph = fontClient.GetEllipsisGlyph(fontClient.GetPointSize(glyphToRemove.fontId)); + const Size& controlSize = mModel->GetControlSize(); - // Change the 'x' and 'y' position of the ellipsis glyph. - Vector2& position = *elidedPositionsBuffer; + // Set index where to set Ellipsis according to the selected position of Ellipsis. + // Start with this index to replace its glyph by Ellipsis, if the width is not enough, then remove more glyphs. + GlyphIndex startIndexOfEllipsis = 0u; + if(ellipsisPosition == DevelText::EllipsisPosition::START) + { + // It's the fisrt glyph in line. + startIndexOfEllipsis = ellipsisLine->glyphRun.glyphIndex; + } + else if(ellipsisPosition == DevelText::EllipsisPosition::MIDDLE) + { + // It's the second middle of the line in case the line split to two halves. + // Otherwise it's It's the last glyph in line (line before all removed lines). + startIndexOfEllipsis = ellipsisLine->isSplitToTwoHalves ? (ellipsisLine->glyphRunSecondHalf.glyphIndex) : (ellipsisLine->glyphRun.glyphIndex + ellipsisLine->glyphRun.numberOfGlyphs - 1u); + } + else // DevelText::EllipsisPosition::END + { + // It's the last glyph in line. + startIndexOfEllipsis = ellipsisLine->glyphRun.glyphIndex + ellipsisLine->glyphRun.numberOfGlyphs - 1u; + } - position.x = ellipsisGlyph.xBearing; - position.y = -lastLine.ascender + controlSize.height - ellipsisGlyph.yBearing; + // When the hight is not enough then show one glyph and that should be the first laid out glyph. + if((1u == numberOfLines) && + (ellipsisLine->ascender - ellipsisLine->descender > controlSize.height)) + { + // Replace the first glyph with ellipsis glyph + auto indexOfFirstGlyph = (ellipsisPosition == DevelText::EllipsisPosition::START) ? startIndexOfEllipsis : 0u; - // Replace the glyph by the ellipsis glyph and resize the buffers. - glyphToRemove = ellipsisGlyph; + // Regardless where the location of ellipsis,in-case the hight of line is greater than control's height + // then replace the first glyph with ellipsis glyph. - mElidedGlyphs.Resize(1u); - mElidedLayout.Resize(1u); + // Get the first glyph which is going to be replaced and the ellipsis glyph. + GlyphInfo& glyphToRemove = *(elidedGlyphsBuffer + indexOfFirstGlyph); + const GlyphInfo& ellipsisGlyph = fontClient.GetEllipsisGlyph(fontClient.GetPointSize(glyphToRemove.fontId)); - return; - } + // Change the 'x' and 'y' position of the ellipsis glyph. + Vector2& position = *(elidedPositionsBuffer + indexOfFirstGlyph); - // firstPenX, penY and firstPenSet are used to position the ellipsis glyph if needed. - float firstPenX = 0.f; // Used if rtl text is elided. - float penY = 0.f; - bool firstPenSet = false; + position.x = ellipsisGlyph.xBearing; + position.y = -ellipsisLine->ascender + controlSize.height - ellipsisGlyph.yBearing; - // Add the ellipsis glyph. - bool inserted = false; - float removedGlypsWidth = 0.f; - Length numberOfRemovedGlyphs = 0u; - GlyphIndex index = numberOfLaidOutGlyphs - 1u; + // Replace the glyph by the ellipsis glyph and resize the buffers. + glyphToRemove = ellipsisGlyph; - // The ellipsis glyph has to fit in the place where the last glyph(s) is(are) removed. - while(!inserted) - { - const GlyphInfo& glyphToRemove = *(elidedGlyphsBuffer + index); + mElidedGlyphs.Resize(1u); + mElidedLayout.Resize(1u); - if(0u != glyphToRemove.fontId) - { - // i.e. The font id of the glyph shaped from the '\n' character is zero. + mEndIndexOfElidedGlyphs = mStartIndexOfElidedGlyphs = mFirstMiddleIndexOfElidedGlyphs = mSecondMiddleIndexOfElidedGlyphs = indexOfFirstGlyph; - // Need to reshape the glyph as the font may be different in size. - const GlyphInfo& ellipsisGlyph = fontClient.GetEllipsisGlyph(fontClient.GetPointSize(glyphToRemove.fontId)); + return; + } + + // firstPenX, penY and firstPenSet are used to position the ellipsis glyph if needed. + float firstPenX = 0.f; // Used if rtl text is elided. + float penY = 0.f; + bool firstPenSet = false; + + // Add the ellipsis glyph. + bool inserted = false; + float removedGlypsWidth = 0.f; + Length numberOfRemovedGlyphs = 0u; + GlyphIndex indexOfEllipsis = startIndexOfEllipsis; - if(!firstPenSet || EqualsZero(glyphToRemove.advance)) + // Tail Mode: start by the end of line. + bool isTailMode = (ellipsisPosition == DevelText::EllipsisPosition::END) || + (ellipsisPosition == DevelText::EllipsisPosition::MIDDLE && numberOfLines != 1u); + + // The ellipsis glyph has to fit in the place where the last glyph(s) is(are) removed. + while(!inserted) + { + const GlyphInfo& glyphToRemove = *(elidedGlyphsBuffer + indexOfEllipsis); + + if(0u != glyphToRemove.fontId) { - const Vector2& position = *(elidedPositionsBuffer + index); + // i.e. The font id of the glyph shaped from the '\n' character is zero. - // Calculates the penY of the current line. It will be used to position the ellipsis glyph. - penY = position.y + glyphToRemove.yBearing; + // Need to reshape the glyph as the font may be different in size. + const GlyphInfo& ellipsisGlyph = fontClient.GetEllipsisGlyph(fontClient.GetPointSize(glyphToRemove.fontId)); - // Calculates the first penX which will be used if rtl text is elided. - firstPenX = position.x - glyphToRemove.xBearing; - if(firstPenX < -ellipsisGlyph.xBearing) + if(!firstPenSet || EqualsZero(glyphToRemove.advance)) { - // Avoids to exceed the bounding box when rtl text is elided. - firstPenX = -ellipsisGlyph.xBearing; - } + const Vector2& position = *(elidedPositionsBuffer + indexOfEllipsis); - removedGlypsWidth = -ellipsisGlyph.xBearing; + // Calculates the penY of the current line. It will be used to position the ellipsis glyph. + penY = position.y + glyphToRemove.yBearing; + + // Calculates the first penX which will be used if rtl text is elided. + firstPenX = position.x - glyphToRemove.xBearing; + if(firstPenX < -ellipsisGlyph.xBearing) + { + // Avoids to exceed the bounding box when rtl text is elided. + firstPenX = -ellipsisGlyph.xBearing; + } + + removedGlypsWidth = -ellipsisGlyph.xBearing; - if(!EqualsZero(firstPenX)) - { firstPenSet = true; } - } - removedGlypsWidth += std::min(glyphToRemove.advance, (glyphToRemove.xBearing + glyphToRemove.width)); + calculatedAdvance = GetCalculatedAdvance(*(textBuffer + (*(glyphToCharacterMapBuffer + indexOfEllipsis))), characterSpacing, glyphToRemove.advance); + removedGlypsWidth += std::min(calculatedAdvance, (glyphToRemove.xBearing + glyphToRemove.width)); - // Calculate the width of the ellipsis glyph and check if it fits. - const float ellipsisGlyphWidth = ellipsisGlyph.width + ellipsisGlyph.xBearing; + // Calculate the width of the ellipsis glyph and check if it fits. + const float ellipsisGlyphWidth = ellipsisGlyph.width + ellipsisGlyph.xBearing; - // If it is the last glyph to remove, add the ellipsis glyph without checking its width. - if((ellipsisGlyphWidth < removedGlypsWidth) || (index == 0u)) - { - GlyphInfo& glyphInfo = *(elidedGlyphsBuffer + index); - Vector2& position = *(elidedPositionsBuffer + index); - position.x -= (0.f > glyphInfo.xBearing) ? glyphInfo.xBearing : 0.f; + // If it is the last glyph to remove, add the ellipsis glyph without checking its width. + if((ellipsisGlyphWidth < removedGlypsWidth) || (isTailMode ? (indexOfEllipsis == 0u) : (indexOfEllipsis == numberOfGlyphs - 1u))) + { + GlyphInfo& glyphInfo = *(elidedGlyphsBuffer + indexOfEllipsis); + Vector2& position = *(elidedPositionsBuffer + indexOfEllipsis); + position.x -= (0.f > glyphInfo.xBearing) ? glyphInfo.xBearing : 0.f; - // Replace the glyph by the ellipsis glyph. - glyphInfo = ellipsisGlyph; + // Replace the glyph by the ellipsis glyph. + glyphInfo = ellipsisGlyph; - // Change the 'x' and 'y' position of the ellipsis glyph. - if(position.x > firstPenX) - { - position.x = firstPenX; - if(ellipsisGlyphWidth < removedGlypsWidth) + // Change the 'x' and 'y' position of the ellipsis glyph. + if(position.x > firstPenX) { - position.x += removedGlypsWidth - ellipsisGlyphWidth; + if(isTailMode) + { + // To handle case of the mixed languages (LTR then RTL) with + // EllipsisPosition::END and the LayoutDirection::RIGHT_TO_LEFT + float nextXPositions = ellipsisLine->width; + if(indexOfEllipsis + 1u < numberOfGlyphs) + { + Vector2& positionOfNextGlyph = *(elidedPositionsBuffer + indexOfEllipsis + 1u); + nextXPositions = positionOfNextGlyph.x; + } + + if(position.x > nextXPositions) // RTL language + { + if((indexOfEllipsis > 0u) && ((position.x - nextXPositions) > removedGlypsWidth)) + { + // To handle mixed directions + // Re-calculates the first penX which will be used if rtl text is elided. + firstPenX = position.x - glyphToRemove.xBearing; + if(firstPenX < -ellipsisGlyph.xBearing) + { + // Avoids to exceed the bounding box when rtl text is elided. + firstPenX = -ellipsisGlyph.xBearing; + } + //Reset the width of removed glyphs + removedGlypsWidth = std::min(calculatedAdvance, (glyphToRemove.xBearing + glyphToRemove.width)) - ellipsisGlyph.xBearing; + + --indexOfEllipsis; + continue; + } + else + { + // To handle the case of RTL language with EllipsisPosition::END + position.x = firstPenX + removedGlypsWidth - ellipsisGlyphWidth; + } + } + } + else + { + // To handle the case of LTR language with EllipsisPosition::START + position.x = firstPenX + removedGlypsWidth - ellipsisGlyphWidth; + } + } + else + { + if(!isTailMode) + { + // To handle case of the mixed languages (RTL then LTR) with + // EllipsisPosition::START and the LayoutDirection::RIGHT_TO_LEFT + float nextXPositions = ellipsisLine->width; + if(indexOfEllipsis + 1u < numberOfGlyphs) + { + Vector2& positionOfNextGlyph = *(elidedPositionsBuffer + indexOfEllipsis + 1u); + nextXPositions = positionOfNextGlyph.x; + } + + if(position.x < nextXPositions) // LTR language + { + position.x = firstPenX + removedGlypsWidth - ellipsisGlyphWidth; + + if((position.x + ellipsisGlyphWidth + ellipsisGlyph.xBearing) > nextXPositions) + { + position.x -= (position.x + ellipsisGlyphWidth + ellipsisGlyph.xBearing) - nextXPositions; + } + } + } } - } - position.x += ellipsisGlyph.xBearing; - position.y = penY - ellipsisGlyph.yBearing; + position.x += ellipsisGlyph.xBearing; + position.y = penY - ellipsisGlyph.yBearing; - inserted = true; + inserted = true; + } } - } - if(!inserted) + if(!inserted) + { + if(!isTailMode && indexOfEllipsis < numberOfGlyphs - 1u) + { + // Tail Mode: remove glyphs from startIndexOfEllipsis then decrement indexOfEllipsis, until arrive to index zero. + ++indexOfEllipsis; + } + else if(isTailMode && indexOfEllipsis > 0u) + { + // Not Tail Mode: remove glyphs from startIndexOfEllipsis then increase indexOfEllipsis, until arrive to last index (numberOfGlyphs - 1u). + --indexOfEllipsis; + } + else + { + // No space for the ellipsis. + inserted = true; + } + ++numberOfRemovedGlyphs; + } + } // while( !inserted ) + + //Reduce size, shift glyphs and start from ellipsis glyph + Length numberOfElidedGlyphs = numberOfActualLaidOutGlyphs - numberOfRemovedGlyphs; + mElidedGlyphs.Resize(numberOfElidedGlyphs); + mElidedLayout.Resize(numberOfElidedGlyphs); + + if(ellipsisPosition == DevelText::EllipsisPosition::START) { - if(index > 0u) + // 'Shifts' glyphs after ellipsis glyph and 'Removes' before ellipsis glyph + memcpy(elidedGlyphsBuffer, elidedGlyphsBuffer + indexOfEllipsis, numberOfElidedGlyphs * sizeof(GlyphInfo)); + memcpy(elidedPositionsBuffer, elidedPositionsBuffer + indexOfEllipsis, numberOfElidedGlyphs * sizeof(Vector2)); + + mStartIndexOfElidedGlyphs = mFirstMiddleIndexOfElidedGlyphs = mSecondMiddleIndexOfElidedGlyphs = indexOfEllipsis; + } + else if(ellipsisPosition == DevelText::EllipsisPosition::MIDDLE) + { + // 'Shifts and connects' glyphs before and after ellipsis glyph and 'Removes' in-between. + bool isOnlySecondHalf = false; + + if(isTailMode) { - --index; + mFirstMiddleIndexOfElidedGlyphs = indexOfEllipsis; + if(ellipsisNextLine != nullptr) + { + mSecondMiddleIndexOfElidedGlyphs = ellipsisNextLine->glyphRun.glyphIndex; + } + else + { + mEndIndexOfElidedGlyphs = mSecondMiddleIndexOfElidedGlyphs = mFirstMiddleIndexOfElidedGlyphs; + } } else { - // No space for the ellipsis. - inserted = true; + mFirstMiddleIndexOfElidedGlyphs = (ellipsisLine->glyphRun.numberOfGlyphs > 0u) ? (ellipsisLine->glyphRun.glyphIndex + ellipsisLine->glyphRun.numberOfGlyphs - 1u) : (ellipsisLine->glyphRun.glyphIndex); + mSecondMiddleIndexOfElidedGlyphs = indexOfEllipsis; + isOnlySecondHalf = ellipsisLine->glyphRun.numberOfGlyphs == 0u && ellipsisLine->glyphRunSecondHalf.numberOfGlyphs > 0u; } - ++numberOfRemovedGlyphs; - } - } // while( !inserted ) - // 'Removes' all the glyphs after the ellipsis glyph. - const Length numberOfGlyphs = numberOfLaidOutGlyphs - numberOfRemovedGlyphs; - mElidedGlyphs.Resize(numberOfGlyphs); - mElidedLayout.Resize(numberOfGlyphs); + if(isOnlySecondHalf) + { + Length numberOfSecondHalfGlyphs = numberOfElidedGlyphs - mFirstMiddleIndexOfElidedGlyphs; + + //Copy elided glyphs after the ellipsis glyph. + memcpy(elidedGlyphsBuffer + mFirstMiddleIndexOfElidedGlyphs, elidedGlyphsBuffer + mSecondMiddleIndexOfElidedGlyphs, numberOfSecondHalfGlyphs * sizeof(GlyphInfo)); + memcpy(elidedPositionsBuffer + mFirstMiddleIndexOfElidedGlyphs, elidedPositionsBuffer + mSecondMiddleIndexOfElidedGlyphs, numberOfSecondHalfGlyphs * sizeof(Vector2)); + } + else + { + Length numberOfSecondHalfGlyphs = numberOfElidedGlyphs - mFirstMiddleIndexOfElidedGlyphs + 1u; + + //Copy elided glyphs after the ellipsis glyph. + memcpy(elidedGlyphsBuffer + mFirstMiddleIndexOfElidedGlyphs + 1u, elidedGlyphsBuffer + mSecondMiddleIndexOfElidedGlyphs, numberOfSecondHalfGlyphs * sizeof(GlyphInfo)); + memcpy(elidedPositionsBuffer + mFirstMiddleIndexOfElidedGlyphs + 1u, elidedPositionsBuffer + mSecondMiddleIndexOfElidedGlyphs, numberOfSecondHalfGlyphs * sizeof(Vector2)); + } + } + else // DevelText::EllipsisPosition::END + { + // 'Removes' all the glyphs after the ellipsis glyph. + mEndIndexOfElidedGlyphs = indexOfEllipsis; + } + } } } } } +float ViewModel::GetStrikethroughHeight() const +{ + return mModel->GetStrikethroughHeight(); +} + +const Vector4& ViewModel::GetStrikethroughColor() const +{ + return mModel->GetStrikethroughColor(); +} + +bool ViewModel::IsStrikethroughEnabled() const +{ + return mModel->IsStrikethroughEnabled(); +} + +bool ViewModel::IsMarkupStrikethroughSet() const +{ + return mModel->IsMarkupStrikethroughSet(); +} + +Length ViewModel::GetNumberOfStrikethroughRuns() const +{ + return mModel->GetNumberOfStrikethroughRuns(); +} + +void ViewModel::GetStrikethroughRuns(StrikethroughGlyphRun* strikethroughRuns, StrikethroughRunIndex index, Length numberOfRuns) const +{ + mModel->GetStrikethroughRuns(strikethroughRuns, index, numberOfRuns); +} + +Length ViewModel::GetNumberOfBoundedParagraphRuns() const +{ + return mModel->GetNumberOfBoundedParagraphRuns(); +} + +const Vector& ViewModel::GetBoundedParagraphRuns() const +{ + return mModel->GetBoundedParagraphRuns(); +} + +Length ViewModel::GetNumberOfCharacterSpacingGlyphRuns() const +{ + return mModel->GetNumberOfCharacterSpacingGlyphRuns(); +} + +const Vector& ViewModel::GetCharacterSpacingGlyphRuns() const +{ + return mModel->GetCharacterSpacingGlyphRuns(); +} + +const Vector& ViewModel::GetFontRuns() const +{ + return mModel->GetFontRuns(); +} + +const Vector& ViewModel::GetFontDescriptionRuns() const +{ + return mModel->GetFontDescriptionRuns(); +} + } // namespace Text } // namespace Toolkit