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
42 * Updates the word size and ascender.
44 * It's called after deleting some characters.
46 * @param[in] wordLayout The word layout info.
48 void UpdateLayoutInfo( WordLayoutInfo& wordLayout )
50 // Initialize layout info for the whole word.
51 wordLayout.mSize = Size();
52 wordLayout.mAscender = 0.f;
54 // Traverse the character layout info to update the word layout.
55 for( CharacterLayoutInfoContainer::iterator layoutIt = wordLayout.mCharactersLayoutInfo.begin(), layoutEndIt = wordLayout.mCharactersLayoutInfo.end();
56 layoutIt != layoutEndIt;
59 // Layout info for the current character.
60 CharacterLayoutInfo& layoutInfo( *layoutIt );
62 // Update layout info for the current word.
63 UpdateSize( wordLayout.mSize, layoutInfo.mSize );
64 wordLayout.mAscender = std::max( wordLayout.mAscender, layoutInfo.mAscender );
74 WordLayoutInfo::WordLayoutInfo()
78 mCharactersLayoutInfo()
82 WordLayoutInfo::WordLayoutInfo( const WordLayoutInfo& word )
83 : mSize( word.mSize ),
84 mAscender( word.mAscender ),
86 mCharactersLayoutInfo( word.mCharactersLayoutInfo )
90 WordLayoutInfo& WordLayoutInfo::operator=( const WordLayoutInfo& word )
93 mAscender = word.mAscender;
95 mCharactersLayoutInfo = word.mCharactersLayoutInfo;
100 void CreateWordTextInfo( const MarkupProcessor::StyledTextArray& word,
101 TextViewProcessor::WordLayoutInfo& wordLayoutInfo )
103 DALI_LOG_INFO( gTextViewProcessorLogFilter, Debug::General, "-->TextViewProcessor::CreateWordTextInfo\n" );
104 // Split in characters.
105 for( MarkupProcessor::StyledTextArray::const_iterator charIt = word.begin(), charEndIt = word.end(); charIt != charEndIt; ++charIt )
107 const MarkupProcessor::StyledText& styledText( *charIt );
109 const std::size_t length = styledText.mText.GetLength();
111 // It could be a group of characters.
112 for( std::size_t index = 0; index < length; ++index )
114 MarkupProcessor::StyledText styledCharacter;
115 styledCharacter.mStyle = styledText.mStyle;
116 Character character = styledText.mText[index];
117 styledCharacter.mText.Append( character );
119 //Choose the right font for the given character and style.
120 ChooseFontFamilyName( styledCharacter );
122 const Font font = Font::New( FontParameters( styledCharacter.mStyle.GetFontName(), styledCharacter.mStyle.GetFontStyle(), styledCharacter.mStyle.GetFontPointSize() ) );
123 const Font::Metrics metrics = font.GetMetrics( character );
124 const float ascender = font.GetAscender();
126 // Create layout character info.
127 CharacterLayoutInfo characterLayoutInfo;
129 characterLayoutInfo.mIsColorGlyph = GlyphImage::IsColorGlyph( character );
130 DALI_LOG_INFO( gTextViewProcessorLogFilter, Debug::General, " Is color glyph: %s\n", ( characterLayoutInfo.mIsColorGlyph ? "True" : "False" ) );
132 // Fill Natural size info for current character.
133 characterLayoutInfo.mHeight = font.GetLineHeight();
134 characterLayoutInfo.mAdvance = metrics.GetAdvance();
135 characterLayoutInfo.mBearing = metrics.GetBearing();
137 if( character.IsNewLine() && !characterLayoutInfo.mIsColorGlyph )
139 // A new line character doesn't have any width.
140 characterLayoutInfo.mSize.width = 0.f;
144 // Uses advance as width.
145 characterLayoutInfo.mSize.width = characterLayoutInfo.mAdvance;
147 characterLayoutInfo.mSize.height = characterLayoutInfo.mHeight;
148 characterLayoutInfo.mAscender = ascender;
150 if( styledCharacter.mStyle.GetUnderline() )
152 characterLayoutInfo.mUnderlineThickness = font.GetUnderlineThickness(); // Both thickness and position includes the
153 characterLayoutInfo.mUnderlinePosition = font.GetUnderlinePosition(); // vertical pad adjust used in effects like glow or shadow.
156 // stores the styled text.
157 characterLayoutInfo.mStyledText.mText = styledCharacter.mText;
158 characterLayoutInfo.mStyledText.mStyle = styledCharacter.mStyle;
160 // Add character layout info to the word layout info and update it.
161 wordLayoutInfo.mCharactersLayoutInfo.push_back( characterLayoutInfo );
162 UpdateSize( wordLayoutInfo.mSize, characterLayoutInfo.mSize );
163 wordLayoutInfo.mAscender = std::max( wordLayoutInfo.mAscender, characterLayoutInfo.mAscender );
164 wordLayoutInfo.mType = GetTextSeparatorType( character );
165 } // end of each character in the group of characters.
166 } // end of characters in the word.
167 DALI_LOG_INFO( gTextViewProcessorLogFilter, Debug::General, "<--TextViewProcessor::CreateWordTextInfo\n" );
170 void RemoveCharactersFromWordInfo( TextView::RelayoutData& relayoutData,
171 const std::size_t numberOfCharacters,
174 TextViewProcessor::TextInfoIndices& textInfoIndicesBegin,
175 TextViewProcessor::TextInfoIndices& textInfoIndicesEnd,
176 TextViewProcessor::TextInfoIndices& textInfoMergeIndicesBegin,
177 TextViewProcessor::TextInfoIndices& textInfoMergeIndicesEnd,
178 TextViewProcessor::WordGroupLayoutInfo& groupLayout,
179 std::vector<TextActor>& removedTextActors )
181 const TextViewProcessor::TextLayoutInfo& textLayoutInfo = relayoutData.mTextLayoutInfo;
184 WordLayoutInfo& wordLayout( *( groupLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex ) );
186 if( TextViewProcessor::LineSeparator == wordLayout.mType )
188 // If the word is a line separator and there is more lines, then current line and the line after need to be merged.
189 if( textInfoIndicesBegin.mLineIndex + 1 < textLayoutInfo.mLinesLayoutInfo.size() )
191 // current line is not the last one.
193 // Update indices to merge lines.
194 textInfoMergeIndicesBegin.mLineIndex = textInfoIndicesBegin.mLineIndex;
195 textInfoMergeIndicesEnd.mLineIndex = textInfoIndicesBegin.mLineIndex + 1;
199 ++textInfoIndicesBegin.mLineIndex; // increase both indices,
200 textInfoIndicesEnd.mLineIndex +=2; // will delete last line.
203 ++textInfoIndicesEnd.mWordIndex; //will delete the line separator;
205 else if( WordSeparator == wordLayout.mType )
207 // If the word is a word separator. Check if the word before and the word after can be merged.
209 if( ( 0 < textInfoIndicesBegin.mWordIndex ) && ( groupLayout.mWordsLayoutInfo.size() > textInfoIndicesBegin.mWordIndex + 1 ) )
211 const WordLayoutInfo& wordLayoutBefore( *( groupLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex - 1 ) );
212 const WordLayoutInfo& wordLayoutAfter( *( groupLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex + 1 ) );
214 if( ( NoSeparator == wordLayoutBefore.mType ) && ( NoSeparator == wordLayoutAfter.mType ) )
216 // This word is a word separator (white space) and is not the first word of the group nor the last one.
219 // Set indices to merge the words.
220 textInfoMergeIndicesBegin.mWordIndex = textInfoIndicesBegin.mWordIndex - 1; // word before word separator.
221 textInfoMergeIndicesEnd.mWordIndex = textInfoIndicesBegin.mWordIndex + 1; // word after word separator.
223 textInfoIndicesEnd.mWordIndex += 2; // will delete the word separator and the merged word.
227 ++textInfoIndicesEnd.mWordIndex; // will delete the word separator;
232 ++textInfoIndicesEnd.mWordIndex; // will delete the word separator;
235 else if( numberOfCharacters == wordLayout.mCharactersLayoutInfo.size() )
237 // The whole word needs to be removed.
238 ++textInfoIndicesEnd.mWordIndex; // will delete the current word.
242 // Store text-actors before removing them.
243 CollectTextActors( removedTextActors, wordLayout, textInfoIndicesBegin.mCharacterIndex, textInfoIndicesBegin.mCharacterIndex + numberOfCharacters );
245 // just remove some characters from current word.
246 RemoveCharactersFromWord( textInfoIndicesBegin.mCharacterIndex,
252 void RemoveCharactersFromWord( const std::size_t position,
253 const std::size_t numberOfCharacters,
254 WordLayoutInfo& wordLayout )
256 // Removes a given number of characters from the given word starting from the 'position' index.
259 if( 0 == numberOfCharacters )
261 // nothing to do if the number of characters is zero.
266 // Remove characters from layout and text-actor info.
267 wordLayout.mCharactersLayoutInfo.erase( wordLayout.mCharactersLayoutInfo.begin() + position, wordLayout.mCharactersLayoutInfo.begin() + position + numberOfCharacters );
269 // Some characters have been removed from the word. Update the layout info is needed.
270 UpdateLayoutInfo( wordLayout );
273 void SplitWord( const std::size_t position,
274 WordLayoutInfo& firstWordLayoutInfo,
275 WordLayoutInfo& lastWordLayoutInfo )
277 // Splits a word in two.
278 // It moves characters from the first part of the word to the last one.
283 // the whole word goes to the last part of the word.
284 lastWordLayoutInfo = firstWordLayoutInfo;
286 firstWordLayoutInfo = WordLayoutInfo();
291 if( position == firstWordLayoutInfo.mCharactersLayoutInfo.size() )
293 // the whole word goes to the first part of the word.
295 // Just delete whatever there is in the last part of the word.
296 lastWordLayoutInfo = WordLayoutInfo();
301 // Initialize output data structures.
304 lastWordLayoutInfo = WordLayoutInfo();
306 // Split layout info.
308 // Insert characters from the given index 'position' to the end.
309 lastWordLayoutInfo.mCharactersLayoutInfo.insert( lastWordLayoutInfo.mCharactersLayoutInfo.end(),
310 firstWordLayoutInfo.mCharactersLayoutInfo.begin() + position, firstWordLayoutInfo.mCharactersLayoutInfo.end() );
312 // Delete characters from the first part of the word.
313 firstWordLayoutInfo.mCharactersLayoutInfo.erase( firstWordLayoutInfo.mCharactersLayoutInfo.begin() + position, firstWordLayoutInfo.mCharactersLayoutInfo.end() );
315 // Update the layout info of both new words.
316 UpdateLayoutInfo( firstWordLayoutInfo );
317 UpdateLayoutInfo( lastWordLayoutInfo );
320 void MergeWord( WordLayoutInfo& firstWordLayoutInfo,
321 const WordLayoutInfo& lastWordLayoutInfo )
323 // Merges two given words.
326 if( lastWordLayoutInfo.mCharactersLayoutInfo.empty() )
332 if( firstWordLayoutInfo.mCharactersLayoutInfo.empty() )
334 // copy last to first
336 firstWordLayoutInfo = lastWordLayoutInfo;
341 if( ( NoSeparator != firstWordLayoutInfo.mType ) || ( NoSeparator != lastWordLayoutInfo.mType ) )
343 // Do not merge white spaces or new line characters.
344 DALI_ASSERT_ALWAYS( !"TextViewProcessor::MergeWord(). ERROR: White spaces or new line characters can't be merged with other words." );
348 firstWordLayoutInfo.mCharactersLayoutInfo.insert( firstWordLayoutInfo.mCharactersLayoutInfo.end(),
349 lastWordLayoutInfo.mCharactersLayoutInfo.begin(),
350 lastWordLayoutInfo.mCharactersLayoutInfo.end() );
352 // Update the word layout info.
353 UpdateSize( firstWordLayoutInfo.mSize, lastWordLayoutInfo.mSize );
354 firstWordLayoutInfo.mAscender = std::max( firstWordLayoutInfo.mAscender, lastWordLayoutInfo.mAscender );
357 CharacterLayoutInfo GetFirstCharacterLayoutInfo( const WordLayoutInfo& wordLayoutInfo )
359 CharacterLayoutInfo layoutInfo;
361 if( !wordLayoutInfo.mCharactersLayoutInfo.empty() )
363 layoutInfo = *wordLayoutInfo.mCharactersLayoutInfo.begin();
369 CharacterLayoutInfo GetLastCharacterLayoutInfo( const WordLayoutInfo& wordLayoutInfo )
371 CharacterLayoutInfo layoutInfo;
373 if( !wordLayoutInfo.mCharactersLayoutInfo.empty() )
375 layoutInfo = *( wordLayoutInfo.mCharactersLayoutInfo.end() - 1 );
381 void CollectTextActors( std::vector<TextActor>& textActors, const WordLayoutInfo& word, const std::size_t characterIndexBegin, const std::size_t characterIndexEnd )
383 for( CharacterLayoutInfoContainer::const_iterator characterIt = word.mCharactersLayoutInfo.begin() + characterIndexBegin,
384 characterEndIt = word.mCharactersLayoutInfo.begin() + characterIndexEnd;
385 characterIt != characterEndIt;
388 const CharacterLayoutInfo& characterLayout( *characterIt );
390 if( !characterLayout.mIsColorGlyph )
392 TextActor textActor = TextActor::DownCast( characterLayout.mGlyphActor );
395 textActors.push_back( textActor );
401 void CollectTextActorsFromWords( std::vector<TextActor>& textActors, const WordGroupLayoutInfo& group, const std::size_t wordIndexBegin, const std::size_t wordIndexEnd )
403 for( WordLayoutInfoContainer::const_iterator wordIt = group.mWordsLayoutInfo.begin() + wordIndexBegin, wordEndIt = group.mWordsLayoutInfo.begin() + wordIndexEnd;
407 const WordLayoutInfo& word( *wordIt );
409 for( CharacterLayoutInfoContainer::const_iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
410 characterIt != characterEndIt;
413 const CharacterLayoutInfo& characterLayout( *characterIt );
415 if( !characterLayout.mIsColorGlyph )
417 TextActor textActor = TextActor::DownCast( characterLayout.mGlyphActor );
420 textActors.push_back( textActor );
427 } //namespace TextViewProcessor
429 } //namespace Internal
431 } //namespace Toolkit