2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 // Licensed under the Flora License, Version 1.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://floralicense.org/license/
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.
18 #include "text-view-word-processor.h"
21 #include <dali/dali.h>
22 #include "text-view-processor-helper-functions.h"
23 #include "text-view-processor-dbg.h"
34 namespace TextViewProcessor
41 * Updates the word size and ascender.
43 * It's called after deleting some characters.
45 * @param[in] wordLayout The word layout info.
47 void UpdateLayoutInfo( WordLayoutInfo& wordLayout )
49 // Initialize layout info for the whole word.
50 wordLayout.mSize = Size();
51 wordLayout.mAscender = 0.f;
53 // Traverse the character layout info to update the word layout.
54 for( CharacterLayoutInfoContainer::iterator layoutIt = wordLayout.mCharactersLayoutInfo.begin(), layoutEndIt = wordLayout.mCharactersLayoutInfo.end();
55 layoutIt != layoutEndIt;
58 // Layout info for the current character.
59 CharacterLayoutInfo& layoutInfo( *layoutIt );
61 // Update layout info for the current word.
62 UpdateSize( wordLayout.mSize, layoutInfo.mSize );
63 wordLayout.mAscender = std::max( wordLayout.mAscender, layoutInfo.mAscender );
73 WordLayoutInfo::WordLayoutInfo()
77 mCharactersLayoutInfo()
81 WordLayoutInfo::WordLayoutInfo( const WordLayoutInfo& word )
82 : mSize( word.mSize ),
83 mAscender( word.mAscender ),
85 mCharactersLayoutInfo( word.mCharactersLayoutInfo )
89 WordLayoutInfo& WordLayoutInfo::operator=( const WordLayoutInfo& word )
92 mAscender = word.mAscender;
94 mCharactersLayoutInfo = word.mCharactersLayoutInfo;
99 void CreateWordTextInfo( const MarkupProcessor::StyledTextArray& word,
100 TextViewProcessor::WordLayoutInfo& wordLayoutInfo )
102 DALI_LOG_INFO( gTextViewProcessorLogFilter, Debug::General, "-->TextViewProcessor::CreateWordTextInfo\n" );
103 // Split in characters.
104 for( MarkupProcessor::StyledTextArray::const_iterator charIt = word.begin(), charEndIt = word.end(); charIt != charEndIt; ++charIt )
106 const MarkupProcessor::StyledText& styledText( *charIt );
108 const std::size_t length = styledText.mText.GetLength();
110 // It could be a group of characters.
111 for( std::size_t index = 0; index < length; ++index )
113 MarkupProcessor::StyledText styledCharacter;
114 styledCharacter.mStyle = styledText.mStyle;
115 Character character = styledText.mText[index];
116 styledCharacter.mText.Append( character );
118 //Choose the right font for the given character and style.
119 ChooseFontFamilyName( styledCharacter );
121 const Font font = Font::New( FontParameters( styledCharacter.mStyle.GetFontName(), styledCharacter.mStyle.GetFontStyle(), styledCharacter.mStyle.GetFontPointSize() ) );
122 const Font::Metrics metrics = font.GetMetrics( character );
123 const float ascender = font.GetAscender();
125 // Create layout character info.
126 CharacterLayoutInfo characterLayoutInfo;
128 characterLayoutInfo.mIsColorGlyph = GlyphImage::IsColorGlyph( character );
129 DALI_LOG_INFO( gTextViewProcessorLogFilter, Debug::General, " Is color glyph: %s\n", ( characterLayoutInfo.mIsColorGlyph ? "True" : "False" ) );
131 // Fill Natural size info for current character.
132 characterLayoutInfo.mHeight = font.GetLineHeight();
133 characterLayoutInfo.mAdvance = metrics.GetAdvance();
134 characterLayoutInfo.mBearing = metrics.GetBearing();
136 if( character.IsNewLine() && !characterLayoutInfo.mIsColorGlyph )
138 // A new line character doesn't have any width.
139 characterLayoutInfo.mSize.width = 0.f;
143 // Uses advance as width.
144 characterLayoutInfo.mSize.width = characterLayoutInfo.mAdvance;
146 characterLayoutInfo.mSize.height = characterLayoutInfo.mHeight;
147 characterLayoutInfo.mAscender = ascender;
149 if( styledCharacter.mStyle.GetUnderline() )
151 characterLayoutInfo.mUnderlineThickness = font.GetUnderlineThickness(); // Both thickness and position includes the
152 characterLayoutInfo.mUnderlinePosition = font.GetUnderlinePosition(); // vertical pad adjust used in effects like glow or shadow.
155 // stores the styled text.
156 characterLayoutInfo.mStyledText.mText = styledCharacter.mText;
157 characterLayoutInfo.mStyledText.mStyle = styledCharacter.mStyle;
159 // Add character layout info to the word layout info and update it.
160 wordLayoutInfo.mCharactersLayoutInfo.push_back( characterLayoutInfo );
161 UpdateSize( wordLayoutInfo.mSize, characterLayoutInfo.mSize );
162 wordLayoutInfo.mAscender = std::max( wordLayoutInfo.mAscender, characterLayoutInfo.mAscender );
163 wordLayoutInfo.mType = GetTextSeparatorType( character );
164 } // end of each character in the group of characters.
165 } // end of characters in the word.
166 DALI_LOG_INFO( gTextViewProcessorLogFilter, Debug::General, "<--TextViewProcessor::CreateWordTextInfo\n" );
169 void RemoveCharactersFromWordInfo( TextView::RelayoutData& relayoutData,
170 const std::size_t numberOfCharacters,
173 TextViewProcessor::TextInfoIndices& textInfoIndicesBegin,
174 TextViewProcessor::TextInfoIndices& textInfoIndicesEnd,
175 TextViewProcessor::TextInfoIndices& textInfoMergeIndicesBegin,
176 TextViewProcessor::TextInfoIndices& textInfoMergeIndicesEnd,
177 TextViewProcessor::WordGroupLayoutInfo& groupLayout,
178 std::vector<TextActor>& removedTextActors )
180 const TextViewProcessor::TextLayoutInfo& textLayoutInfo = relayoutData.mTextLayoutInfo;
183 WordLayoutInfo& wordLayout( *( groupLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex ) );
185 if( TextViewProcessor::LineSeparator == wordLayout.mType )
187 // If the word is a line separator and there is more lines, then current line and the line after need to be merged.
188 if( textInfoIndicesBegin.mLineIndex + 1 < textLayoutInfo.mLinesLayoutInfo.size() )
190 // current line is not the last one.
192 // Update indices to merge lines.
193 textInfoMergeIndicesBegin.mLineIndex = textInfoIndicesBegin.mLineIndex;
194 textInfoMergeIndicesEnd.mLineIndex = textInfoIndicesBegin.mLineIndex + 1;
198 ++textInfoIndicesBegin.mLineIndex; // increase both indices,
199 textInfoIndicesEnd.mLineIndex +=2; // will delete last line.
202 ++textInfoIndicesEnd.mWordIndex; //will delete the line separator;
204 else if( WordSeparator == wordLayout.mType )
206 // If the word is a word separator. Check if the word before and the word after can be merged.
208 if( ( 0 < textInfoIndicesBegin.mWordIndex ) && ( groupLayout.mWordsLayoutInfo.size() > textInfoIndicesBegin.mWordIndex + 1 ) )
210 const WordLayoutInfo& wordLayoutBefore( *( groupLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex - 1 ) );
211 const WordLayoutInfo& wordLayoutAfter( *( groupLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex + 1 ) );
213 if( ( NoSeparator == wordLayoutBefore.mType ) && ( NoSeparator == wordLayoutAfter.mType ) )
215 // This word is a word separator (white space) and is not the first word of the group nor the last one.
218 // Set indices to merge the words.
219 textInfoMergeIndicesBegin.mWordIndex = textInfoIndicesBegin.mWordIndex - 1; // word before word separator.
220 textInfoMergeIndicesEnd.mWordIndex = textInfoIndicesBegin.mWordIndex + 1; // word after word separator.
222 textInfoIndicesEnd.mWordIndex += 2; // will delete the word separator and the merged word.
226 ++textInfoIndicesEnd.mWordIndex; // will delete the word separator;
231 ++textInfoIndicesEnd.mWordIndex; // will delete the word separator;
234 else if( numberOfCharacters == wordLayout.mCharactersLayoutInfo.size() )
236 // The whole word needs to be removed.
237 ++textInfoIndicesEnd.mWordIndex; // will delete the current word.
241 // Store text-actors before removing them.
242 CollectTextActors( removedTextActors, wordLayout, textInfoIndicesBegin.mCharacterIndex, textInfoIndicesBegin.mCharacterIndex + numberOfCharacters );
244 // just remove some characters from current word.
245 RemoveCharactersFromWord( textInfoIndicesBegin.mCharacterIndex,
251 void RemoveCharactersFromWord( const std::size_t position,
252 const std::size_t numberOfCharacters,
253 WordLayoutInfo& wordLayout )
255 // Removes a given number of characters from the given word starting from the 'position' index.
258 if( 0 == numberOfCharacters )
260 // nothing to do if the number of characters is zero.
265 // Remove characters from layout and text-actor info.
266 wordLayout.mCharactersLayoutInfo.erase( wordLayout.mCharactersLayoutInfo.begin() + position, wordLayout.mCharactersLayoutInfo.begin() + position + numberOfCharacters );
268 // Some characters have been removed from the word. Update the layout info is needed.
269 UpdateLayoutInfo( wordLayout );
272 void SplitWord( const std::size_t position,
273 WordLayoutInfo& firstWordLayoutInfo,
274 WordLayoutInfo& lastWordLayoutInfo )
276 // Splits a word in two.
277 // It moves characters from the first part of the word to the last one.
282 // the whole word goes to the last part of the word.
283 lastWordLayoutInfo = firstWordLayoutInfo;
285 firstWordLayoutInfo = WordLayoutInfo();
290 if( position == firstWordLayoutInfo.mCharactersLayoutInfo.size() )
292 // the whole word goes to the first part of the word.
294 // Just delete whatever there is in the last part of the word.
295 lastWordLayoutInfo = WordLayoutInfo();
300 // Initialize output data structures.
303 lastWordLayoutInfo = WordLayoutInfo();
305 // Split layout info.
307 // Insert characters from the given index 'position' to the end.
308 lastWordLayoutInfo.mCharactersLayoutInfo.insert( lastWordLayoutInfo.mCharactersLayoutInfo.end(),
309 firstWordLayoutInfo.mCharactersLayoutInfo.begin() + position, firstWordLayoutInfo.mCharactersLayoutInfo.end() );
311 // Delete characters from the first part of the word.
312 firstWordLayoutInfo.mCharactersLayoutInfo.erase( firstWordLayoutInfo.mCharactersLayoutInfo.begin() + position, firstWordLayoutInfo.mCharactersLayoutInfo.end() );
314 // Update the layout info of both new words.
315 UpdateLayoutInfo( firstWordLayoutInfo );
316 UpdateLayoutInfo( lastWordLayoutInfo );
319 void MergeWord( WordLayoutInfo& firstWordLayoutInfo,
320 const WordLayoutInfo& lastWordLayoutInfo )
322 // Merges two given words.
325 if( lastWordLayoutInfo.mCharactersLayoutInfo.empty() )
331 if( firstWordLayoutInfo.mCharactersLayoutInfo.empty() )
333 // copy last to first
335 firstWordLayoutInfo = lastWordLayoutInfo;
340 if( ( NoSeparator != firstWordLayoutInfo.mType ) || ( NoSeparator != lastWordLayoutInfo.mType ) )
342 // Do not merge white spaces or new line characters.
343 DALI_ASSERT_ALWAYS( !"TextViewProcessor::MergeWord(). ERROR: White spaces or new line characters can't be merged with other words." );
347 firstWordLayoutInfo.mCharactersLayoutInfo.insert( firstWordLayoutInfo.mCharactersLayoutInfo.end(),
348 lastWordLayoutInfo.mCharactersLayoutInfo.begin(),
349 lastWordLayoutInfo.mCharactersLayoutInfo.end() );
351 // Update the word layout info.
352 UpdateSize( firstWordLayoutInfo.mSize, lastWordLayoutInfo.mSize );
353 firstWordLayoutInfo.mAscender = std::max( firstWordLayoutInfo.mAscender, lastWordLayoutInfo.mAscender );
356 CharacterLayoutInfo GetFirstCharacterLayoutInfo( const WordLayoutInfo& wordLayoutInfo )
358 CharacterLayoutInfo layoutInfo;
360 if( !wordLayoutInfo.mCharactersLayoutInfo.empty() )
362 layoutInfo = *wordLayoutInfo.mCharactersLayoutInfo.begin();
368 CharacterLayoutInfo GetLastCharacterLayoutInfo( const WordLayoutInfo& wordLayoutInfo )
370 CharacterLayoutInfo layoutInfo;
372 if( !wordLayoutInfo.mCharactersLayoutInfo.empty() )
374 layoutInfo = *( wordLayoutInfo.mCharactersLayoutInfo.end() - 1 );
380 void CollectTextActors( std::vector<TextActor>& textActors, const WordLayoutInfo& word, const std::size_t characterIndexBegin, const std::size_t characterIndexEnd )
382 for( CharacterLayoutInfoContainer::const_iterator characterIt = word.mCharactersLayoutInfo.begin() + characterIndexBegin,
383 characterEndIt = word.mCharactersLayoutInfo.begin() + characterIndexEnd;
384 characterIt != characterEndIt;
387 const CharacterLayoutInfo& characterLayout( *characterIt );
389 if( !characterLayout.mIsColorGlyph )
391 TextActor textActor = TextActor::DownCast( characterLayout.mGlyphActor );
394 textActors.push_back( textActor );
400 void CollectTextActorsFromWords( std::vector<TextActor>& textActors, const WordGroupLayoutInfo& group, const std::size_t wordIndexBegin, const std::size_t wordIndexEnd )
402 for( WordLayoutInfoContainer::const_iterator wordIt = group.mWordsLayoutInfo.begin() + wordIndexBegin, wordEndIt = group.mWordsLayoutInfo.begin() + wordIndexEnd;
406 const WordLayoutInfo& word( *wordIt );
408 for( CharacterLayoutInfoContainer::const_iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
409 characterIt != characterEndIt;
412 const CharacterLayoutInfo& characterLayout( *characterIt );
414 if( !characterLayout.mIsColorGlyph )
416 TextActor textActor = TextActor::DownCast( characterLayout.mGlyphActor );
419 textActors.push_back( textActor );
426 } //namespace TextViewProcessor
428 } //namespace Internal
430 } //namespace Toolkit