Fix issues related with cameras.
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / text-view / text-view-word-processor.cpp
1 //
2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
3 //
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
7 //
8 //     http://floralicense.org/license/
9 //
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.
15 //
16
17 // INTERNAL INCLUDES
18 #include "text-view-word-processor.h"
19 #include "text-view-processor-helper-functions.h"
20
21 namespace Dali
22 {
23
24 namespace Toolkit
25 {
26
27 namespace Internal
28 {
29
30 namespace TextViewProcessor
31 {
32
33 namespace
34 {
35
36 /**
37  * Updates the word size and ascender.
38  *
39  * It's called after deleting some characters.
40  *
41  * @param[in] wordLayout The word layout info.
42  */
43 void UpdateLayoutInfo( WordLayoutInfo& wordLayout )
44 {
45   // Initialize layout info for the whole word.
46   wordLayout.mSize = Size();
47   wordLayout.mAscender = 0.f;
48
49   // Traverse the character layout info to update the word layout.
50   for( CharacterLayoutInfoContainer::iterator layoutIt = wordLayout.mCharactersLayoutInfo.begin(), layoutEndIt = wordLayout.mCharactersLayoutInfo.end();
51        layoutIt != layoutEndIt;
52        ++layoutIt )
53   {
54     // Layout info for the current character.
55     CharacterLayoutInfo& layoutInfo( *layoutIt );
56
57     // Update layout info for the current word.
58     UpdateSize( wordLayout.mSize, layoutInfo.mSize );
59     wordLayout.mAscender = std::max( wordLayout.mAscender, layoutInfo.mAscender );
60   }
61 }
62
63 } // namespace
64
65 /////////////////////
66 // Layout info.
67 /////////////////////
68
69 WordLayoutInfo::WordLayoutInfo()
70 : mSize(),
71   mAscender( 0.f ),
72   mType( NoSeparator ),
73   mCharactersLayoutInfo()
74 {
75 }
76
77 WordLayoutInfo::WordLayoutInfo( const WordLayoutInfo& word )
78 : mSize( word.mSize ),
79   mAscender( word.mAscender ),
80   mType( word.mType ),
81   mCharactersLayoutInfo( word.mCharactersLayoutInfo )
82 {
83 }
84
85 WordLayoutInfo& WordLayoutInfo::operator=( const WordLayoutInfo& word )
86 {
87   mSize = word.mSize;
88   mAscender = word.mAscender;
89   mType = word.mType;
90   mCharactersLayoutInfo = word.mCharactersLayoutInfo;
91
92   return *this;
93 }
94
95 void CreateWordTextInfo( const MarkupProcessor::StyledTextArray& word,
96                          TextViewProcessor::WordLayoutInfo& wordLayoutInfo )
97 {
98   // Split in characters.
99   for( MarkupProcessor::StyledTextArray::const_iterator charIt = word.begin(), charEndIt = word.end(); charIt != charEndIt; ++charIt )
100   {
101     const MarkupProcessor::StyledText& styledText( *charIt );
102
103     const std::size_t length = styledText.mText.GetLength();
104
105     // It could be a group of characters.
106     for( std::size_t index = 0; index < length; ++index )
107     {
108       MarkupProcessor::StyledText styledCharacter;
109       styledCharacter.mStyle = styledText.mStyle;
110       Character character = styledText.mText[index];
111       styledCharacter.mText.Append( character );
112
113       //Choose the right font for the given character and style.
114       ChooseFontFamilyName( styledCharacter );
115
116       const Font font = Font::New( FontParameters( styledCharacter.mStyle.GetFontName(), styledCharacter.mStyle.GetFontStyle(), styledCharacter.mStyle.GetFontPointSize() ) );
117       const Font::Metrics metrics = font.GetMetrics( character );
118       const float ascender = font.GetAscender();
119
120       // Create layout character info.
121       CharacterLayoutInfo characterLayoutInfo;
122
123       // Fill Natural size info for current character.
124       characterLayoutInfo.mHeight = font.GetLineHeight();
125       characterLayoutInfo.mAdvance = metrics.GetAdvance();
126       characterLayoutInfo.mBearing = metrics.GetBearing();
127
128       if( character.IsNewLine() )
129       {
130         // A new line character doesn't have any width.
131         characterLayoutInfo.mSize.width = 0.f;
132       }
133       else
134       {
135         // Uses advance as width.
136         characterLayoutInfo.mSize.width = characterLayoutInfo.mAdvance;
137       }
138       characterLayoutInfo.mSize.height = characterLayoutInfo.mHeight;
139       characterLayoutInfo.mAscender = ascender;
140
141       if( styledCharacter.mStyle.GetUnderline() )
142       {
143         characterLayoutInfo.mUnderlineThickness = font.GetUnderlineThickness(); // Both thickness and position includes the
144         characterLayoutInfo.mUnderlinePosition = font.GetUnderlinePosition();   // vertical pad adjust used in effects like glow or shadow.
145       }
146
147       // stores the styled text.
148       characterLayoutInfo.mStyledText.mText = styledCharacter.mText;
149       characterLayoutInfo.mStyledText.mStyle = styledCharacter.mStyle;
150
151       // Add character layout info to the word layout info and update it.
152       wordLayoutInfo.mCharactersLayoutInfo.push_back( characterLayoutInfo );
153       UpdateSize( wordLayoutInfo.mSize, characterLayoutInfo.mSize );
154       wordLayoutInfo.mAscender = std::max( wordLayoutInfo.mAscender, characterLayoutInfo.mAscender );
155       wordLayoutInfo.mType = GetTextSeparatorType( character );
156     } // end of each character in the group of characters.
157   } // end of characters in the word.
158 }
159
160 void RemoveCharactersFromWordInfo( TextView::RelayoutData& relayoutData,
161                                    const std::size_t numberOfCharacters,
162                                    bool& mergeWords,
163                                    bool& mergeLines,
164                                    TextViewProcessor::TextInfoIndices& textInfoIndicesBegin,
165                                    TextViewProcessor::TextInfoIndices& textInfoIndicesEnd,
166                                    TextViewProcessor::TextInfoIndices& textInfoMergeIndicesBegin,
167                                    TextViewProcessor::TextInfoIndices& textInfoMergeIndicesEnd,
168                                    TextViewProcessor::WordGroupLayoutInfo& groupLayout,
169                                    std::vector<TextActor>& removedTextActors )
170 {
171   const TextViewProcessor::TextLayoutInfo& textLayoutInfo = relayoutData.mTextLayoutInfo;
172
173   // Get the word.
174   WordLayoutInfo& wordLayout( *( groupLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex ) );
175
176   if( TextViewProcessor::LineSeparator == wordLayout.mType )
177   {
178     // If the word is a line separator and there is more lines, then current line and the line after need to be merged.
179     if( textInfoIndicesBegin.mLineIndex + 1 < textLayoutInfo.mLinesLayoutInfo.size() )
180     {
181       // current line is not the last one.
182
183       // Update indices to merge lines.
184       textInfoMergeIndicesBegin.mLineIndex = textInfoIndicesBegin.mLineIndex;
185       textInfoMergeIndicesEnd.mLineIndex = textInfoIndicesBegin.mLineIndex + 1;
186
187       mergeLines = true;
188
189       ++textInfoIndicesBegin.mLineIndex; // increase both indices,
190       textInfoIndicesEnd.mLineIndex +=2; // will delete last line.
191     }
192
193     ++textInfoIndicesEnd.mWordIndex; //will delete the line separator;
194   }
195   else if( WordSeparator == wordLayout.mType )
196   {
197     // If the word is a word separator. Check if the word before and the word after can be merged.
198
199     if( ( 0 < textInfoIndicesBegin.mWordIndex ) && ( groupLayout.mWordsLayoutInfo.size() > textInfoIndicesBegin.mWordIndex + 1 ) )
200     {
201       const WordLayoutInfo& wordLayoutBefore( *( groupLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex - 1 ) );
202       const WordLayoutInfo& wordLayoutAfter( *( groupLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex + 1 ) );
203
204       if( ( NoSeparator == wordLayoutBefore.mType ) && ( NoSeparator == wordLayoutAfter.mType ) )
205       {
206         // This word is a word separator (white space) and is not the first word of the group nor the last one.
207         mergeWords = true;
208
209         // Set indices to merge the words.
210         textInfoMergeIndicesBegin.mWordIndex = textInfoIndicesBegin.mWordIndex - 1; // word before word separator.
211         textInfoMergeIndicesEnd.mWordIndex = textInfoIndicesBegin.mWordIndex + 1; // word after word separator.
212
213         textInfoIndicesEnd.mWordIndex += 2; // will delete the word separator and the merged word.
214       }
215       else
216       {
217         ++textInfoIndicesEnd.mWordIndex; // will delete the word separator;
218       }
219     }
220     else
221     {
222       ++textInfoIndicesEnd.mWordIndex; // will delete the word separator;
223     }
224   }
225   else if( numberOfCharacters == wordLayout.mCharactersLayoutInfo.size() )
226   {
227     // The whole word needs to be removed.
228     ++textInfoIndicesEnd.mWordIndex; // will delete the current word.
229   }
230   else
231   {
232     // Store text-actors before removing them.
233     CollectTextActors( removedTextActors, wordLayout, textInfoIndicesBegin.mCharacterIndex, textInfoIndicesBegin.mCharacterIndex + numberOfCharacters );
234
235     // just remove some characters from current word.
236     RemoveCharactersFromWord( textInfoIndicesBegin.mCharacterIndex,
237                               numberOfCharacters,
238                               wordLayout );
239   }
240 }
241
242 void RemoveCharactersFromWord( const std::size_t position,
243                                const std::size_t numberOfCharacters,
244                                WordLayoutInfo& wordLayout )
245 {
246   // Removes a given number of characters from the given word starting from the 'position' index.
247
248   // Early return.
249   if( 0 == numberOfCharacters )
250   {
251     // nothing to do if the number of characters is zero.
252
253     return;
254   }
255
256   // Remove characters from layout and text-actor info.
257   wordLayout.mCharactersLayoutInfo.erase( wordLayout.mCharactersLayoutInfo.begin() + position, wordLayout.mCharactersLayoutInfo.begin() + position + numberOfCharacters );
258
259   // Some characters have been removed from the word. Update the layout info is needed.
260   UpdateLayoutInfo( wordLayout );
261 }
262
263 void SplitWord( const std::size_t position,
264                 WordLayoutInfo& firstWordLayoutInfo,
265                 WordLayoutInfo& lastWordLayoutInfo )
266 {
267   // Splits a word in two.
268   // It moves characters from the first part of the word to the last one.
269
270   // early returns
271   if( 0 == position )
272   {
273     // the whole word goes to the last part of the word.
274     lastWordLayoutInfo = firstWordLayoutInfo;
275
276     firstWordLayoutInfo = WordLayoutInfo();
277
278     return;
279   }
280
281   if( position == firstWordLayoutInfo.mCharactersLayoutInfo.size() )
282   {
283     // the whole word goes to the first part of the word.
284
285     // Just delete whatever there is in the last part of the word.
286     lastWordLayoutInfo = WordLayoutInfo();
287
288     return;
289   }
290
291   // Initialize output data structures.
292
293   // Layout info
294   lastWordLayoutInfo = WordLayoutInfo();
295
296   // Split layout info.
297
298   // Insert characters from the given index 'position' to the end.
299   lastWordLayoutInfo.mCharactersLayoutInfo.insert( lastWordLayoutInfo.mCharactersLayoutInfo.end(),
300                                                    firstWordLayoutInfo.mCharactersLayoutInfo.begin() + position, firstWordLayoutInfo.mCharactersLayoutInfo.end() );
301
302   // Delete characters from the first part of the word.
303   firstWordLayoutInfo.mCharactersLayoutInfo.erase( firstWordLayoutInfo.mCharactersLayoutInfo.begin() + position, firstWordLayoutInfo.mCharactersLayoutInfo.end() );
304
305   // Update the layout info of both new words.
306   UpdateLayoutInfo( firstWordLayoutInfo );
307   UpdateLayoutInfo( lastWordLayoutInfo );
308 }
309
310 void MergeWord( WordLayoutInfo& firstWordLayoutInfo,
311                 const WordLayoutInfo& lastWordLayoutInfo )
312 {
313   // Merges two given words.
314
315   // Early returns.
316   if( lastWordLayoutInfo.mCharactersLayoutInfo.empty() )
317   {
318     // nothing to do
319     return;
320   }
321
322   if( firstWordLayoutInfo.mCharactersLayoutInfo.empty() )
323   {
324     // copy last to first
325
326     firstWordLayoutInfo = lastWordLayoutInfo;
327
328     return;
329   }
330
331   if( ( NoSeparator != firstWordLayoutInfo.mType ) || ( NoSeparator != lastWordLayoutInfo.mType ) )
332   {
333     // Do not merge white spaces or new line characters.
334     DALI_ASSERT_ALWAYS( !"TextViewProcessor::MergeWord(). ERROR: White spaces or new line characters can't be merged with other words." );
335   }
336
337   // Merge layout info
338   firstWordLayoutInfo.mCharactersLayoutInfo.insert( firstWordLayoutInfo.mCharactersLayoutInfo.end(),
339                                                     lastWordLayoutInfo.mCharactersLayoutInfo.begin(),
340                                                     lastWordLayoutInfo.mCharactersLayoutInfo.end() );
341
342   // Update the word layout info.
343   UpdateSize( firstWordLayoutInfo.mSize, lastWordLayoutInfo.mSize );
344   firstWordLayoutInfo.mAscender = std::max( firstWordLayoutInfo.mAscender, lastWordLayoutInfo.mAscender );
345 }
346
347 CharacterLayoutInfo GetFirstCharacterLayoutInfo( const WordLayoutInfo& wordLayoutInfo )
348 {
349   CharacterLayoutInfo layoutInfo;
350
351   if( !wordLayoutInfo.mCharactersLayoutInfo.empty() )
352   {
353     layoutInfo = *wordLayoutInfo.mCharactersLayoutInfo.begin();
354   }
355
356   return layoutInfo;
357 }
358
359 CharacterLayoutInfo GetLastCharacterLayoutInfo( const WordLayoutInfo& wordLayoutInfo )
360 {
361   CharacterLayoutInfo layoutInfo;
362
363   if( !wordLayoutInfo.mCharactersLayoutInfo.empty() )
364   {
365     layoutInfo = *( wordLayoutInfo.mCharactersLayoutInfo.end() - 1 );
366   }
367
368   return layoutInfo;
369 }
370
371 void CollectTextActors( std::vector<TextActor>& textActors, const WordLayoutInfo& word, const std::size_t characterIndexBegin, const std::size_t characterIndexEnd )
372 {
373   for( CharacterLayoutInfoContainer::const_iterator characterIt = word.mCharactersLayoutInfo.begin() + characterIndexBegin,
374          characterEndIt = word.mCharactersLayoutInfo.begin() + characterIndexEnd;
375        characterIt != characterEndIt;
376        ++characterIt )
377   {
378     const CharacterLayoutInfo& characterLayout( *characterIt );
379
380     if( characterLayout.mTextActor )
381     {
382       textActors.push_back( characterLayout.mTextActor );
383     }
384   }
385 }
386
387 void CollectTextActorsFromWords( std::vector<TextActor>& textActors, const WordGroupLayoutInfo& group, const std::size_t wordIndexBegin, const std::size_t wordIndexEnd )
388 {
389   for( WordLayoutInfoContainer::const_iterator wordIt = group.mWordsLayoutInfo.begin() + wordIndexBegin, wordEndIt = group.mWordsLayoutInfo.begin() + wordIndexEnd;
390        wordIt != wordEndIt;
391        ++wordIt )
392   {
393     const WordLayoutInfo& word( *wordIt );
394
395     for( CharacterLayoutInfoContainer::const_iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
396          characterIt != characterEndIt;
397          ++characterIt )
398     {
399       const CharacterLayoutInfo& characterLayout( *characterIt );
400
401       if( characterLayout.mTextActor )
402       {
403         textActors.push_back( characterLayout.mTextActor );
404       }
405     }
406   }
407 }
408
409 } //namespace TextViewProcessor
410
411 } //namespace Internal
412
413 } //namespace Toolkit
414
415 } //namespace Dali