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.
48 WordLayoutInfo::WordLayoutInfo()
52 mFirstCharacter( 0u ),
53 mCharactersLayoutInfo()
57 WordLayoutInfo::~WordLayoutInfo()
61 WordLayoutInfo::WordLayoutInfo( const WordLayoutInfo& word )
62 : mSize( word.mSize ),
63 mAscender( word.mAscender ),
65 mFirstCharacter( word.mFirstCharacter ),
66 mCharactersLayoutInfo( word.mCharactersLayoutInfo )
70 WordLayoutInfo& WordLayoutInfo::operator=( const WordLayoutInfo& word )
73 mAscender = word.mAscender;
75 mFirstCharacter = word.mFirstCharacter;
76 mCharactersLayoutInfo = word.mCharactersLayoutInfo;
81 void CreateWordTextInfo( const Text& paragraph,
82 Vector<TextStyle*>& textStyles,
83 WordLayoutInfo& wordLayoutInfo )
85 DALI_LOG_INFO( gTextViewProcessorLogFilter, Debug::General, "-->TextViewProcessor::CreateWordTextInfo\n" );
86 // Split in characters.
87 std::size_t characterIndex = wordLayoutInfo.mFirstCharacter;
88 for( CharacterLayoutInfoContainer::iterator it = wordLayoutInfo.mCharactersLayoutInfo.begin(),
89 endIt = wordLayoutInfo.mCharactersLayoutInfo.end();
91 ++it, ++characterIndex )
93 // Gets a reference of the character's layout info.
94 CharacterLayoutInfo& characterLayoutInfo( *it );
96 // Gets the character and the style for that character from the paragraph.
97 Character character = paragraph[characterIndex];
98 TextStyle* textStyle = *( textStyles.Begin() + characterIndex );
100 // Checks whether the character is an emoticon.
101 characterLayoutInfo.mIsColorGlyph = GlyphImage::IsColorGlyph( character );
102 DALI_LOG_INFO( gTextViewProcessorLogFilter, Debug::General, " Is color glyph: %s\n", ( characterLayoutInfo.mIsColorGlyph ? "True" : "False" ) );
104 if( characterLayoutInfo.mIsColorGlyph )
106 // If the character is an emoticon a predefined font is set.
107 textStyle->SetFontName( EMOJI_FONT_NAME );
111 // Checks if the font family and the font style set in the text style supports the character.
112 // If not, it chooses the right font for the given character and style.
113 ChooseFontFamilyName( character, *textStyle );
116 // Gets the metrics of the font.
117 const Font font = Font::New( FontParameters( textStyle->GetFontName(), textStyle->GetFontStyle(), textStyle->GetFontPointSize() ) );
118 const Font::Metrics metrics = font.GetMetrics( character );
119 const float ascender = font.GetAscender();
121 // Fill Natural size info for current character.
123 // The font line's height is used as character's height.
124 characterLayoutInfo.mSize.height = font.GetLineHeight();
126 // The character's advance is used as charcter's width.
127 characterLayoutInfo.mSize.width = metrics.GetAdvance();
129 // The ascender and bearing are used to position correctly glyphs of different font sizes.
130 characterLayoutInfo.mAscender = ascender;
131 characterLayoutInfo.mBearing = metrics.GetBearing();
133 if( character.IsNewLine() && !characterLayoutInfo.mIsColorGlyph )
135 // A new paragraph character '\n' doesn't have any width.
136 characterLayoutInfo.mSize.width = 0.f;
139 // Set's the underline thickness and position.
140 // Both thickness and position includes the vertical pad adjust used in effects like glow or shadow.
141 if( textStyle->IsUnderlineEnabled() )
143 characterLayoutInfo.mUnderlineThickness = font.GetUnderlineThickness();
144 characterLayoutInfo.mUnderlinePosition = font.GetUnderlinePosition();
147 // Updates the word size and ascender.
148 UpdateSize( wordLayoutInfo.mSize, characterLayoutInfo.mSize );
149 wordLayoutInfo.mAscender = std::max( wordLayoutInfo.mAscender, characterLayoutInfo.mAscender );
150 } // end of characters in the word.
151 DALI_LOG_INFO( gTextViewProcessorLogFilter, Debug::General, "<--TextViewProcessor::CreateWordTextInfo\n" );
154 void UpdateLayoutInfo( WordLayoutInfo& wordLayout )
156 // Initialize layout info for the whole word.
157 wordLayout.mSize = Size::ZERO;
158 wordLayout.mAscender = 0.f;
160 // Traverse the character layout info to update the word layout.
161 for( CharacterLayoutInfoContainer::iterator layoutIt = wordLayout.mCharactersLayoutInfo.begin(), layoutEndIt = wordLayout.mCharactersLayoutInfo.end();
162 layoutIt != layoutEndIt;
165 // Layout info for the current character.
166 CharacterLayoutInfo& layoutInfo( *layoutIt );
168 // Update layout info for the current word.
169 UpdateSize( wordLayout.mSize, layoutInfo.mSize );
170 wordLayout.mAscender = std::max( wordLayout.mAscender, layoutInfo.mAscender );
174 void RemoveCharactersFromWordInfo( TextView::RelayoutData& relayoutData,
175 const std::size_t numberOfCharacters,
177 bool& mergeParagraphs,
178 TextInfoIndices& textInfoIndicesBegin,
179 TextInfoIndices& textInfoIndicesEnd,
180 TextInfoIndices& textInfoMergeIndicesBegin,
181 TextInfoIndices& textInfoMergeIndicesEnd,
182 ParagraphLayoutInfo& paragraphLayout,
183 std::vector<TextActor>& removedTextActors )
185 const TextLayoutInfo& textLayoutInfo = relayoutData.mTextLayoutInfo;
188 WordLayoutInfo& wordLayout( *( paragraphLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex ) );
190 if( ParagraphSeparator == wordLayout.mType )
192 // If the word is a paragraph separator and there is more paragraphs, then current paragraph and the paragraph after need to be merged.
193 if( textInfoIndicesBegin.mParagraphIndex + 1u < textLayoutInfo.mParagraphsLayoutInfo.size() )
195 // current paragraph is not the last one.
197 // Update indices to merge paragraphs.
198 textInfoMergeIndicesBegin.mParagraphIndex = textInfoIndicesBegin.mParagraphIndex;
199 textInfoMergeIndicesEnd.mParagraphIndex = textInfoIndicesBegin.mParagraphIndex + 1u;
201 mergeParagraphs = true;
203 ++textInfoIndicesBegin.mParagraphIndex; // increase both indices,
204 textInfoIndicesEnd.mParagraphIndex += 2u; // will delete last paragraph.
207 ++textInfoIndicesEnd.mWordIndex; //will delete the paragraph separator;
209 else if( WordSeparator == wordLayout.mType )
211 // If the word is a word separator. Check if the word before and the word after can be merged.
213 if( ( 0u < textInfoIndicesBegin.mWordIndex ) && ( paragraphLayout.mWordsLayoutInfo.size() > textInfoIndicesBegin.mWordIndex + 1u ) )
215 const WordLayoutInfo& wordLayoutBefore( *( paragraphLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex - 1u ) );
216 const WordLayoutInfo& wordLayoutAfter( *( paragraphLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex + 1u ) );
218 if( ( NoSeparator == wordLayoutBefore.mType ) && ( NoSeparator == wordLayoutAfter.mType ) )
220 // This word is a word separator (white space) and is not the first word of the paragraph nor the last one.
223 // Set indices to merge the words.
224 textInfoMergeIndicesBegin.mWordIndex = textInfoIndicesBegin.mWordIndex - 1u; // word before word separator.
225 textInfoMergeIndicesEnd.mWordIndex = textInfoIndicesBegin.mWordIndex + 1u; // word after word separator.
227 textInfoIndicesEnd.mWordIndex += 2u; // will delete the word separator and the merged word.
231 ++textInfoIndicesEnd.mWordIndex; // will delete the word separator;
236 ++textInfoIndicesEnd.mWordIndex; // will delete the word separator;
239 else if( numberOfCharacters == wordLayout.mCharactersLayoutInfo.size() )
241 // The whole word needs to be removed.
242 ++textInfoIndicesEnd.mWordIndex; // will delete the current word.
246 // Store text-actors before removing them.
247 CollectTextActors( removedTextActors, wordLayout, textInfoIndicesBegin.mCharacterIndex, textInfoIndicesBegin.mCharacterIndex + numberOfCharacters );
249 // just remove some characters from current word.
250 RemoveCharactersFromWord( textInfoIndicesBegin.mCharacterIndex,
256 void RemoveCharactersFromWord( const std::size_t position,
257 const std::size_t numberOfCharacters,
258 WordLayoutInfo& wordLayout )
260 // Removes a given number of characters from the given word starting from the 'position' index.
263 if( 0u == numberOfCharacters )
265 // nothing to do if the number of characters is zero.
270 // Remove characters from layout and text-actor info.
271 wordLayout.mCharactersLayoutInfo.erase( wordLayout.mCharactersLayoutInfo.begin() + position, wordLayout.mCharactersLayoutInfo.begin() + position + numberOfCharacters );
273 // Some characters have been removed from the word. Update the layout info is needed.
274 UpdateLayoutInfo( wordLayout );
277 void SplitWord( const std::size_t position,
278 WordLayoutInfo& firstWordLayoutInfo,
279 WordLayoutInfo& lastWordLayoutInfo )
281 // Splits a word in two.
282 // It moves characters from the first part of the word to the last one.
287 // the whole word goes to the last part of the word.
288 lastWordLayoutInfo = firstWordLayoutInfo;
290 firstWordLayoutInfo = WordLayoutInfo();
295 if( position == firstWordLayoutInfo.mCharactersLayoutInfo.size() )
297 // the whole word goes to the first part of the word.
299 // Just delete whatever there is in the last part of the word.
300 lastWordLayoutInfo = WordLayoutInfo();
305 // Initialize output data structures.
308 lastWordLayoutInfo = WordLayoutInfo();
310 // Split layout info.
312 // Insert characters from the given index 'position' to the end.
313 lastWordLayoutInfo.mCharactersLayoutInfo.insert( lastWordLayoutInfo.mCharactersLayoutInfo.end(),
314 firstWordLayoutInfo.mCharactersLayoutInfo.begin() + position, firstWordLayoutInfo.mCharactersLayoutInfo.end() );
316 // Delete characters from the first part of the word.
317 firstWordLayoutInfo.mCharactersLayoutInfo.erase( firstWordLayoutInfo.mCharactersLayoutInfo.begin() + position, firstWordLayoutInfo.mCharactersLayoutInfo.end() );
319 // Update the layout info of both new words.
320 UpdateLayoutInfo( firstWordLayoutInfo );
321 UpdateLayoutInfo( lastWordLayoutInfo );
324 void MergeWord( WordLayoutInfo& firstWordLayoutInfo,
325 const WordLayoutInfo& lastWordLayoutInfo )
327 // Merges two given words.
330 if( lastWordLayoutInfo.mCharactersLayoutInfo.empty() )
336 if( firstWordLayoutInfo.mCharactersLayoutInfo.empty() )
338 // copy last to first
340 firstWordLayoutInfo = lastWordLayoutInfo;
345 if( ( NoSeparator != firstWordLayoutInfo.mType ) || ( NoSeparator != lastWordLayoutInfo.mType ) )
347 // Do not merge white spaces or new paragraph characters.
348 DALI_ASSERT_ALWAYS( !"TextViewProcessor::MergeWord(). ERROR: White spaces or new paragraph characters can't be merged with other words." );
352 firstWordLayoutInfo.mCharactersLayoutInfo.insert( firstWordLayoutInfo.mCharactersLayoutInfo.end(),
353 lastWordLayoutInfo.mCharactersLayoutInfo.begin(),
354 lastWordLayoutInfo.mCharactersLayoutInfo.end() );
356 // Update the word layout info.
357 UpdateSize( firstWordLayoutInfo.mSize, lastWordLayoutInfo.mSize );
358 firstWordLayoutInfo.mAscender = std::max( firstWordLayoutInfo.mAscender, lastWordLayoutInfo.mAscender );
361 CharacterLayoutInfo GetFirstCharacterLayoutInfo( const WordLayoutInfo& wordLayoutInfo )
363 CharacterLayoutInfo layoutInfo;
365 if( !wordLayoutInfo.mCharactersLayoutInfo.empty() )
367 layoutInfo = *wordLayoutInfo.mCharactersLayoutInfo.begin();
373 CharacterLayoutInfo GetLastCharacterLayoutInfo( const WordLayoutInfo& wordLayoutInfo )
375 CharacterLayoutInfo layoutInfo;
377 if( !wordLayoutInfo.mCharactersLayoutInfo.empty() )
379 layoutInfo = *( wordLayoutInfo.mCharactersLayoutInfo.end() - 1u );
385 void CollectTextActors( std::vector<TextActor>& textActors, const WordLayoutInfo& word, const std::size_t characterIndexBegin, const std::size_t characterIndexEnd )
387 for( CharacterLayoutInfoContainer::const_iterator characterIt = word.mCharactersLayoutInfo.begin() + characterIndexBegin,
388 characterEndIt = word.mCharactersLayoutInfo.begin() + characterIndexEnd;
389 characterIt != characterEndIt;
392 const CharacterLayoutInfo& characterLayout( *characterIt );
394 if( !characterLayout.mIsColorGlyph )
396 TextActor textActor = TextActor::DownCast( characterLayout.mGlyphActor );
399 textActors.push_back( textActor );
405 void CollectTextActorsFromWords( std::vector<TextActor>& textActors, const ParagraphLayoutInfo& paragraph, const std::size_t wordIndexBegin, const std::size_t wordIndexEnd )
407 for( WordLayoutInfoContainer::const_iterator wordIt = paragraph.mWordsLayoutInfo.begin() + wordIndexBegin, wordEndIt = paragraph.mWordsLayoutInfo.begin() + wordIndexEnd;
411 const WordLayoutInfo& word( *wordIt );
413 for( CharacterLayoutInfoContainer::const_iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
414 characterIt != characterEndIt;
417 const CharacterLayoutInfo& characterLayout( *characterIt );
419 if( !characterLayout.mIsColorGlyph )
421 TextActor textActor = TextActor::DownCast( characterLayout.mGlyphActor );
424 textActors.push_back( textActor );
431 } //namespace TextViewProcessor
433 } //namespace Internal
435 } //namespace Toolkit