2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 // Licensed under the Flora License, Version 1.0 (the License);
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
8 // http://floralicense.org/license/
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an AS IS BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
18 #include "text-view-word-processor.h"
19 #include "text-view-processor-helper-functions.h"
30 namespace TextViewProcessor
37 * Updates the word size and ascender.
39 * It's called after deleting some characters.
41 * @param[in] wordLayout The word layout info.
43 void UpdateLayoutInfo( WordLayoutInfo& wordLayout )
45 // Initialize layout info for the whole word.
46 wordLayout.mSize = Size();
47 wordLayout.mAscender = 0.f;
49 // Traverse the character layout info to update the word layout.
50 for( CharacterLayoutInfoContainer::iterator layoutIt = wordLayout.mCharactersLayoutInfo.begin(), layoutEndIt = wordLayout.mCharactersLayoutInfo.end();
51 layoutIt != layoutEndIt;
54 // Layout info for the current character.
55 CharacterLayoutInfo& layoutInfo( *layoutIt );
57 // Update layout info for the current word.
58 UpdateSize( wordLayout.mSize, layoutInfo.mSize );
59 wordLayout.mAscender = std::max( wordLayout.mAscender, layoutInfo.mAscender );
69 WordLayoutInfo::WordLayoutInfo()
73 mCharactersLayoutInfo()
77 WordLayoutInfo::WordLayoutInfo( const WordLayoutInfo& word )
78 : mSize( word.mSize ),
79 mAscender( word.mAscender ),
81 mCharactersLayoutInfo( word.mCharactersLayoutInfo )
85 WordLayoutInfo& WordLayoutInfo::operator=( const WordLayoutInfo& word )
88 mAscender = word.mAscender;
90 mCharactersLayoutInfo = word.mCharactersLayoutInfo;
95 void CreateWordTextInfo( const MarkupProcessor::StyledTextArray& word,
96 TextViewProcessor::WordLayoutInfo& wordLayoutInfo )
98 // Split in characters.
99 for( MarkupProcessor::StyledTextArray::const_iterator charIt = word.begin(), charEndIt = word.end(); charIt != charEndIt; ++charIt )
101 const MarkupProcessor::StyledText& styledText( *charIt );
103 const std::size_t length = styledText.mText.GetLength();
105 // It could be a group of characters.
106 for( std::size_t index = 0; index < length; ++index )
108 MarkupProcessor::StyledText styledCharacter;
109 styledCharacter.mStyle = styledText.mStyle;
110 Character character = styledText.mText[index];
111 styledCharacter.mText.Append( character );
113 //Choose the right font for the given character and style.
114 ChooseFontFamilyName( styledCharacter );
116 const Font font = Font::New( FontParameters( styledCharacter.mStyle.GetFontName(), styledCharacter.mStyle.GetFontStyle(), styledCharacter.mStyle.GetFontPointSize() ) );
117 const Font::Metrics metrics = font.GetMetrics( character );
118 const float ascender = font.GetAscender();
120 // Create layout character info.
121 CharacterLayoutInfo characterLayoutInfo;
123 // Fill Natural size info for current character.
124 characterLayoutInfo.mHeight = font.GetLineHeight();
125 characterLayoutInfo.mAdvance = metrics.GetAdvance();
126 characterLayoutInfo.mBearing = metrics.GetBearing();
128 if( character.IsNewLine() )
130 // A new line character doesn't have any width.
131 characterLayoutInfo.mSize.width = 0.f;
135 // Uses advance as width.
136 characterLayoutInfo.mSize.width = characterLayoutInfo.mAdvance;
138 characterLayoutInfo.mSize.height = characterLayoutInfo.mHeight;
139 characterLayoutInfo.mAscender = ascender;
141 if( styledCharacter.mStyle.GetUnderline() )
143 characterLayoutInfo.mUnderlineThickness = font.GetUnderlineThickness(); // Both thickness and position includes the
144 characterLayoutInfo.mUnderlinePosition = font.GetUnderlinePosition(); // vertical pad adjust used in effects like glow or shadow.
147 // stores the styled text.
148 characterLayoutInfo.mStyledText.mText = styledCharacter.mText;
149 characterLayoutInfo.mStyledText.mStyle = styledCharacter.mStyle;
151 // Add character layout info to the word layout info and update it.
152 wordLayoutInfo.mCharactersLayoutInfo.push_back( characterLayoutInfo );
153 UpdateSize( wordLayoutInfo.mSize, characterLayoutInfo.mSize );
154 wordLayoutInfo.mAscender = std::max( wordLayoutInfo.mAscender, characterLayoutInfo.mAscender );
155 wordLayoutInfo.mType = GetTextSeparatorType( character );
156 } // end of each character in the group of characters.
157 } // end of characters in the word.
160 void RemoveCharactersFromWordInfo( TextView::RelayoutData& relayoutData,
161 const std::size_t numberOfCharacters,
164 TextViewProcessor::TextInfoIndices& textInfoIndicesBegin,
165 TextViewProcessor::TextInfoIndices& textInfoIndicesEnd,
166 TextViewProcessor::TextInfoIndices& textInfoMergeIndicesBegin,
167 TextViewProcessor::TextInfoIndices& textInfoMergeIndicesEnd,
168 TextViewProcessor::WordGroupLayoutInfo& groupLayout,
169 std::vector<TextActor>& removedTextActors )
171 const TextViewProcessor::TextLayoutInfo& textLayoutInfo = relayoutData.mTextLayoutInfo;
174 WordLayoutInfo& wordLayout( *( groupLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex ) );
176 if( TextViewProcessor::LineSeparator == wordLayout.mType )
178 // If the word is a line separator and there is more lines, then current line and the line after need to be merged.
179 if( textInfoIndicesBegin.mLineIndex + 1 < textLayoutInfo.mLinesLayoutInfo.size() )
181 // current line is not the last one.
183 // Update indices to merge lines.
184 textInfoMergeIndicesBegin.mLineIndex = textInfoIndicesBegin.mLineIndex;
185 textInfoMergeIndicesEnd.mLineIndex = textInfoIndicesBegin.mLineIndex + 1;
189 ++textInfoIndicesBegin.mLineIndex; // increase both indices,
190 textInfoIndicesEnd.mLineIndex +=2; // will delete last line.
193 ++textInfoIndicesEnd.mWordIndex; //will delete the line separator;
195 else if( WordSeparator == wordLayout.mType )
197 // If the word is a word separator. Check if the word before and the word after can be merged.
199 if( ( 0 < textInfoIndicesBegin.mWordIndex ) && ( groupLayout.mWordsLayoutInfo.size() > textInfoIndicesBegin.mWordIndex + 1 ) )
201 const WordLayoutInfo& wordLayoutBefore( *( groupLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex - 1 ) );
202 const WordLayoutInfo& wordLayoutAfter( *( groupLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex + 1 ) );
204 if( ( NoSeparator == wordLayoutBefore.mType ) && ( NoSeparator == wordLayoutAfter.mType ) )
206 // This word is a word separator (white space) and is not the first word of the group nor the last one.
209 // Set indices to merge the words.
210 textInfoMergeIndicesBegin.mWordIndex = textInfoIndicesBegin.mWordIndex - 1; // word before word separator.
211 textInfoMergeIndicesEnd.mWordIndex = textInfoIndicesBegin.mWordIndex + 1; // word after word separator.
213 textInfoIndicesEnd.mWordIndex += 2; // will delete the word separator and the merged word.
217 ++textInfoIndicesEnd.mWordIndex; // will delete the word separator;
222 ++textInfoIndicesEnd.mWordIndex; // will delete the word separator;
225 else if( numberOfCharacters == wordLayout.mCharactersLayoutInfo.size() )
227 // The whole word needs to be removed.
228 ++textInfoIndicesEnd.mWordIndex; // will delete the current word.
232 // Store text-actors before removing them.
233 CollectTextActors( removedTextActors, wordLayout, textInfoIndicesBegin.mCharacterIndex, textInfoIndicesBegin.mCharacterIndex + numberOfCharacters );
235 // just remove some characters from current word.
236 RemoveCharactersFromWord( textInfoIndicesBegin.mCharacterIndex,
242 void RemoveCharactersFromWord( const std::size_t position,
243 const std::size_t numberOfCharacters,
244 WordLayoutInfo& wordLayout )
246 // Removes a given number of characters from the given word starting from the 'position' index.
249 if( 0 == numberOfCharacters )
251 // nothing to do if the number of characters is zero.
256 // Remove characters from layout and text-actor info.
257 wordLayout.mCharactersLayoutInfo.erase( wordLayout.mCharactersLayoutInfo.begin() + position, wordLayout.mCharactersLayoutInfo.begin() + position + numberOfCharacters );
259 // Some characters have been removed from the word. Update the layout info is needed.
260 UpdateLayoutInfo( wordLayout );
263 void SplitWord( const std::size_t position,
264 WordLayoutInfo& firstWordLayoutInfo,
265 WordLayoutInfo& lastWordLayoutInfo )
267 // Splits a word in two.
268 // It moves characters from the first part of the word to the last one.
273 // the whole word goes to the last part of the word.
274 lastWordLayoutInfo = firstWordLayoutInfo;
276 firstWordLayoutInfo = WordLayoutInfo();
281 if( position == firstWordLayoutInfo.mCharactersLayoutInfo.size() )
283 // the whole word goes to the first part of the word.
285 // Just delete whatever there is in the last part of the word.
286 lastWordLayoutInfo = WordLayoutInfo();
291 // Initialize output data structures.
294 lastWordLayoutInfo = WordLayoutInfo();
296 // Split layout info.
298 // Insert characters from the given index 'position' to the end.
299 lastWordLayoutInfo.mCharactersLayoutInfo.insert( lastWordLayoutInfo.mCharactersLayoutInfo.end(),
300 firstWordLayoutInfo.mCharactersLayoutInfo.begin() + position, firstWordLayoutInfo.mCharactersLayoutInfo.end() );
302 // Delete characters from the first part of the word.
303 firstWordLayoutInfo.mCharactersLayoutInfo.erase( firstWordLayoutInfo.mCharactersLayoutInfo.begin() + position, firstWordLayoutInfo.mCharactersLayoutInfo.end() );
305 // Update the layout info of both new words.
306 UpdateLayoutInfo( firstWordLayoutInfo );
307 UpdateLayoutInfo( lastWordLayoutInfo );
310 void MergeWord( WordLayoutInfo& firstWordLayoutInfo,
311 const WordLayoutInfo& lastWordLayoutInfo )
313 // Merges two given words.
316 if( lastWordLayoutInfo.mCharactersLayoutInfo.empty() )
322 if( firstWordLayoutInfo.mCharactersLayoutInfo.empty() )
324 // copy last to first
326 firstWordLayoutInfo = lastWordLayoutInfo;
331 if( ( NoSeparator != firstWordLayoutInfo.mType ) || ( NoSeparator != lastWordLayoutInfo.mType ) )
333 // Do not merge white spaces or new line characters.
334 DALI_ASSERT_ALWAYS( !"TextViewProcessor::MergeWord(). ERROR: White spaces or new line characters can't be merged with other words." );
338 firstWordLayoutInfo.mCharactersLayoutInfo.insert( firstWordLayoutInfo.mCharactersLayoutInfo.end(),
339 lastWordLayoutInfo.mCharactersLayoutInfo.begin(),
340 lastWordLayoutInfo.mCharactersLayoutInfo.end() );
342 // Update the word layout info.
343 UpdateSize( firstWordLayoutInfo.mSize, lastWordLayoutInfo.mSize );
344 firstWordLayoutInfo.mAscender = std::max( firstWordLayoutInfo.mAscender, lastWordLayoutInfo.mAscender );
347 CharacterLayoutInfo GetFirstCharacterLayoutInfo( const WordLayoutInfo& wordLayoutInfo )
349 CharacterLayoutInfo layoutInfo;
351 if( !wordLayoutInfo.mCharactersLayoutInfo.empty() )
353 layoutInfo = *wordLayoutInfo.mCharactersLayoutInfo.begin();
359 CharacterLayoutInfo GetLastCharacterLayoutInfo( const WordLayoutInfo& wordLayoutInfo )
361 CharacterLayoutInfo layoutInfo;
363 if( !wordLayoutInfo.mCharactersLayoutInfo.empty() )
365 layoutInfo = *( wordLayoutInfo.mCharactersLayoutInfo.end() - 1 );
371 void CollectTextActors( std::vector<TextActor>& textActors, const WordLayoutInfo& word, const std::size_t characterIndexBegin, const std::size_t characterIndexEnd )
373 for( CharacterLayoutInfoContainer::const_iterator characterIt = word.mCharactersLayoutInfo.begin() + characterIndexBegin,
374 characterEndIt = word.mCharactersLayoutInfo.begin() + characterIndexEnd;
375 characterIt != characterEndIt;
378 const CharacterLayoutInfo& characterLayout( *characterIt );
380 if( characterLayout.mTextActor )
382 textActors.push_back( characterLayout.mTextActor );
387 void CollectTextActorsFromWords( std::vector<TextActor>& textActors, const WordGroupLayoutInfo& group, const std::size_t wordIndexBegin, const std::size_t wordIndexEnd )
389 for( WordLayoutInfoContainer::const_iterator wordIt = group.mWordsLayoutInfo.begin() + wordIndexBegin, wordEndIt = group.mWordsLayoutInfo.begin() + wordIndexEnd;
393 const WordLayoutInfo& word( *wordIt );
395 for( CharacterLayoutInfoContainer::const_iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
396 characterIt != characterEndIt;
399 const CharacterLayoutInfo& characterLayout( *characterIt );
401 if( characterLayout.mTextActor )
403 textActors.push_back( characterLayout.mTextActor );
409 } //namespace TextViewProcessor
411 } //namespace Internal
413 } //namespace Toolkit