* Text and style is stored in the paragraph instead inside the character.
* If a paragraph has bidirectional text, it stores the
minimum common data needed to reorder a line.
* Before creating text-actors, text-view reorders
the bidirectional text, keeping the logical order.
Change-Id: Iff9c7e9223eb9c9a7d15b1e41cc6dc2f47096aa0
Signed-off-by: Victor Cebollada <v.cebollada@samsung.com>
DALI_TEST_EQUALS( characterLayoutInfo.mUnderlineThickness, 0.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
DALI_TEST_EQUALS( characterLayoutInfo.mUnderlinePosition, 0.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
DALI_TEST_CHECK( !characterLayoutInfo.mGlyphActor );
- DALI_TEST_CHECK( characterLayoutInfo.mStyledText.mText.IsEmpty() );
DALI_TEST_EQUALS( characterLayoutInfo.mColorAlpha, 1.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
DALI_TEST_CHECK( NULL == characterLayoutInfo.mGradientInfo );
DALI_TEST_CHECK( characterLayoutInfo.mIsVisible );
- DALI_TEST_CHECK( characterLayoutInfo.mSetText );
- DALI_TEST_CHECK( characterLayoutInfo.mSetStyle );
+ DALI_TEST_CHECK( !characterLayoutInfo.mSetText );
+ DALI_TEST_CHECK( !characterLayoutInfo.mSetStyle );
TextViewProcessor::WordLayoutInfo wordLayoutInfo;
DALI_TEST_EQUALS( wordLayoutInfo.mSize, Vector2::ZERO, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
characterLayoutInfo.mUnderlinePosition = 1.f;
characterLayoutInfo.mGlyphActor = TextActor::New( "Hello" );
- characterLayoutInfo.mStyledText.mText = Text( "Hello" );
TextViewProcessor::GradientInfo* info = new TextViewProcessor::GradientInfo();
info->mGradientColor = Vector4( 1.f, 1.f, 1.f, 1.f );
DALI_TEST_EQUALS( characterLayoutInfo1.mUnderlineThickness, 1.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
DALI_TEST_EQUALS( characterLayoutInfo1.mUnderlinePosition, 1.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
DALI_TEST_CHECK( characterLayoutInfo1.mGlyphActor );
- DALI_TEST_EQUALS( characterLayoutInfo1.mStyledText.mText.GetLength(), 5u, TEST_LOCATION );
DALI_TEST_EQUALS( characterLayoutInfo1.mColorAlpha, 0.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
DALI_TEST_EQUALS( characterLayoutInfo1.mGradientInfo->mGradientColor, Vector4( 1.f, 1.f, 1.f, 1.f ), Math::MACHINE_EPSILON_1000, TEST_LOCATION );
DALI_TEST_EQUALS( characterLayoutInfo1.mGradientInfo->mStartPoint, Vector2( 1.f, 1.f ), Math::MACHINE_EPSILON_1000, TEST_LOCATION );
DALI_TEST_EQUALS( characterLayoutInfo2.mUnderlineThickness, 1.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
DALI_TEST_EQUALS( characterLayoutInfo2.mUnderlinePosition, 1.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
DALI_TEST_CHECK( characterLayoutInfo2.mGlyphActor );
- DALI_TEST_EQUALS( characterLayoutInfo2.mStyledText.mText.GetLength(), 5u, TEST_LOCATION );
DALI_TEST_EQUALS( characterLayoutInfo2.mColorAlpha, 0.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
DALI_TEST_EQUALS( characterLayoutInfo2.mGradientInfo->mGradientColor, Vector4( 1.f, 1.f, 1.f, 1.f ), Math::MACHINE_EPSILON_1000, TEST_LOCATION );
DALI_TEST_EQUALS( characterLayoutInfo2.mGradientInfo->mStartPoint, Vector2( 1.f, 1.f ), Math::MACHINE_EPSILON_1000, TEST_LOCATION );
// Internal headers are allowed here
#include <dali-toolkit/internal/controls/text-view/text-processor.h>
+#include <dali-toolkit/internal/controls/text-view/text-processor-bidirectional-info.h>
using namespace Dali;
using namespace Dali::Toolkit;
bool TestBeginsRightToLeftCharacter( const std::string& description, const std::string& input, const bool result, const char* location )
{
- // Creates a styled text with the markup or plain string.
- MarkupProcessor::StyledTextArray styledText;
- MarkupProcessor::GetStyledTextArray( input, styledText, true );
+ // Creates a text with the string.
+ Text text( input );
- const bool ret = ( result == TextProcessor::BeginsRightToLeftCharacter( styledText ) );
+ const bool ret = ( result == TextProcessor::BeginsRightToLeftCharacter( text ) );
if( !ret )
{
bool TestContainsRightToLeftCharacter( const std::string& description, const std::string& input, const bool result, const char* location )
{
- // Creates a styled text with the markup or plain string.
- MarkupProcessor::StyledTextArray styledText;
- MarkupProcessor::GetStyledTextArray( input, styledText, true );
+ // Creates a text with the string.
+ Text text( input );
- const bool ret = ( result == TextProcessor::ContainsRightToLeftCharacter( styledText ) );
+ const bool ret = ( result == TextProcessor::ContainsRightToLeftCharacter( text ) );
if( !ret )
{
MarkupProcessor::StyledTextArray styledText;
MarkupProcessor::GetStyledTextArray( test.inputText, styledText, true );
- std::vector<MarkupProcessor::StyledTextArray> paragraphs;
+ std::vector<Text> paragraphs;
+ std::vector< Vector<TextStyle*> > styles;
TextProcessor::SplitInParagraphs( styledText,
- paragraphs );
+ paragraphs,
+ styles );
if( paragraphs.size() != test.resultNumberOfParagraphs )
{
{
std::string inputText;
- std::size_t resultNumberOfWords;
+ std::size_t resultNumberOfSeparators;
};
bool TestSplitInWords( const SplitInWordsTest& test, const char* location )
{
- // Creates a styled text with the markup or plain string.
- MarkupProcessor::StyledTextArray styledText;
- MarkupProcessor::GetStyledTextArray( test.inputText, styledText, true );
+ // Creates a text with the string.
+ Text text( test.inputText );
- std::vector<MarkupProcessor::StyledTextArray> words;
+ Vector<std::size_t> positions;
- TextProcessor::SplitInWords( styledText,
- words );
+ TextProcessor::SplitInWords( text,
+ positions );
- if( words.size() != test.resultNumberOfWords )
+ if( positions.Count() != test.resultNumberOfSeparators )
{
tet_printf( "Fail. %s", location );
- tet_printf( "Different number of words, result %d, expected result %d", words.size(), test.resultNumberOfWords );
+ tet_printf( "Different number of separators, result %d, expected result %d", positions.Count(), test.resultNumberOfSeparators );
return false;
}
{
{
std::string( "Hello world, hello word!" ),
- 7
+ 3u
},
+ {
+ std::string( "Hello world\n" ),
+ 2u
+ }
};
- const std::size_t numberOfTests( 1 );
+ const std::size_t numberOfTests( 2u );
for( std::size_t index = 0; index < numberOfTests; ++index )
{
// Creaqte indices.
TextViewProcessor::TextInfoIndices indices( 0u, test.wordIndex, test.characterIndex );
+ indices.mCharacterParagraphIndex = test.characterParagraphIndex;
// Get the input paragraph.
TextViewProcessor::ParagraphLayoutInfo inputParagraphLayout;
std::string input;
std::size_t wordIndex;
std::size_t characterIndex;
+ std::size_t characterParagraphIndex;
float lineHeightOffset;
std::string firstResult;
std::string lastResult;
{
std::cout << "[" << textActor.GetText() << "]";
}
- else
- {
- std::cout << "{" << character.mStyledText.mText.GetText() << "}";
- }
}
void Print( const TextViewProcessor::WordLayoutInfo& word )
std::cout << "||" << std::endl;
}
-std::string GetText( const TextViewProcessor::CharacterLayoutInfo& character )
-{
- return character.mStyledText.mText.GetText();
-}
-
-std::string GetText( const TextViewProcessor::WordLayoutInfo& word )
+std::string GetText( const TextViewProcessor::WordLayoutInfo& word, const Text& paragraphText )
{
- std::string text;
+ Text text;
- for( TextViewProcessor::CharacterLayoutInfoContainer::const_iterator it = word.mCharactersLayoutInfo.begin(), endIt = word.mCharactersLayoutInfo.end(); it != endIt; ++it )
- {
- text += GetText( *it );
- }
+ paragraphText.GetSubText( word.mFirstCharacter, word.mFirstCharacter + word.mCharactersLayoutInfo.size() - 1u, text );
- return text;
+ return text.GetText();
}
std::string GetText( const TextViewProcessor::ParagraphLayoutInfo& paragraph )
for( TextViewProcessor::WordLayoutInfoContainer::const_iterator it = paragraph.mWordsLayoutInfo.begin(), endIt = paragraph.mWordsLayoutInfo.end(); it != endIt; ++it )
{
- text += GetText( *it );
+ text += GetText( *it, paragraph.mText );
}
return text;
return false;
}
- text1 = character1.mStyledText.mText.GetText();
- style1 = character1.mStyledText.mStyle;
-
- text2 = character2.mStyledText.mText.GetText();
- style2 = character2.mStyledText.mStyle;
-
- if( text1 != text2 )
- {
- return false;
- }
-
- if( style1 != style2 )
- {
- std::cout << " style1 : " << std::endl;
- TextViewProcessor::dbgPrint( style1 );
-
- std::cout << " style2 : " << std::endl;
- TextViewProcessor::dbgPrint( style2 );
- return false;
- }
-
return true;
}
* @param input The input word.
* @param wordIndex Index to the word within the paragraph where to split it.
* @param characterIndex Where to split the word.
+ * @param characterIndex Character index within the paragraph.
* @param lineHeightOffset Offset between lines.
* @param firstResult First part of the split paragraph.
* @param lastResult Last part of the split paragraph.
const std::string& input,
size_t wordIndex,
size_t characterIndex,
+ size_t characterParagraphIndex,
float lineHeightOffset,
const std::string& firstResult,
const std::string& lastResult,
static_cast<Toolkit::Alignment::Type>( Toolkit::Alignment::HorizontalCenter | Toolkit::Alignment::VerticalCenter ),
Toolkit::TextView::Center,
PointSize( lineHeightOffset ),
- std::string( "..." ),
true ),
relayoutData );
static_cast<Toolkit::Alignment::Type>( Toolkit::Alignment::HorizontalCenter | Toolkit::Alignment::VerticalCenter ),
Toolkit::TextView::Center,
PointSize( lineHeightOffset ),
- std::string( "..." ),
true ),
firstRelayoutData );
static_cast<Toolkit::Alignment::Type>( Toolkit::Alignment::HorizontalCenter | Toolkit::Alignment::VerticalCenter ),
Toolkit::TextView::Center,
PointSize( lineHeightOffset ),
- std::string( "..."),
true ),
lastRelayoutData );
TextViewProcessor::ParagraphLayoutInfo lastParagraphLayoutInfo;
TextViewProcessor::TextInfoIndices indices( 0, wordIndex, characterIndex );
+ indices.mCharacterParagraphIndex = characterParagraphIndex;
SplitParagraph( indices,
PointSize( lineHeightOffset ),
static_cast<Toolkit::Alignment::Type>( Toolkit::Alignment::HorizontalCenter | Toolkit::Alignment::VerticalCenter ),
Toolkit::TextView::Center,
PointSize( lineHeightOffset ),
- std::string( "..." ),
true ),
firstRelayoutData );
static_cast<Toolkit::Alignment::Type>( Toolkit::Alignment::HorizontalCenter | Toolkit::Alignment::VerticalCenter ),
Toolkit::TextView::Center,
PointSize( lineHeightOffset ),
- std::string( "..." ),
true ),
lastRelayoutData );
static_cast<Toolkit::Alignment::Type>( Toolkit::Alignment::HorizontalCenter | Toolkit::Alignment::VerticalCenter ),
Toolkit::TextView::Center,
PointSize( lineHeightOffset ),
- std::string( "..." ),
true ),
resultRelayoutData );
static_cast<Toolkit::Alignment::Type>( Toolkit::Alignment::HorizontalCenter | Toolkit::Alignment::VerticalCenter ),
Toolkit::TextView::Center,
PointSize( lineHeightOffset ),
- std::string( "..." ),
true ),
relayoutData );
static_cast<Toolkit::Alignment::Type>( Toolkit::Alignment::HorizontalCenter | Toolkit::Alignment::VerticalCenter ),
Toolkit::TextView::Center,
PointSize( lineHeightOffset ),
- std::string( "..." ),
true ),
resultRelayoutData );
static_cast<Toolkit::Alignment::Type>( Toolkit::Alignment::HorizontalCenter | Toolkit::Alignment::VerticalCenter ),
Toolkit::TextView::Center,
PointSize( lineHeightOffset ),
- std::string( "..." ),
true ),
relayoutData );
static_cast<Toolkit::Alignment::Type>( Toolkit::Alignment::HorizontalCenter | Toolkit::Alignment::VerticalCenter ),
Toolkit::TextView::Center,
PointSize( lineHeightOffset ),
- std::string( "..." ),
true ),
resultRelayoutData );
static_cast<Toolkit::Alignment::Type>( Toolkit::Alignment::HorizontalCenter | Toolkit::Alignment::VerticalCenter ),
Toolkit::TextView::Center,
PointSize( lineHeightOffset ),
- std::string( "..." ),
true );
switch( operation )
layoutInfo12.mBearing = BEARING_12;
layoutInfo12.mAscender = ASCENDER_12;
- TextStyle style10;
- style10.SetFontName( "" );
- style10.SetFontPointSize( PointSize( 10.f ) );
- TextStyle style12;
- style12.SetFontName( "" );
-
- layoutInfo12.mStyledText.mStyle = style12;
- layoutInfo10.mStyledText.mStyle = style10;
-
// Words
TextViewProcessor::WordLayoutInfo wordLayout1, wordLayout2, wordLayout3, wordLayout4;
wordLayout1.mAscender = ASCENDER_12;
wordLayout1.mType = TextViewProcessor::NoSeparator;
- layoutInfo12.mStyledText.mText = Text( "H" );
wordLayout1.mCharactersLayoutInfo.push_back( layoutInfo12 ); // H
- layoutInfo12.mStyledText.mText = Text( "e" );
wordLayout1.mCharactersLayoutInfo.push_back( layoutInfo12 ); // e
- layoutInfo12.mStyledText.mText = Text( "l" );
wordLayout1.mCharactersLayoutInfo.push_back( layoutInfo12 ); // l
- layoutInfo10.mStyledText.mText = Text( "l" );
wordLayout1.mCharactersLayoutInfo.push_back( layoutInfo10 ); // l
- layoutInfo10.mStyledText.mText = Text( "o" );
wordLayout1.mCharactersLayoutInfo.push_back( layoutInfo10 ); // o
// (white space)
wordLayout2.mSize = Size( ADVANCE_10, HEIGHT_10 );
wordLayout2.mAscender = ASCENDER_10;
wordLayout2.mType = TextViewProcessor::WordSeparator;
- layoutInfo10.mStyledText.mText = Text( " " );
wordLayout2.mCharactersLayoutInfo.push_back( layoutInfo10 ); // (white space)
// world!
wordLayout3.mSize = Size( 2.f * ADVANCE_10 + 4.f * ADVANCE_12, HEIGHT_12 );
wordLayout3.mAscender = ASCENDER_12;
wordLayout3.mType = TextViewProcessor::NoSeparator;
- layoutInfo10.mStyledText.mText = Text( "w" );
wordLayout3.mCharactersLayoutInfo.push_back( layoutInfo10 ); // w
- layoutInfo10.mStyledText.mText = Text( "o" );
wordLayout3.mCharactersLayoutInfo.push_back( layoutInfo10 ); // o
- layoutInfo12.mStyledText.mText = Text( "r" );
wordLayout3.mCharactersLayoutInfo.push_back( layoutInfo12 ); // r
- layoutInfo12.mStyledText.mText = Text( "l" );
wordLayout3.mCharactersLayoutInfo.push_back( layoutInfo12 ); // l
- layoutInfo12.mStyledText.mText = Text( "d" );
wordLayout3.mCharactersLayoutInfo.push_back( layoutInfo12 ); // d
- layoutInfo12.mStyledText.mText = Text( "!" );
wordLayout3.mCharactersLayoutInfo.push_back( layoutInfo12 ); // !
// (new paragraph character)
wordLayout4.mSize = Size( 0.f, HEIGHT_12 );
wordLayout4.mAscender = ASCENDER_12;
wordLayout4.mType = TextViewProcessor::ParagraphSeparator;
- layoutInfo12.mStyledText.mText = Text( "\n" );
layoutInfo12.mSize.width = 0.f;
wordLayout4.mCharactersLayoutInfo.push_back( layoutInfo12 ); // (new paragraph char)
std::string( "Hello <font size='30'>w</font>orl<font size='10'>dhello</font> world" )
},
// * Remove RTL text within LTR
- /* TODO check this when RTL text is working
{
std::string( "Remove within the same paragraph, RTL text within LTR." ),
Remove,
0.f,
std::string( "Hello worlello world" )
},
- */
// * Remove whole paragraph
{
std::string( "Remove whole paragraph" ),
std::string( "Touch <b>me\nhello\n</b>world" )
},
};
- const std::size_t numberOfTests( 21u );
+ const std::size_t numberOfTests( 22u );
for( std::size_t index = 0u; index < numberOfTests; ++index )
{
std::string( "<font size='10'>He<font size='12'>ll</font>oooo wooorld</font> שלום עולם text text" ),
0,
0,
+ 0,
3.f,
std::string( "" ),
std::string( "<font size='10'>He<font size='12'>ll</font>oooo wooorld</font> שלום עולם text text" ),
std::string( "<font size='10'>He<font size='12'>ll</font>oooo wooorld</font> שלום עולם text text" ),
10,
4,
+ 36,
0.f,
std::string( "<font size='10'>He<font size='12'>ll</font>oooo wooorld</font> שלום עולם text text" ),
std::string( "" ),
std::string("<font size='10'>Hello </font>wor<font size='12'>ld, hello wo</font>rld"),
2,
4,
+ 10,
0.f,
std::string("<font size='10'>Hello </font>wor<font size='12'>l</font>"),
std::string("<font size='12'>d, hello wo</font>rld")
- }
- /* TODO RTL
+ },
{
std::string( "Split paragraph, wordPosition 6, position 0." ),
std::string( "<font size='10'>He<font size='12'>ll</font>oooo wooorld</font> שלום עולם text text" ),
6,
0,
+ 21,
0.f,
std::string( "<font size='10'>He<font size='12'>ll</font>oooo wooorld</font> שלום " ),
std::string( "עולם text text" ),
std::string( "<font size='10'>He<font size='12'>ll</font>oooo wooorld</font> שלום עולם text text" ),
4,
0,
+ 17,
0.f,
std::string( "<font size='10'>He<font size='12'>ll</font>oooo wooorld</font> " ),
std::string( "שלום עולם text text" ),
std::string( "<font size='10'>He<font size='12'>ll</font>oooo wooorld</font> שלום עולם text text" ),
8,
0,
+ 27,
6.f,
std::string( "<font size='10'>He<font size='12'>ll</font>oooo wooorld</font> שלום עולם " ),
std::string( "text text" ),
},
- */
};
- const std::size_t numberOfTests( 3u );
+ const std::size_t numberOfTests( 6u );
for( std::size_t index = 0u; index < numberOfTests; ++index )
{
test.input,
test.wordIndex,
test.characterIndex,
+ test.characterParagraphIndex,
test.lineHeightOffset,
test.firstResult,
test.lastResult,
0.f,
std::string( "Hello world, this is a whole paragraph" )
},
- /* TODO RTL
{
std::string( "Merge paragraphs: last starting with RTL text and first ending with RTL" ),
std::string( "Hello world, שלום" ),
3.f,
std::string( "Hello world, שלום עולם, hello world." )
},
- */
{
std::string( "Merge paragraphs. Don't merge words" ),
std::string( "Hello world," ),
std::string( "Hello world, this is a whole paragraph" )
},
};
- const std::size_t numberOfTests( 4u );
+ const std::size_t numberOfTests( 6u );
for( std::size_t index = 0u; index < numberOfTests; ++index )
{
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/license/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
#include <dali-toolkit/internal/controls/text-view/relayout-utilities.h>
// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/text-view/text-processor.h>
+#include <dali-toolkit/internal/controls/text-view/text-processor-bidirectional-info.h>
+#include <dali-toolkit/internal/controls/text-view/text-view-word-processor.h>
#include <dali-toolkit/internal/controls/text-view/text-view-processor-helper-functions.h>
+#include <dali-toolkit/internal/controls/text-view/text-view-processor-dbg.h>
// EXTERNAL INCLUDES
#include <cmath>
Vector3 position;
Size size;
Vector4 color;
- TextViewProcessor::GradientInfo* gradientInfo;
+ TextViewProcessor::CharacterLayoutInfo* characterLayout;
};
void SetVisualParameters( CurrentTextActorInfo& currentTextActorInfo,
const float lineHeight )
{
currentTextActorInfo.textActor.SetTextColor( currentTextActorInfo.color );
- if( NULL != currentTextActorInfo.gradientInfo )
+ if( ( NULL != currentTextActorInfo.characterLayout ) &&
+ ( NULL != currentTextActorInfo.characterLayout->mGradientInfo ) )
{
- currentTextActorInfo.textActor.SetGradientColor( currentTextActorInfo.gradientInfo->mGradientColor );
- currentTextActorInfo.textActor.SetGradientStartPoint( currentTextActorInfo.gradientInfo->mStartPoint );
- currentTextActorInfo.textActor.SetGradientEndPoint( currentTextActorInfo.gradientInfo->mEndPoint );
+ currentTextActorInfo.textActor.SetGradientColor( currentTextActorInfo.characterLayout->mGradientInfo->mGradientColor );
+ currentTextActorInfo.textActor.SetGradientStartPoint( currentTextActorInfo.characterLayout->mGradientInfo->mStartPoint );
+ currentTextActorInfo.textActor.SetGradientEndPoint( currentTextActorInfo.characterLayout->mGradientInfo->mEndPoint );
}
// The italics offset is used in the offscreen rendering. When text is in italics, it may exceed the text-view's boundary
subLineInfo.mMaxAscender *= shrinkFactor;
}
+
+/**
+ * Sets a character of a line of a bidirectional paragraph in the new position.
+ *
+ * @param[in] wordsLayoutInfo Layout info of all the words of the paragraph.
+ * @param[in] index Index within the paragraph to the character to be set in the new position.
+ * @param[in,out] character Reference to the character in the new position.
+ */
+void SetCharacter( const TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo,
+ std::size_t index,
+ TextViewProcessor::CharacterLayoutInfo& character )
+{
+ // Traverse all the characters of the paragraph till the one pointed by index is found.
+ std::size_t traversedCharacters = 0u;
+ for( TextViewProcessor::WordLayoutInfoContainer::const_iterator wordIt = wordsLayoutInfo.begin(),
+ wordEndIt = wordsLayoutInfo.end();
+ wordIt != wordEndIt;
+ ++wordIt )
+ {
+ const TextViewProcessor::WordLayoutInfo& word( *wordIt );
+
+ const std::size_t numberOfCharacters = word.mCharactersLayoutInfo.size();
+ if( index < traversedCharacters + numberOfCharacters )
+ {
+ character = *( word.mCharactersLayoutInfo.begin() + ( index - traversedCharacters ) );
+ return;
+ }
+ traversedCharacters += numberOfCharacters;
+ }
+}
+
+/**
+ * Reorders the layout info of each line of the paragraph.
+ *
+ * Uses the visual to logical conversion table to order the text, styles and character's layout (metrics).
+ *
+ * @param[in,out] rtlParagraph Layout info for the paragraph with rtl text.
+ */
+void ReorderLayout( TextViewProcessor::ParagraphLayoutInfo& paragraph )
+{
+ // Clear any previous right to left layout.
+ if( NULL != paragraph.mRightToLeftLayout )
+ {
+ paragraph.mRightToLeftLayout->Clear();
+ paragraph.mRightToLeftLayout->mPreviousLayoutCleared = true;
+ }
+ else
+ {
+ // Create a new right to left layout if there isn't any.
+ paragraph.mRightToLeftLayout = new TextViewProcessor::RightToLeftParagraphLayout();
+ }
+
+ // Reorder Text and Styles.
+
+ // Reserve space for the styles.
+ paragraph.mRightToLeftLayout->mTextStyles.Reserve( paragraph.mTextStyles.Count() );
+
+ // Traverses all the bidirectional info per line.
+ for( Vector<TextProcessor::BidirectionalLineInfo*>::ConstIterator it = paragraph.mBidirectionalLinesInfo.Begin(), endIt = paragraph.mBidirectionalLinesInfo.End(); it != endIt; ++it )
+ {
+ TextProcessor::BidirectionalLineInfo* info( *it );
+
+ const std::size_t characterParagraphIndex = info->mCharacterParagraphIndex;
+ const Vector<int>& visualToLogicalMap = info->mVisualToLogicalMap;
+
+ // The text can be appended as it's already reordered.
+ paragraph.mRightToLeftLayout->mText.Append( info->mText );
+
+ // The visual to logical map needs to be used to reorder the styles.
+ for( std::size_t index = 0u, size = visualToLogicalMap.Count(); index < size; ++index )
+ {
+ paragraph.mRightToLeftLayout->mTextStyles.PushBack( *( paragraph.mTextStyles.Begin() + ( characterParagraphIndex + *( visualToLogicalMap.Begin() + index ) ) ) );
+ }
+ }
+
+ // Reorder Layout Info.
+
+ // Reserve space for the new word layout.
+ paragraph.mRightToLeftLayout->mWordsLayoutInfo.reserve( paragraph.mWordsLayoutInfo.size() );
+
+ // Traverses all the bidirectional info per line.
+ for( Vector<TextProcessor::BidirectionalLineInfo*>::ConstIterator it = paragraph.mBidirectionalLinesInfo.Begin(), endIt = paragraph.mBidirectionalLinesInfo.End(); it != endIt; ++it )
+ {
+ TextProcessor::BidirectionalLineInfo* info( *it );
+
+ // Reserve space for all characters.
+ TextViewProcessor::CharacterLayoutInfoContainer characters;
+ characters.resize( info->mNumberOfCharacters );
+
+ // Uses the visual to logical map to set every character in its new position.
+ for( std::size_t index = 0u; index < info->mNumberOfCharacters; ++index )
+ {
+ SetCharacter( paragraph.mWordsLayoutInfo,
+ info->mCharacterParagraphIndex + info->mVisualToLogicalMap[index],
+ *( characters.begin() + index ) );
+ }
+
+ // Sets the new 'x' position for each character.
+ float xPosition = 0.f;
+ for( TextViewProcessor::CharacterLayoutInfoContainer::iterator it = characters.begin(), endIt = characters.end(); it != endIt; ++it )
+ {
+ TextViewProcessor::CharacterLayoutInfo& character( *it );
+
+ character.mPosition.x = xPosition;
+ xPosition += character.mSize.width;
+ }
+
+ // Split the reordered text in words.
+ std::size_t previousPosition = 0u;
+ Vector<std::size_t> positions;
+ TextProcessor::SplitInWords( info->mText, positions );
+
+ // Sets the characters into the words they belong to.
+ for( Vector<size_t>::ConstIterator it = positions.Begin(), endIt = positions.End(); it != endIt; ++it )
+ {
+ const std::size_t position = *it;
+
+ TextViewProcessor::WordLayoutInfo word;
+ word.mCharactersLayoutInfo.insert( word.mCharactersLayoutInfo.end(),
+ characters.begin() + previousPosition,
+ characters.begin() + position );
+
+ if( !word.mCharactersLayoutInfo.empty() )
+ {
+ // Updates the layout of the word.
+ TextViewProcessor::UpdateLayoutInfo( word );
+
+ paragraph.mRightToLeftLayout->mWordsLayoutInfo.push_back( word );
+ }
+
+ // white space or new paragraph.
+ TextViewProcessor::WordLayoutInfo space;
+ space.mCharactersLayoutInfo.insert( space.mCharactersLayoutInfo.end(),
+ characters.begin() + position,
+ characters.begin() + position + 1u );
+
+ TextViewProcessor::UpdateLayoutInfo( space );
+
+ paragraph.mRightToLeftLayout->mWordsLayoutInfo.push_back( space );
+
+ previousPosition = position + 1u;
+ }
+
+ // The last word.
+ if( previousPosition < paragraph.mRightToLeftLayout->mText.GetLength() )
+ {
+ TextViewProcessor::WordLayoutInfo word;
+ word.mCharactersLayoutInfo.insert( word.mCharactersLayoutInfo.end(),
+ characters.begin() + previousPosition,
+ characters.end() );
+
+ TextViewProcessor::UpdateLayoutInfo( word );
+
+ paragraph.mRightToLeftLayout->mWordsLayoutInfo.push_back( word );
+ }
+ }
+}
+
+/**
+ * Creates the bidirectional info needed to reorder each line of the paragraph.
+ *
+ * @param[in,out] relayoutData Natural size (metrics), layout, text-actor info.
+ * @param[in,out] paragraph Layout info for the paragraph.
+ * @param[in] characterGlobalIndex Index to the character within the whole text.
+ * @param[in] lineLayoutInfoIndex Index to the table of lines.
+ */
+void CreateBidirectionalInfoForLines( TextView::RelayoutData& relayoutData,
+ TextViewProcessor::ParagraphLayoutInfo& paragraph,
+ std::size_t& characterGlobalIndex,
+ std::size_t& lineLayoutInfoIndex )
+{
+ const std::size_t lineLayoutInfoSize = relayoutData.mLines.size(); // Number or laid out lines.
+ bool lineLayoutEnd = false; // Whether lineLayoutInfoIndex points at the last laid out line.
+
+ // Clear previously created bidirectional info.
+ paragraph.ClearBidirectionalInfo();
+
+ std::size_t characterParagraphIndex = 0u; // Index to the character (within the paragraph).
+ for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = paragraph.mWordsLayoutInfo.begin(), wordEndIt = paragraph.mWordsLayoutInfo.end();
+ wordIt != wordEndIt;
+ ++wordIt )
+ {
+ TextViewProcessor::WordLayoutInfo& word( *wordIt );
+
+ for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
+ characterIt != characterEndIt;
+ ++characterIt )
+ {
+ TextProcessor::BidirectionalLineInfo* bidirectionalLineInfo = NULL;
+
+ // Check if there is a new line.
+ const bool newLine = !lineLayoutEnd && ( characterGlobalIndex == relayoutData.mLines[lineLayoutInfoIndex].mCharacterGlobalIndex );
+
+ if( newLine )
+ {
+ // Point to the next line.
+ ++lineLayoutInfoIndex;
+ if( lineLayoutInfoIndex >= lineLayoutInfoSize )
+ {
+ // Arrived at last line.
+ lineLayoutEnd = true; // Avoids access out of bounds in the relayoutData.mLines vector.
+ }
+
+ // Number of characters of the line.
+ const size_t numberOfCharacters = ( lineLayoutEnd ? relayoutData.mTextLayoutInfo.mNumberOfCharacters : relayoutData.mLines[lineLayoutInfoIndex].mCharacterGlobalIndex ) - characterGlobalIndex;
+
+ // There is right to left characters in this line. It needs to be reordered.
+ bidirectionalLineInfo = new TextProcessor::BidirectionalLineInfo();
+ bidirectionalLineInfo->mCharacterParagraphIndex = characterParagraphIndex;
+ bidirectionalLineInfo->mNumberOfCharacters = numberOfCharacters;
+
+ // Set all the Text's characters in the visual order and creates the mapping tables.
+ TextProcessor::ReorderLine( paragraph.mBidirectionalParagraphInfo,
+ bidirectionalLineInfo );
+
+ paragraph.mBidirectionalLinesInfo.PushBack( bidirectionalLineInfo );
+
+ for( std::size_t index = 0u; index < numberOfCharacters; ++index )
+ {
+ relayoutData.mCharacterLogicalToVisualMap.push_back( characterGlobalIndex + bidirectionalLineInfo->mLogicalToVisualMap[index] );
+ relayoutData.mCharacterVisualToLogicalMap.push_back( characterGlobalIndex + bidirectionalLineInfo->mVisualToLogicalMap[index] );
+ }
+ }
+
+ ++characterGlobalIndex;
+ ++characterParagraphIndex;
+ } // characters
+ } // words
+}
+
+void ReorderRightToLeftLayout( TextView::RelayoutData& relayoutData )
+{
+ // Reset conversion tables shared through public-api
+ relayoutData.mCharacterLogicalToVisualMap.clear();
+ relayoutData.mCharacterVisualToLogicalMap.clear();
+
+ std::size_t characterGlobalIndex = 0u; // Index to the global character (within the whole text).
+ std::size_t lineLayoutInfoIndex = 0u; // Index to the line info.
+
+ for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(), paragraphEndIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
+ paragraphIt != paragraphEndIt;
+ ++paragraphIt )
+ {
+ TextViewProcessor::ParagraphLayoutInfo& paragraph( *paragraphIt );
+
+ if( NULL != paragraph.mBidirectionalParagraphInfo )
+ {
+ // There is right to left text in this paragraph.
+
+ // Creates the bidirectional info needed to reorder each line of the paragraph.
+ CreateBidirectionalInfoForLines( relayoutData,
+ paragraph,
+ characterGlobalIndex,
+ lineLayoutInfoIndex );
+
+ // Reorder each line of the paragraph
+ ReorderLayout( paragraph );
+ }
+ else
+ {
+ // Identity in case the paragraph has no right to left text.
+ for( std::size_t index = 0u; index < paragraph.mNumberOfCharacters; ++index )
+ {
+ const std::size_t globalIndex = characterGlobalIndex + index;
+ relayoutData.mCharacterLogicalToVisualMap.push_back( globalIndex );
+ relayoutData.mCharacterVisualToLogicalMap.push_back( globalIndex );
+ }
+ characterGlobalIndex += paragraph.mNumberOfCharacters;
+ }
+ } // paragraphs
+}
+
float CalculateXoffset( Toolkit::Alignment::Type horizontalTextAlignment, float parentWidth, float wholeTextWidth )
{
float xOffset( 0.f );
const float textHorizontalOffset = CalculateXoffset( layoutParameters.mHorizontalAlignment, relayoutData.mTextViewSize.width, relayoutData.mTextSizeForRelayoutOption.width );
const float textVerticalOffset = CalculateYoffset( layoutParameters.mVerticalAlignment, relayoutData.mTextViewSize.height, relayoutData.mTextSizeForRelayoutOption.height );
- std::size_t lineJustificationIndex = 0u; // Index to the first position of the vector which stores all line justification info.
- std::size_t infoTableCharacterIndex = 0u;
+ // Index to the global character (within the whole text).
+ std::size_t characterGlobalIndex = 0u;
+
+ // Index to the line info.
+ std::size_t lineLayoutInfoIndex = 0u;
relayoutParameters.mIndices.mParagraphIndex = 0u;
float justificationOffset = 0.f;
+ const std::size_t lineLayoutInfoSize = relayoutData.mLines.size(); // Number of lines.
+ bool lineLayoutEnd = false; // Whether lineLayoutInfoIndex points at the last line.
+
relayoutParameters.mIndices.mWordIndex = 0u;
- for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = paragraphLayoutInfo.mWordsLayoutInfo.begin(),
- endWordLayoutIt = paragraphLayoutInfo.mWordsLayoutInfo.end();
+ const bool isRightToLeftLayout = NULL != paragraphLayoutInfo.mRightToLeftLayout;
+ TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayoutInfo.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayoutInfo.mWordsLayoutInfo;
+
+ for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordsLayoutInfo.begin(),
+ endWordLayoutIt = wordsLayoutInfo.end();
wordLayoutIt != endWordLayoutIt;
++wordLayoutIt, ++relayoutParameters.mIndices.mWordIndex )
{
for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
characterLayoutIt != endCharacterLayoutIt;
- ++characterLayoutIt, ++relayoutParameters.mIndices.mCharacterIndex, ++infoTableCharacterIndex )
+ ++characterLayoutIt, ++relayoutParameters.mIndices.mCharacterIndex, ++characterGlobalIndex )
{
TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
- // Calculate line justification offset.
- if( lineJustificationIndex < relayoutData.mLineJustificationInfo.size() )
+ // Check if there is a new line.
+ const bool newLine = !lineLayoutEnd && ( characterGlobalIndex == relayoutData.mLines[lineLayoutInfoIndex].mCharacterGlobalIndex );
+
+ if( newLine )
{
- const TextView::LineJustificationInfo lineJustificationInfo( *( relayoutData.mLineJustificationInfo.begin() + lineJustificationIndex ) );
+ // Calculate line justification offset.
+ justificationOffset = CalculateJustificationOffset( layoutParameters.mLineJustification, relayoutData.mTextSizeForRelayoutOption.width, relayoutData.mLines[lineLayoutInfoIndex].mSize.width );
- if( relayoutParameters.mIndices == lineJustificationInfo.mIndices )
+ // Point to the next line.
+ ++lineLayoutInfoIndex;
+ if( lineLayoutInfoIndex >= lineLayoutInfoSize )
{
- justificationOffset = CalculateJustificationOffset( layoutParameters.mLineJustification, relayoutData.mTextSizeForRelayoutOption.width, lineJustificationInfo.mLineLength );
- ++lineJustificationIndex; // increase the index to point the next position in the vector.
+ // Arrived at last line.
+ lineLayoutEnd = true; // Avoids access out of bounds in the relayoutData.mLines vector.
}
}
// Updates the size and position table for text-input with the alignment offset.
Vector3 positionOffset( characterLayoutInfo.mPosition );
- std::vector<Toolkit::TextView::CharacterLayoutInfo>::iterator infoTableIt = relayoutData.mCharacterLayoutInfoTable.begin() + infoTableCharacterIndex;
+ std::vector<Toolkit::TextView::CharacterLayoutInfo>::iterator infoTableIt = relayoutData.mCharacterLayoutInfoTable.begin() + characterGlobalIndex;
Toolkit::TextView::CharacterLayoutInfo& characterTableInfo( *infoTableIt );
characterTableInfo.mPosition.x = positionOffset.x + characterLayoutInfo.mOffset.x;
characterLayoutInfo.mSize.height * relayoutData.mShrinkFactor ),
positionOffset,
( TextViewProcessor::ParagraphSeparator == wordLayoutInfo.mType ),
- false, // VCC set the correct direction if needed.
+ false,
true,
descender );
void CalculateVisibilityForFade( const Internal::TextView::LayoutParameters& layoutParameters,
TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
+ const TextStyle& style,
RelayoutParameters& relayoutParameters,
FadeParameters& fadeParameters,
TextView::RelayoutData& relayoutData )
Vector2 startPoint = Vector2::ZERO;
Vector2 endPoint = Vector2::ZERO;
- if( NULL == characterLayoutInfo.mGradientInfo )
- {
- characterLayoutInfo.mGradientInfo = new TextViewProcessor::GradientInfo();
- }
-
if( !( rightFadeOut && leftFadeOut ) )
{
// Current implementation can't set gradient parameters for a text-actor exceeding at the same time the left and the right boundaries.
if( rightFadeOut )
{
- gradientColor = characterLayoutInfo.mStyledText.mStyle.GetTextColor();
+ gradientColor = style.GetTextColor();
// Calculates gradient coeficients.
characterLayoutInfo.mColorAlpha = gradientColor.a * std::min( 1.f, fadeParameters.mRightAlphaCoeficients.x * position.x + fadeParameters.mRightAlphaCoeficients.y );
gradientColor.a *= std::max( 0.f, fadeParameters.mRightAlphaCoeficients.x * characterPositionPlusWidth + fadeParameters.mRightAlphaCoeficients.y );
- startPoint = Vector2( std::max( 0.f, ( fadeParameters.mRightFadeThresholdOffset - position.x ) / size.width ), 0.5f );
- endPoint = Vector2( std::min( 1.f, ( relayoutData.mTextViewSize.width - position.x ) / size.width ), 0.5f );
+ startPoint = Vector2( std::max( 0.f, std::min( 1.f, ( fadeParameters.mRightFadeThresholdOffset - position.x ) / size.width ) ), 0.5f );
+ endPoint = Vector2( std::min( 1.f, std::max( 0.f, ( relayoutData.mTextViewSize.width - position.x ) / size.width ) ), 0.5f );
+
+ if( NULL == characterLayoutInfo.mGradientInfo )
+ {
+ characterLayoutInfo.mGradientInfo = new TextViewProcessor::GradientInfo();
+ }
}
else if( leftFadeOut )
{
- gradientColor = characterLayoutInfo.mStyledText.mStyle.GetTextColor();
+ gradientColor = style.GetTextColor();
// Calculates gradient coeficients.
characterLayoutInfo.mColorAlpha = std::min( 1.f, fadeParameters.mLeftAlphaCoeficients.x * characterPositionPlusWidth + fadeParameters.mLeftAlphaCoeficients.y );
gradientColor.a *= gradientColor.a * std::max( 0.f, fadeParameters.mLeftAlphaCoeficients.x * position.x + fadeParameters.mLeftAlphaCoeficients.y );
- startPoint = Vector2( std::max( 0.f, ( fadeParameters.mLeftFadeThresholdOffset - position.x ) / size.width ), 0.5f );
- endPoint = Vector2( std::min( 1.f, -position.x / size.width ), 0.5f );
+ startPoint = Vector2( std::max( 0.f, std::min( 1.f, ( fadeParameters.mLeftFadeThresholdOffset - position.x ) / size.width ) ), 0.5f );
+ endPoint = Vector2( std::min( 1.f, std::max( 0.f, -position.x / size.width ) ), 0.5f );
+
+ if( NULL == characterLayoutInfo.mGradientInfo )
+ {
+ characterLayoutInfo.mGradientInfo = new TextViewProcessor::GradientInfo();
+ }
}
}
// Current implementation can't set gradient parameters for a text-actor exceeding at the same time the top and the bottom boundaries.
if( bottomFadeOut )
{
- gradientColor = characterLayoutInfo.mStyledText.mStyle.GetTextColor();
+ gradientColor = style.GetTextColor();
// Calculates gradient coeficients.
characterLayoutInfo.mColorAlpha = gradientColor.a * std::min( 1.f, fadeParameters.mBottomAlphaCoeficients.x * characterPositionMinusHeight + fadeParameters.mBottomAlphaCoeficients.y );
gradientColor.a *= std::max( 0.f, fadeParameters.mBottomAlphaCoeficients.x * position.y + fadeParameters.mBottomAlphaCoeficients.y );
- startPoint = Vector2( 0.5f, std::max( 0.f, ( fadeParameters.mBottomFadeThresholdOffset - characterPositionMinusHeight ) / size.height ) );
- endPoint = Vector2( 0.5f, std::min( 1.f, ( relayoutData.mTextViewSize.height - characterPositionMinusHeight ) / size.height ) );
+ startPoint = Vector2( 0.5f, std::max( 0.f, std::min( 1.f, ( fadeParameters.mBottomFadeThresholdOffset - characterPositionMinusHeight ) / size.height ) ) );
+ endPoint = Vector2( 0.5f, std::min( 1.f, std::max( 0.f, ( relayoutData.mTextViewSize.height - characterPositionMinusHeight ) / size.height ) ) );
+
+ if( NULL == characterLayoutInfo.mGradientInfo )
+ {
+ characterLayoutInfo.mGradientInfo = new TextViewProcessor::GradientInfo();
+ }
}
else if( topFadeOut )
{
- gradientColor = characterLayoutInfo.mStyledText.mStyle.GetTextColor();
+ gradientColor = style.GetTextColor();
// Calculates gradient coeficients.
characterLayoutInfo.mColorAlpha *= gradientColor.a * std::min( 1.f, fadeParameters.mTopAlphaCoeficients.x * position.y + fadeParameters.mTopAlphaCoeficients.y );
gradientColor.a *= std::max( 0.f, fadeParameters.mTopAlphaCoeficients.x * characterPositionMinusHeight + fadeParameters.mTopAlphaCoeficients.y );
- startPoint = Vector2( 0.5f, std::max( 0.f, ( fadeParameters.mTopFadeThresholdOffset - characterPositionMinusHeight ) / size.height ) );
- endPoint = Vector2( 0.5f, std::min( 1.f, -characterPositionMinusHeight / size.height ) );
+ startPoint = Vector2( 0.5f, std::max( 0.f, std::min( 1.f, ( fadeParameters.mTopFadeThresholdOffset - characterPositionMinusHeight ) / size.height ) ) );
+ endPoint = Vector2( 0.5f, std::min( 1.f, std::max( 0.f, -characterPositionMinusHeight / size.height ) ) );
+
+ if( NULL == characterLayoutInfo.mGradientInfo )
+ {
+ characterLayoutInfo.mGradientInfo = new TextViewProcessor::GradientInfo();
+ }
}
}
- characterLayoutInfo.mGradientInfo->mGradientColor = gradientColor;
- characterLayoutInfo.mGradientInfo->mStartPoint = startPoint;
- characterLayoutInfo.mGradientInfo->mEndPoint = endPoint;
+ if( NULL != characterLayoutInfo.mGradientInfo )
+ {
+ characterLayoutInfo.mGradientInfo->mGradientColor = gradientColor;
+ characterLayoutInfo.mGradientInfo->mStartPoint = startPoint;
+ characterLayoutInfo.mGradientInfo->mEndPoint = endPoint;
+ }
}
else
{
float bearingOffset = 0.f;
// Create ellipsize text-actor.
+ std::size_t characterIndex = 0u;
for( TextViewProcessor::CharacterLayoutInfoContainer::const_iterator ellipsizeCharacterLayoutIt = relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mCharactersLayoutInfo.begin(),
endEllipsizeCharacterLayoutIt = relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mCharactersLayoutInfo.end();
ellipsizeCharacterLayoutIt != endEllipsizeCharacterLayoutIt;
- ++ellipsizeCharacterLayoutIt )
+ ++ellipsizeCharacterLayoutIt, ++characterIndex )
{
const TextViewProcessor::CharacterLayoutInfo& ellipsizeCharacterLayoutInfo( *ellipsizeCharacterLayoutIt );
+ const TextStyle& style = *( *( relayoutData.mTextLayoutInfo.mEllipsisTextStyles.Begin() + characterIndex ) );
if( isColorGlyph ||
( isColorGlyph != ellipsizeCharacterLayoutInfo.mIsColorGlyph ) ||
- ( ellipsizeStyle != ellipsizeCharacterLayoutInfo.mStyledText.mStyle ) )
+ ( ellipsizeStyle != style ) )
{
// The style is different, so a new text-actor is needed.
if( !ellipsizeText.IsEmpty() )
}
// Resets the current ellipsize info.
- ellipsizeText = ellipsizeCharacterLayoutInfo.mStyledText.mText;
- ellipsizeStyle = ellipsizeCharacterLayoutInfo.mStyledText.mStyle;
+ ellipsizeText = Text( relayoutData.mTextLayoutInfo.mEllipsisText[characterIndex] );
+ ellipsizeStyle = style;
ellipsizeSize = ellipsizeCharacterLayoutInfo.mSize;
isColorGlyph = ellipsizeCharacterLayoutInfo.mIsColorGlyph;
else
{
// Updates text and size with the new character.
- ellipsizeText.Append( ellipsizeCharacterLayoutInfo.mStyledText.mText );
+ ellipsizeText.Append( relayoutData.mTextLayoutInfo.mEllipsisText[characterIndex] );
TextViewProcessor::UpdateSize( ellipsizeSize, ellipsizeCharacterLayoutInfo.mSize );
}
}
std::size_t wordCount = 0u;
- for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = paragraphLayoutInfo.mWordsLayoutInfo.begin() + firstIndices.mWordIndex,
- endWordLayoutIt = paragraphLayoutInfo.mWordsLayoutInfo.begin() + lastIndices.mWordIndex + 1u;
+ const bool isRightToLeftLayout = NULL != paragraphLayoutInfo.mRightToLeftLayout;
+ TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayoutInfo.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayoutInfo.mWordsLayoutInfo;
+
+ for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordsLayoutInfo.begin() + firstIndices.mWordIndex,
+ endWordLayoutIt = wordsLayoutInfo.begin() + lastIndices.mWordIndex + 1u;
wordLayoutIt != endWordLayoutIt;
++wordLayoutIt, ++wordCount )
{
++paragraphLayoutIt )
{
TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphLayoutIt );
+ std::size_t characterIndex = 0u;
+
+ const bool isRightToLeftLayout = NULL != paragraphLayoutInfo.mRightToLeftLayout;
+ TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayoutInfo.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayoutInfo.mWordsLayoutInfo;
- for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = paragraphLayoutInfo.mWordsLayoutInfo.begin(),
- endWordLayoutIt = paragraphLayoutInfo.mWordsLayoutInfo.end();
+ for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordsLayoutInfo.begin(),
+ endWordLayoutIt = wordsLayoutInfo.end();
wordLayoutIt != endWordLayoutIt;
++wordLayoutIt )
{
for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
characterLayoutIt != endCharacterLayoutIt;
- ++characterLayoutIt )
+ ++characterLayoutIt, ++characterIndex )
{
TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
characterLayoutInfo.mIsVisible = true;
delete characterLayoutInfo.mGradientInfo;
characterLayoutInfo.mGradientInfo = NULL;
- characterLayoutInfo.mColorAlpha = characterLayoutInfo.mStyledText.mStyle.GetTextColor().a;
+ characterLayoutInfo.mColorAlpha = ( *( paragraphLayoutInfo.mTextStyles.Begin() + characterIndex ) )->GetTextColor().a;
} // end characters
} // end words
} // end paragraphs
{
TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphLayoutIt );
+ std::size_t characterIndex = 0u;
relayoutParameters.mIndices.mWordIndex = 0u;
- for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = paragraphLayoutInfo.mWordsLayoutInfo.begin(),
- endWordLayoutIt = paragraphLayoutInfo.mWordsLayoutInfo.end();
+ const bool isRightToLeftLayout = NULL != paragraphLayoutInfo.mRightToLeftLayout;
+ TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayoutInfo.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayoutInfo.mWordsLayoutInfo;
+
+ for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordsLayoutInfo.begin(),
+ endWordLayoutIt = wordsLayoutInfo.end();
wordLayoutIt != endWordLayoutIt;
++wordLayoutIt, ++relayoutParameters.mIndices.mWordIndex )
{
for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
characterLayoutIt != endCharacterLayoutIt;
- ++characterLayoutIt, ++relayoutParameters.mIndices.mCharacterIndex, ++infoTableCharacterIndex )
+ ++characterLayoutIt, ++relayoutParameters.mIndices.mCharacterIndex, ++infoTableCharacterIndex, ++characterIndex )
{
TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
// Calculates the visibility for the current character.
CalculateVisibilityForFade( layoutParameters,
characterLayoutInfo,
+ *( *( paragraphLayoutInfo.mTextStyles.Begin() + characterIndex ) ),
relayoutParameters,
fadeParameters,
relayoutData );
// Set the text-actor for the current traversed text.
if( currentTextActorInfo.textActor )
{
- currentTextActorInfo.textActor.SetText( currentTextActorInfo.text );
+ if( ( NULL != currentTextActorInfo.characterLayout ) &&
+ currentTextActorInfo.characterLayout->mSetText )
+ {
+ currentTextActorInfo.textActor.SetText( currentTextActorInfo.text );
+ currentTextActorInfo.characterLayout->mSetText = false;
+ }
currentTextActorInfo.textActor.SetPosition( currentTextActorInfo.position );
currentTextActorInfo.textActor.SetSize( currentTextActorInfo.size );
paragraph.mSize.height );
}
+ float rightToLeftOffset = 0.f;
+ if( character.IsWhiteSpace() )
+ {
+ // In left to right text, a word never starts with a white space but
+ // it may happen in right to left text as the text is reversed.
+ // The text alignment and justification offset is calculated without this white space.
+ // It causes a missalignment which can be corrected by removing the size of the white space.
+ rightToLeftOffset = characterLayout.mSize.width * relayoutData.mShrinkFactor;
+ }
+
currentTextActorInfo.text = Text( character );
- currentTextActorInfo.position = Vector3( characterLayout.mPosition.x + characterLayout.mOffset.x,
+ currentTextActorInfo.position = Vector3( characterLayout.mPosition.x + characterLayout.mOffset.x - rightToLeftOffset,
characterLayout.mPosition.y + characterLayout.mOffset.y,
characterLayout.mPosition.z );
currentTextActorInfo.size = characterLayout.mSize * relayoutData.mShrinkFactor;
currentTextActorInfo.color = style.GetTextColor();
currentTextActorInfo.color.a = characterLayout.mColorAlpha;
- currentTextActorInfo.gradientInfo = characterLayout.mGradientInfo;
-
TextActor textActor = TextActor::DownCast( characterLayout.mGlyphActor );
if( createGlyphActors )
textActor.SetTextStyle( style );
}
}
+ characterLayout.mSetText = true;
+ currentTextActorInfo.characterLayout = &characterLayout;
+
characterLayout.mGlyphActor = textActor;
}
*/
void UpdateTextActorInfoForParagraph( const TextView::VisualParameters& visualParameters,
TextView::RelayoutData& relayoutData,
- TextViewProcessor::ParagraphLayoutInfo& paragraph,
+ TextViewProcessor::ParagraphLayoutInfo& paragraphLayout,
std::size_t& characterGlobalIndex,
std::size_t& lineLayoutInfoIndex,
bool createGlyphActors )
{
CurrentTextActorInfo currentTextActorInfo;
+ currentTextActorInfo.characterLayout = NULL;
const std::size_t lineLayoutInfoSize = relayoutData.mLines.size(); // Number of lines.
bool lineLayoutEnd = false; // Whether lineLayoutInfoIndex points at the last line.
std::vector<TextActor> textActorsToRemove; // Keep a vector of text-actors to be included into the cache.
+ // Retrieve the layout info to traverse. If there is right to left text it retrieves the right to left layout.
+ const bool isRightToLeftLayout = NULL != paragraphLayout.mRightToLeftLayout;
+
+ TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayout.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayout.mWordsLayoutInfo;
+ Text& text = isRightToLeftLayout ? paragraphLayout.mRightToLeftLayout->mText : paragraphLayout.mText;
+ Vector<TextStyle*>& textStyles = isRightToLeftLayout ? paragraphLayout.mRightToLeftLayout->mTextStyles : paragraphLayout.mTextStyles;
+
+ // In case the previous right to left layout has been cleared, all text-actors have been removed as well. If this bool is set to true, text-actors will be created again.
+ const bool previousRightToLeftLayoutCleared = isRightToLeftLayout ? paragraphLayout.mRightToLeftLayout->mPreviousLayoutCleared : false;
+
std::size_t characterParagraphIndex = 0u; // Index to the character (within the paragraph).
- for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = paragraph.mWordsLayoutInfo.begin(), wordEndIt = paragraph.mWordsLayoutInfo.end();
+ for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = wordsLayoutInfo.begin(), wordEndIt = wordsLayoutInfo.end();
wordIt != wordEndIt;
++wordIt )
{
- TextViewProcessor::WordLayoutInfo& word( *wordIt );
+ TextViewProcessor::WordLayoutInfo& wordLayout( *wordIt );
- for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
+ for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = wordLayout.mCharactersLayoutInfo.begin(), characterEndIt = wordLayout.mCharactersLayoutInfo.end();
characterIt != characterEndIt;
++characterIt )
{
}
// Do not create a glyph-actor if there is no text.
- const Character character = characterLayout.mStyledText.mText[0u]; // there are only one character per character layout.
- const TextStyle& style = characterLayout.mStyledText.mStyle;
+ const Character character = text[characterParagraphIndex];
+ const TextStyle& style = *( *( textStyles.Begin() + characterParagraphIndex ) );
bool appendCharacter = false;
if( characterLayout.mIsColorGlyph ||
- !character.IsWhiteSpace() || // A new paragraph character is also a white space.
- ( character.IsWhiteSpace() && style.IsUnderlineEnabled() ) )
+ ( TextViewProcessor::NoSeparator == wordLayout.mType ) ||
+ ( ( TextViewProcessor::WordSeparator == wordLayout.mType ) && style.IsUnderlineEnabled() ) )
{
// Do not create a glyph-actor if it's a white space (without underline) or a new paragraph character.
characterLayout.mSetText = false;
characterLayout.mSetStyle = false;
- // There is a new style or a new line.
- glyphActorCreatedForLine = true;
-
if( characterLayout.mIsColorGlyph )
{
CreateEmoticon( visualParameters,
{
CreateTextActor( visualParameters,
relayoutData,
- paragraph,
+ paragraphLayout,
characterLayout,
character,
style,
currentTextActorInfo,
- createGlyphActors );
+ createGlyphActors || previousRightToLeftLayoutCleared );
}
+ // There is a new style or a new line.
+ glyphActorCreatedForLine = true;
+
// Update style to be checked with next characters.
currentStyle = style;
currentGradientInfo = characterLayout.mGradientInfo;
if( appendCharacter )
{
// Add the character to the current text-actor and update the size.
- if( characterLayout.mIsVisible && ( TextViewProcessor::ParagraphSeparator != word.mType ) )
+ if( characterLayout.mIsVisible && ( TextViewProcessor::ParagraphSeparator != wordLayout.mType ) )
{
currentTextActorInfo.text.Append( character );
{
if( currentTextActorInfo.textActor )
{
- currentTextActorInfo.textActor.SetText( currentTextActorInfo.text );
+ if( ( NULL != currentTextActorInfo.characterLayout ) &&
+ currentTextActorInfo.characterLayout->mSetText )
+ {
+ currentTextActorInfo.textActor.SetText( currentTextActorInfo.text );
+ currentTextActorInfo.characterLayout->mSetText = false;
+ }
currentTextActorInfo.textActor.SetPosition( currentTextActorInfo.position );
currentTextActorInfo.textActor.SetSize( currentTextActorInfo.size );
SetVisualParameters( currentTextActorInfo,
visualParameters,
relayoutData,
- paragraph.mSize.height );
+ paragraphLayout.mSize.height );
}
}
{
TextViewProcessor::ParagraphLayoutInfo& paragraph( *paragraphIt );
- for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = paragraph.mWordsLayoutInfo.begin(), wordEndIt = paragraph.mWordsLayoutInfo.end();
+ std::size_t characterIndex = 0u;
+
+ const bool isRightToLeftLayout = NULL != paragraph.mRightToLeftLayout;
+ TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraph.mRightToLeftLayout->mWordsLayoutInfo : paragraph.mWordsLayoutInfo;
+
+ for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = wordsLayoutInfo.begin(), wordEndIt = wordsLayoutInfo.end();
wordIt != wordEndIt;
++wordIt )
{
for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
characterIt != characterEndIt;
- ++characterIt )
+ ++characterIt, ++characterIndex )
{
TextViewProcessor::CharacterLayoutInfo& character( *characterIt );
+ const TextStyle& style = *( *( paragraph.mTextStyles.Begin() + characterIndex ) );
// Check if current character is the first of a new line
const bool isNewLine = ( textUnderlineStatus.mLineGlobalIndex < relayoutData.mLines.size() ) &&
++textUnderlineStatus.mLineGlobalIndex; // If it's a new line, point to the next one.
}
- if( character.mStyledText.mStyle.IsUnderlineEnabled() )
+ if( style.IsUnderlineEnabled() )
{
if( !textUnderlineStatus.mCurrentUnderlineStatus || // Current character is underlined but previous one it wasn't.
isNewLine ) // Current character is underlined and is the first of current line.
++paragraphIt )
{
TextViewProcessor::ParagraphLayoutInfo& paragraph( *paragraphIt );
+ std::size_t characterIndex = 0u;
+
+ const bool isRightToLeftLayout = NULL != paragraph.mRightToLeftLayout;
+ TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraph.mRightToLeftLayout->mWordsLayoutInfo : paragraph.mWordsLayoutInfo;
- for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = paragraph.mWordsLayoutInfo.begin(), wordEndIt = paragraph.mWordsLayoutInfo.end();
+ for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = wordsLayoutInfo.begin(), wordEndIt = wordsLayoutInfo.end();
wordIt != wordEndIt;
++wordIt )
{
for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
characterIt != characterEndIt;
- ++characterIt )
+ ++characterIt, ++characterIndex )
{
TextViewProcessor::CharacterLayoutInfo& character( *characterIt );
+ TextStyle& style = *( *( paragraph.mTextStyles.Begin() + characterIndex ) );
// Check if current character is the first of a new line
}
}
- if( character.mStyledText.mStyle.IsUnderlineEnabled() )
+ if( style.IsUnderlineEnabled() )
{
if( textUnderlineStatus.mCurrentUnderlineStatus )
{
const float positionOffset = ( underlineInfo.mMaxHeight - character.mSize.height ) - bearingOffset;
// Sets the underline's parameters.
- character.mStyledText.mStyle.SetUnderline( true, underlineInfo.mMaxThickness, underlineInfo.mPosition - positionOffset );
+ style.SetUnderline( true, underlineInfo.mMaxThickness, underlineInfo.mPosition - positionOffset );
// Mark the character to be set the new style into the text-actor.
character.mSetStyle = true;
{
TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphLayoutIt );
- for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = paragraphLayoutInfo.mWordsLayoutInfo.begin(),
- endWordLayoutIt = paragraphLayoutInfo.mWordsLayoutInfo.end();
+ // Retrieve the layout info to traverse. If there is right to left text it retrieves the right to left layout.
+ const bool isRightToLeftLayout = NULL != paragraphLayoutInfo.mRightToLeftLayout;
+ TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayoutInfo.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayoutInfo.mWordsLayoutInfo;
+
+ for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordsLayoutInfo.begin(),
+ endWordLayoutIt = wordsLayoutInfo.end();
wordLayoutIt != endWordLayoutIt;
++wordLayoutIt )
{
*/
// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/alignment/alignment.h>
+#include <dali-toolkit/public-api/controls/text-view/text-view.h>
#include <dali-toolkit/internal/controls/text-view/text-view-impl.h>
-#include <dali-toolkit/internal/controls/text-view/text-view-processor-types.h>
namespace Dali
{
LineLayoutInfo& layoutInfo );
/**
+ * Reorders the text layout of each line of each paragraph of the text.
+ *
+ * @param[in,out] relayoutData The text-view's data structures.
+ */
+void ReorderRightToLeftLayout( TextView::RelayoutData& relayoutData );
+
+/**
* Calculates the \e x offset position for the whole text.
*
* @param[in] horizontalTextAlignment The horizontal alignment type.
*
* @param[in] layoutParameters The layout parameters.
* @param[in] characterLayoutInfo Character layout info.
+ * @param[in] style The style of the character. Used to get the color (and alpha) of the character.
* @param[in,out] relayoutParameters Temporary layout parameters.
* @param[in,out] fadeParameters Temporary fade parameters.
* @param[in,out] relayoutData The text-view's data structures.
*/
void CalculateVisibilityForFade( const Internal::TextView::LayoutParameters& layoutParameters,
TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
+ const TextStyle& style,
RelayoutParameters& relayoutParameters,
FadeParameters& fadeParameters,
TextView::RelayoutData& relayoutData );
TextView::RelayoutData& relayoutData );
/**
+ * Replace the text which exceeds the boundary by the ellipsis text.
*
+ * @param[in] layoutParameters The layout parameters.
+ * @param[in,out] ellipsisParameters Temporary ellipsis parameters.
+ * @param[in,out] relayoutData The text-view's data structures.
*/
void EllipsizeLine( const TextView::LayoutParameters& layoutParameters,
EllipsizeParameters& ellipsizeParameters,
1.f, // Shrink factor
subLineInfo );
- // Stores some info to calculate the line justification in a post-process.
- TextView::LineJustificationInfo justificationInfo;
-
- justificationInfo.mIndices = relayoutParameters.mIndices;
- justificationInfo.mLineLength = subLineInfo.mLineLength;
-
- relayoutData.mLineJustificationInfo.push_back( justificationInfo );
-
Toolkit::TextView::LineLayoutInfo lineInfo;
lineInfo.mCharacterGlobalIndex = relayoutParameters.mCharacterGlobalIndex; // Index to the first character of the next line.
lineInfo.mSize = Size( subLineInfo.mLineLength, subLineInfo.mMaxCharHeight ); // Size of this piece of paragraph.
{
if( relayoutOperationMask & TextView::RELAYOUT_SIZE_POSITION )
{
- relayoutData.mLineJustificationInfo.clear();
CalculateSizeAndPosition( layoutParameters,
relayoutData );
+ TextViewRelayout::ReorderRightToLeftLayout( relayoutData );
+
TextViewRelayout::SetUnderlineInfo( relayoutData );
}
1.f, // Shrink factor
subLineInfo );
- // Stores some info to calculate the line justification in a post-process.
- TextView::LineJustificationInfo justificationInfo;
-
- justificationInfo.mIndices = relayoutParameters.mIndices;
- justificationInfo.mLineLength = subLineInfo.mLineLength;
-
- relayoutData.mLineJustificationInfo.push_back( justificationInfo );
-
Toolkit::TextView::LineLayoutInfo lineInfo;
lineInfo.mCharacterGlobalIndex = relayoutParameters.mCharacterGlobalIndex; // Index to the first character of the next line.
lineInfo.mSize = Size( subLineInfo.mLineLength, subLineInfo.mMaxCharHeight ); // Size of this piece of paragraph.
relayoutParameters.mWordSize = wordLayoutInfo.mSize;
relayoutParameters.mIndices.mCharacterIndex = 0u;
- if( relayoutParameters.mIsNewLine )
- {
- // Stores some info to calculate the line justification in a post-process.
- const bool isSplitOriginal = layoutParameters.mExceedPolicy == TextView::SplitOriginal;
-
- if( !isSplitOriginal )
- {
- TextView::LineJustificationInfo justificationInfo;
-
- justificationInfo.mIndices = relayoutParameters.mIndices;
- justificationInfo.mLineLength = relayoutParameters.mParagraphSize.width;
-
- relayoutData.mLineJustificationInfo.push_back( justificationInfo );
- }
- }
-
for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
characterLayoutIt != endCharacterLayoutIt;
{
if( relayoutOperationMask & TextView::RELAYOUT_SIZE_POSITION )
{
- relayoutData.mLineJustificationInfo.clear();
CalculateSizeAndPosition( layoutParameters,
relayoutData );
+ TextViewRelayout::ReorderRightToLeftLayout( relayoutData );
+
TextViewRelayout::SetUnderlineInfo( relayoutData );
}
}
}
- // Stores some info to calculate the line justification in a post-process.
- TextView::LineJustificationInfo justificationInfo;
-
- justificationInfo.mIndices = relayoutParameters.mIndices;
- justificationInfo.mLineLength = subLineInfo.mLineLength;
-
- relayoutData.mLineJustificationInfo.push_back( justificationInfo );
-
Toolkit::TextView::LineLayoutInfo lineInfo;
lineInfo.mCharacterGlobalIndex = relayoutParameters.mCharacterGlobalIndex; // Index to the first character of the next line.
lineInfo.mSize = Size( subLineInfo.mLineLength, subLineInfo.mMaxCharHeight ); // Size of this piece of paragraph.
1.f, // Shrink factor.
subLineInfo );
- // Stores some info to calculate the line justification in a post-process.
- TextView::LineJustificationInfo justificationInfo;
-
- justificationInfo.mIndices = relayoutParameters.mIndices;
- justificationInfo.mLineLength = subLineInfo.mLineLength;
-
- relayoutData.mLineJustificationInfo.push_back( justificationInfo );
-
Toolkit::TextView::LineLayoutInfo lineInfo;
lineInfo.mCharacterGlobalIndex = relayoutParameters.mCharacterGlobalIndex; // Index to the first character of the next line.
lineInfo.mSize = Size( subLineInfo.mLineLength, subLineInfo.mMaxCharHeight ); // Size of this piece of paragraph.
relayoutData.mShrinkFactor,
subLineInfo );
- // Stores some info to calculate the line justification in a post-process.
- TextView::LineJustificationInfo justificationInfo;
-
- justificationInfo.mIndices = relayoutParameters.mIndices;
- justificationInfo.mLineLength = subLineInfo.mLineLength;
-
- relayoutData.mLineJustificationInfo.push_back( justificationInfo );
-
Toolkit::TextView::LineLayoutInfo lineInfo;
lineInfo.mCharacterGlobalIndex = relayoutParameters.mCharacterGlobalIndex; // Index to the first character of the next line.
lineInfo.mSize = Size( subLineInfo.mLineLength, subLineInfo.mMaxCharHeight ); // Size of this piece of paragraph.
const float parentWidth = relayoutData.mTextViewSize.width;
TextViewProcessor::TextLayoutInfo& textLayoutInfo = relayoutData.mTextLayoutInfo;
- relayoutData.mLineJustificationInfo.clear();
-
// Reset the text height. This value is returned in order to shrink further or not the text.
newTextHeight = 0.f;
lineInfo.mSize = Size( subLineInfo.mLineLength, subLineInfo.mMaxCharHeight ); // Size of this piece of paragraph.
lineInfo.mAscender = subLineInfo.mMaxAscender; // Ascender of this piece of paragraph.
relayoutData.mLines.push_back( lineInfo );
-
- // Stores some info to calculate the line justification in a post-process.
- TextView::LineJustificationInfo justificationInfo;
-
- justificationInfo.mIndices = indices;
- justificationInfo.mLineLength = subLineInfo.mLineLength;
-
- relayoutData.mLineJustificationInfo.push_back( justificationInfo );
}
else
{
{
if( relayoutOperationMask & TextView::RELAYOUT_SIZE_POSITION )
{
- relayoutData.mLineJustificationInfo.clear();
CalculateSizeAndPosition( layoutParameters,
relayoutData );
+ TextViewRelayout::ReorderRightToLeftLayout( relayoutData );
+
TextViewRelayout::SetUnderlineInfo( relayoutData );
}
--- /dev/null
+/*
+ * Copyright (c) 2014 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// FILE HEADER
+#include <dali-toolkit/internal/controls/text-view/text-processor-bidirectional-info.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace TextProcessor
+{
+
+BidirectionalParagraphInfo::BidirectionalParagraphInfo()
+: mDirection( FRIBIDI_TYPE_ON ),
+ mCharactersTypeBuffer(),
+ mLevelsBuffer(),
+ mLogicalUnicodeBuffer()
+{
+}
+
+BidirectionalParagraphInfo::~BidirectionalParagraphInfo()
+{
+}
+
+BidirectionalParagraphInfo::BidirectionalParagraphInfo( const BidirectionalParagraphInfo& info )
+: mDirection( info.mDirection ),
+ mCharactersTypeBuffer( info.mCharactersTypeBuffer ),
+ mLevelsBuffer( info.mLevelsBuffer ),
+ mLogicalUnicodeBuffer( info.mLogicalUnicodeBuffer )
+{
+}
+
+BidirectionalParagraphInfo& BidirectionalParagraphInfo::operator=( const BidirectionalParagraphInfo& info )
+{
+ if( this != &info )
+ {
+ mDirection = info.mDirection;
+ mCharactersTypeBuffer = info.mCharactersTypeBuffer;
+ mLevelsBuffer = info.mLevelsBuffer;
+ mLogicalUnicodeBuffer = info.mLogicalUnicodeBuffer;
+ }
+
+ return *this;
+}
+
+BidirectionalLineInfo::BidirectionalLineInfo()
+: mCharacterParagraphIndex(),
+ mNumberOfCharacters(),
+ mText(),
+ mVisualToLogicalMap(),
+ mLogicalToVisualMap()
+{
+}
+
+BidirectionalLineInfo::~BidirectionalLineInfo()
+{
+}
+
+BidirectionalLineInfo::BidirectionalLineInfo( const BidirectionalLineInfo& info )
+: mCharacterParagraphIndex( info.mCharacterParagraphIndex ),
+ mNumberOfCharacters( info.mNumberOfCharacters ),
+ mText( info.mText ),
+ mVisualToLogicalMap( info.mVisualToLogicalMap ),
+ mLogicalToVisualMap( info.mLogicalToVisualMap )
+{
+}
+
+BidirectionalLineInfo& BidirectionalLineInfo::operator=( const BidirectionalLineInfo& info )
+{
+ if( this != &info )
+ {
+ mCharacterParagraphIndex = info.mCharacterParagraphIndex;
+ mNumberOfCharacters = info.mNumberOfCharacters;
+ mText = info.mText;
+ mVisualToLogicalMap = info.mVisualToLogicalMap;
+ mLogicalToVisualMap = info.mLogicalToVisualMap;
+ }
+
+ return *this;
+}
+
+bool BeginsRightToLeftCharacter( const Text& text )
+{
+ for( size_t i = 0u, length = text.GetLength(); i < length; ++i )
+ {
+ Character::CharacterDirection direction = text[i].GetCharacterDirection();
+ if( direction != Character::Neutral )
+ {
+ return ( direction == Character::RightToLeft || direction == Character::RightToLeftWeak );
+ }
+ }
+
+ return false;
+}
+
+bool ContainsRightToLeftCharacter( const Dali::Text& text )
+{
+ for( size_t i = 0u, length = text.GetLength(); i < length; ++i )
+ {
+ Character::CharacterDirection direction = ( text[i] ).GetCharacterDirection();
+ if( ( Character::RightToLeft == direction ) || ( Character::RightToLeftWeak == direction ) )
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void ProcessBidirectionalText( Text& paragraph, BidirectionalParagraphInfo* info )
+{
+ if( paragraph.IsEmpty() )
+ {
+ // nothing to do if the paragraph is empty.
+ return;
+ }
+
+ const std::size_t stringSize = paragraph.GetText().size();
+
+ // Text buffer in logical order. Coded in unicode.
+ info->mLogicalUnicodeBuffer.resize( stringSize + 1u, 0u );
+ FriBidiChar* logicalUnicodeBufferPointer = &info->mLogicalUnicodeBuffer[0u];
+
+ // Converts from utf8 to unicode.
+ const std::size_t length = fribidi_charset_to_unicode( FRIBIDI_CHAR_SET_UTF8, paragraph.GetText().c_str(), stringSize, logicalUnicodeBufferPointer );
+
+ // Character type buffer.
+ info->mCharactersTypeBuffer.resize( length, 0u );
+
+ // Levels buffer.
+ info->mLevelsBuffer.resize( length, 0u );
+
+ // Joining type buffer.
+ std::vector<FriBidiJoiningType> joiningTypeBuffer;
+ joiningTypeBuffer.resize( length, 0u );
+
+ // Pointers to the buffers.
+ FriBidiCharType* charactersTypeBufferPointer = &info->mCharactersTypeBuffer[0u];
+ FriBidiLevel* levelsBufferPointer = &info->mLevelsBuffer[0u];
+ FriBidiJoiningType* joiningTypeBufferPointer = &joiningTypeBuffer[0u];
+
+ // Retrieves the type of each character.
+ fribidi_get_bidi_types( logicalUnicodeBufferPointer, length, charactersTypeBufferPointer );
+
+ // Retrieves the paragraph direction.
+ info->mDirection = fribidi_get_par_direction( charactersTypeBufferPointer, length );
+
+ // Retrieve the embedding levels.
+ fribidi_get_par_embedding_levels( charactersTypeBufferPointer, length, &info->mDirection, levelsBufferPointer );
+
+ // Retrieve the joining types.
+ fribidi_get_joining_types( logicalUnicodeBufferPointer, length, joiningTypeBufferPointer );
+
+ fribidi_join_arabic( charactersTypeBufferPointer, length, levelsBufferPointer, joiningTypeBufferPointer );
+
+ const FriBidiFlags flags = FRIBIDI_FLAGS_DEFAULT | FRIBIDI_FLAGS_ARABIC;
+
+ fribidi_shape( flags, levelsBufferPointer, length, joiningTypeBufferPointer, logicalUnicodeBufferPointer );
+
+ std::vector<char> bidiTextConverted;
+
+ bidiTextConverted.resize( length * 4u + 1u ); // Maximum bytes to represent one UTF-8 character is 6.
+ // Currently Dali doesn't support this UTF-8 extension. Dali only supports 'regular' UTF-8 which has a maximum of 4 bytes per character.
+
+ fribidi_unicode_to_charset( FRIBIDI_CHAR_SET_UTF8, logicalUnicodeBufferPointer, length, &bidiTextConverted[0] );
+
+ paragraph = Text( &bidiTextConverted[0u] );
+}
+
+void ReorderLine( BidirectionalParagraphInfo* paragraphInfo,
+ BidirectionalLineInfo* lineInfo )
+{
+ const FriBidiFlags flags = FRIBIDI_FLAGS_DEFAULT | FRIBIDI_FLAGS_ARABIC;
+
+ lineInfo->mVisualToLogicalMap.Resize( lineInfo->mNumberOfCharacters, 0u );
+ lineInfo->mLogicalToVisualMap.Resize( lineInfo->mNumberOfCharacters, 0u );
+
+ std::vector<FriBidiChar> visualUnicodeBuffer;
+ visualUnicodeBuffer.insert( visualUnicodeBuffer.end(),
+ paragraphInfo->mLogicalUnicodeBuffer.begin() + lineInfo->mCharacterParagraphIndex,
+ paragraphInfo->mLogicalUnicodeBuffer.begin() + ( lineInfo->mCharacterParagraphIndex + lineInfo->mNumberOfCharacters ) );
+
+ // Pointers to the buffers.
+ FriBidiCharType* charactersTypeBufferPointer = ¶graphInfo->mCharactersTypeBuffer[lineInfo->mCharacterParagraphIndex];
+ FriBidiLevel* levelsBufferPointer = ¶graphInfo->mLevelsBuffer[lineInfo->mCharacterParagraphIndex];
+ FriBidiChar* visualUnicodeBufferPointer = &visualUnicodeBuffer[0u];
+ FriBidiStrIndex* visualToLogicalMapPointer = &lineInfo->mVisualToLogicalMap[0u];
+
+ // Initialize the visual to logical mapping table to the identity. Otherwise fribidi_reorder_line fails to retrieve a valid mapping table.
+ for( std::size_t index = 0u; index < lineInfo->mNumberOfCharacters; ++index )
+ {
+ lineInfo->mVisualToLogicalMap[ index ] = index;
+ }
+
+ fribidi_reorder_line( flags,
+ charactersTypeBufferPointer,
+ lineInfo->mNumberOfCharacters,
+ 0u,
+ paragraphInfo->mDirection,
+ levelsBufferPointer,
+ visualUnicodeBufferPointer,
+ visualToLogicalMapPointer );
+
+ // Fill the logical to visual mapping table.
+ for( std::size_t index = 0u; index < lineInfo->mNumberOfCharacters; ++index )
+ {
+ lineInfo->mLogicalToVisualMap[ lineInfo->mVisualToLogicalMap[ index ] ] = index;
+ }
+
+ std::vector<char> bidiTextConverted;
+
+ bidiTextConverted.resize( lineInfo->mNumberOfCharacters * 4u + 1u ); // Maximum bytes to represent one UTF-8 character is 6.
+ // Currently Dali doesn't support this UTF-8 extension.
+ // Dali only supports 'regular' UTF-8 which has a maximum of 4 bytes per character.
+
+ fribidi_unicode_to_charset( FRIBIDI_CHAR_SET_UTF8, visualUnicodeBufferPointer, lineInfo->mNumberOfCharacters, &bidiTextConverted[0u] );
+
+ lineInfo->mText = Text( &bidiTextConverted[0u] );
+}
+
+} // namespace TextProcessor
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
--- /dev/null
+#ifndef __DALI_TOOLKIT_TEXT_PROCESSOR_BIDIRECTIONAL_INFO_H__
+#define __DALI_TOOLKIT_TEXT_PROCESSOR_BIDIRECTIONAL_INFO_H__
+
+/*
+ * Copyright (c) 2014 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/text/text.h>
+
+// EXTERNAL INCLUDES
+#include <fribidi/fribidi.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace TextProcessor
+{
+
+/**
+ * Stores the text containing right to left characters and info for each character needed by fribidi to reorder a line.
+ */
+struct BidirectionalParagraphInfo
+{
+ /**
+ * Default constructor.
+ *
+ * Initializes all members to their default values.
+ */
+ BidirectionalParagraphInfo();
+
+ /**
+ * Default destructor.
+ */
+ ~BidirectionalParagraphInfo();
+
+ /**
+ * Copy constructor.
+ */
+ BidirectionalParagraphInfo( const BidirectionalParagraphInfo& info );
+
+ /**
+ * Assignment operator.
+ */
+ BidirectionalParagraphInfo& operator=( const BidirectionalParagraphInfo& info );
+
+ FriBidiParType mDirection; ///< The paragraph direction.
+ std::vector<FriBidiCharType> mCharactersTypeBuffer; ///< Character type buffer.
+ std::vector<FriBidiLevel> mLevelsBuffer; ///< Levels buffer.
+ std::vector<FriBidiChar> mLogicalUnicodeBuffer; ///< Text buffer in logical order. Coded in unicode.
+};
+
+/**
+ * Stores the reordered text, the conversion tables for a paragraph's line,
+ * the index to the first character of the line and the number of characters.
+ */
+struct BidirectionalLineInfo
+{
+ /**
+ * Default constructor.
+ *
+ * Initializes all members to their default values.
+ */
+ BidirectionalLineInfo();
+
+ /**
+ * Default destructor.
+ */
+ ~BidirectionalLineInfo();
+
+ /**
+ * Copy constructor.
+ */
+ BidirectionalLineInfo( const BidirectionalLineInfo& info );
+
+ /**
+ * Assignment operator.
+ */
+ BidirectionalLineInfo& operator=( const BidirectionalLineInfo& info );
+
+ std::size_t mCharacterParagraphIndex; ///< Index within the paragraph of the first character of the line.
+ std::size_t mNumberOfCharacters; ///< Number of characters of the line.
+ Text mText; ///< Text in visual order.
+ Vector<int> mVisualToLogicalMap; ///< The character position map from the visual output text to the logical input text.
+ Vector<int> mLogicalToVisualMap; ///< The character position map from the logical input text to the visual output text.
+};
+
+/**
+ * Whether the text begins with right-to-left (bidirectional) character.
+ * @param [in] text The given text.
+ * @return \e true if the text begins right-to-left character.
+ */
+bool BeginsRightToLeftCharacter( const Text& text );
+
+/**
+ * Whether the text contains any right-to-left (bidirectional) character.
+ * @param [in] text The given text.
+ * @return \e true if the text contains right-to-left character.
+ */
+bool ContainsRightToLeftCharacter( const Text& text );
+
+/**
+ * Processes a bidirectional paragraph's text.
+ *
+ * It stores the paragraph's direction (the direction of the first non neutral character),
+ * the direction of all characters, and the ligatures in case of arabic glyphs.
+ *
+ * It doesn't reorder the paragraph as this task must be done per line.
+ * The stored info is needed to reorder each line of the paragraph.
+ *
+ * @param[in] paragraph The paragraph to be processed.
+ * @param[out] info Struct containing the needed info to reorder each line of the paragraph.
+ */
+void ProcessBidirectionalText( Text& paragraph,
+ BidirectionalParagraphInfo* info );
+
+/**
+ * Reorders one line of the paragraph according the Unicode Bidirectional Algorithm.
+ *
+ * The result is the text in the visual order and the conversion tables: logical <--> visual order
+ *
+ * @param[in] paragraphInfo Struct containing the needed info to reorder each line of the paragraph.
+ * @param[in,out] lineInfo Struct containing (in) A character index pointing the first character of the line and the number of characters, (out) the reordered line and the conversion tables.
+ */
+void ReorderLine( BidirectionalParagraphInfo* paragraphInfo,
+ BidirectionalLineInfo* lineInfo );
+
+} // namespace TextProcessor
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // __DALI_TOOLKIT_TEXT_PROCESSOR_BIDIRECTIONAL_INFO_H__
+
// FILE HEADER
#include <dali-toolkit/internal/controls/text-view/text-processor.h>
-// EXTERNAL INCLUDES
-#include <fribidi/fribidi.h>
-
namespace Dali
{
namespace TextProcessor
{
-void SplitInParagraphs( const MarkupProcessor::StyledTextArray& text,
- std::vector<MarkupProcessor::StyledTextArray>& paragraphs )
+void SplitInParagraphs( const MarkupProcessor::StyledTextArray& styledTextArray,
+ std::vector<Text>& paragraphs,
+ std::vector< Vector<TextStyle*> >& styles )
{
- MarkupProcessor::StyledTextArray paragraph;
- for( MarkupProcessor::StyledTextArray::const_iterator it = text.begin(), endIt = text.end(); it != endIt; ++it )
+ // Stores the text for a paragraph.
+ Text paragraph;
+
+ // Stores the styles for each character of the paragraph.
+ Vector<TextStyle*> stylesForParagraph;
+
+ // Traverses all styled texts of the array.
+ for( MarkupProcessor::StyledTextArray::const_iterator it = styledTextArray.begin(), endIt = styledTextArray.end(); it != endIt; ++it )
{
const MarkupProcessor::StyledText& styledText( *it );
+ // Traverses all the characters of the styled text (It may have more than one).
for( size_t i = 0u, length = styledText.mText.GetLength(); i < length; ++i )
{
const Dali::Character character = styledText.mText[i];
if( character.IsNewLine() ) // LF
{
- Text newText( character );
- MarkupProcessor::StyledText newStyledText( newText, styledText.mStyle );
- paragraph.push_back( newStyledText );
+ // The character is a new paragraph character.
- paragraphs.push_back( paragraph );
- paragraph.clear();
- }
- else
- {
- Text newText( character );
- MarkupProcessor::StyledText newStyledText( newText, styledText.mStyle );
- paragraph.push_back( newStyledText );
- }
- }
- }
+ // Append the new paragraph character.
+ paragraph.Append( character );
- // This paragraph could be empty if the last character of the previous paragraph is a 'new paragraph' character
- // and is the last of the text.
- paragraphs.push_back( paragraph );
-}
+ // Creates a new text style for the character and insert it to the vector of styles for that paragraph.
+ TextStyle* style = new TextStyle( styledText.mStyle );
+ stylesForParagraph.PushBack( style );
-void SplitInWords( const MarkupProcessor::StyledTextArray& paragraph,
- std::vector<MarkupProcessor::StyledTextArray>& words )
-{
- MarkupProcessor::StyledTextArray word;
- for( MarkupProcessor::StyledTextArray::const_iterator it = paragraph.begin(), endIt = paragraph.end(); it != endIt; ++it )
- {
- const MarkupProcessor::StyledText& styledText( *it );
- const Dali::Character character = styledText.mText[0u];
+ // Inserts the paragraph and the styles to the vector of paragraphs and the vector of styles.
+ paragraphs.push_back( paragraph );
+ styles.push_back( stylesForParagraph );
- if( character.IsWhiteSpace() )
- {
- // When a separator is found, the previous word is added to the list,
- // then a new word is initialized and the separator is also added as a word.
- if( !word.empty() )
- {
- words.push_back( word );
- word.clear(); // initializes a new word.
+ // Clears the text and the vector of styles for the next paragraph.
+ paragraph = Text();
+ stylesForParagraph.Clear();
}
-
- // Separator added as a word.
- MarkupProcessor::StyledText separatorChar;
- separatorChar.mText.Append( character );
- separatorChar.mStyle = styledText.mStyle;
-
- MarkupProcessor::StyledTextArray separatorWord;
- separatorWord.push_back( separatorChar );
-
- words.push_back( separatorWord );
- }
- else
- {
- MarkupProcessor::StyledText styledChar;
- styledChar.mStyle = styledText.mStyle;
- styledChar.mText.Append( character );
-
- // Add the character to the current word.
- word.push_back( styledChar );
- }
- }
-
- //Finally the last word need to be added.
- if( !word.empty() )
- {
- words.push_back( word );
- }
-}
-
-bool BeginsRightToLeftCharacter( const MarkupProcessor::StyledTextArray& styledText )
-{
- for( MarkupProcessor::StyledTextArray::const_iterator it = styledText.begin(), endIt = styledText.end(); it != endIt; ++it )
- {
- const Text& text( (*it).mText );
-
- for( size_t i = 0u, length = text.GetLength(); i < length; ++i )
- {
- Character::CharacterDirection direction = text[i].GetCharacterDirection();
- if( direction != Character::Neutral )
+ else
{
- return ( direction == Character::RightToLeft || direction == Character::RightToLeftWeak );
- }
- }
- }
+ // The character is not a new paragraph character.
- return false;
-}
+ // Append it to the paragraph's text
+ paragraph.Append( character );
-bool BeginsRightToLeftCharacter( const Text& text )
-{
- for( size_t i = 0u, length = text.GetLength(); i < length; ++i )
- {
- Character::CharacterDirection direction = text[i].GetCharacterDirection();
- if( direction != Character::Neutral )
- {
- return ( direction == Character::RightToLeft || direction == Character::RightToLeftWeak );
- }
- }
-
- return false;
-}
-
-bool ContainsRightToLeftCharacter( const MarkupProcessor::StyledTextArray& styledText )
-{
- for( MarkupProcessor::StyledTextArray::const_iterator it = styledText.begin(), endIt = styledText.end(); it != endIt; ++it )
- {
- const Text& text( (*it).mText );
-
- for( size_t i = 0u, length = text.GetLength(); i < length; ++i )
- {
- Character::CharacterDirection direction = text[i].GetCharacterDirection();
- if( ( Character::RightToLeft == direction ) || ( Character::RightToLeftWeak == direction ) )
- {
- return true;
+ // Add the style to the vector of styles for that paragraph.
+ TextStyle* style = new TextStyle( styledText.mStyle );
+ stylesForParagraph.PushBack( style );
}
}
}
- return false;
-}
-
-bool ContainsRightToLeftCharacter( const Dali::Text& text )
-{
- for( size_t i = 0u, length = text.GetLength(); i < length; ++i )
- {
- Character::CharacterDirection direction = ( text[i] ).GetCharacterDirection();
- if( ( Character::RightToLeft == direction ) || ( Character::RightToLeftWeak == direction ) )
- {
- return true;
- }
- }
-
- return false;
+ // This paragraph could be empty if the last character of the previous paragraph is a 'new paragraph' character
+ // and is the last of the text.
+ paragraphs.push_back( paragraph );
+ styles.push_back( stylesForParagraph );
}
-void ConvertBidirectionalText( const MarkupProcessor::StyledTextArray& line,
- MarkupProcessor::StyledTextArray& convertedText,
- std::vector<int>& logicalToVisualMap,
- std::vector<int>& visualToLogicalMap )
+void SplitInWords( const Dali::Text& paragraph,
+ Vector<std::size_t>& positions )
{
- // Clean vectors first. This function doesn't use any previous value.
- logicalToVisualMap.clear();
- visualToLogicalMap.clear();
- convertedText.clear();
-
- if( line.empty() )
- {
- // nothing to do if the line is empty.
- return;
- }
-
- // Get the plain text from the line to be reordered by the BiDirectional algorithm.
- std::string textToBeConverted;
- GetPlainString( line, textToBeConverted );
-
- const std::size_t stringSize = textToBeConverted.size();
-
- std::vector<FriBidiChar> logicalStrBuffer;
- std::vector<FriBidiChar> visualStrBuffer;
- // unicode length <= UTF-8 length in bytes (reserve one extra for terminator)
- // pad these buffers with 0's, as it's unclear what fribidi_log2vis does w.r.t.
- // the length of it's output content (appears the same as input content, and does
- // not seem to generate bidi marks i.e. FRIBIDI_CHAR_LRM/FRIBIDI_CHAR_RLM)
- logicalStrBuffer.resize( stringSize+1u, 0u );
- visualStrBuffer.resize( stringSize+1u, 0u );
- FriBidiChar *logicalStr( &logicalStrBuffer[0u] );
- FriBidiChar *visualStr( &visualStrBuffer[0u] );
-
- // Convert UTF-8 string to unicode string
- const std::size_t length = fribidi_charset_to_unicode( FRIBIDI_CHAR_SET_UTF8, textToBeConverted.c_str(), stringSize, logicalStr );
-
- if( 0u == length )
- {
- DALI_ASSERT_DEBUG( !"TextProcessor::ConvertBidirectionalText. Error when calling at fribidi_charset_to_unicode" );
-
- return;
- }
-
- logicalToVisualMap.resize( length );
- visualToLogicalMap.resize( length );
+ const std::size_t length = paragraph.GetLength();
- // Convert and reorder the string as specified by the Unicode Bidirectional Algorithm
- FriBidiCharType baseDirection = FRIBIDI_TYPE_ON;
- fribidi_boolean log2vis = fribidi_log2vis( logicalStr, length, &baseDirection, visualStr, &logicalToVisualMap[0u], &visualToLogicalMap[0u], NULL );
+ // Magic number: Let's soupose there is ~6 characters per word. Used to do less memory reallocation inside Vector.
+ const size_t magicNumberOfWords = ( length / 6u ) + 1u;
- if(log2vis)
- {
- // Convert the unicode string back to the UTF-8 string
- std::vector<char> bidiTextConverted;
-
- bidiTextConverted.resize( length * 4u + 1u ); // Maximum bytes to represent one UTF-8 character is 6.
- // Currently Dali doesn't support this UTF-8 extension. Dali only supports 'regular' UTF-8 which has a maximum of 4 bytes per character.
-
- fribidi_unicode_to_charset( FRIBIDI_CHAR_SET_UTF8, visualStr, length, &bidiTextConverted[0u] );
-
- textToBeConverted = &bidiTextConverted[0u];
-
- // After reorder the text, rebuild the text with the original styles is needed.
- // To assign the original style is needed to use the characterLogicalToVisualMap table.
- Text text( &bidiTextConverted[0u] );
-
- // Split the line in words.
- // Add the correct styles for the characters after they are reordered.
+ // Find the positions of the new paragraph characters.
+ positions.Reserve( magicNumberOfWords );
- for( size_t i = 0u; i < length; ++i )
- {
- const Character character( text[i] );
-
- MarkupProcessor::StyledText styledText;
- styledText.mText.Append( character );
- styledText.mStyle = line[visualToLogicalMap[i]].mStyle;
-
- convertedText.push_back( styledText );
- }
- }
+ // Find the position of all white spaces. A new paragraph character is also considered a white space but it doesn't matter at this point.
+ paragraph.Find( Text::WHITE_SPACE, 0u, length - 1u, positions );
}
/**
DALI_ASSERT_DEBUG( offset < text.size() );
// assume 1 Character per StyledText
- return text[offset].mText[0u].IsWhiteSpace();
+ return ( *( text.begin() + offset ) ).mText[0u].IsWhiteSpace();
}
void FindNearestWord( const MarkupProcessor::StyledTextArray& text, size_t offset, size_t& start, size_t& end)
namespace TextProcessor
{
+// Forward declarations.
+struct BidirectionalParagraphInfo;
/**
* Splits the given text in paragraphs.
* @note Assumes the StyledTextArray has 1 Character per Text element. (which is the case for text in TextInput, but
* not necessarily the case for text in TextView)
*
- * @param [in] text The given text.
+ * @param [in] styledTextArray The given text.
* @param [out] paragraphs The text split in paragraphs.
+ * @param [out] styles The styles of each character of each paragraph.
*/
-void SplitInParagraphs( const MarkupProcessor::StyledTextArray& text,
- std::vector<MarkupProcessor::StyledTextArray>& paragraphs );
+void SplitInParagraphs( const MarkupProcessor::StyledTextArray& styledTextArray,
+ std::vector<Text>& paragraphs,
+ std::vector< Vector<TextStyle*> >& styles );
/**
- * Splits the given paragraph in words.
- *
- * @note Assumes the StyledTextArray has 1 Character per Text element. (which is the case for text in TextInput, but
- * not necessarily the case for text in TextView)
+ * Finds the position of all word separators (currently white spaces and new paragraph characters '\n') in the given text.
*
* @param [in] paragraph The given paragraph.
- * @param [out] words The paragraph split in words.
- */
-void SplitInWords( const MarkupProcessor::StyledTextArray& paragraph,
- std::vector<MarkupProcessor::StyledTextArray>& words );
-
-/**
- * Whether the text begins with right-to-left (bidirectional) character.
- * @param [in] text The given text.
- * @return \e true if the text begins right-to-left character.
- */
-bool BeginsRightToLeftCharacter( const Text& text );
-
-/**
- * @copydoc BeginsRightToLeftCharacter( const Text& text )
- */
-bool BeginsRightToLeftCharacter( const MarkupProcessor::StyledTextArray& text );
-
-/**
- * Whether the text contains any right-to-left (bidirectional) character.
- * @param [in] text The given text.
- * @return \e true if the text contains right-to-left character.
- */
-bool ContainsRightToLeftCharacter( const Text& text );
-
-/**
- * @copydoc ContainsRightToLeftCharacter( const Text& text )
- */
-bool ContainsRightToLeftCharacter( const MarkupProcessor::StyledTextArray& text );
-
-/**
- * Convert the text as specified by the Unicode Bidirectional Algorithm.
- * The text is converted only if it is bidirectional.
- * @param[in] line The line of text to be converted.
- * @param[out] convertedText The text converted.
- * @param[out] logicalToVisualMap The character position map from the logical input text to the visual output text.
- * @param[out] visualToLogicalMap The character position map from the visual output text to the logical input text.
+ * @param [out] positions Positions within the paragraph of all word sepatators.
*/
- void ConvertBidirectionalText( const MarkupProcessor::StyledTextArray& line,
- MarkupProcessor::StyledTextArray& convertedText,
- std::vector<int>& logicalToVisualMap,
- std::vector<int>& visualToLogicalMap );
+void SplitInWords( const Text& paragraph,
+ Vector<std::size_t>& positions );
/**
* Finds the nearest word in a string to a specified
mPosition(),
mOffset(),
mGlyphActor(),
- mStyledText(),
mColorAlpha( 1.f ),
mGradientInfo( NULL ),
mIsVisible( true ),
- mSetText( true ),
- mSetStyle( true ),
+ mSetText( false ),
+ mSetStyle( false ),
mIsColorGlyph( false )
{
}
mPosition( character.mPosition ),
mOffset( character.mOffset ),
mGlyphActor( character.mGlyphActor ),
- mStyledText( character.mStyledText ),
mColorAlpha( character.mColorAlpha ),
mGradientInfo( ( NULL == character.mGradientInfo ) ? NULL : new GradientInfo( *character.mGradientInfo ) ), // Copies the gradient info.
mIsVisible( character.mIsVisible ),
mOffset = character.mOffset;
mGlyphActor = character.mGlyphActor;
- mStyledText = character.mStyledText;
mColorAlpha = character.mColorAlpha;
#include <dali-toolkit/internal/controls/text-view/split-by-new-line-char-policies.h>
#include <dali-toolkit/internal/controls/text-view/split-by-word-policies.h>
#include <dali-toolkit/internal/controls/text-view/split-by-char-policies.h>
+#include <dali-toolkit/internal/controls/text-view/text-processor-bidirectional-info.h>
#include <dali-toolkit/internal/controls/text-view/text-view-processor.h>
#include <dali-toolkit/internal/controls/text-view/text-view-word-processor.h>
#include <dali-toolkit/internal/controls/text-view/relayout-utilities.h>
void TextView::InsertTextAt( std::size_t position, const MarkupProcessor::StyledTextArray& text )
{
- // Creates metadata with the Insert operation.
- TextViewProcessorMetadata metadata;
- metadata.mType = TextView::TextInserted;
- metadata.mPosition = position;
- metadata.mText = text;
+ std::string textStr;
+ MarkupProcessor::GetPlainString( text, textStr );
- // Store metadata.
- mTextViewProcessorOperations.push_back( metadata );
+ if( TextProcessor::ContainsRightToLeftCharacter( Text( textStr ) ) ||
+ TextProcessor::ContainsRightToLeftCharacter( Text( GetText() ) ) )
+ {
+ // Temporary fix. Creates the whole layout if there is rtl text.
- // Updates current styled text.
- mCurrentStyledText.insert( mCurrentStyledText.begin() + position, text.begin(), text.end() );
+ MarkupProcessor::StyledTextArray textToSet = mCurrentStyledText;
+ textToSet.insert( textToSet.begin() + position, text.begin(), text.end() );
+ SetText( textToSet );
+ }
+ else
+ {
+ // Creates metadata with the Insert operation.
+ TextViewProcessorMetadata metadata;
+ metadata.mType = TextView::TextInserted;
+ metadata.mPosition = position;
+ metadata.mText = text;
- // Request to be relaid out
- RelayoutRequest();
+ // Store metadata.
+ mTextViewProcessorOperations.push_back( metadata );
- // If a GetTextLayoutInfo() or GetHeightForWidth() arrives, relayout the text synchronously is needed on order to retrieve the right values.
- mRelayoutOperations = RELAYOUT_ALL;
+ // Updates current styled text.
+ mCurrentStyledText.insert( mCurrentStyledText.begin() + position, text.begin(), text.end() );
+
+ // Request to be relaid out
+ RelayoutRequest();
+
+ // If a GetTextLayoutInfo() or GetHeightForWidth() arrives, relayout the text synchronously is needed on order to retrieve the right values.
+ mRelayoutOperations = RELAYOUT_ALL;
+ }
}
void TextView::ReplaceTextFromTo( std::size_t position, std::size_t numberOfCharacters, const std::string& text )
}
// Sets the new style to the ellipsize text
- if( !mLayoutParameters.mEllipsizeText.empty() )
+ // TODO: fix this as a call to SetEllipsizeText will trigger the creation of new text actors.
+ if( 0u < mRelayoutData.mTextLayoutInfo.mEllipsisTextStyles.Count() )
{
- for( MarkupProcessor::StyledTextArray::iterator it = mLayoutParameters.mEllipsizeText.begin(), endIt = mLayoutParameters.mEllipsizeText.end(); it != endIt; ++it )
+ for( Vector<TextStyle*>::Iterator it = mRelayoutData.mTextLayoutInfo.mEllipsisTextStyles.Begin(),
+ endIt = mRelayoutData.mTextLayoutInfo.mEllipsisTextStyles.End();
+ it != endIt;
+ ++it )
{
- (*it).mStyle.Copy( style, mask );
+ (*it)->Copy( style, mask );
}
- SetEllipsizeText( mLayoutParameters.mEllipsizeText );
+ SetEllipsizeText( mRelayoutData.mTextLayoutInfo.mEllipsisText, mRelayoutData.mTextLayoutInfo.mEllipsisTextStyles );
}
}
MarkupProcessor::StyledTextArray styledText;
MarkupProcessor::GetStyledTextArray( ellipsizeText, styledText, IsMarkupProcessingEnabled() );
+ // Creates the ellipsis layout info and sets the text and styles.
SetEllipsizeText( styledText );
}
void TextView::SetEllipsizeText( const MarkupProcessor::StyledTextArray& ellipsizeText )
{
- mLayoutParameters.mEllipsizeText = ellipsizeText;
+ // Converts the styled text array into a Text and a vector of TextStyles.
+ Text text;
+ Vector<TextStyle*> styles;
+ for( MarkupProcessor::StyledTextArray::const_iterator it = ellipsizeText.begin(), endIt = ellipsizeText.end(); it != endIt; ++it )
+ {
+ const MarkupProcessor::StyledText& styledText( *it );
- mRelayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo = TextViewProcessor::WordLayoutInfo();
+ text.Append( styledText.mText );
+ styles.PushBack( new TextStyle( styledText.mStyle ) );
+ }
- TextViewProcessor::CreateWordTextInfo( mLayoutParameters.mEllipsizeText,
- mRelayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo );
+ // Creates the ellipsis layout info and sets the text and styles.
+ SetEllipsizeText( text, styles );
+}
+
+void TextView::SetEllipsizeText( const Text& ellipsizeText, const Vector<TextStyle*>& ellipsizeStyles )
+{
+ // Sets the text and styles for the ellipsis text.
+ mRelayoutData.mTextLayoutInfo.mEllipsisText = ellipsizeText;
+ mRelayoutData.mTextLayoutInfo.mEllipsisTextStyles = ellipsizeStyles;
+
+ // Creates the ellipsis layout info.
+ CreateEllipsizeLayout();
// Request to be relaid out
RelayoutRequest();
std::string TextView::GetEllipsizeText() const
{
- std::string text;
- for( MarkupProcessor::StyledTextArray::const_iterator it = mLayoutParameters.mEllipsizeText.begin(), endIt = mLayoutParameters.mEllipsizeText.end(); it != endIt; ++it )
- {
- text.append( (*it).mText.GetText() );
- }
-
- return text;
+ return mRelayoutData.mTextLayoutInfo.mEllipsisText.GetText();
}
void TextView::GetTextLayoutInfo()
{
mRelayoutOperations = static_cast<RelayoutOperationMask>( mRelayoutOperations | RELAYOUT_INSERT_TO_TEXT_VIEW );
}
-
}
}
}
mVerticalAlignment( Toolkit::Alignment::VerticalCenter ),
mLineJustification( Toolkit::TextView::Left ),
mLineHeightOffset( 0.f ),
- mEllipsizeText(),
mMarkUpEnabled( false )
{
- // Sets ellipsize text
- MarkupProcessor::StyledTextArray styledEllipsize;
- MarkupProcessor::GetStyledTextArray( std::string( "..." ), mEllipsizeText, false );
}
TextView::LayoutParameters::~LayoutParameters()
Toolkit::Alignment::Type alignmentType,
Toolkit::TextView::LineJustification lineJustification,
float lineHeightOffset,
- const std::string& ellipsizeText,
bool markUpEnabled )
: mMultilinePolicy( multilinePolicy ),
mWidthExceedPolicy( widthExceedPolicy ),
mVerticalAlignment(),
mLineJustification( lineJustification ),
mLineHeightOffset( lineHeightOffset ),
- mEllipsizeText(),
mMarkUpEnabled( markUpEnabled )
{
// Sets alignment
mHorizontalAlignment = horizontalAlignment;
mVerticalAlignment = verticalAlignment;
-
- // Sets ellipsize text
- MarkupProcessor::StyledTextArray styledEllipsize;
- MarkupProcessor::GetStyledTextArray( ellipsizeText, mEllipsizeText, mMarkUpEnabled );
}
TextView::LayoutParameters::LayoutParameters( const TextView::LayoutParameters& layoutParameters )
mVerticalAlignment( layoutParameters.mVerticalAlignment ),
mLineJustification( layoutParameters.mLineJustification ),
mLineHeightOffset( layoutParameters.mLineHeightOffset ),
- mEllipsizeText( layoutParameters.mEllipsizeText ),
mMarkUpEnabled( layoutParameters.mMarkUpEnabled )
{
}
mVerticalAlignment = layoutParameters.mVerticalAlignment;
mLineJustification = layoutParameters.mLineJustification;
mLineHeightOffset = layoutParameters.mLineHeightOffset;
- mEllipsizeText = layoutParameters.mEllipsizeText;
mMarkUpEnabled = layoutParameters.mMarkUpEnabled;
return *this;
static_cast<Toolkit::Alignment::Type>( Toolkit::Alignment::HorizontalCenter | Toolkit::Alignment::VerticalCenter ),
Toolkit::TextView::Left,
PointSize( 0.f ),
- std::string( "..." ),
false ),
mVisualParameters(),
mRelayoutData(),
mPreviousSnapshotModeEnabled( false ),
mMarkUpEnabled( false )
{
- TextViewProcessor::CreateWordTextInfo( mLayoutParameters.mEllipsizeText,
- mRelayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo );
+ // Creates the ellipsis layout info.
+ CreateEllipsizeLayout();
}
TextView::~TextView()
void TextView::OnFontChange( bool defaultFontChange, bool defaultFontSizeChange )
{
- mRelayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo = TextViewProcessor::WordLayoutInfo();
- TextViewProcessor::CreateWordTextInfo( mLayoutParameters.mEllipsizeText,
- mRelayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo );
+ // Creates the ellipsis layout info.
+ CreateEllipsizeLayout();
SetText( mCurrentStyledText );
}
}
}
+ if( ( Toolkit::TextView::Fade == mLayoutParameters.mWidthExceedPolicy ) ||
+ ( Toolkit::TextView::Fade == mLayoutParameters.mHeightExceedPolicy ) )
+ {
+ if( mRelayoutOperations & RELAYOUT_ALIGNMENT )
+ {
+ // If the text of the alignment changes and a fade exceed policy is set,
+ // some characters may need new TextActor.
+ mRelayoutOperations = RELAYOUT_ALL;
+ }
+ }
+
// Remove glyph-actors from text-view
if( !mRelayoutData.mGlyphActors.empty() && ( mRelayoutOperations & RELAYOUT_REMOVE_TEXT_ACTORS ) )
{
return rootActor;
}
+void TextView::CreateEllipsizeLayout()
+{
+ // Creates the ellipsis layout info for the ellipsis text and styles.
+ mRelayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo = TextViewProcessor::WordLayoutInfo();
+ mRelayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mCharactersLayoutInfo.resize( mRelayoutData.mTextLayoutInfo.mEllipsisText.GetLength(), TextViewProcessor::CharacterLayoutInfo() );
+ TextViewProcessor::CreateWordTextInfo( mRelayoutData.mTextLayoutInfo.mEllipsisText,
+ mRelayoutData.mTextLayoutInfo.mEllipsisTextStyles,
+ mRelayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo );
+}
+
void TextView::OnMarkupEnabledPeopertySet( Property::Value propertyValue )
{
bool newValue( propertyValue.Get<bool>() );
TextViewProcessorMetadataType mType; ///< Stores the type of operation.
std::size_t mPosition; ///< Character position within the text.
- std::size_t mNumberOfCharacters; ///< Number of characters to be removed/ replaced.
+ std::size_t mNumberOfCharacters; ///< Number of characters to be removed/replaced.
MarkupProcessor::StyledTextArray mText; ///< The new text.
TextStyle::Mask mStyleMask; ///< The style mask.
};
void SetEllipsizeText( const MarkupProcessor::StyledTextArray& ellipsizeText );
/**
+ * @copydoc SetEllipsizeText()
+ */
+ void SetEllipsizeText( const Text& ellipsizeText, const Vector<TextStyle*>& ellipsizeStyles );
+
+ /**
* @copydoc GetEllipsizeText()
*/
std::string GetEllipsizeText() const;
Actor GetRootActor() const;
/**
+ * Creates the ellipsize text layout.
+ */
+ void CreateEllipsizeLayout();
+
+ /**
* Handle SetProperty for markup processing.
* @param[in] propertyValue The new property value.
*/
Toolkit::Alignment::Type alignment,
Toolkit::TextView::LineJustification lineJustification,
float lineHeightOffset,
- const std::string& ellipsizeText,
bool markUpEnabled );
/**
LayoutParameters& operator=( const LayoutParameters& layoutParameters );
Toolkit::TextView::MultilinePolicy mMultilinePolicy; ///< Stores the multiline policy.
- TextView::ExceedPolicy mExceedPolicy; ///< Stores a combination of both policies;
+ TextView::ExceedPolicy mExceedPolicy; ///< Stores a combination of both policies.
Toolkit::TextView::ExceedPolicy mWidthExceedPolicy; ///< Stores the text width exceed policy.
Toolkit::TextView::ExceedPolicy mHeightExceedPolicy; ///< Stores the text height exceed policy.
Toolkit::Alignment::Type mHorizontalAlignment; ///< Stores the horizontal alignment for the whole text.
Toolkit::Alignment::Type mVerticalAlignment; ///< Stores the vertical alignment for the whole text.
Toolkit::TextView::LineJustification mLineJustification; ///< Stores the line justification.
float mLineHeightOffset; ///< Line height offset to be addded to the font line height (measured in PointSize).
- MarkupProcessor::StyledTextArray mEllipsizeText; ///< Stores the ellipsize text
- bool mMarkUpEnabled:1; ///< Is markup string scanning enabled
+ bool mMarkUpEnabled:1; ///< Is markup string scanning enabled.
};
/**
};
/**
- * Temporary data used to calculate line justification.
- */
- struct LineJustificationInfo
- {
- TextViewProcessor::TextInfoIndices mIndices; ///< Indices to the first character of the new line.
- float mLineLength; ///< Length of the line (or portion of line).
- };
-
- /**
* The results of the relayout process.
*/
struct RelayoutData
Toolkit::TextView::CharacterLayoutInfoContainer mCharacterLayoutInfoTable; ///< Stores layout info per character sorted by the character's visual index.
Toolkit::TextView::LineLayoutInfoContainer mLines; ///< Stores an index to the first character of each line.
Size mTextSizeForRelayoutOption; ///< Stores the text size after relayout.
- std::vector<LineJustificationInfo> mLineJustificationInfo; ///< Stores justification info per line.
TextActorCache mTextActorCache; ///< Stores previously created text-actors to be reused.
};
#include <dali-toolkit/internal/controls/text-view/text-view-word-processor.h>
#include <dali-toolkit/internal/controls/text-view/text-view-processor-helper-functions.h>
#include <dali-toolkit/internal/controls/text-view/text-processor.h>
+#include <dali-toolkit/internal/controls/text-view/text-processor-bidirectional-info.h>
namespace Dali
{
// Layout info.
/////////////////////
+void RightToLeftParagraphLayout::Clear()
+{
+ mWordsLayoutInfo.clear();
+ mText = Text();
+ mTextStyles.Clear();
+}
+
ParagraphLayoutInfo::ParagraphLayoutInfo()
: mSize(),
mAscender( 0.f ),
mLineHeightOffset( 0.f ),
+ mFirstCharacter( 0u ),
mNumberOfCharacters( 0u ),
- mWordsLayoutInfo()
+ mWordsLayoutInfo(),
+ mText(),
+ mTextStyles(),
+ mRightToLeftLayout( NULL ),
+ mBidirectionalParagraphInfo( NULL ),
+ mBidirectionalLinesInfo()
{
}
ParagraphLayoutInfo::~ParagraphLayoutInfo()
{
+ if( NULL != mRightToLeftLayout )
+ {
+ // TextStyle pointers are the same than the ones stored at ParagraphLayoutInfo::mTextStyles.
+ // Do not delete them, just clear the vector.
+ mRightToLeftLayout->mTextStyles.Clear();
+
+ delete mRightToLeftLayout;
+ }
+
+ // Clears text styles. It destroys TextStyle objects.
+ ClearStyles();
+
+ // Deletes the bidirectional info for the whole paragraph.
+ delete mBidirectionalParagraphInfo;
+
+ // Clears the bidirectional info for all lines. Destroys the BidirectionalLineInfo objects.
+ ClearBidirectionalInfo();
}
ParagraphLayoutInfo::ParagraphLayoutInfo( const ParagraphLayoutInfo& paragraph )
: mSize( paragraph.mSize ),
mAscender( paragraph.mAscender ),
mLineHeightOffset( paragraph.mLineHeightOffset ),
+ mFirstCharacter( paragraph.mFirstCharacter ),
mNumberOfCharacters( paragraph.mNumberOfCharacters ),
- mWordsLayoutInfo( paragraph.mWordsLayoutInfo )
+ mWordsLayoutInfo( paragraph.mWordsLayoutInfo ),
+ mText( paragraph.mText ),
+ mTextStyles(),
+ mRightToLeftLayout( NULL ),
+ // Copies bidirectional info for the whole paragraph.
+ mBidirectionalParagraphInfo( ( NULL == paragraph.mBidirectionalParagraphInfo ) ? NULL : new TextProcessor::BidirectionalParagraphInfo( *paragraph.mBidirectionalParagraphInfo ) ),
+ mBidirectionalLinesInfo()
{
+ // Copies styles.
+ for( Vector<TextStyle*>::ConstIterator it = paragraph.mTextStyles.Begin(), endIt = paragraph.mTextStyles.End(); it != endIt; ++it )
+ {
+ mTextStyles.PushBack( new TextStyle( *(*it) ) );
+ }
+
+ // Copies bidirectional info for each line.
+ for( Vector<TextProcessor::BidirectionalLineInfo*>::ConstIterator it = mBidirectionalLinesInfo.Begin(), endIt = mBidirectionalLinesInfo.End(); it != endIt; ++it )
+ {
+ mBidirectionalLinesInfo.PushBack( new TextProcessor::BidirectionalLineInfo( *( *it ) ) );
+ }
}
ParagraphLayoutInfo& ParagraphLayoutInfo::operator=( const ParagraphLayoutInfo& paragraph )
mSize = paragraph.mSize;
mAscender = paragraph.mAscender;
mLineHeightOffset = paragraph.mLineHeightOffset;
+ mFirstCharacter = paragraph.mFirstCharacter;
mNumberOfCharacters = paragraph.mNumberOfCharacters;
mWordsLayoutInfo = paragraph.mWordsLayoutInfo;
+ mText = paragraph.mText;
- return *this;
-}
+ // If it has styles, destroy them.
+ ClearStyles();
-void CreateParagraphInfo( const MarkupProcessor::StyledTextArray& paragraph,
- TextView::RelayoutData& relayoutData,
- ParagraphLayoutInfo& paragraphLayoutInfo )
-{
- // Split the paragraph in words.
- // TODO: Proper RTL support.
- MarkupProcessor::StyledTextArray convertedParagraph;
- if( TextProcessor::ContainsRightToLeftCharacter( paragraph ) )
+ // Copies styles.
+ for( Vector<TextStyle*>::ConstIterator it = paragraph.mTextStyles.Begin(), endIt = paragraph.mTextStyles.End(); it != endIt; ++it )
{
- // If the text is bidirectional, the characters will be converted and reordered
- // as specified by the Unicode Bidirectional Algorithm.
+ mTextStyles.PushBack( new TextStyle( *(*it) ) );
+ }
- // Reorders the paragraph and converts arabic glyphs (if any).
- TextProcessor::ConvertBidirectionalText( paragraph,
- convertedParagraph,
- relayoutData.mCharacterLogicalToVisualMap,
- relayoutData.mCharacterVisualToLogicalMap);
+ // Copies the paragraph's bidirectiona info.
+ if( NULL == paragraph.mBidirectionalParagraphInfo )
+ {
+ // The source doesn't have bidirectiona info. Deletes the current one.
+ delete mBidirectionalParagraphInfo;
+ mBidirectionalParagraphInfo = NULL;
}
else
{
- // No bidirectional text to process.
- convertedParagraph = paragraph;
-
- // Create trivial bidirectional map tables.
- std::size_t index = 0u;
- for( MarkupProcessor::StyledTextArray::const_iterator it = convertedParagraph.begin(), endIt = convertedParagraph.end(); it != endIt; ++it )
+ // The source has bidirectional info.
+ if( NULL != mBidirectionalParagraphInfo )
{
- const MarkupProcessor::StyledText& styledText( *it );
-
- for( std::size_t i = 0u, length = styledText.mText.GetLength(); i < length; ++i )
- {
- relayoutData.mCharacterLogicalToVisualMap.push_back( relayoutData.mTextLayoutInfo.mNumberOfCharacters + index );
- relayoutData.mCharacterVisualToLogicalMap.push_back( relayoutData.mTextLayoutInfo.mNumberOfCharacters + index );
- ++index;
- }
+ // It it has, copy to it.
+ *mBidirectionalParagraphInfo = *paragraph.mBidirectionalParagraphInfo;
+ }
+ else
+ {
+ // If it doesn't have, create a new one.
+ mBidirectionalParagraphInfo = new TextProcessor::BidirectionalParagraphInfo( *paragraph.mBidirectionalParagraphInfo );
}
}
- // Split the paragraph in words
- std::vector<MarkupProcessor::StyledTextArray> words;
- TextProcessor::SplitInWords( convertedParagraph, words );
+ // If it has bidirectiona info per line, destroy them.
+ ClearBidirectionalInfo();
- // if last word has a new paragraph separator, create a new word.
- if( !words.empty() )
+ // Copies bidirectional info per line.
+ for( Vector<TextProcessor::BidirectionalLineInfo*>::ConstIterator it = mBidirectionalLinesInfo.Begin(), endIt = mBidirectionalLinesInfo.End(); it != endIt; ++it )
{
- MarkupProcessor::StyledTextArray& word( *( words.end() - 1u ) );
- if( word.size() > 1u )
- {
- // do nothing if the word has only one character.
- MarkupProcessor::StyledText& styledText( *( word.end() - 1u ) );
- if( !styledText.mText.IsEmpty() )
- {
- const std::size_t length = styledText.mText.GetLength();
- if( styledText.mText[length-1u].IsNewLine() )
- {
- // Last character of this word is a new paragraph character.
+ mBidirectionalLinesInfo.PushBack( new TextProcessor::BidirectionalLineInfo( *( *it ) ) );
+ }
- // Remove paragraph separator character from current word.
- styledText.mText.Remove( length - 1u, 1u );
+ return *this;
+}
- // Create a new word with the paragraph separator character.
- MarkupProcessor::StyledText newParagraphText( Text( styledText.mText[length-1u] ), styledText.mStyle );
+void ParagraphLayoutInfo::ClearBidirectionalInfo()
+{
+ // Destroys the bidirectional infor per line.
+ for( Vector<TextProcessor::BidirectionalLineInfo*>::Iterator it = mBidirectionalLinesInfo.Begin(), endIt = mBidirectionalLinesInfo.End(); it != endIt; ++it )
+ {
+ delete *it;
+ }
+ mBidirectionalLinesInfo.Clear();
+}
- MarkupProcessor::StyledTextArray newParagraphWord;
- newParagraphWord.push_back( newParagraphText );
+void ParagraphLayoutInfo::ClearStyles()
+{
+ // Destroys the styles.
+ for( Vector<TextStyle*>::Iterator it = mTextStyles.Begin(), endIt = mTextStyles.End(); it != endIt; ++it )
+ {
+ delete *it;
+ }
+ mTextStyles.Clear();
+}
- words.push_back( newParagraphWord );
- }
- }
- }
+void CreateParagraphInfo( TextView::RelayoutData& relayoutData,
+ ParagraphLayoutInfo& paragraphLayoutInfo )
+{
+ if( TextProcessor::ContainsRightToLeftCharacter( paragraphLayoutInfo.mText ) )
+ {
+ // If the text is bidirectional, the characters will be converted and reordered
+ // as specified by the Unicode Bidirectional Algorithm.
+
+ paragraphLayoutInfo.mBidirectionalParagraphInfo = new TextProcessor::BidirectionalParagraphInfo();
+
+ TextProcessor::ProcessBidirectionalText( paragraphLayoutInfo.mText, paragraphLayoutInfo.mBidirectionalParagraphInfo );
}
- std::string lastCharacterFont; // Keeps the font used by the last character. It's used to set the font to a word separator.
+ // Split the paragraph in words. It retrieves the positions of white spaces and the last '\n' if there is one.
+ Vector<std::size_t> positions;
+ TextProcessor::SplitInWords( paragraphLayoutInfo.mText, positions );
- // Traverse all words.
- for( std::vector<MarkupProcessor::StyledTextArray>::const_iterator wordIt = words.begin(), wordEndIt = words.end(); wordIt != wordEndIt; ++wordIt )
- {
- const MarkupProcessor::StyledTextArray& word( *wordIt );
+ const std::size_t lastCharacterIndex = paragraphLayoutInfo.mText.GetLength() - 1u;
+ const bool isLastCharacterParagraphSeparator = paragraphLayoutInfo.mText.IsNewLine( lastCharacterIndex );
- // Data structures for the new word.
- WordLayoutInfo wordLayoutInfo;
+ // The number of words is ~the number of white spaces found + 1u.
+ // White spaces are also words.
+ // New line characters are also white spaces. If the last character is a white space the +1 is not needed.
+ const std::size_t numberOfWords = 2u * positions.Count() + ( isLastCharacterParagraphSeparator ? 0u : 1u );
- CreateWordTextInfo( word,
- wordLayoutInfo );
+ // Reserve space for all the words.
+ paragraphLayoutInfo.mWordsLayoutInfo.resize( numberOfWords, WordLayoutInfo() );
+
+ // Traverses all positions creating and setting all character layout info objects to every word.
+ std::size_t wordIndex = 0u;
+ Vector<std::size_t>::ConstIterator positionIt = positions.Begin();
+ Vector<std::size_t>::ConstIterator positionEndIt = positions.End();
+ std::size_t from = 0u;
+ for( std::size_t positionIndex = 0u, size = positions.Count() + 1u; positionIndex < size; ++positionIndex )
+ {
+ const bool isEndPosition = positionIt == positionEndIt;
+ const std::size_t to = isEndPosition ? lastCharacterIndex + 1u : *positionIt;
- // White space's size could be different depending on the type of font. It's important to use the same font than the previous character to
- // avoid 'jumps' of characters when there is a switch between one text-actor per character and one text-actor per line and/or style.
- if( WordSeparator == wordLayoutInfo.mType )
+ if( from < to )
{
- // If current word is a word separator (white space) then the font of the last character is set.
- for( CharacterLayoutInfoContainer::iterator characterIt = wordLayoutInfo.mCharactersLayoutInfo.begin(), characterEndIt = wordLayoutInfo.mCharactersLayoutInfo.end();
- characterIt != characterEndIt;
- ++characterIt )
- {
- CharacterLayoutInfo& characterLayout( *characterIt );
+ // The word is not a white space.
+ WordLayoutInfo& wordLayoutInfo = *( paragraphLayoutInfo.mWordsLayoutInfo.begin() + wordIndex );
+ ++wordIndex;
+ // Sets the index within the paragraph to the first character of the word.
+ wordLayoutInfo.mFirstCharacter = from;
+ // Creates character layout info objects.
+ wordLayoutInfo.mCharactersLayoutInfo.resize( ( to - from ), CharacterLayoutInfo() );
+ }
- characterLayout.mStyledText.mStyle.SetFontName( lastCharacterFont );
- }
+ if( !isEndPosition )
+ {
+ // Create a word for the white space.
+ WordLayoutInfo& wordLayoutInfo = *( paragraphLayoutInfo.mWordsLayoutInfo.begin() + wordIndex );
+ ++wordIndex;
+ // Sets the index within the paragraph to the white space.
+ wordLayoutInfo.mFirstCharacter = to;
+ wordLayoutInfo.mType = WordSeparator;
+
+ CharacterLayoutInfo characterLayoutInfo;
+ wordLayoutInfo.mCharactersLayoutInfo.push_back( characterLayoutInfo );
+ }
+
+ from = to + 1u;
+
+ if( !isEndPosition )
+ {
+ // next white space position.
+ ++positionIt;
}
else
{
- // kepps the font of the last character.
- if( !wordLayoutInfo.mCharactersLayoutInfo.empty() )
+ // All white space positiona have been traversed.
+ // It may be some extra words. i.e if the text is \n.
+ // Erase them.
+ paragraphLayoutInfo.mWordsLayoutInfo.erase( paragraphLayoutInfo.mWordsLayoutInfo.begin() + wordIndex, paragraphLayoutInfo.mWordsLayoutInfo.end() );
+
+ // Check if the last character is a new paragraph character.
+ if( isLastCharacterParagraphSeparator )
{
- lastCharacterFont = ( *( wordLayoutInfo.mCharactersLayoutInfo.end() - 1u ) ).mStyledText.mStyle.GetFontName();
+ ( *( paragraphLayoutInfo.mWordsLayoutInfo.end() - 1u ) ).mType = ParagraphSeparator;
}
}
+ }
- // Update the max word width figure.
- relayoutData.mTextLayoutInfo.mMaxWordWidth = std::max( relayoutData.mTextLayoutInfo.mMaxWordWidth, wordLayoutInfo.mSize.width );
+ // Traverse all words and fill the layout info.
+ for( WordLayoutInfoContainer::iterator it = paragraphLayoutInfo.mWordsLayoutInfo.begin(), endIt = paragraphLayoutInfo.mWordsLayoutInfo.end(); it != endIt; ++it )
+ {
+ WordLayoutInfo& wordLayoutInfo( *it );
+
+ CreateWordTextInfo( paragraphLayoutInfo.mText,
+ paragraphLayoutInfo.mTextStyles,
+ wordLayoutInfo );
// Update layout info for the current paragraph.
+ UpdateSize( paragraphLayoutInfo.mSize, wordLayoutInfo.mSize );
paragraphLayoutInfo.mAscender = std::max( paragraphLayoutInfo.mAscender, wordLayoutInfo.mAscender );
paragraphLayoutInfo.mNumberOfCharacters += wordLayoutInfo.mCharactersLayoutInfo.size();
- UpdateSize( paragraphLayoutInfo.mSize, wordLayoutInfo.mSize );
- // Add the word to the current paragraph.
- paragraphLayoutInfo.mWordsLayoutInfo.push_back( wordLayoutInfo );
+ // Update the max word width figure.
+ relayoutData.mTextLayoutInfo.mMaxWordWidth = std::max( relayoutData.mTextLayoutInfo.mMaxWordWidth, wordLayoutInfo.mSize.width );
} // end of words
}
void UpdateLayoutInfo( ParagraphLayoutInfo& paragraphLayoutInfo, float lineHeightOffset )
{
// Update layout info.
+
+ // Initialize members to be updated.
paragraphLayoutInfo.mSize = Size::ZERO;
paragraphLayoutInfo.mAscender = 0.f;
paragraphLayoutInfo.mNumberOfCharacters = 0u;
+
+ // Traverses all words.
for( WordLayoutInfoContainer::iterator it = paragraphLayoutInfo.mWordsLayoutInfo.begin(), endIt = paragraphLayoutInfo.mWordsLayoutInfo.end();
it != endIt;
++it )
{
WordLayoutInfo& word( *it );
+ // Sets the index within the paragraph to the first character of the word.
+ word.mFirstCharacter = paragraphLayoutInfo.mNumberOfCharacters;
+
+ // Updates the paragraph's size.
UpdateSize( paragraphLayoutInfo.mSize, word.mSize );
+
+ // Updates the paragraph's max asender.
paragraphLayoutInfo.mAscender = std::max( paragraphLayoutInfo.mAscender, word.mAscender );
+
+ // Updates the paragraph's number of characters.
paragraphLayoutInfo.mNumberOfCharacters += word.mCharactersLayoutInfo.size();
}
+ // Sets the line height offset.
paragraphLayoutInfo.mSize.height += lineHeightOffset;
paragraphLayoutInfo.mLineHeightOffset = lineHeightOffset;
}
// 6) update layout info of the first paragraph.
UpdateLayoutInfo( firstParagraphLayoutInfo, lineHeightOffset );
+
+ // 7) Split text and styles.
+
+ // Copies the whole text to the last part of the paragraph.
+ lastParagraphLayoutInfo.mText = firstParagraphLayoutInfo.mText;
+
+ // Removes from the first part of the paragraph the text that goes to the last part.
+ firstParagraphLayoutInfo.mText.Remove( indices.mCharacterParagraphIndex, firstParagraphLayoutInfo.mText.GetLength() - indices.mCharacterParagraphIndex );
+
+ // Removes from the last part of the paragraph the text that remains in the first part.
+ lastParagraphLayoutInfo.mText.Remove( 0u, indices.mCharacterParagraphIndex );
+
+ // Sets the character's styles for the last part of the paragraph.
+ lastParagraphLayoutInfo.mTextStyles.Insert( lastParagraphLayoutInfo.mTextStyles.End(),
+ firstParagraphLayoutInfo.mTextStyles.Begin() + indices.mCharacterParagraphIndex,
+ firstParagraphLayoutInfo.mTextStyles.End() );
+
+ // Removes the character's styles that go to the last part of the paragraph.
+ firstParagraphLayoutInfo.mTextStyles.Erase( firstParagraphLayoutInfo.mTextStyles.Begin() + indices.mCharacterParagraphIndex,
+ firstParagraphLayoutInfo.mTextStyles.End() );
}
void MergeParagraph( ParagraphLayoutInfo& firstParagraphLayoutInfo,
// Merge layout info
// Insert the layout of the words.
+ const std::size_t numberOfWords = firstParagraphLayoutInfo.mWordsLayoutInfo.size();
firstParagraphLayoutInfo.mWordsLayoutInfo.insert( firstParagraphLayoutInfo.mWordsLayoutInfo.end(),
lastParagraphLayoutInfo.mWordsLayoutInfo.begin() + index, lastParagraphLayoutInfo.mWordsLayoutInfo.end() );
+ // Increase the index of the first character of each inserted word.
+ for( WordLayoutInfoContainer::iterator it = firstParagraphLayoutInfo.mWordsLayoutInfo.begin() + numberOfWords, endIt = firstParagraphLayoutInfo.mWordsLayoutInfo.end(); it != endIt; ++it )
+ {
+ WordLayoutInfo& word( *it );
+ word.mFirstCharacter += firstParagraphLayoutInfo.mNumberOfCharacters;
+ }
+
// Update the size and other layout parameters.
UpdateSize( firstParagraphLayoutInfo.mSize, lastParagraphLayoutInfo.mSize );
firstParagraphLayoutInfo.mAscender = std::max( firstParagraphLayoutInfo.mAscender, lastParagraphLayoutInfo.mAscender );
firstParagraphLayoutInfo.mLineHeightOffset = std::max( firstParagraphLayoutInfo.mLineHeightOffset, lastParagraphLayoutInfo.mLineHeightOffset );
firstParagraphLayoutInfo.mNumberOfCharacters += lastParagraphLayoutInfo.mNumberOfCharacters;
+
+ // Merge text and styles.
+ firstParagraphLayoutInfo.mText.Append( lastParagraphLayoutInfo.mText );
+ for( Vector<TextStyle*>::ConstIterator it = lastParagraphLayoutInfo.mTextStyles.Begin(), endIt = lastParagraphLayoutInfo.mTextStyles.End(); it != endIt; ++it )
+ {
+ firstParagraphLayoutInfo.mTextStyles.PushBack( new TextStyle( *(*it) ) );
+ }
}
WordLayoutInfo GetLastWordLayoutInfo( const ParagraphLayoutInfo& paragraphLayoutInfo )
/**
* Creates a data structure with info to layout the paragraph, and data structures with useful info to modify the layout data structure if characters are added or removed.
*
- * @param[in] paragraph The styled paragraph.
* @param[in,out] relayoutData Natural size (metrics), layout, text-actor info and conversion from visual to logical order and vice versa (for RTL text).
* @param[out] paragraphLayoutInfo Layout info for the whole paragraph.
*/
-void CreateParagraphInfo( const MarkupProcessor::StyledTextArray& line,
- TextView::RelayoutData& relayoutData,
+void CreateParagraphInfo( TextView::RelayoutData& relayoutData,
ParagraphLayoutInfo& paragraphLayoutInfo );
/**
#include <dali-toolkit/internal/controls/text-view/text-view-processor-dbg.h>
// INTERNAL INCLUDES
-#include <dali/public-api/actors/text-actor.h>
+#include <dali-toolkit/internal/controls/text-view/text-view-processor-types.h>
namespace Dali
{
void dbgPrint( const WordLayoutInfo& word )
{
- for( CharacterLayoutInfoContainer::const_iterator characterIt = word.mCharactersLayoutInfo.begin(), endCharacterIt = word.mCharactersLayoutInfo.end();
- characterIt != endCharacterIt;
- ++characterIt )
- {
- const CharacterLayoutInfo& character( *characterIt );
-
- std::cout << "[" << character.mSize << std::endl;
- std::cout << " ascender " << character.mAscender << std::endl;
-
- TextActor textActor = TextActor::DownCast( character.mGlyphActor );
- if( textActor )
- {
- std::cout << "[" << textActor.GetText() << "]";
- }
- else
- {
- std::cout << "[ImageActor]" << std::endl;
- }
- std::cout << "{" << character.mStyledText.mText.GetText() << "}";
- }
- std::cout << " size " << word.mSize << std::endl;
- std::cout << " ascender " << word.mAscender << std::endl;
- std::cout << " num char " << word.mCharactersLayoutInfo.size() << std::endl;
- std::cout << " type ";
+ std::cout << " size " << word.mSize << std::endl;
+ std::cout << " ascender " << word.mAscender << std::endl;
+ std::cout << " type ";
switch( word.mType )
{
case NoSeparator:
break;
}
}
+ std::cout << " first char " << word.mFirstCharacter << std::endl;
+ std::cout << " num char " << word.mCharactersLayoutInfo.size() << std::endl;
+ for( CharacterLayoutInfoContainer::const_iterator characterIt = word.mCharactersLayoutInfo.begin(), endCharacterIt = word.mCharactersLayoutInfo.end();
+ characterIt != endCharacterIt;
+ ++characterIt )
+ {
+ const CharacterLayoutInfo& character( *characterIt );
+
+ std::cout << "[" << character.mSize << std::endl;
+ std::cout << " ascender " << character.mAscender << std::endl;
+ }
}
void dbgPrint( const ParagraphLayoutInfo& paragraph )
{
std::cout << "< ";
+ std::cout << " text : [" << paragraph.mText.GetText() << "]" << std::endl;
+ std::cout << " number of styles : " << paragraph.mTextStyles.Count() << std::endl;
std::cout << paragraph.mSize;
for( WordLayoutInfoContainer::const_iterator wordIt = paragraph.mWordsLayoutInfo.begin(), endWordIt = paragraph.mWordsLayoutInfo.end();
wordIt != endWordIt;
std::cout << " paragraph : " << indices.mParagraphIndex << std::endl;
std::cout << " word : " << indices.mWordIndex << std::endl;
std::cout << " char : " << indices.mCharacterIndex << std::endl;
+ std::cout << " char in paragraph : " << indices.mCharacterParagraphIndex << std::endl;
}
void dbgPrint( const MarkupProcessor::StyledTextArray& textArray )
}
}
-void dbgPrintText( const WordLayoutInfo& word )
-{
- for( CharacterLayoutInfoContainer::const_iterator characterIt = word.mCharactersLayoutInfo.begin(), endCharacterIt = word.mCharactersLayoutInfo.end();
- characterIt != endCharacterIt;
- ++characterIt )
- {
- const CharacterLayoutInfo& character( *characterIt );
-
- std::cout << character.mStyledText.mText.GetText();
- }
-}
-
} // namespace TextViewProcessor
} // namespace Internal
*/
// INTERNAL INCLUDES
-#include <dali/integration-api/debug.h>
#include <dali-toolkit/public-api/markup-processor/markup-processor.h>
-#include <dali-toolkit/internal/controls/text-view/text-view-processor-types.h>
+#include <dali/integration-api/debug.h>
namespace Dali
{
+//Forward declarations.
+class TextStyle;
+
namespace Toolkit
{
namespace TextViewProcessor
{
+//Forward declarations.
+struct WordLayoutInfo;
+struct ParagraphLayoutInfo;
+struct TextLayoutInfo;
+struct TextInfoIndices;
+
#if defined(DEBUG_ENABLED)
extern Debug::Filter* gTextViewProcessorLogFilter;
#endif
void dbgPrint( const TextInfoIndices& indices );
void dbgPrint( const MarkupProcessor::StyledTextArray& text );
-void dbgPrintText( const WordLayoutInfo& word );
-
} // namespace TextViewProcessor
} // namespace Internal
return ( character.IsNewLine() ? ParagraphSeparator : ( character.IsWhiteSpace() ? WordSeparator : NoSeparator ) );
}
-void ChooseFontFamilyName( MarkupProcessor::StyledText& text )
+void ChooseFontFamilyName( const Character& character, TextStyle& style )
{
DALI_LOG_INFO( gTextViewProcessorLogFilter, Debug::General, "-->TextViewProcessor::ChooseFontFamilyName\n" );
- DALI_LOG_INFO( gTextViewProcessorLogFilter, Debug::General, " input font name: [%s]\n", text.mStyle.GetFontName().c_str() );
+ DALI_LOG_INFO( gTextViewProcessorLogFilter, Debug::General, " input font name: [%s]\n", style.GetFontName().c_str() );
bool userDefinedFontFamilyName = false;
// First check if there is a font defined in the style and it supports the given text.
- if( !text.mStyle.GetFontName().empty() )
+ if( !style.GetFontName().empty() )
{
- const FontParameters fontParams( text.mStyle.GetFontName(), text.mStyle.GetFontStyle() , text.mStyle.GetFontPointSize() );
+ const FontParameters fontParams( style.GetFontName(), style.GetFontStyle() , style.GetFontPointSize() );
const Font font = Font::New( fontParams );
- if( !font.IsDefaultSystemFont() && font.AllGlyphsSupported( text.mText ) )
+ if( !font.IsDefaultSystemFont() && font.AllGlyphsSupported( character ) )
{
userDefinedFontFamilyName = true;
}
const Font defaultSystemFont = Font::New();
// At this point no font is set or doesn't support the given text.
- if( !defaultSystemFont.AllGlyphsSupported( text.mText ) )
+ if( !defaultSystemFont.AllGlyphsSupported( character ) )
{
// If the default system font doesn't support the given text,
// an appropiate font is selected.
- text.mStyle.SetFontName( Font::GetFamilyForText( text.mText ) );
+ style.SetFontName( Font::GetFamilyForText( character ) );
// @TODO Font::GetFamilyForText() should return font family and font style.
}
else
{
// All characters are supported with default font, so use it
- text.mStyle.SetFontName( "" );
+ style.SetFontName( "" );
}
}
- DALI_LOG_INFO( gTextViewProcessorLogFilter, Debug::General, " output font name: [%s]\n", text.mStyle.GetFontName().c_str() );
+ DALI_LOG_INFO( gTextViewProcessorLogFilter, Debug::General, " output font name: [%s]\n", style.GetFontName().c_str() );
DALI_LOG_INFO( gTextViewProcessorLogFilter, Debug::General, "<--TextViewProcessor::ChooseFontFamilyName\n" );
}
++paragraphIt, ++indices.mParagraphIndex )
{
const ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphIt );
+ std::size_t currentCharactersTraversed = currentIndex; // stores how many characters have been traversed until this paragraph.
if( currentIndex + paragraphLayoutInfo.mNumberOfCharacters > index )
{
{
// The character is in this word
indices.mCharacterIndex = index - currentIndex;
+ indices.mCharacterParagraphIndex = index - currentCharactersTraversed;
found = true;
}
else
TextSeparatorType GetTextSeparatorType( const Character& character );
/**
- * Choose a suitable font family name for the given styled text.
+ * Choose a suitable font family name for the given character.
*
- * It may modify the text-style of the given text by setting a suitable font-family.
+ * It may modify the text-style of the given character by setting a suitable font-family.
*
- * @param[in,out] text Text with style.
+ * @param[in] character The character.
+ * @param[in,out] style The style of the character.
*/
-void ChooseFontFamilyName( MarkupProcessor::StyledText& text );
+void ChooseFontFamilyName( const Character& character, TextStyle& style );
/**
* Retrieves the line, word and character indices for the given global character's index.
// INTERNAL INCLUDES
#include <dali/public-api/actors/renderable-actor.h>
-#include <dali-toolkit/public-api/markup-processor/markup-processor.h>
+#include <dali/public-api/text/text.h>
namespace Dali
{
+class TextStyle;
+
namespace Toolkit
{
namespace Internal
{
+namespace TextProcessor
+{
+// Forward declarations.
+struct BidirectionalParagraphInfo;
+struct BidirectionalLineInfo;
+} // namespace TextProcessor
+
namespace TextViewProcessor
{
std::size_t mParagraphIndex; ///< The paragraph index within the text.
std::size_t mWordIndex; ///< The word index within the paragraph.
std::size_t mCharacterIndex; ///< The character index within the word.
+ std::size_t mCharacterParagraphIndex; ///< The character index within the paragraph.
};
/**
Vector3 mPosition; ///< Position within the text-view
Vector2 mOffset; ///< Alignment and justification offset.
- RenderableActor mGlyphActor; ///< Handle to a text-actor.
- MarkupProcessor::StyledText mStyledText; ///< Stores the text and its style.
- float mColorAlpha; ///< Alpha component for the initial text color when text is faded.
- GradientInfo* mGradientInfo; ///< Stores gradient info.
+ RenderableActor mGlyphActor; ///< Handle to a text-actor.
+ float mColorAlpha; ///< Alpha component for the initial text color when text is faded.
+ GradientInfo* mGradientInfo; ///< Stores gradient info.
bool mIsVisible:1; ///< Whether the text-actor is visible.
bool mSetText:1; ///< Whether a new text needs to be set in the text-actor.
Size mSize; ///< Size of the word.
float mAscender; ///< Max of all ascenders of all characters.
TextSeparatorType mType; ///< Whether this word is a word separator, a line separator or is not a separator.
+ std::size_t mFirstCharacter; ///< Index to the first character of the word within the paragraph.
CharacterLayoutInfoContainer mCharactersLayoutInfo; ///< Layout info for all characters.
};
typedef std::vector<WordLayoutInfo> WordLayoutInfoContainer;
/**
+ * Stores the reordered layout for right to left text.
+ */
+struct RightToLeftParagraphLayout
+{
+ RightToLeftParagraphLayout()
+ : mWordsLayoutInfo(),
+ mText(),
+ mTextStyles(),
+ mPreviousLayoutCleared( false )
+ {
+ }
+
+ WordLayoutInfoContainer mWordsLayoutInfo; ///< Layout info for all words.
+ Text mText; ///< Stores the text.
+ Vector<TextStyle*> mTextStyles; ///< Stores the style per each character.
+ bool mPreviousLayoutCleared:1; ///< Whether the previous right to left layout has been cleared.
+
+ /**
+ * Clears the word layout vector, the text and the vector of styles.
+ */
+ void Clear();
+};
+
+/**
* Layout information for a paragraph.
*/
struct ParagraphLayoutInfo
/**
* Default destructor.
*
- * Clears all words.
+ * Clears all words, deletes all text styles, the paragraph bidirectional info and all bidirectional infor for each line.
*/
~ParagraphLayoutInfo();
*/
ParagraphLayoutInfo& operator=( const ParagraphLayoutInfo& paragraph );
+ /**
+ * Deletes the bidirectional info for each line.
+ */
+ void ClearBidirectionalInfo();
+
+private:
+
+ /**
+ * Deletes all text styles.
+ */
+ void ClearStyles();
+
+public:
Size mSize; ///< Size of the paragraph.
float mAscender; ///< Max of all ascenders of all words.
float mLineHeightOffset; ///< Line height offset.
+ std::size_t mFirstCharacter; ///< Index to the first character of the paragraph.
std::size_t mNumberOfCharacters; ///< Stores the number of characters.
WordLayoutInfoContainer mWordsLayoutInfo; ///< Layout info for all words.
+ Text mText; ///< Stores the text.
+ Vector<TextStyle*> mTextStyles; ///< Stores the style per each character.
+ RightToLeftParagraphLayout* mRightToLeftLayout; ///< Stores the reordered layout for the paragraph.
+ TextProcessor::BidirectionalParagraphInfo* mBidirectionalParagraphInfo; ///< Contains bidirectional info for the whole paragraph. Set to NULL if the paragraph has left to right characters only.
+ Vector<TextProcessor::BidirectionalLineInfo*> mBidirectionalLinesInfo; ///< Contains bidirectional info for each laid-out line.
};
typedef std::vector<ParagraphLayoutInfo> ParagraphLayoutInfoContainer;
TextLayoutInfo();
/**
+ * Defualt destructor.
+ *
+ * Clears the paragraph vector, the ellipsis text and deletes all ellipsis styles.
+ */
+ ~TextLayoutInfo();
+
+ /**
* Copy constructor.
*/
TextLayoutInfo( const TextLayoutInfo& text );
*/
TextLayoutInfo& operator=( const TextLayoutInfo& text );
+private:
+ /**
+ * Deletes all the ellipsis text styles.
+ */
+ void ClearStyles();
+
+public:
Size mWholeTextSize; ///< width and height of the whole text.
float mMaxWordWidth; ///< maximum width between all words.
float mMaxItalicsOffset; ///< When rendering text-view in offscreen an extra width offset is needed to prevent italic characters to be cut if they are in the right edge.
std::size_t mNumberOfCharacters; ///< Stores the number of characters.
ParagraphLayoutInfoContainer mParagraphsLayoutInfo; ///< Layout information for all paragraphs.
WordLayoutInfo mEllipsizeLayoutInfo; ///< Layout information for the ellipsize text.
+ Dali::Text mEllipsisText; ///< The ellipsis text.
+ Vector<TextStyle*> mEllipsisTextStyles; ///< Stores the style per each character of the ellipsis text.
};
} // namespace TextViewProcessor
#include <dali-toolkit/internal/controls/text-view/text-view-processor.h>
// INTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
#include <dali-toolkit/internal/controls/text-view/text-view-word-processor.h>
#include <dali-toolkit/internal/controls/text-view/text-view-paragraph-processor.h>
#include <dali-toolkit/internal/controls/text-view/text-view-processor-helper-functions.h>
#include <dali-toolkit/internal/controls/text-view/text-processor.h>
+#include <dali-toolkit/internal/controls/text-view/text-processor-bidirectional-info.h>
namespace Dali
{
TextInfoIndices::TextInfoIndices()
: mParagraphIndex( 0u ),
mWordIndex( 0u ),
- mCharacterIndex( 0u )
+ mCharacterIndex( 0u ),
+ mCharacterParagraphIndex( 0u )
{
}
const std::size_t characterIndex )
: mParagraphIndex( paragraphIndex ),
mWordIndex( wordIndex ),
- mCharacterIndex( characterIndex )
+ mCharacterIndex( characterIndex ),
+ mCharacterParagraphIndex( 0u )
{
}
{
return ( ( mParagraphIndex == indices.mParagraphIndex ) &&
( mWordIndex == indices.mWordIndex ) &&
- ( mCharacterIndex == indices.mCharacterIndex ) );
+ ( mCharacterIndex == indices.mCharacterIndex ) &&
+ ( mCharacterParagraphIndex == indices.mCharacterParagraphIndex ) );
}
/////////////////////
mMaxItalicsOffset( 0.f ),
mNumberOfCharacters( 0u ),
mParagraphsLayoutInfo(),
- mEllipsizeLayoutInfo()
+ mEllipsizeLayoutInfo(),
+ mEllipsisText( "..." ),
+ mEllipsisTextStyles()
{
+ // Sets default styles for the default ellipsis text.
+ mEllipsisTextStyles.PushBack( new TextStyle() );
+ mEllipsisTextStyles.PushBack( new TextStyle() );
+ mEllipsisTextStyles.PushBack( new TextStyle() );
+}
+
+TextLayoutInfo::~TextLayoutInfo()
+{
+ ClearStyles();
}
TextLayoutInfo::TextLayoutInfo( const TextLayoutInfo& text )
mMaxItalicsOffset( text.mMaxItalicsOffset ),
mNumberOfCharacters( text.mNumberOfCharacters ),
mParagraphsLayoutInfo( text.mParagraphsLayoutInfo ),
- mEllipsizeLayoutInfo( text.mEllipsizeLayoutInfo )
+ mEllipsizeLayoutInfo( text.mEllipsizeLayoutInfo ),
+ mEllipsisText( text.mEllipsisText ),
+ mEllipsisTextStyles()
{
+ for( Vector<TextStyle*>::ConstIterator it = text.mEllipsisTextStyles.Begin(), endIt = text.mEllipsisTextStyles.End(); it != endIt; ++it )
+ {
+ mEllipsisTextStyles.PushBack( new TextStyle( *(*it) ) );
+ }
}
TextLayoutInfo& TextLayoutInfo::operator=( const TextLayoutInfo& text )
mNumberOfCharacters = text.mNumberOfCharacters;
mParagraphsLayoutInfo = text.mParagraphsLayoutInfo;
mEllipsizeLayoutInfo = text.mEllipsizeLayoutInfo;
- }
+ mEllipsisText = text.mEllipsisText;
+ ClearStyles();
+
+ for( Vector<TextStyle*>::ConstIterator it = text.mEllipsisTextStyles.Begin(), endIt = text.mEllipsisTextStyles.End(); it != endIt; ++it )
+ {
+ mEllipsisTextStyles.PushBack( new TextStyle( *(*it) ) );
+ }
+ }
return *this;
}
+void TextLayoutInfo::ClearStyles()
+{
+ for( Vector<TextStyle*>::Iterator it = mEllipsisTextStyles.Begin(), endIt = mEllipsisTextStyles.End(); it != endIt; ++it )
+ {
+ delete *it;
+ }
+ mEllipsisTextStyles.Clear();
+}
+
/////////////////////////////////////////////////////////////////////////////////////////////
void CreateTextInfo( const MarkupProcessor::StyledTextArray& text,
// * Traverse the given text spliting it in paragraphs and each paragraph in words.
// * White spaces and new paragraph characters are alone in one word.
// * Bidirectional text is processed in each paragraph.
+ // It creates the conversion tables
+ // It does the ligatures if there is arabic glyphs.
+ // It doesn't reorder the text as it must be done for each line not for the paragraph.
// * Generates a layout data structure to store layout information (size, position, ascender, text direction, etc) and metrics of all characters.
- // * Generates a text-actor data structure to store text, style and text-actors.
- // TODO: finish and test the bidirectional implementation.
+ // * Store text for each paragraph and the style for each character.
// Collect previously created text-actors.
std::vector<TextActor> textActors;
}
// Store the ellipsize layout info before clearing the previous created info.
+ // TODO: fix this. Don't clear the ellipsis layout, store it somewhere else ...
const WordLayoutInfo ellipsizeInfo = relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo;
+ Dali::Text ellipsisText = relayoutData.mTextLayoutInfo.mEllipsisText;
+ Vector<TextStyle*> ellipsisTextStyles = relayoutData.mTextLayoutInfo.mEllipsisTextStyles;
+ relayoutData.mTextLayoutInfo.mEllipsisTextStyles.Clear();
- // clear previous created info.
+ // clear previously created info.
relayoutData.mTextLayoutInfo = TextLayoutInfo();
relayoutData.mCharacterLogicalToVisualMap.clear();
relayoutData.mCharacterVisualToLogicalMap.clear();
// Sets the ellipsize layout info.
relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo = ellipsizeInfo;
+ relayoutData.mTextLayoutInfo.mEllipsisText = ellipsisText;
+ relayoutData.mTextLayoutInfo.mEllipsisTextStyles = ellipsisTextStyles;
// Split the whole text in paragraphs.
- std::vector<MarkupProcessor::StyledTextArray> paragraphs;
+ // It returns a vector of Text with all the paragraphs.
+ // and for each paragraph a vector of styles per character. TODO: don't create a style per character.
+ std::vector<Text> paragraphs;
+ std::vector< Vector<TextStyle*> > styles;
TextProcessor::SplitInParagraphs( text,
- paragraphs );
+ paragraphs,
+ styles );
+
+ // Reserve space for the current number of paragraphs.
+ relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.resize( paragraphs.size(), ParagraphLayoutInfo() );
// Traverse all paragraphs
- for( std::vector<MarkupProcessor::StyledTextArray>::const_iterator paragraphIt = paragraphs.begin(), paragraphEndIt = paragraphs.end(); paragraphIt != paragraphEndIt; ++paragraphIt )
+ std::size_t paragraphIndex = 0u;
+ std::vector<Text>::iterator paragraphIt, paragraphEndIt;
+ std::vector< Vector<TextStyle*> >::const_iterator styleIt, styleEndIt;
+ for( paragraphIt = paragraphs.begin(), paragraphEndIt = paragraphs.end(),
+ styleIt = styles.begin(), styleEndIt = styles.end();
+ ( paragraphIt != paragraphEndIt ) && ( styleIt != styleEndIt );
+ ++paragraphIndex,
+ ++paragraphIt,
+ ++styleIt )
{
- const MarkupProcessor::StyledTextArray& paragraph( *paragraphIt );
+ // Gets the paragraph and the styles for each character.
+ Text& paragraph( *paragraphIt );
+ const Vector<TextStyle*>& textStyles( *styleIt );
+
+ // Retrieve the data structure for the current paragraph.
+ ParagraphLayoutInfo& paragraphLayoutInfo = *( relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin() + paragraphIndex );
- // Data structures for the new paragraph
- ParagraphLayoutInfo paragraphLayoutInfo;
+ // Sets text and styles.
+ paragraphLayoutInfo.mText = paragraph;
+ paragraphLayoutInfo.mTextStyles = textStyles;
- // Fills the paragraph data structures with the layout info.
- CreateParagraphInfo( paragraph,
- relayoutData,
- paragraphLayoutInfo );
+ // Fills the paragraph data structure with the layout info.
- if( 0u < paragraphLayoutInfo.mNumberOfCharacters )
+ if( !paragraph.IsEmpty() )
{
+ CreateParagraphInfo( relayoutData,
+ paragraphLayoutInfo );
+
// do not add the line offset if the paragraph has no characters.
paragraphLayoutInfo.mSize.height += layoutParameters.mLineHeightOffset;
paragraphLayoutInfo.mLineHeightOffset = layoutParameters.mLineHeightOffset;
}
else
{
- // line height needs to be added for the last paragraph.
+ // This paragraph has no text. i.e. the previous paragraph ends with '\n'.
+ // Even though, line height needs to be set in order to align the whole text correctly.
float lineHeight = 0.f;
// Get the last character of the last paragraph.
- if( !relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.empty() )
+ if( 0u < paragraphIndex )
{
- const ParagraphLayoutInfo& paragraphInfo( *( relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end() - 1u ) );
+ const ParagraphLayoutInfo& paragraphInfo( *( relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin() + ( paragraphIndex - 1u ) ) );
const CharacterLayoutInfo characterInfo = GetLastCharacterLayoutInfo( paragraphInfo );
paragraphLayoutInfo.mSize.height = lineHeight;
}
+ // Fills the conversion tables used to get the logical or visual position of a character is case there is right to left text.
+ // If there is right to left text, it needs to be updated every time the text is relaid-out.
+ for( std::size_t index = 0u; index < paragraphLayoutInfo.mNumberOfCharacters; ++index )
+ {
+ relayoutData.mCharacterLogicalToVisualMap.push_back( relayoutData.mTextLayoutInfo.mNumberOfCharacters + index );
+ relayoutData.mCharacterVisualToLogicalMap.push_back( relayoutData.mTextLayoutInfo.mNumberOfCharacters + index );
+ }
+
// Update layout info for the whole text.
UpdateSize( relayoutData.mTextLayoutInfo.mWholeTextSize, paragraphLayoutInfo.mSize, GrowHeight );
relayoutData.mTextLayoutInfo.mNumberOfCharacters += paragraphLayoutInfo.mNumberOfCharacters;
-
- // Add the paragraph to the current text.
- relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.push_back( paragraphLayoutInfo );
} // end of paragraphs
}
-void UpdateTextInfo( const std::size_t position,
+void UpdateTextInfo( std::size_t position,
const MarkupProcessor::StyledTextArray& text,
const TextView::LayoutParameters& layoutParameters,
TextView::RelayoutData& relayoutData )
// * Merge the last paragraph of the new text to the last part or the split paragraph.
// * Add paragraphs between first and last of the new text.
// * Merge the first part of the split paragraph with the first paragraph of the new text.
- // * Update layout info and create new text actors if needed.
+ // * Update the layout info for the whole text.
// Early returns:
DALI_ASSERT_ALWAYS( !"TextViewProcessor::UpdateTextInfo (insert). Trying to insert text out of bounds." );
}
+
+ // TODO
+ // If in the insertion is involved right to left text,
+ // check the neighbour characters is needed.
+ // i.e. Arabic characters may have four different glyphs (isolated, end, middle, begin).
+ // So check the neighbours on each side is needed in order to render
+ // the correct ligatures.
+
+
TextView::RelayoutData relayoutDataForNewText;
// Creates layout info for the given text.
layoutParameters,
relayoutDataForNewText );
- // Update logical-to-visual and visual-to-logical tables.
- // TODO: check that for mixed RTL/LTR text.
+ // Fills the conversion tables used to get the logical or visual position of a character is case there is right to left text.
+ // If there is right to left text, it needs to be updated every time the text is relaid-out.
std::size_t index = 0u;
for( std::size_t i = 0u; i < relayoutDataForNewText.mTextLayoutInfo.mNumberOfCharacters; ++i )
{
const WordLayoutInfo& wordLayoutInfo( *( paragraphLayoutInfo.mWordsLayoutInfo.end() - 1u ) );
textInfoIndices.mCharacterIndex = wordLayoutInfo.mCharactersLayoutInfo.size();
+
+ // Sets the character index within the paragraph.
+ textInfoIndices.mCharacterParagraphIndex = 0u;
+ for( WordLayoutInfoContainer::const_iterator it = paragraphLayoutInfo.mWordsLayoutInfo.begin(), endIt = paragraphLayoutInfo.mWordsLayoutInfo.end(); it != endIt; ++it )
+ {
+ textInfoIndices.mCharacterParagraphIndex += wordLayoutInfo.mCharactersLayoutInfo.size();
+ }
}
}
}
UpdateLayoutInfo( relayoutData.mTextLayoutInfo );
}
-void UpdateTextInfo( const std::size_t position,
- const std::size_t numberOfCharacters,
+void UpdateTextInfo( std::size_t position,
+ std::size_t numberOfCharacters,
const TextView::LayoutParameters& layoutParameters,
TextView::RelayoutData& relayoutData,
const TextOperationOnRemove clearText )
// Asserts if trying to delete text out of bounds.
DALI_ASSERT_ALWAYS( position + numberOfCharacters <= relayoutData.mTextLayoutInfo.mNumberOfCharacters && "TextViewProcessor::UpdateTextInfo. ERROR: trying to delete characters out of boundary" );
- // Remove characters from character to visual map and vs //TODO: check this for RTL text!!
+ // Remove characters from character to visual map and vs.
+ // If there is right to left text, it needs to be updated every time the text is relaid-out.
relayoutData.mCharacterLogicalToVisualMap.erase( relayoutData.mCharacterLogicalToVisualMap.end() - numberOfCharacters, relayoutData.mCharacterLogicalToVisualMap.end() );
relayoutData.mCharacterVisualToLogicalMap.erase( relayoutData.mCharacterVisualToLogicalMap.end() - numberOfCharacters, relayoutData.mCharacterVisualToLogicalMap.end() );
// As paragraphIndexBegin has been increased just to not to remove the paragraph, decrease now is needed to access it.
ParagraphLayoutInfo& paragraphLayout( *( relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin() + textInfoIndicesBegin.mParagraphIndex - 1u ) );
+ // Remove the characters from the text and the styles.
+ paragraphLayout.mText.Remove( textInfoIndicesBegin.mCharacterParagraphIndex, paragraphLayout.mNumberOfCharacters - textInfoIndicesBegin.mCharacterParagraphIndex );
+
+ for( Vector<TextStyle*>::Iterator it = paragraphLayout.mTextStyles.Begin() + textInfoIndicesBegin.mCharacterParagraphIndex,
+ endIt = paragraphLayout.mTextStyles.End();
+ it != endIt;
+ ++it )
+ {
+ delete *it;
+ }
+ paragraphLayout.mTextStyles.Erase( paragraphLayout.mTextStyles.Begin() + textInfoIndicesBegin.mCharacterParagraphIndex,
+ paragraphLayout.mTextStyles.End() );
+
if( ( textInfoIndicesBegin.mWordIndex + 1u < paragraphLayout.mWordsLayoutInfo.size() ) || ( 0u == textInfoIndicesBegin.mCharacterIndex ) )
{
// Remove extra words within current paragraph. (and current word if whole characters are removed)
// Get the last paragraph.
ParagraphLayoutInfo& paragraphLayout( *( relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin() + paragraphIndex ) );
+ // Remove the characters from the text and the styles.
+ const std::size_t lastCharacterIndex = textInfoIndicesEnd.mCharacterParagraphIndex + 1u;
+
+ paragraphLayout.mText.Remove( 0u, lastCharacterIndex );
+
+ for( Vector<TextStyle*>::Iterator it = paragraphLayout.mTextStyles.Begin(),
+ endIt = paragraphLayout.mTextStyles.Begin() + lastCharacterIndex;
+ it != endIt;
+ ++it )
+ {
+ delete *it;
+ }
+ paragraphLayout.mTextStyles.Erase( paragraphLayout.mTextStyles.Begin(),
+ paragraphLayout.mTextStyles.Begin() + lastCharacterIndex );
+
// Check if is needed remove the whole word. (If the character index is pointing just after the end of the word)
const WordLayoutInfo& wordLayout( *( paragraphLayout.mWordsLayoutInfo.begin() + textInfoIndicesEnd.mWordIndex ) );
bool removeWholeWord = wordLayout.mCharactersLayoutInfo.size() == textInfoIndicesEnd.mCharacterIndex + 1u;
// Paragraph which contains the characters to be deleted.
ParagraphLayoutInfo& paragraphLayout( *( relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin() + textInfoIndicesBegin.mParagraphIndex ) );
+ // Remove the characters from the text and the styles.
+ const std::size_t firstCharacterIndex = textInfoIndicesBegin.mCharacterParagraphIndex;
+ const std::size_t lastCharacterIndex = textInfoIndicesEnd.mCharacterParagraphIndex + 1u;
+
+ paragraphLayout.mText.Remove( firstCharacterIndex, lastCharacterIndex - firstCharacterIndex );
+
+ for( Vector<TextStyle*>::Iterator it = paragraphLayout.mTextStyles.Begin() + firstCharacterIndex,
+ endIt = paragraphLayout.mTextStyles.Begin() + lastCharacterIndex;
+ it != endIt;
+ ++it )
+ {
+ delete *it;
+ }
+ paragraphLayout.mTextStyles.Erase( paragraphLayout.mTextStyles.Begin() + firstCharacterIndex,
+ paragraphLayout.mTextStyles.Begin() + lastCharacterIndex );
+
// Remove the characters from the paragraph layout info. It returns whether the current paragraph can be merged with the next one.
RemoveCharactersFromParagraphInfo( relayoutData,
numberOfCharacters,
relayoutData.mTextActorCache.InsertTextActors( removedTextActorsFromBegin );
}
-void UpdateTextInfo( const std::size_t position,
- const std::size_t numberOfCharacters,
+void UpdateTextInfo( std::size_t position,
+ std::size_t numberOfCharacters,
const MarkupProcessor::StyledTextArray& text,
const TextView::LayoutParameters& layoutParameters,
TextView::RelayoutData& relayoutData )
{
ParagraphLayoutInfo& paragraph( *paragraphIt );
+ std::size_t index = 0u;
+ for( Vector<TextStyle*>::Iterator it = paragraph.mTextStyles.Begin(), endIt = paragraph.mTextStyles.End(); it != endIt; ++it )
+ {
+ (*it)->Copy( style, mask );
+
+ // Checks if the font family supports all glyphs. If not, chooses a most suitable one.
+ ChooseFontFamilyName( paragraph.mText[index], *(*it) );
+
+ ++index;
+ }
+
for( WordLayoutInfoContainer::iterator wordIt = paragraph.mWordsLayoutInfo.begin(), wordEndIt = paragraph.mWordsLayoutInfo.end();
wordIt != wordEndIt;
++wordIt )
{
CharacterLayoutInfo& characterLayout( *characterIt );
- characterLayout.mStyledText.mStyle.Copy( style, mask );
-
- // Checks if the font family supports all glyphs. If not, chooses a most suitable one.
- ChooseFontFamilyName( characterLayout.mStyledText );
-
// Mark the character to be set the new style into the text-actor.
characterLayout.mSetStyle = true;
} // end characters
const std::string EMOJI_FONT_NAME( "SamsungEmoji" ); // Emoticons font family name.
-/**
- * Updates the word size and ascender.
- *
- * It's called after deleting some characters.
- *
- * @param[in] wordLayout The word layout info.
- */
-void UpdateLayoutInfo( WordLayoutInfo& wordLayout )
-{
- // Initialize layout info for the whole word.
- wordLayout.mSize = Size::ZERO;
- wordLayout.mAscender = 0.f;
-
- // Traverse the character layout info to update the word layout.
- for( CharacterLayoutInfoContainer::iterator layoutIt = wordLayout.mCharactersLayoutInfo.begin(), layoutEndIt = wordLayout.mCharactersLayoutInfo.end();
- layoutIt != layoutEndIt;
- ++layoutIt )
- {
- // Layout info for the current character.
- CharacterLayoutInfo& layoutInfo( *layoutIt );
-
- // Update layout info for the current word.
- UpdateSize( wordLayout.mSize, layoutInfo.mSize );
- wordLayout.mAscender = std::max( wordLayout.mAscender, layoutInfo.mAscender );
- }
-}
-
} // namespace
/////////////////////
: mSize(),
mAscender( 0.f ),
mType( NoSeparator ),
+ mFirstCharacter( 0u ),
mCharactersLayoutInfo()
{
}
: mSize( word.mSize ),
mAscender( word.mAscender ),
mType( word.mType ),
+ mFirstCharacter( word.mFirstCharacter ),
mCharactersLayoutInfo( word.mCharactersLayoutInfo )
{
}
mSize = word.mSize;
mAscender = word.mAscender;
mType = word.mType;
+ mFirstCharacter = word.mFirstCharacter;
mCharactersLayoutInfo = word.mCharactersLayoutInfo;
return *this;
}
-void CreateWordTextInfo( const MarkupProcessor::StyledTextArray& word,
+void CreateWordTextInfo( const Text& paragraph,
+ Vector<TextStyle*>& textStyles,
WordLayoutInfo& wordLayoutInfo )
{
DALI_LOG_INFO( gTextViewProcessorLogFilter, Debug::General, "-->TextViewProcessor::CreateWordTextInfo\n" );
// Split in characters.
- for( MarkupProcessor::StyledTextArray::const_iterator charIt = word.begin(), charEndIt = word.end(); charIt != charEndIt; ++charIt )
+ std::size_t characterIndex = wordLayoutInfo.mFirstCharacter;
+ for( CharacterLayoutInfoContainer::iterator it = wordLayoutInfo.mCharactersLayoutInfo.begin(),
+ endIt = wordLayoutInfo.mCharactersLayoutInfo.end();
+ it != endIt;
+ ++it, ++characterIndex )
{
- const MarkupProcessor::StyledText& styledText( *charIt );
+ // Gets a reference of the character's layout info.
+ CharacterLayoutInfo& characterLayoutInfo( *it );
+
+ // Gets the character and the style for that character from the paragraph.
+ Character character = paragraph[characterIndex];
+ TextStyle* textStyle = *( textStyles.Begin() + characterIndex );
- const std::size_t length = styledText.mText.GetLength();
+ // Checks whether the character is an emoticon.
+ characterLayoutInfo.mIsColorGlyph = GlyphImage::IsColorGlyph( character );
+ DALI_LOG_INFO( gTextViewProcessorLogFilter, Debug::General, " Is color glyph: %s\n", ( characterLayoutInfo.mIsColorGlyph ? "True" : "False" ) );
- // It could be a group of characters.
- for( std::size_t index = 0u; index < length; ++index )
+ if( characterLayoutInfo.mIsColorGlyph )
{
- MarkupProcessor::StyledText styledCharacter;
- styledCharacter.mStyle = styledText.mStyle;
- Character character = styledText.mText[index];
- styledCharacter.mText.Append( character );
+ // If the character is an emoticon a predefined font is set.
+ textStyle->SetFontName( EMOJI_FONT_NAME );
+ }
+ else
+ {
+ // Checks if the font family and the font style set in the text style supports the character.
+ // If not, it chooses the right font for the given character and style.
+ ChooseFontFamilyName( character, *textStyle );
+ }
- // Create layout character info.
- CharacterLayoutInfo characterLayoutInfo;
+ // Gets the metrics of the font.
+ const Font font = Font::New( FontParameters( textStyle->GetFontName(), textStyle->GetFontStyle(), textStyle->GetFontPointSize() ) );
+ const Font::Metrics metrics = font.GetMetrics( character );
+ const float ascender = font.GetAscender();
- characterLayoutInfo.mIsColorGlyph = GlyphImage::IsColorGlyph( character );
- DALI_LOG_INFO( gTextViewProcessorLogFilter, Debug::General, " Is color glyph: %s\n", ( characterLayoutInfo.mIsColorGlyph ? "True" : "False" ) );
+ // Fill Natural size info for current character.
- if( characterLayoutInfo.mIsColorGlyph )
- {
- styledCharacter.mStyle.SetFontName( EMOJI_FONT_NAME );
- }
- else
- {
- //Choose the right font for the given character and style.
- ChooseFontFamilyName( styledCharacter );
- }
+ // The font line's height is used as character's height.
+ characterLayoutInfo.mSize.height = font.GetLineHeight();
- // Gets the metrics of the font.
- const Font font = Font::New( FontParameters( styledCharacter.mStyle.GetFontName(), styledCharacter.mStyle.GetFontStyle(), styledCharacter.mStyle.GetFontPointSize() ) );
- const Font::Metrics metrics = font.GetMetrics( character );
- const float ascender = font.GetAscender();
+ // The character's advance is used as charcter's width.
+ characterLayoutInfo.mSize.width = metrics.GetAdvance();
- // The font line's height is used as character's height.
- characterLayoutInfo.mSize.height = font.GetLineHeight();
+ // The ascender and bearing are used to position correctly glyphs of different font sizes.
+ characterLayoutInfo.mAscender = ascender;
+ characterLayoutInfo.mBearing = metrics.GetBearing();
- // The character's advance is used as charcter's width.
- characterLayoutInfo.mSize.width = metrics.GetAdvance();
+ if( character.IsNewLine() && !characterLayoutInfo.mIsColorGlyph )
+ {
+ // A new paragraph character '\n' doesn't have any width.
+ characterLayoutInfo.mSize.width = 0.f;
+ }
- // The ascender and bearing are used to position correctly glyphs of different font sizes.
- characterLayoutInfo.mAscender = ascender;
- characterLayoutInfo.mBearing = metrics.GetBearing();
+ // Set's the underline thickness and position.
+ // Both thickness and position includes the vertical pad adjust used in effects like glow or shadow.
+ if( textStyle->IsUnderlineEnabled() )
+ {
+ characterLayoutInfo.mUnderlineThickness = font.GetUnderlineThickness();
+ characterLayoutInfo.mUnderlinePosition = font.GetUnderlinePosition();
+ }
- if( character.IsNewLine() && !characterLayoutInfo.mIsColorGlyph )
- {
- // A new paragraph character doesn't have any width.
- characterLayoutInfo.mSize.width = 0.f;
- }
+ // Updates the word size and ascender.
+ UpdateSize( wordLayoutInfo.mSize, characterLayoutInfo.mSize );
+ wordLayoutInfo.mAscender = std::max( wordLayoutInfo.mAscender, characterLayoutInfo.mAscender );
+ } // end of characters in the word.
+ DALI_LOG_INFO( gTextViewProcessorLogFilter, Debug::General, "<--TextViewProcessor::CreateWordTextInfo\n" );
+}
- // Set's the underline thickness and position.
- // Both thickness and position includes the vertical pad adjust used in effects like glow or shadow.
- if( styledCharacter.mStyle.IsUnderlineEnabled() )
- {
- characterLayoutInfo.mUnderlineThickness = font.GetUnderlineThickness();
- characterLayoutInfo.mUnderlinePosition = font.GetUnderlinePosition();
- }
+void UpdateLayoutInfo( WordLayoutInfo& wordLayout )
+{
+ // Initialize layout info for the whole word.
+ wordLayout.mSize = Size::ZERO;
+ wordLayout.mAscender = 0.f;
- // stores the styled text.
- characterLayoutInfo.mStyledText.mText = styledCharacter.mText;
- characterLayoutInfo.mStyledText.mStyle = styledCharacter.mStyle;
+ // Traverse the character layout info to update the word layout.
+ for( CharacterLayoutInfoContainer::iterator layoutIt = wordLayout.mCharactersLayoutInfo.begin(), layoutEndIt = wordLayout.mCharactersLayoutInfo.end();
+ layoutIt != layoutEndIt;
+ ++layoutIt )
+ {
+ // Layout info for the current character.
+ CharacterLayoutInfo& layoutInfo( *layoutIt );
- // Add character layout info to the word layout info and update it.
- wordLayoutInfo.mCharactersLayoutInfo.push_back( characterLayoutInfo );
- UpdateSize( wordLayoutInfo.mSize, characterLayoutInfo.mSize );
- wordLayoutInfo.mAscender = std::max( wordLayoutInfo.mAscender, characterLayoutInfo.mAscender );
- wordLayoutInfo.mType = GetTextSeparatorType( character );
- } // end of each character in the group of characters.
- } // end of characters in the word.
- DALI_LOG_INFO( gTextViewProcessorLogFilter, Debug::General, "<--TextViewProcessor::CreateWordTextInfo\n" );
+ // Update layout info for the current word.
+ UpdateSize( wordLayout.mSize, layoutInfo.mSize );
+ wordLayout.mAscender = std::max( wordLayout.mAscender, layoutInfo.mAscender );
+ }
}
void RemoveCharactersFromWordInfo( TextView::RelayoutData& relayoutData,
/**
* Creates a data structure with info to layout the word, and data structures with useful info to modify the layout data structure if characters are added or removed.
*
- * @param[in] word The styled word.
+ * @param[in] paragraphText The paragraph's text.
+ * @param[in] textStyles The styles for each character of the paragraph.
* @param[out] wordLayoutInfo Layout info for all characters of the word.
*/
-void CreateWordTextInfo( const MarkupProcessor::StyledTextArray& word,
+void CreateWordTextInfo( const Text& paragraphText,
+ Vector<TextStyle*>& textStyles,
WordLayoutInfo& wordLayoutInfo );
/**
+ * Updates the word size and ascender.
+ *
+ * It's called after deleting some characters, split a word in two,
+ * or when a new word is created when right to left text is reordered.
+ *
+ * @param[in] wordLayout The word layout info.
+ */
+void UpdateLayoutInfo( WordLayoutInfo& wordLayout );
+
+/**
* Removes a given number of characters from the given word.
*
* It calls the RemoveCharactersFromWord() function to remove characters from the word.
$(toolkit_base_src_dir)/controls/text-view/split-by-char-policies.cpp \
$(toolkit_base_src_dir)/controls/text-view/text-actor-cache.cpp \
$(toolkit_base_src_dir)/controls/text-view/text-processor.cpp \
+ $(toolkit_base_src_dir)/controls/text-view/text-processor-bidirectional-info.cpp \
$(toolkit_base_src_dir)/controls/text-view/text-view-impl.cpp \
$(toolkit_base_src_dir)/controls/text-view/text-view-character-processor.cpp \
$(toolkit_base_src_dir)/controls/text-view/text-view-paragraph-processor.cpp \