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 "text-view-word-processor.h"
22 #include <dali/dali.h>
23 #include "text-view-processor-helper-functions.h"
24 #include "text-view-processor-dbg.h"
35 namespace TextViewProcessor
41 const std::string EMOJI_FONT_NAME( "SamsungEmoji" ); // Emoticons font family name.
44 * Updates the word size and ascender.
46 * It's called after deleting some characters.
48 * @param[in] wordLayout The word layout info.
50 void UpdateLayoutInfo( WordLayoutInfo& wordLayout )
52 // Initialize layout info for the whole word.
53 wordLayout.mSize = Size();
54 wordLayout.mAscender = 0.f;
56 // Traverse the character layout info to update the word layout.
57 for( CharacterLayoutInfoContainer::iterator layoutIt = wordLayout.mCharactersLayoutInfo.begin(), layoutEndIt = wordLayout.mCharactersLayoutInfo.end();
58 layoutIt != layoutEndIt;
61 // Layout info for the current character.
62 CharacterLayoutInfo& layoutInfo( *layoutIt );
64 // Update layout info for the current word.
65 UpdateSize( wordLayout.mSize, layoutInfo.mSize );
66 wordLayout.mAscender = std::max( wordLayout.mAscender, layoutInfo.mAscender );
76 WordLayoutInfo::WordLayoutInfo()
80 mCharactersLayoutInfo()
84 WordLayoutInfo::WordLayoutInfo( const WordLayoutInfo& word )
85 : mSize( word.mSize ),
86 mAscender( word.mAscender ),
88 mCharactersLayoutInfo( word.mCharactersLayoutInfo )
92 WordLayoutInfo& WordLayoutInfo::operator=( const WordLayoutInfo& word )
95 mAscender = word.mAscender;
97 mCharactersLayoutInfo = word.mCharactersLayoutInfo;
102 void CreateWordTextInfo( const MarkupProcessor::StyledTextArray& word,
103 TextViewProcessor::WordLayoutInfo& wordLayoutInfo )
105 DALI_LOG_INFO( gTextViewProcessorLogFilter, Debug::General, "-->TextViewProcessor::CreateWordTextInfo\n" );
106 // Split in characters.
107 for( MarkupProcessor::StyledTextArray::const_iterator charIt = word.begin(), charEndIt = word.end(); charIt != charEndIt; ++charIt )
109 const MarkupProcessor::StyledText& styledText( *charIt );
111 const std::size_t length = styledText.mText.GetLength();
113 // It could be a group of characters.
114 for( std::size_t index = 0; index < length; ++index )
116 MarkupProcessor::StyledText styledCharacter;
117 styledCharacter.mStyle = styledText.mStyle;
118 Character character = styledText.mText[index];
119 styledCharacter.mText.Append( character );
121 // Create layout character info.
122 CharacterLayoutInfo characterLayoutInfo;
124 characterLayoutInfo.mIsColorGlyph = GlyphImage::IsColorGlyph( character );
125 DALI_LOG_INFO( gTextViewProcessorLogFilter, Debug::General, " Is color glyph: %s\n", ( characterLayoutInfo.mIsColorGlyph ? "True" : "False" ) );
127 if( characterLayoutInfo.mIsColorGlyph )
129 styledCharacter.mStyle.SetFontName( EMOJI_FONT_NAME );
133 //Choose the right font for the given character and style.
134 ChooseFontFamilyName( styledCharacter );
137 const Font font = Font::New( FontParameters( styledCharacter.mStyle.GetFontName(), styledCharacter.mStyle.GetFontStyle(), styledCharacter.mStyle.GetFontPointSize() ) );
138 const Font::Metrics metrics = font.GetMetrics( character );
139 const float ascender = font.GetAscender();
141 // Fill Natural size info for current character.
142 characterLayoutInfo.mHeight = font.GetLineHeight();
143 characterLayoutInfo.mAdvance = metrics.GetAdvance();
144 characterLayoutInfo.mBearing = metrics.GetBearing();
146 if( character.IsNewLine() && !characterLayoutInfo.mIsColorGlyph )
148 // A new line character doesn't have any width.
149 characterLayoutInfo.mSize.width = 0.f;
153 // Uses advance as width.
154 characterLayoutInfo.mSize.width = characterLayoutInfo.mAdvance;
156 characterLayoutInfo.mSize.height = characterLayoutInfo.mHeight;
157 characterLayoutInfo.mAscender = ascender;
159 if( styledCharacter.mStyle.GetUnderline() )
161 characterLayoutInfo.mUnderlineThickness = font.GetUnderlineThickness(); // Both thickness and position includes the
162 characterLayoutInfo.mUnderlinePosition = font.GetUnderlinePosition(); // vertical pad adjust used in effects like glow or shadow.
165 // stores the styled text.
166 characterLayoutInfo.mStyledText.mText = styledCharacter.mText;
167 characterLayoutInfo.mStyledText.mStyle = styledCharacter.mStyle;
169 // Add character layout info to the word layout info and update it.
170 wordLayoutInfo.mCharactersLayoutInfo.push_back( characterLayoutInfo );
171 UpdateSize( wordLayoutInfo.mSize, characterLayoutInfo.mSize );
172 wordLayoutInfo.mAscender = std::max( wordLayoutInfo.mAscender, characterLayoutInfo.mAscender );
173 wordLayoutInfo.mType = GetTextSeparatorType( character );
174 } // end of each character in the group of characters.
175 } // end of characters in the word.
176 DALI_LOG_INFO( gTextViewProcessorLogFilter, Debug::General, "<--TextViewProcessor::CreateWordTextInfo\n" );
179 void RemoveCharactersFromWordInfo( TextView::RelayoutData& relayoutData,
180 const std::size_t numberOfCharacters,
183 TextViewProcessor::TextInfoIndices& textInfoIndicesBegin,
184 TextViewProcessor::TextInfoIndices& textInfoIndicesEnd,
185 TextViewProcessor::TextInfoIndices& textInfoMergeIndicesBegin,
186 TextViewProcessor::TextInfoIndices& textInfoMergeIndicesEnd,
187 TextViewProcessor::WordGroupLayoutInfo& groupLayout,
188 std::vector<TextActor>& removedTextActors )
190 const TextViewProcessor::TextLayoutInfo& textLayoutInfo = relayoutData.mTextLayoutInfo;
193 WordLayoutInfo& wordLayout( *( groupLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex ) );
195 if( TextViewProcessor::LineSeparator == wordLayout.mType )
197 // If the word is a line separator and there is more lines, then current line and the line after need to be merged.
198 if( textInfoIndicesBegin.mLineIndex + 1 < textLayoutInfo.mLinesLayoutInfo.size() )
200 // current line is not the last one.
202 // Update indices to merge lines.
203 textInfoMergeIndicesBegin.mLineIndex = textInfoIndicesBegin.mLineIndex;
204 textInfoMergeIndicesEnd.mLineIndex = textInfoIndicesBegin.mLineIndex + 1;
208 ++textInfoIndicesBegin.mLineIndex; // increase both indices,
209 textInfoIndicesEnd.mLineIndex +=2; // will delete last line.
212 ++textInfoIndicesEnd.mWordIndex; //will delete the line separator;
214 else if( WordSeparator == wordLayout.mType )
216 // If the word is a word separator. Check if the word before and the word after can be merged.
218 if( ( 0 < textInfoIndicesBegin.mWordIndex ) && ( groupLayout.mWordsLayoutInfo.size() > textInfoIndicesBegin.mWordIndex + 1 ) )
220 const WordLayoutInfo& wordLayoutBefore( *( groupLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex - 1 ) );
221 const WordLayoutInfo& wordLayoutAfter( *( groupLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex + 1 ) );
223 if( ( NoSeparator == wordLayoutBefore.mType ) && ( NoSeparator == wordLayoutAfter.mType ) )
225 // This word is a word separator (white space) and is not the first word of the group nor the last one.
228 // Set indices to merge the words.
229 textInfoMergeIndicesBegin.mWordIndex = textInfoIndicesBegin.mWordIndex - 1; // word before word separator.
230 textInfoMergeIndicesEnd.mWordIndex = textInfoIndicesBegin.mWordIndex + 1; // word after word separator.
232 textInfoIndicesEnd.mWordIndex += 2; // will delete the word separator and the merged word.
236 ++textInfoIndicesEnd.mWordIndex; // will delete the word separator;
241 ++textInfoIndicesEnd.mWordIndex; // will delete the word separator;
244 else if( numberOfCharacters == wordLayout.mCharactersLayoutInfo.size() )
246 // The whole word needs to be removed.
247 ++textInfoIndicesEnd.mWordIndex; // will delete the current word.
251 // Store text-actors before removing them.
252 CollectTextActors( removedTextActors, wordLayout, textInfoIndicesBegin.mCharacterIndex, textInfoIndicesBegin.mCharacterIndex + numberOfCharacters );
254 // just remove some characters from current word.
255 RemoveCharactersFromWord( textInfoIndicesBegin.mCharacterIndex,
261 void RemoveCharactersFromWord( const std::size_t position,
262 const std::size_t numberOfCharacters,
263 WordLayoutInfo& wordLayout )
265 // Removes a given number of characters from the given word starting from the 'position' index.
268 if( 0 == numberOfCharacters )
270 // nothing to do if the number of characters is zero.
275 // Remove characters from layout and text-actor info.
276 wordLayout.mCharactersLayoutInfo.erase( wordLayout.mCharactersLayoutInfo.begin() + position, wordLayout.mCharactersLayoutInfo.begin() + position + numberOfCharacters );
278 // Some characters have been removed from the word. Update the layout info is needed.
279 UpdateLayoutInfo( wordLayout );
282 void SplitWord( const std::size_t position,
283 WordLayoutInfo& firstWordLayoutInfo,
284 WordLayoutInfo& lastWordLayoutInfo )
286 // Splits a word in two.
287 // It moves characters from the first part of the word to the last one.
292 // the whole word goes to the last part of the word.
293 lastWordLayoutInfo = firstWordLayoutInfo;
295 firstWordLayoutInfo = WordLayoutInfo();
300 if( position == firstWordLayoutInfo.mCharactersLayoutInfo.size() )
302 // the whole word goes to the first part of the word.
304 // Just delete whatever there is in the last part of the word.
305 lastWordLayoutInfo = WordLayoutInfo();
310 // Initialize output data structures.
313 lastWordLayoutInfo = WordLayoutInfo();
315 // Split layout info.
317 // Insert characters from the given index 'position' to the end.
318 lastWordLayoutInfo.mCharactersLayoutInfo.insert( lastWordLayoutInfo.mCharactersLayoutInfo.end(),
319 firstWordLayoutInfo.mCharactersLayoutInfo.begin() + position, firstWordLayoutInfo.mCharactersLayoutInfo.end() );
321 // Delete characters from the first part of the word.
322 firstWordLayoutInfo.mCharactersLayoutInfo.erase( firstWordLayoutInfo.mCharactersLayoutInfo.begin() + position, firstWordLayoutInfo.mCharactersLayoutInfo.end() );
324 // Update the layout info of both new words.
325 UpdateLayoutInfo( firstWordLayoutInfo );
326 UpdateLayoutInfo( lastWordLayoutInfo );
329 void MergeWord( WordLayoutInfo& firstWordLayoutInfo,
330 const WordLayoutInfo& lastWordLayoutInfo )
332 // Merges two given words.
335 if( lastWordLayoutInfo.mCharactersLayoutInfo.empty() )
341 if( firstWordLayoutInfo.mCharactersLayoutInfo.empty() )
343 // copy last to first
345 firstWordLayoutInfo = lastWordLayoutInfo;
350 if( ( NoSeparator != firstWordLayoutInfo.mType ) || ( NoSeparator != lastWordLayoutInfo.mType ) )
352 // Do not merge white spaces or new line characters.
353 DALI_ASSERT_ALWAYS( !"TextViewProcessor::MergeWord(). ERROR: White spaces or new line characters can't be merged with other words." );
357 firstWordLayoutInfo.mCharactersLayoutInfo.insert( firstWordLayoutInfo.mCharactersLayoutInfo.end(),
358 lastWordLayoutInfo.mCharactersLayoutInfo.begin(),
359 lastWordLayoutInfo.mCharactersLayoutInfo.end() );
361 // Update the word layout info.
362 UpdateSize( firstWordLayoutInfo.mSize, lastWordLayoutInfo.mSize );
363 firstWordLayoutInfo.mAscender = std::max( firstWordLayoutInfo.mAscender, lastWordLayoutInfo.mAscender );
366 CharacterLayoutInfo GetFirstCharacterLayoutInfo( const WordLayoutInfo& wordLayoutInfo )
368 CharacterLayoutInfo layoutInfo;
370 if( !wordLayoutInfo.mCharactersLayoutInfo.empty() )
372 layoutInfo = *wordLayoutInfo.mCharactersLayoutInfo.begin();
378 CharacterLayoutInfo GetLastCharacterLayoutInfo( const WordLayoutInfo& wordLayoutInfo )
380 CharacterLayoutInfo layoutInfo;
382 if( !wordLayoutInfo.mCharactersLayoutInfo.empty() )
384 layoutInfo = *( wordLayoutInfo.mCharactersLayoutInfo.end() - 1 );
390 void CollectTextActors( std::vector<TextActor>& textActors, const WordLayoutInfo& word, const std::size_t characterIndexBegin, const std::size_t characterIndexEnd )
392 for( CharacterLayoutInfoContainer::const_iterator characterIt = word.mCharactersLayoutInfo.begin() + characterIndexBegin,
393 characterEndIt = word.mCharactersLayoutInfo.begin() + characterIndexEnd;
394 characterIt != characterEndIt;
397 const CharacterLayoutInfo& characterLayout( *characterIt );
399 if( !characterLayout.mIsColorGlyph )
401 TextActor textActor = TextActor::DownCast( characterLayout.mGlyphActor );
404 textActors.push_back( textActor );
410 void CollectTextActorsFromWords( std::vector<TextActor>& textActors, const WordGroupLayoutInfo& group, const std::size_t wordIndexBegin, const std::size_t wordIndexEnd )
412 for( WordLayoutInfoContainer::const_iterator wordIt = group.mWordsLayoutInfo.begin() + wordIndexBegin, wordEndIt = group.mWordsLayoutInfo.begin() + wordIndexEnd;
416 const WordLayoutInfo& word( *wordIt );
418 for( CharacterLayoutInfoContainer::const_iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
419 characterIt != characterEndIt;
422 const CharacterLayoutInfo& characterLayout( *characterIt );
424 if( !characterLayout.mIsColorGlyph )
426 TextActor textActor = TextActor::DownCast( characterLayout.mGlyphActor );
429 textActors.push_back( textActor );
436 } //namespace TextViewProcessor
438 } //namespace Internal
440 } //namespace Toolkit