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 // Gets the metrics of the font.
141 const Font font = Font::New( FontParameters( styledCharacter.mStyle.GetFontName(), styledCharacter.mStyle.GetFontStyle(), styledCharacter.mStyle.GetFontPointSize() ) );
142 const Font::Metrics metrics = font.GetMetrics( character );
143 const float ascender = font.GetAscender();
145 // The font line's height is used as character's height.
146 characterLayoutInfo.mSize.height = font.GetLineHeight();
148 // The character's advance is used as charcter's width.
149 characterLayoutInfo.mSize.width = metrics.GetAdvance();
151 // The ascender and bearing are used to position correctly glyphs of different font sizes.
152 characterLayoutInfo.mAscender = ascender;
153 characterLayoutInfo.mBearing = metrics.GetBearing();
155 if( character.IsNewLine() && !characterLayoutInfo.mIsColorGlyph )
157 // A new paragraph character doesn't have any width.
158 characterLayoutInfo.mSize.width = 0.f;
161 // Set's the underline thickness and position.
162 // Both thickness and position includes the vertical pad adjust used in effects like glow or shadow.
163 if( styledCharacter.mStyle.IsUnderlineEnabled() )
165 characterLayoutInfo.mUnderlineThickness = font.GetUnderlineThickness();
166 characterLayoutInfo.mUnderlinePosition = font.GetUnderlinePosition();
169 // stores the styled text.
170 characterLayoutInfo.mStyledText.mText = styledCharacter.mText;
171 characterLayoutInfo.mStyledText.mStyle = styledCharacter.mStyle;
173 // Add character layout info to the word layout info and update it.
174 wordLayoutInfo.mCharactersLayoutInfo.push_back( characterLayoutInfo );
175 UpdateSize( wordLayoutInfo.mSize, characterLayoutInfo.mSize );
176 wordLayoutInfo.mAscender = std::max( wordLayoutInfo.mAscender, characterLayoutInfo.mAscender );
177 wordLayoutInfo.mType = GetTextSeparatorType( character );
178 } // end of each character in the group of characters.
179 } // end of characters in the word.
180 DALI_LOG_INFO( gTextViewProcessorLogFilter, Debug::General, "<--TextViewProcessor::CreateWordTextInfo\n" );
183 void RemoveCharactersFromWordInfo( TextView::RelayoutData& relayoutData,
184 const std::size_t numberOfCharacters,
186 bool& mergeParagraphs,
187 TextInfoIndices& textInfoIndicesBegin,
188 TextInfoIndices& textInfoIndicesEnd,
189 TextInfoIndices& textInfoMergeIndicesBegin,
190 TextInfoIndices& textInfoMergeIndicesEnd,
191 ParagraphLayoutInfo& paragraphLayout,
192 std::vector<TextActor>& removedTextActors )
194 const TextLayoutInfo& textLayoutInfo = relayoutData.mTextLayoutInfo;
197 WordLayoutInfo& wordLayout( *( paragraphLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex ) );
199 if( ParagraphSeparator == wordLayout.mType )
201 // If the word is a paragraph separator and there is more paragraphs, then current paragraph and the paragraph after need to be merged.
202 if( textInfoIndicesBegin.mParagraphIndex + 1u < textLayoutInfo.mParagraphsLayoutInfo.size() )
204 // current paragraph is not the last one.
206 // Update indices to merge paragraphs.
207 textInfoMergeIndicesBegin.mParagraphIndex = textInfoIndicesBegin.mParagraphIndex;
208 textInfoMergeIndicesEnd.mParagraphIndex = textInfoIndicesBegin.mParagraphIndex + 1u;
210 mergeParagraphs = true;
212 ++textInfoIndicesBegin.mParagraphIndex; // increase both indices,
213 textInfoIndicesEnd.mParagraphIndex += 2u; // will delete last paragraph.
216 ++textInfoIndicesEnd.mWordIndex; //will delete the paragraph separator;
218 else if( WordSeparator == wordLayout.mType )
220 // If the word is a word separator. Check if the word before and the word after can be merged.
222 if( ( 0u < textInfoIndicesBegin.mWordIndex ) && ( paragraphLayout.mWordsLayoutInfo.size() > textInfoIndicesBegin.mWordIndex + 1u ) )
224 const WordLayoutInfo& wordLayoutBefore( *( paragraphLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex - 1u ) );
225 const WordLayoutInfo& wordLayoutAfter( *( paragraphLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex + 1u ) );
227 if( ( NoSeparator == wordLayoutBefore.mType ) && ( NoSeparator == wordLayoutAfter.mType ) )
229 // This word is a word separator (white space) and is not the first word of the paragraph nor the last one.
232 // Set indices to merge the words.
233 textInfoMergeIndicesBegin.mWordIndex = textInfoIndicesBegin.mWordIndex - 1u; // word before word separator.
234 textInfoMergeIndicesEnd.mWordIndex = textInfoIndicesBegin.mWordIndex + 1u; // word after word separator.
236 textInfoIndicesEnd.mWordIndex += 2u; // will delete the word separator and the merged word.
240 ++textInfoIndicesEnd.mWordIndex; // will delete the word separator;
245 ++textInfoIndicesEnd.mWordIndex; // will delete the word separator;
248 else if( numberOfCharacters == wordLayout.mCharactersLayoutInfo.size() )
250 // The whole word needs to be removed.
251 ++textInfoIndicesEnd.mWordIndex; // will delete the current word.
255 // Store text-actors before removing them.
256 CollectTextActors( removedTextActors, wordLayout, textInfoIndicesBegin.mCharacterIndex, textInfoIndicesBegin.mCharacterIndex + numberOfCharacters );
258 // just remove some characters from current word.
259 RemoveCharactersFromWord( textInfoIndicesBegin.mCharacterIndex,
265 void RemoveCharactersFromWord( const std::size_t position,
266 const std::size_t numberOfCharacters,
267 WordLayoutInfo& wordLayout )
269 // Removes a given number of characters from the given word starting from the 'position' index.
272 if( 0u == numberOfCharacters )
274 // nothing to do if the number of characters is zero.
279 // Remove characters from layout and text-actor info.
280 wordLayout.mCharactersLayoutInfo.erase( wordLayout.mCharactersLayoutInfo.begin() + position, wordLayout.mCharactersLayoutInfo.begin() + position + numberOfCharacters );
282 // Some characters have been removed from the word. Update the layout info is needed.
283 UpdateLayoutInfo( wordLayout );
286 void SplitWord( const std::size_t position,
287 WordLayoutInfo& firstWordLayoutInfo,
288 WordLayoutInfo& lastWordLayoutInfo )
290 // Splits a word in two.
291 // It moves characters from the first part of the word to the last one.
296 // the whole word goes to the last part of the word.
297 lastWordLayoutInfo = firstWordLayoutInfo;
299 firstWordLayoutInfo = WordLayoutInfo();
304 if( position == firstWordLayoutInfo.mCharactersLayoutInfo.size() )
306 // the whole word goes to the first part of the word.
308 // Just delete whatever there is in the last part of the word.
309 lastWordLayoutInfo = WordLayoutInfo();
314 // Initialize output data structures.
317 lastWordLayoutInfo = WordLayoutInfo();
319 // Split layout info.
321 // Insert characters from the given index 'position' to the end.
322 lastWordLayoutInfo.mCharactersLayoutInfo.insert( lastWordLayoutInfo.mCharactersLayoutInfo.end(),
323 firstWordLayoutInfo.mCharactersLayoutInfo.begin() + position, firstWordLayoutInfo.mCharactersLayoutInfo.end() );
325 // Delete characters from the first part of the word.
326 firstWordLayoutInfo.mCharactersLayoutInfo.erase( firstWordLayoutInfo.mCharactersLayoutInfo.begin() + position, firstWordLayoutInfo.mCharactersLayoutInfo.end() );
328 // Update the layout info of both new words.
329 UpdateLayoutInfo( firstWordLayoutInfo );
330 UpdateLayoutInfo( lastWordLayoutInfo );
333 void MergeWord( WordLayoutInfo& firstWordLayoutInfo,
334 const WordLayoutInfo& lastWordLayoutInfo )
336 // Merges two given words.
339 if( lastWordLayoutInfo.mCharactersLayoutInfo.empty() )
345 if( firstWordLayoutInfo.mCharactersLayoutInfo.empty() )
347 // copy last to first
349 firstWordLayoutInfo = lastWordLayoutInfo;
354 if( ( NoSeparator != firstWordLayoutInfo.mType ) || ( NoSeparator != lastWordLayoutInfo.mType ) )
356 // Do not merge white spaces or new paragraph characters.
357 DALI_ASSERT_ALWAYS( !"TextViewProcessor::MergeWord(). ERROR: White spaces or new paragraph characters can't be merged with other words." );
361 firstWordLayoutInfo.mCharactersLayoutInfo.insert( firstWordLayoutInfo.mCharactersLayoutInfo.end(),
362 lastWordLayoutInfo.mCharactersLayoutInfo.begin(),
363 lastWordLayoutInfo.mCharactersLayoutInfo.end() );
365 // Update the word layout info.
366 UpdateSize( firstWordLayoutInfo.mSize, lastWordLayoutInfo.mSize );
367 firstWordLayoutInfo.mAscender = std::max( firstWordLayoutInfo.mAscender, lastWordLayoutInfo.mAscender );
370 CharacterLayoutInfo GetFirstCharacterLayoutInfo( const WordLayoutInfo& wordLayoutInfo )
372 CharacterLayoutInfo layoutInfo;
374 if( !wordLayoutInfo.mCharactersLayoutInfo.empty() )
376 layoutInfo = *wordLayoutInfo.mCharactersLayoutInfo.begin();
382 CharacterLayoutInfo GetLastCharacterLayoutInfo( const WordLayoutInfo& wordLayoutInfo )
384 CharacterLayoutInfo layoutInfo;
386 if( !wordLayoutInfo.mCharactersLayoutInfo.empty() )
388 layoutInfo = *( wordLayoutInfo.mCharactersLayoutInfo.end() - 1u );
394 void CollectTextActors( std::vector<TextActor>& textActors, const WordLayoutInfo& word, const std::size_t characterIndexBegin, const std::size_t characterIndexEnd )
396 for( CharacterLayoutInfoContainer::const_iterator characterIt = word.mCharactersLayoutInfo.begin() + characterIndexBegin,
397 characterEndIt = word.mCharactersLayoutInfo.begin() + characterIndexEnd;
398 characterIt != characterEndIt;
401 const CharacterLayoutInfo& characterLayout( *characterIt );
403 if( !characterLayout.mIsColorGlyph )
405 TextActor textActor = TextActor::DownCast( characterLayout.mGlyphActor );
408 textActors.push_back( textActor );
414 void CollectTextActorsFromWords( std::vector<TextActor>& textActors, const ParagraphLayoutInfo& paragraph, const std::size_t wordIndexBegin, const std::size_t wordIndexEnd )
416 for( WordLayoutInfoContainer::const_iterator wordIt = paragraph.mWordsLayoutInfo.begin() + wordIndexBegin, wordEndIt = paragraph.mWordsLayoutInfo.begin() + wordIndexEnd;
420 const WordLayoutInfo& word( *wordIt );
422 for( CharacterLayoutInfoContainer::const_iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
423 characterIt != characterEndIt;
426 const CharacterLayoutInfo& characterLayout( *characterIt );
428 if( !characterLayout.mIsColorGlyph )
430 TextActor textActor = TextActor::DownCast( characterLayout.mGlyphActor );
433 textActors.push_back( textActor );
440 } //namespace TextViewProcessor
442 } //namespace Internal
444 } //namespace Toolkit