2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.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://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali-toolkit/internal/controls/text-view/text-view-word-processor.h>
22 #include <dali-toolkit/internal/controls/text-view/text-view-processor-helper-functions.h>
23 #include <dali-toolkit/internal/controls/text-view/text-view-processor-dbg.h>
34 namespace TextViewProcessor
40 const std::string EMOJI_FONT_NAME( "SamsungEmoji" ); // Emoticons font family name.
43 * Updates the word size and ascender.
45 * It's called after deleting some characters.
47 * @param[in] wordLayout The word layout info.
49 void UpdateLayoutInfo( WordLayoutInfo& wordLayout )
51 // Initialize layout info for the whole word.
52 wordLayout.mSize = Size::ZERO;
53 wordLayout.mAscender = 0.f;
55 // Traverse the character layout info to update the word layout.
56 for( CharacterLayoutInfoContainer::iterator layoutIt = wordLayout.mCharactersLayoutInfo.begin(), layoutEndIt = wordLayout.mCharactersLayoutInfo.end();
57 layoutIt != layoutEndIt;
60 // Layout info for the current character.
61 CharacterLayoutInfo& layoutInfo( *layoutIt );
63 // Update layout info for the current word.
64 UpdateSize( wordLayout.mSize, layoutInfo.mSize );
65 wordLayout.mAscender = std::max( wordLayout.mAscender, layoutInfo.mAscender );
75 WordLayoutInfo::WordLayoutInfo()
79 mCharactersLayoutInfo()
83 WordLayoutInfo::~WordLayoutInfo()
87 WordLayoutInfo::WordLayoutInfo( const WordLayoutInfo& word )
88 : mSize( word.mSize ),
89 mAscender( word.mAscender ),
91 mCharactersLayoutInfo( word.mCharactersLayoutInfo )
95 WordLayoutInfo& WordLayoutInfo::operator=( const WordLayoutInfo& word )
98 mAscender = word.mAscender;
100 mCharactersLayoutInfo = word.mCharactersLayoutInfo;
105 void CreateWordTextInfo( const MarkupProcessor::StyledTextArray& word,
106 WordLayoutInfo& wordLayoutInfo )
108 DALI_LOG_INFO( gTextViewProcessorLogFilter, Debug::General, "-->TextViewProcessor::CreateWordTextInfo\n" );
109 // Split in characters.
110 for( MarkupProcessor::StyledTextArray::const_iterator charIt = word.begin(), charEndIt = word.end(); charIt != charEndIt; ++charIt )
112 const MarkupProcessor::StyledText& styledText( *charIt );
114 const std::size_t length = styledText.mText.GetLength();
116 // It could be a group of characters.
117 for( std::size_t index = 0u; index < length; ++index )
119 MarkupProcessor::StyledText styledCharacter;
120 styledCharacter.mStyle = styledText.mStyle;
121 Character character = styledText.mText[index];
122 styledCharacter.mText.Append( character );
124 // Create layout character info.
125 CharacterLayoutInfo characterLayoutInfo;
127 characterLayoutInfo.mIsColorGlyph = GlyphImage::IsColorGlyph( character );
128 DALI_LOG_INFO( gTextViewProcessorLogFilter, Debug::General, " Is color glyph: %s\n", ( characterLayoutInfo.mIsColorGlyph ? "True" : "False" ) );
130 if( characterLayoutInfo.mIsColorGlyph )
132 styledCharacter.mStyle.SetFontName( EMOJI_FONT_NAME );
136 //Choose the right font for the given character and style.
137 ChooseFontFamilyName( styledCharacter );
140 const Font font = Font::New( FontParameters( styledCharacter.mStyle.GetFontName(), styledCharacter.mStyle.GetFontStyle(), styledCharacter.mStyle.GetFontPointSize() ) );
141 const Font::Metrics metrics = font.GetMetrics( character );
142 const float ascender = font.GetAscender();
144 // Fill Natural size info for current character.
145 characterLayoutInfo.mHeight = font.GetLineHeight();
146 characterLayoutInfo.mAdvance = metrics.GetAdvance();
147 characterLayoutInfo.mBearing = metrics.GetBearing();
149 if( character.IsNewLine() && !characterLayoutInfo.mIsColorGlyph )
151 // A new paragraph character doesn't have any width.
152 characterLayoutInfo.mSize.width = 0.f;
156 // Uses advance as width.
157 characterLayoutInfo.mSize.width = characterLayoutInfo.mAdvance;
159 characterLayoutInfo.mSize.height = characterLayoutInfo.mHeight;
160 characterLayoutInfo.mAscender = ascender;
162 if( styledCharacter.mStyle.IsUnderlineEnabled() )
164 characterLayoutInfo.mUnderlineThickness = font.GetUnderlineThickness(); // Both thickness and position includes the
165 characterLayoutInfo.mUnderlinePosition = font.GetUnderlinePosition(); // vertical pad adjust used in effects like glow or shadow.
168 // stores the styled text.
169 characterLayoutInfo.mStyledText.mText = styledCharacter.mText;
170 characterLayoutInfo.mStyledText.mStyle = styledCharacter.mStyle;
172 // Add character layout info to the word layout info and update it.
173 wordLayoutInfo.mCharactersLayoutInfo.push_back( characterLayoutInfo );
174 UpdateSize( wordLayoutInfo.mSize, characterLayoutInfo.mSize );
175 wordLayoutInfo.mAscender = std::max( wordLayoutInfo.mAscender, characterLayoutInfo.mAscender );
176 wordLayoutInfo.mType = GetTextSeparatorType( character );
177 } // end of each character in the group of characters.
178 } // end of characters in the word.
179 DALI_LOG_INFO( gTextViewProcessorLogFilter, Debug::General, "<--TextViewProcessor::CreateWordTextInfo\n" );
182 void RemoveCharactersFromWordInfo( TextView::RelayoutData& relayoutData,
183 const std::size_t numberOfCharacters,
185 bool& mergeParagraphs,
186 TextInfoIndices& textInfoIndicesBegin,
187 TextInfoIndices& textInfoIndicesEnd,
188 TextInfoIndices& textInfoMergeIndicesBegin,
189 TextInfoIndices& textInfoMergeIndicesEnd,
190 ParagraphLayoutInfo& paragraphLayout,
191 std::vector<TextActor>& removedTextActors )
193 const TextLayoutInfo& textLayoutInfo = relayoutData.mTextLayoutInfo;
196 WordLayoutInfo& wordLayout( *( paragraphLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex ) );
198 if( ParagraphSeparator == wordLayout.mType )
200 // If the word is a paragraph separator and there is more paragraphs, then current paragraph and the paragraph after need to be merged.
201 if( textInfoIndicesBegin.mParagraphIndex + 1u < textLayoutInfo.mParagraphsLayoutInfo.size() )
203 // current paragraph is not the last one.
205 // Update indices to merge paragraphs.
206 textInfoMergeIndicesBegin.mParagraphIndex = textInfoIndicesBegin.mParagraphIndex;
207 textInfoMergeIndicesEnd.mParagraphIndex = textInfoIndicesBegin.mParagraphIndex + 1u;
209 mergeParagraphs = true;
211 ++textInfoIndicesBegin.mParagraphIndex; // increase both indices,
212 textInfoIndicesEnd.mParagraphIndex += 2u; // will delete last paragraph.
215 ++textInfoIndicesEnd.mWordIndex; //will delete the paragraph separator;
217 else if( WordSeparator == wordLayout.mType )
219 // If the word is a word separator. Check if the word before and the word after can be merged.
221 if( ( 0u < textInfoIndicesBegin.mWordIndex ) && ( paragraphLayout.mWordsLayoutInfo.size() > textInfoIndicesBegin.mWordIndex + 1u ) )
223 const WordLayoutInfo& wordLayoutBefore( *( paragraphLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex - 1u ) );
224 const WordLayoutInfo& wordLayoutAfter( *( paragraphLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex + 1u ) );
226 if( ( NoSeparator == wordLayoutBefore.mType ) && ( NoSeparator == wordLayoutAfter.mType ) )
228 // This word is a word separator (white space) and is not the first word of the paragraph nor the last one.
231 // Set indices to merge the words.
232 textInfoMergeIndicesBegin.mWordIndex = textInfoIndicesBegin.mWordIndex - 1u; // word before word separator.
233 textInfoMergeIndicesEnd.mWordIndex = textInfoIndicesBegin.mWordIndex + 1u; // word after word separator.
235 textInfoIndicesEnd.mWordIndex += 2u; // will delete the word separator and the merged word.
239 ++textInfoIndicesEnd.mWordIndex; // will delete the word separator;
244 ++textInfoIndicesEnd.mWordIndex; // will delete the word separator;
247 else if( numberOfCharacters == wordLayout.mCharactersLayoutInfo.size() )
249 // The whole word needs to be removed.
250 ++textInfoIndicesEnd.mWordIndex; // will delete the current word.
254 // Store text-actors before removing them.
255 CollectTextActors( removedTextActors, wordLayout, textInfoIndicesBegin.mCharacterIndex, textInfoIndicesBegin.mCharacterIndex + numberOfCharacters );
257 // just remove some characters from current word.
258 RemoveCharactersFromWord( textInfoIndicesBegin.mCharacterIndex,
264 void RemoveCharactersFromWord( const std::size_t position,
265 const std::size_t numberOfCharacters,
266 WordLayoutInfo& wordLayout )
268 // Removes a given number of characters from the given word starting from the 'position' index.
271 if( 0u == numberOfCharacters )
273 // nothing to do if the number of characters is zero.
278 // Remove characters from layout and text-actor info.
279 wordLayout.mCharactersLayoutInfo.erase( wordLayout.mCharactersLayoutInfo.begin() + position, wordLayout.mCharactersLayoutInfo.begin() + position + numberOfCharacters );
281 // Some characters have been removed from the word. Update the layout info is needed.
282 UpdateLayoutInfo( wordLayout );
285 void SplitWord( const std::size_t position,
286 WordLayoutInfo& firstWordLayoutInfo,
287 WordLayoutInfo& lastWordLayoutInfo )
289 // Splits a word in two.
290 // It moves characters from the first part of the word to the last one.
295 // the whole word goes to the last part of the word.
296 lastWordLayoutInfo = firstWordLayoutInfo;
298 firstWordLayoutInfo = WordLayoutInfo();
303 if( position == firstWordLayoutInfo.mCharactersLayoutInfo.size() )
305 // the whole word goes to the first part of the word.
307 // Just delete whatever there is in the last part of the word.
308 lastWordLayoutInfo = WordLayoutInfo();
313 // Initialize output data structures.
316 lastWordLayoutInfo = WordLayoutInfo();
318 // Split layout info.
320 // Insert characters from the given index 'position' to the end.
321 lastWordLayoutInfo.mCharactersLayoutInfo.insert( lastWordLayoutInfo.mCharactersLayoutInfo.end(),
322 firstWordLayoutInfo.mCharactersLayoutInfo.begin() + position, firstWordLayoutInfo.mCharactersLayoutInfo.end() );
324 // Delete characters from the first part of the word.
325 firstWordLayoutInfo.mCharactersLayoutInfo.erase( firstWordLayoutInfo.mCharactersLayoutInfo.begin() + position, firstWordLayoutInfo.mCharactersLayoutInfo.end() );
327 // Update the layout info of both new words.
328 UpdateLayoutInfo( firstWordLayoutInfo );
329 UpdateLayoutInfo( lastWordLayoutInfo );
332 void MergeWord( WordLayoutInfo& firstWordLayoutInfo,
333 const WordLayoutInfo& lastWordLayoutInfo )
335 // Merges two given words.
338 if( lastWordLayoutInfo.mCharactersLayoutInfo.empty() )
344 if( firstWordLayoutInfo.mCharactersLayoutInfo.empty() )
346 // copy last to first
348 firstWordLayoutInfo = lastWordLayoutInfo;
353 if( ( NoSeparator != firstWordLayoutInfo.mType ) || ( NoSeparator != lastWordLayoutInfo.mType ) )
355 // Do not merge white spaces or new paragraph characters.
356 DALI_ASSERT_ALWAYS( !"TextViewProcessor::MergeWord(). ERROR: White spaces or new paragraph characters can't be merged with other words." );
360 firstWordLayoutInfo.mCharactersLayoutInfo.insert( firstWordLayoutInfo.mCharactersLayoutInfo.end(),
361 lastWordLayoutInfo.mCharactersLayoutInfo.begin(),
362 lastWordLayoutInfo.mCharactersLayoutInfo.end() );
364 // Update the word layout info.
365 UpdateSize( firstWordLayoutInfo.mSize, lastWordLayoutInfo.mSize );
366 firstWordLayoutInfo.mAscender = std::max( firstWordLayoutInfo.mAscender, lastWordLayoutInfo.mAscender );
369 CharacterLayoutInfo GetFirstCharacterLayoutInfo( const WordLayoutInfo& wordLayoutInfo )
371 CharacterLayoutInfo layoutInfo;
373 if( !wordLayoutInfo.mCharactersLayoutInfo.empty() )
375 layoutInfo = *wordLayoutInfo.mCharactersLayoutInfo.begin();
381 CharacterLayoutInfo GetLastCharacterLayoutInfo( const WordLayoutInfo& wordLayoutInfo )
383 CharacterLayoutInfo layoutInfo;
385 if( !wordLayoutInfo.mCharactersLayoutInfo.empty() )
387 layoutInfo = *( wordLayoutInfo.mCharactersLayoutInfo.end() - 1u );
393 void CollectTextActors( std::vector<TextActor>& textActors, const WordLayoutInfo& word, const std::size_t characterIndexBegin, const std::size_t characterIndexEnd )
395 for( CharacterLayoutInfoContainer::const_iterator characterIt = word.mCharactersLayoutInfo.begin() + characterIndexBegin,
396 characterEndIt = word.mCharactersLayoutInfo.begin() + characterIndexEnd;
397 characterIt != characterEndIt;
400 const CharacterLayoutInfo& characterLayout( *characterIt );
402 if( !characterLayout.mIsColorGlyph )
404 TextActor textActor = TextActor::DownCast( characterLayout.mGlyphActor );
407 textActors.push_back( textActor );
413 void CollectTextActorsFromWords( std::vector<TextActor>& textActors, const ParagraphLayoutInfo& paragraph, const std::size_t wordIndexBegin, const std::size_t wordIndexEnd )
415 for( WordLayoutInfoContainer::const_iterator wordIt = paragraph.mWordsLayoutInfo.begin() + wordIndexBegin, wordEndIt = paragraph.mWordsLayoutInfo.begin() + wordIndexEnd;
419 const WordLayoutInfo& word( *wordIt );
421 for( CharacterLayoutInfoContainer::const_iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
422 characterIt != characterEndIt;
425 const CharacterLayoutInfo& characterLayout( *characterIt );
427 if( !characterLayout.mIsColorGlyph )
429 TextActor textActor = TextActor::DownCast( characterLayout.mGlyphActor );
432 textActors.push_back( textActor );
439 } //namespace TextViewProcessor
441 } //namespace Internal
443 } //namespace Toolkit