Remove redundant orientation settings as default camera already looks at stage
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / text-view / text-view-impl.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
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
18 // CLASS HEADER
19 #include <dali-toolkit/internal/controls/text-view/text-view-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/public-api/common/stage.h>
23 #include <dali/public-api/object/type-registry.h>
24 #include <dali/public-api/object/type-registry-helper.h>
25 #include <dali/public-api/render-tasks/render-task-list.h>
26
27 // INTERNAL INCLUDES
28 #include <dali-toolkit/internal/controls/text-view/split-by-new-line-char-policies.h>
29 #include <dali-toolkit/internal/controls/text-view/split-by-word-policies.h>
30 #include <dali-toolkit/internal/controls/text-view/split-by-char-policies.h>
31 #include <dali-toolkit/internal/controls/text-view/text-processor-bidirectional-info.h>
32 #include <dali-toolkit/internal/controls/text-view/text-view-processor.h>
33 #include <dali-toolkit/internal/controls/text-view/text-view-word-processor.h>
34 #include <dali-toolkit/internal/controls/text-view/relayout-utilities.h>
35
36 namespace Dali
37 {
38
39 namespace Toolkit
40 {
41
42 namespace Internal
43 {
44
45 namespace
46 {
47
48 const char* MULTILINE_POLICY_NAME[] = {"SplitByNewLineChar", "SplitByWord", "SplitByChar"};
49 const char* EXCEED_POLICY_NAME[] = {"Original", "Truncate", "Fade", "Split","ShrinkToFit","EllipsizeEnd"};
50 const char* LINE_JUSTIFICATION_NAME[] = {"Left","Center","Right","Justified"};
51
52 // Currently on desktop machines 2k x 2k is the maximum frame buffer size, on target is 4k x 4k.
53 const float MAX_OFFSCREEN_RENDERING_SIZE = 2048.f;
54
55 // Type Registration
56 BaseHandle Create()
57 {
58   return Toolkit::TextView::New();
59 }
60
61 // Setup properties, signals and actions using the type-registry.
62 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::TextView, Toolkit::Control, Create );
63
64 DALI_PROPERTY_REGISTRATION( TextView, "markup-enabled",       BOOLEAN, MARKUP_ENABLED       )
65 DALI_PROPERTY_REGISTRATION( TextView, "text",                 STRING,  TEXT                 )
66 DALI_PROPERTY_REGISTRATION( TextView, "multiline-policy",     STRING,  MULTILINE_POLICY     )
67 DALI_PROPERTY_REGISTRATION( TextView, "width-exceed-policy",  STRING,  WIDTH_EXCEED_POLICY  )
68 DALI_PROPERTY_REGISTRATION( TextView, "height-exceed-policy", STRING,  HEIGHT_EXCEED_POLICY )
69 DALI_PROPERTY_REGISTRATION( TextView, "line-justification",   STRING,  LINE_JUSTIFICATION   )
70 DALI_PROPERTY_REGISTRATION( TextView, "fade-boundary",        VECTOR4, FADE_BOUNDARY        )
71 DALI_PROPERTY_REGISTRATION( TextView, "line-height-offset",   FLOAT,   LINE_HEIGHT_OFFSET   )
72 DALI_PROPERTY_REGISTRATION( TextView, "horizontal-alignment", STRING,  HORIZONTAL_ALIGNMENT )
73 DALI_PROPERTY_REGISTRATION( TextView, "vertical-alignment",   STRING,  VERTICAL_ALIGNMENT   )
74
75 DALI_SIGNAL_REGISTRATION(   TextView, "scrolled",                      SIGNAL_TEXT_SCROLLED )
76
77 DALI_TYPE_REGISTRATION_END()
78
79 /**
80  * Whether the text-view-processor operation sets, inserts, replaces, removes text.
81  *
82  * @param[in] metadata The text-view-processor operation.
83  *
84  * @return \e true if the given text-view-processor operation is modifying the text.
85  */
86 bool IsTextViewProcessorRelayoutOperation( const TextView::TextViewProcessorMetadata& metadata )
87 {
88   return ( ( metadata.mType == TextView::TextSet ) ||
89            ( metadata.mType == TextView::TextInserted ) ||
90            ( metadata.mType == TextView::TextReplaced ) ||
91            ( metadata.mType == TextView::TextRemoved ) ||
92            ( metadata.mType == TextView::NewStyle ));
93 }
94
95 /**
96  * Whether the text-view-processor operation sets a new line height offset.
97  *
98  * @param[in] metadata The text-view-processor operation.
99  *
100  * @return \e true if the given text-view-processor operation sets a new line height offset.
101  */
102 bool IsTextViewProcessorLineHeightOffsetOperation( const TextView::TextViewProcessorMetadata& metadata )
103 {
104   return ( metadata.mType == TextView::NewLineHeight );
105 }
106
107 /**
108  * Whether the text-view-processor operation sets a new style.
109  *
110  * @param[in] metadata The text-view-processor operation.
111  *
112  * @return \e true if the given text-view-processor operation sets a new style.
113  */
114 bool IsTextViewProcessorNewStyleOperation( const TextView::TextViewProcessorMetadata& metadata )
115 {
116   return ( metadata.mType == TextView::NewStyle );
117 }
118
119 } // namespace
120
121 TextView::TextViewProcessorMetadata::TextViewProcessorMetadata()
122 : mType( TextView::TextSet ),
123   mPosition( 0u ),
124   mNumberOfCharacters( 0u ),
125   mText(),
126   mStyleMask(TextStyle::NONE)
127 {
128 }
129
130 Toolkit::TextView TextView::New()
131 {
132   // Create the implementation, temporarily owned on stack
133   IntrusivePtr<TextView> textView = new TextView();
134
135   // Pass ownership to CustomActor
136   Toolkit::TextView handle( *textView );
137
138   // Second-phase init of the implementation
139   // This can only be done after the CustomActor connection has been made...
140   textView->Initialize();
141
142   // Disables by default the offscreen rendering.
143   textView->SetSnapshotModeEnabled( false );
144
145   return handle;
146 }
147
148 void TextView::SetText( const std::string& text )
149 {
150   // Creates a styled text with the markup or plain string.
151   MarkupProcessor::StyledTextArray styledText;
152   MarkupProcessor::GetStyledTextArray( text, styledText, IsMarkupProcessingEnabled() );
153
154   // Calls SetText() with the styled text array.
155   SetText( styledText );
156 }
157
158 void TextView::SetText( const MarkupProcessor::StyledTextArray& text )
159 {
160   // mTextViewProcessorOperations stores the InsertTextAt and RemoveTextFrom operations to transform the initial text to mCurrentStyledText.
161   // Once again, if a new text is set, any previous call to InsertTextAt or RemoveTextFrom can be discarted.
162
163   std::vector<TextViewProcessorMetadata>::iterator it = std::remove_if( mTextViewProcessorOperations.begin(), mTextViewProcessorOperations.end(), IsTextViewProcessorRelayoutOperation );
164   mTextViewProcessorOperations.erase( it, mTextViewProcessorOperations.end() );
165
166   // Creates metadata with the Set operation.
167   TextViewProcessorMetadata metadata;
168   metadata.mType = TextView::TextSet;
169   metadata.mText = text;
170
171   // Store metadata.
172   mTextViewProcessorOperations.push_back( metadata );
173
174   // Updates current styled text.
175   mCurrentStyledText = text;
176
177   // Request to be relaid out
178   RelayoutRequest();
179
180   // If a GetTextLayoutInfo() or GetHeightForWidth() arrives, relayout the text synchronously is needed on order to retrieve the right values.
181   mRelayoutOperations = RELAYOUT_ALL;
182 }
183
184 void TextView::InsertTextAt( std::size_t position, const std::string& text )
185 {
186   // Creates a styled text with the markup or plain string.
187   MarkupProcessor::StyledTextArray styledText;
188   MarkupProcessor::GetStyledTextArray( text, styledText, IsMarkupProcessingEnabled() );
189
190   // Calls InsertTextAt() with the styled text array.
191   InsertTextAt( position, styledText );
192 }
193
194 void TextView::InsertTextAt( std::size_t position, const MarkupProcessor::StyledTextArray& text )
195 {
196   std::string textStr;
197   MarkupProcessor::GetPlainString( text, textStr );
198
199   if( TextProcessor::ContainsRightToLeftCharacter( Text( textStr ) ) ||
200       TextProcessor::ContainsRightToLeftCharacter( Text( GetText() ) ) )
201   {
202     // Temporary fix. Creates the whole layout if there is rtl text.
203
204     MarkupProcessor::StyledTextArray textToSet = mCurrentStyledText;
205     textToSet.insert( textToSet.begin() + position, text.begin(), text.end() );
206     SetText( textToSet );
207   }
208   else
209   {
210     // Creates metadata with the Insert operation.
211     TextViewProcessorMetadata metadata;
212     metadata.mType = TextView::TextInserted;
213     metadata.mPosition = position;
214     metadata.mText = text;
215
216     // Store metadata.
217     mTextViewProcessorOperations.push_back( metadata );
218
219     // Updates current styled text.
220     mCurrentStyledText.insert( mCurrentStyledText.begin() + position, text.begin(), text.end() );
221
222     // Request to be relaid out
223     RelayoutRequest();
224
225     // If a GetTextLayoutInfo() or GetHeightForWidth() arrives, relayout the text synchronously is needed on order to retrieve the right values.
226     mRelayoutOperations = RELAYOUT_ALL;
227   }
228 }
229
230 void TextView::ReplaceTextFromTo( std::size_t position, std::size_t numberOfCharacters, const std::string& text )
231 {
232   // Creates a styled text with the markup or plain string.
233   MarkupProcessor::StyledTextArray styledText;
234   MarkupProcessor::GetStyledTextArray( text, styledText, IsMarkupProcessingEnabled() );
235
236   // Calls ReplaceTextFromTo() with the styled text array.
237   ReplaceTextFromTo( position, numberOfCharacters, styledText );
238 }
239
240 void TextView::ReplaceTextFromTo( std::size_t position, std::size_t numberOfCharacters, const MarkupProcessor::StyledTextArray& text )
241 {
242   std::string textStr;
243   MarkupProcessor::GetPlainString( text, textStr );
244
245   if( TextProcessor::ContainsRightToLeftCharacter( Text( textStr ) ) ||
246       TextProcessor::ContainsRightToLeftCharacter( Text( GetText() ) ) )
247   {
248     // Temporary fix. Creates the whole layout if there is rtl text.
249
250     // Updates current styled text.
251     MarkupProcessor::StyledTextArray textToSet = mCurrentStyledText;
252
253     MarkupProcessor::StyledTextArray::iterator it = textToSet.begin() + position;
254     textToSet.erase( it, it + numberOfCharacters );
255     it = textToSet.begin() + position;
256     textToSet.insert( it, text.begin(), text.end() );
257
258     SetText( textToSet );
259   }
260   else
261   {
262     // Creates metadata with the Insert operation.
263     TextViewProcessorMetadata metadata;
264     metadata.mType = TextView::TextReplaced;
265     metadata.mPosition = position;
266     metadata.mNumberOfCharacters = numberOfCharacters;
267     metadata.mText = text;
268
269     // Store metadata.
270     mTextViewProcessorOperations.push_back( metadata );
271
272     // Updates current styled text.
273     MarkupProcessor::StyledTextArray::iterator it = mCurrentStyledText.begin() + position;
274     mCurrentStyledText.erase( it, it + numberOfCharacters );
275     it = mCurrentStyledText.begin() + position;
276     mCurrentStyledText.insert( it, text.begin(), text.end() );
277
278     // Request to be relaid out
279     RelayoutRequest();
280
281     // If a GetTextLayoutInfo() or GetHeightForWidth() arrives, relayout the text synchronously is needed on order to retrieve the right values.
282     mRelayoutOperations = RELAYOUT_ALL;
283   }
284 }
285
286 void TextView::RemoveTextFrom( std::size_t position, std::size_t numberOfCharacters )
287 {
288   if( TextProcessor::ContainsRightToLeftCharacter( Text( GetText() ) ) )
289   {
290     // Temporary fix. Creates the whole layout if there is rtl text.
291
292     // Updates current styled text.
293     MarkupProcessor::StyledTextArray textToSet = mCurrentStyledText;
294     MarkupProcessor::StyledTextArray::iterator it = textToSet.begin() + position;
295     textToSet.erase( it, it + numberOfCharacters );
296
297     SetText( textToSet );
298   }
299   else
300   {
301     // Creates metadata with the Remove operation.
302     TextViewProcessorMetadata metadata;
303     metadata.mType = TextView::TextRemoved;
304     metadata.mPosition = position;
305     metadata.mNumberOfCharacters = numberOfCharacters;
306
307     // Store metadata.
308     mTextViewProcessorOperations.push_back( metadata );
309
310     // Updates current styled text.
311     MarkupProcessor::StyledTextArray::iterator it = mCurrentStyledText.begin() + position;
312     mCurrentStyledText.erase( it, it + numberOfCharacters );
313
314     // Request to be relaid out
315     RelayoutRequest();
316
317     // If a GetTextLayoutInfo() or GetHeightForWidth() arrives, relayout the text synchronously is needed on order to retrieve the right values.
318     mRelayoutOperations = RELAYOUT_ALL;
319   }
320 }
321
322 std::string TextView::GetText() const
323 {
324   // Traverses the styled text array getting only the text.
325   //  Note that for some languages a 'character' could be represented by more than one 'char'
326
327   std::string text;
328   for( MarkupProcessor::StyledTextArray::const_iterator it = mCurrentStyledText.begin(), endIt = mCurrentStyledText.end(); it != endIt; ++it )
329   {
330     text.append( (*it).mText.GetText() );
331   }
332
333   return text;
334 }
335
336 void TextView::SetLineHeightOffset( PointSize offset )
337 {
338   if( fabsf( mLayoutParameters.mLineHeightOffset - offset ) > Math::MACHINE_EPSILON_1000 )
339   {
340     // Removes any previous operation which modifies the line height offset.
341     std::vector<TextViewProcessorMetadata>::iterator it = std::remove_if( mTextViewProcessorOperations.begin(), mTextViewProcessorOperations.end(), IsTextViewProcessorLineHeightOffsetOperation );
342     mTextViewProcessorOperations.erase( it, mTextViewProcessorOperations.end() );
343
344     // Creates metadata with the new line height operation.
345     TextViewProcessorMetadata metadata;
346     metadata.mType = TextView::NewLineHeight;
347
348     mTextViewProcessorOperations.push_back( metadata );
349
350     // Updates line height offset.
351     mLayoutParameters.mLineHeightOffset = offset;
352
353     RelayoutRequest();
354
355     // If a GetTextLayoutInfo() or GetHeightForWidth() arrives, relayout the text synchronously is needed on order to retrieve the right values.
356     if( RELAYOUT_ALL != mRelayoutOperations )
357     {
358       mRelayoutOperations = static_cast<RelayoutOperationMask>( mRelayoutOperations |
359                                                                 RELAYOUT_REMOVE_TEXT_ACTORS |
360                                                                 RELAYOUT_SIZE_POSITION |
361                                                                 RELAYOUT_ALIGNMENT |
362                                                                 RELAYOUT_VISIBILITY |
363                                                                 RELAYOUT_TEXT_ACTOR_UPDATE |
364                                                                 RELAYOUT_INSERT_TO_TEXT_VIEW );
365     }
366   }
367 }
368
369 PointSize TextView::GetLineHeightOffset() const
370 {
371   return PointSize( mLayoutParameters.mLineHeightOffset );
372 }
373
374 void TextView::SetStyleToCurrentText( const TextStyle& style, TextStyle::Mask mask )
375 {
376   if( !mCurrentStyledText.empty() )
377   {
378     const bool checkFontName = mask & TextStyle::FONT;
379     const bool checkFontSize = mask & TextStyle::SIZE;
380     const bool checkFontStyle = mask & TextStyle::STYLE;
381
382     // Check first if metrics have changed.
383     bool metricsChanged = false;
384     for( MarkupProcessor::StyledTextArray::const_iterator it = mCurrentStyledText.begin(), endIt = mCurrentStyledText.end(); ( it != endIt ) && !metricsChanged; ++it )
385     {
386       const MarkupProcessor::StyledText& styledText( *it );
387
388       metricsChanged = ( checkFontName && ( styledText.mStyle.GetFontName() != style.GetFontName() ) ) ||
389                        ( checkFontStyle && ( styledText.mStyle.GetFontStyle() != style.GetFontStyle() ) ) ||
390                        ( checkFontSize && ( fabsf( styledText.mStyle.GetFontPointSize() - style.GetFontPointSize() ) > Math::MACHINE_EPSILON_1000 ) );
391     }
392
393     if( metricsChanged )
394     {
395       MarkupProcessor::SetTextStyle( mCurrentStyledText, style, mask );
396
397       // If metrics change, new text measurements are needed.
398       SetText( mCurrentStyledText );
399     }
400     else
401     {
402       // Deletes any previous operation which sets a new style.
403       std::vector<TextViewProcessorMetadata>::iterator it = std::remove_if( mTextViewProcessorOperations.begin(), mTextViewProcessorOperations.end(), IsTextViewProcessorNewStyleOperation );
404       mTextViewProcessorOperations.erase( it, mTextViewProcessorOperations.end() );
405
406       // Creates metadata with the new style operation.
407       TextViewProcessorMetadata metadata;
408       metadata.mType = TextView::NewStyle;
409
410       MarkupProcessor::StyledText text;
411       text.mStyle = style;
412       metadata.mText.push_back( text );
413       metadata.mStyleMask = mask;
414
415       mTextViewProcessorOperations.push_back( metadata );
416
417       MarkupProcessor::SetTextStyle( mCurrentStyledText, style, mask );
418
419       RelayoutRequest();
420
421       if( RELAYOUT_ALL != mRelayoutOperations )
422       {
423         mRelayoutOperations = static_cast<RelayoutOperationMask>( mRelayoutOperations |
424                                                                   RELAYOUT_TEXT_ACTOR_UPDATE );
425       }
426     }
427   }
428
429   // Sets the new style to the ellipsize text
430   // TODO: fix this as a call to SetEllipsizeText will trigger the creation of new text actors.
431   if( 0u < mRelayoutData.mTextLayoutInfo.mEllipsisTextStyles.Count() )
432   {
433     for( Vector<TextStyle*>::Iterator it = mRelayoutData.mTextLayoutInfo.mEllipsisTextStyles.Begin(),
434            endIt = mRelayoutData.mTextLayoutInfo.mEllipsisTextStyles.End();
435          it != endIt;
436          ++it )
437     {
438       (*it)->Copy( style, mask );
439     }
440
441     SetEllipsizeText( mRelayoutData.mTextLayoutInfo.mEllipsisText, mRelayoutData.mTextLayoutInfo.mEllipsisTextStyles );
442   }
443 }
444
445 void TextView::SetTextAlignment( Toolkit::Alignment::Type align )
446 {
447   if( align != ( mLayoutParameters.mHorizontalAlignment | mLayoutParameters.mVerticalAlignment ) )
448   {
449     Toolkit::Alignment::Type horizontalAlignment( ( align & Toolkit::Alignment::HorizontalLeft ? Toolkit::Alignment::HorizontalLeft :
450                                                     ( align & Toolkit::Alignment::HorizontalCenter ? Toolkit::Alignment::HorizontalCenter :
451                                                       ( align & Toolkit::Alignment::HorizontalRight ? Toolkit::Alignment::HorizontalRight : Toolkit::Alignment::HorizontalCenter ) ) ) );
452     Toolkit::Alignment::Type verticalAlignment( ( align & Toolkit::Alignment::VerticalTop ? Toolkit::Alignment::VerticalTop :
453                                                   ( align & Toolkit::Alignment::VerticalCenter ? Toolkit::Alignment::VerticalCenter :
454                                                     ( align & Toolkit::Alignment::VerticalBottom ? Toolkit::Alignment::VerticalBottom : Toolkit::Alignment::VerticalCenter ) ) ) );
455
456     mLayoutParameters.mHorizontalAlignment = horizontalAlignment;
457     mLayoutParameters.mVerticalAlignment = verticalAlignment;
458
459     RelayoutRequest();
460
461     // If a GetTextLayoutInfo() or GetHeightForWidth() arrives, relayout the text synchronously is needed in order to retrieve the right values.
462     if( RELAYOUT_ALL != mRelayoutOperations )
463     {
464       mRelayoutOperations = static_cast<RelayoutOperationMask>( mRelayoutOperations |
465                                                                 RELAYOUT_TEXT_ACTOR_UPDATE |
466                                                                 RELAYOUT_ALIGNMENT |
467                                                                 RELAYOUT_VISIBILITY );
468     }
469   }
470 }
471
472 Toolkit::Alignment::Type TextView::GetTextAlignment() const
473 {
474   return static_cast<Toolkit::Alignment::Type>( mLayoutParameters.mHorizontalAlignment | mLayoutParameters.mVerticalAlignment );
475 }
476
477 void TextView::SetMultilinePolicy( Toolkit::TextView::MultilinePolicy policy )
478 {
479   if( policy != mLayoutParameters.mMultilinePolicy )
480   {
481     mLayoutParameters.mMultilinePolicy = policy;
482
483     // If a GetTextLayoutInfo() or GetHeightForWidth() arrives, relayout the text synchronously is needed on order to retrieve the right values.
484     mRelayoutOperations = RELAYOUT_ALL;
485
486     RelayoutRequest();
487   }
488 }
489
490 Toolkit::TextView::MultilinePolicy TextView::GetMultilinePolicy() const
491 {
492   return mLayoutParameters.mMultilinePolicy;
493 }
494
495 void TextView::SetWidthExceedPolicy( Toolkit::TextView::ExceedPolicy policy )
496 {
497   // The layout info could be invalid depending on the current exceed policy and the new one.
498   // i.e. if the current policy is Split and the new one is ShrinkToFit then
499   // the layout info generated for each char is not needed.
500   if( policy != mLayoutParameters.mWidthExceedPolicy )
501   {
502     mLayoutParameters.mWidthExceedPolicy = policy;
503
504     // If a GetTextLayoutInfo() or GetHeightForWidth() arrives, relayout the text synchronously is needed in order to retrieve the right values.
505     mRelayoutOperations = RELAYOUT_ALL;
506
507     RelayoutRequest();
508   }
509 }
510
511 Toolkit::TextView::ExceedPolicy TextView::GetWidthExceedPolicy() const
512 {
513   return mLayoutParameters.mWidthExceedPolicy;
514 }
515
516 void TextView::SetHeightExceedPolicy( Toolkit::TextView::ExceedPolicy policy )
517 {
518   if( policy != mLayoutParameters.mHeightExceedPolicy )
519   {
520     mLayoutParameters.mHeightExceedPolicy = policy;
521
522     RelayoutRequest();
523
524     // If a GetTextLayoutInfo() or GetHeightForWidth() arrives, relayout the text synchronously is needed in order to retrieve the right values.
525     if( RELAYOUT_ALL != mRelayoutOperations )
526     {
527       mRelayoutOperations = static_cast<RelayoutOperationMask>( mRelayoutOperations |
528                                                                 RELAYOUT_REMOVE_TEXT_ACTORS |
529                                                                 RELAYOUT_SIZE_POSITION |
530                                                                 RELAYOUT_ALIGNMENT |
531                                                                 RELAYOUT_VISIBILITY |
532                                                                 RELAYOUT_TEXT_ACTOR_UPDATE |
533                                                                 RELAYOUT_INSERT_TO_TEXT_VIEW );
534     }
535   }
536 }
537
538 Toolkit::TextView::ExceedPolicy TextView::GetHeightExceedPolicy() const
539 {
540   return mLayoutParameters.mHeightExceedPolicy;
541 }
542
543 void TextView::SetLineJustification( Toolkit::TextView::LineJustification justification )
544 {
545   if( justification != mLayoutParameters.mLineJustification )
546   {
547     mLayoutParameters.mLineJustification = justification;
548
549     RelayoutRequest();
550
551     // If a GetTextLayoutInfo() or GetHeightForWidth() arrives, relayout the text synchronously is needed in order to retrieve the right values.
552     if( RELAYOUT_ALL != mRelayoutOperations )
553     {
554       mRelayoutOperations = static_cast<RelayoutOperationMask>( mRelayoutOperations |
555                                                                 RELAYOUT_REMOVE_TEXT_ACTORS |
556                                                                 RELAYOUT_SIZE_POSITION |
557                                                                 RELAYOUT_ALIGNMENT |
558                                                                 RELAYOUT_VISIBILITY |
559                                                                 RELAYOUT_TEXT_ACTOR_UPDATE |
560                                                                 RELAYOUT_INSERT_TO_TEXT_VIEW );
561     }
562   }
563 }
564
565 Toolkit::TextView::LineJustification TextView::GetLineJustification() const
566 {
567   return mLayoutParameters.mLineJustification;
568 }
569
570 void TextView::SetFadeBoundary( const Toolkit::TextView::FadeBoundary& fadeBoundary )
571 {
572   if( ( fadeBoundary.mLeft != mVisualParameters.mFadeBoundary.mLeft )   ||
573       ( fadeBoundary.mRight != mVisualParameters.mFadeBoundary.mRight ) ||
574       ( fadeBoundary.mTop != mVisualParameters.mFadeBoundary.mTop )     ||
575       ( fadeBoundary.mBottom != mVisualParameters.mFadeBoundary.mBottom ) )
576   {
577     mVisualParameters.mFadeBoundary = fadeBoundary;
578
579     RelayoutRequest();
580
581     // If a GetTextLayoutInfo() or GetHeightForWidth() arrives, relayout the text synchronously is needed in order to retrieve the right values.
582     if( RELAYOUT_ALL != mRelayoutOperations )
583     {
584       mRelayoutOperations = static_cast<RelayoutOperationMask>( mRelayoutOperations |
585                                                                 RELAYOUT_REMOVE_TEXT_ACTORS |
586                                                                 RELAYOUT_VISIBILITY |
587                                                                 RELAYOUT_TEXT_ACTOR_UPDATE |
588                                                                 RELAYOUT_INSERT_TO_TEXT_VIEW );
589     }
590   }
591 }
592
593 const Toolkit::TextView::FadeBoundary& TextView::GetFadeBoundary() const
594 {
595   return mVisualParameters.mFadeBoundary;
596 }
597
598 void TextView::SetEllipsizeText( const std::string& ellipsizeText )
599 {
600   // Creates a styled text with the markup or plain string.
601   MarkupProcessor::StyledTextArray styledText;
602   MarkupProcessor::GetStyledTextArray( ellipsizeText, styledText, IsMarkupProcessingEnabled() );
603
604   // Creates the ellipsis layout info and sets the text and styles.
605   SetEllipsizeText( styledText );
606 }
607
608 void TextView::SetEllipsizeText( const MarkupProcessor::StyledTextArray& ellipsizeText )
609 {
610   // Converts the styled text array into a Text and a vector of TextStyles.
611   Text text;
612   Vector<TextStyle*> styles;
613   for( MarkupProcessor::StyledTextArray::const_iterator it = ellipsizeText.begin(), endIt = ellipsizeText.end(); it != endIt; ++it )
614   {
615     const MarkupProcessor::StyledText& styledText( *it );
616
617     text.Append( styledText.mText );
618     styles.PushBack( new TextStyle( styledText.mStyle ) );
619   }
620
621   // Creates the ellipsis layout info and sets the text and styles.
622   SetEllipsizeText( text, styles );
623 }
624
625 void TextView::SetEllipsizeText( const Text& ellipsizeText, const Vector<TextStyle*>& ellipsizeStyles )
626 {
627   // Sets the text and styles for the ellipsis text.
628   mRelayoutData.mTextLayoutInfo.mEllipsisText = ellipsizeText;
629   mRelayoutData.mTextLayoutInfo.mEllipsisTextStyles = ellipsizeStyles;
630
631   // Creates the ellipsis layout info.
632   CreateEllipsizeLayout();
633
634   // Request to be relaid out
635   RelayoutRequest();
636
637   mRelayoutOperations = RELAYOUT_ALL;
638 }
639
640 std::string TextView::GetEllipsizeText() const
641 {
642   return mRelayoutData.mTextLayoutInfo.mEllipsisText.GetText();
643 }
644
645 void TextView::GetTextLayoutInfo()
646 {
647   const bool relayoutSizeAndPositionNeeded = mRelayoutOperations & RELAYOUT_SIZE_POSITION;
648   const bool relayoutAlignmentNeeded = mRelayoutOperations & RELAYOUT_ALIGNMENT;
649   const bool relayoutVisibilityNeeded = mRelayoutOperations & RELAYOUT_VISIBILITY;
650
651   if( relayoutSizeAndPositionNeeded || relayoutAlignmentNeeded || relayoutVisibilityNeeded )
652   {
653     Vector3 textViewSize = GetControlSize();
654
655     if( ( ( textViewSize.width < Math::MACHINE_EPSILON_1000 ) ||
656           ( textViewSize.height < Math::MACHINE_EPSILON_1000 ) ) &&
657         ( ( Toolkit::TextView::SplitByNewLineChar == mLayoutParameters.mMultilinePolicy ) &&
658           ( Toolkit::TextView::Original == mLayoutParameters.mWidthExceedPolicy ) &&
659           ( Toolkit::TextView::Original == mLayoutParameters.mHeightExceedPolicy ) ) )
660     {
661       // In case the control size is not set but the layout settings are the default (split by new line character and original exceed policies)
662       // the text natural size can be used.
663       textViewSize = GetNaturalSize();
664     }
665
666     if( ( textViewSize.width > Math::MACHINE_EPSILON_1000 ) &&
667         ( textViewSize.height > Math::MACHINE_EPSILON_1000 ) )
668     {
669       // Check if the text-view has glyph-actors.
670       const bool hasGlyphActors = !mRelayoutData.mGlyphActors.empty();
671
672       RelayoutOperationMask mask = NO_RELAYOUT;
673       if( relayoutSizeAndPositionNeeded )
674       {
675         mask = static_cast<RelayoutOperationMask>( mask | RELAYOUT_SIZE_POSITION );
676       }
677       if( relayoutAlignmentNeeded )
678       {
679         mask = static_cast<RelayoutOperationMask>( mask | RELAYOUT_ALIGNMENT );
680       }
681       if( relayoutVisibilityNeeded )
682       {
683         mask = static_cast<RelayoutOperationMask>( mask | RELAYOUT_VISIBILITY );
684       }
685
686       if( hasGlyphActors )
687       {
688         // Remove glyph-actors from the text-view as some text-operation like CreateTextInfo()
689         // add them to the text-actor cache.
690         TextViewRelayout::RemoveGlyphActors( GetRootActor(), mRelayoutData.mGlyphActors );
691         mRelayoutData.mGlyphActors.clear();
692       }
693
694       // Relays-out but doesn't add glyph-actors to the text-view.
695       DoRelayOut( textViewSize.GetVectorXY(), mask );
696
697       if( hasGlyphActors )
698       {
699         mRelayoutOperations = static_cast<RelayoutOperationMask>( mRelayoutOperations | RELAYOUT_INSERT_TO_TEXT_VIEW );
700       }
701     }
702   }
703 }
704
705 void TextView::GetTextLayoutInfo( Toolkit::TextView::TextLayoutInfo& textLayoutInfo )
706 {
707   GetTextLayoutInfo();
708
709   textLayoutInfo.mCharacterLayoutInfoTable = mRelayoutData.mCharacterLayoutInfoTable;
710   textLayoutInfo.mLines = mRelayoutData.mLines;
711
712   textLayoutInfo.mCharacterLogicalToVisualMap = mRelayoutData.mCharacterLogicalToVisualMap;
713   textLayoutInfo.mCharacterVisualToLogicalMap = mRelayoutData.mCharacterVisualToLogicalMap;
714
715   textLayoutInfo.mTextSize = mRelayoutData.mTextSizeForRelayoutOption;
716
717   textLayoutInfo.mScrollOffset = mVisualParameters.mCameraScrollPosition;
718 }
719
720 void TextView::SetSortModifier( float depthOffset )
721 {
722   mVisualParameters.mSortModifier = depthOffset;
723
724   for( std::vector<RenderableActor>::iterator it = mRelayoutData.mGlyphActors.begin(), endIt = mRelayoutData.mGlyphActors.end();
725        it != endIt;
726        ++it )
727   {
728     ( *it ).SetSortModifier( depthOffset );
729   }
730
731   if( mOffscreenImageActor )
732   {
733     mOffscreenImageActor.SetSortModifier( depthOffset );
734   }
735 }
736
737 void TextView::SetSnapshotModeEnabled( bool enable )
738 {
739   if( enable != mVisualParameters.mSnapshotModeEnabled )
740   {
741     // Remove first all glyph-actors
742     if( !mRelayoutData.mGlyphActors.empty() )
743     {
744       TextViewRelayout::RemoveGlyphActors( GetRootActor(), mRelayoutData.mGlyphActors );
745     }
746
747     mVisualParameters.mSnapshotModeEnabled = enable;
748     if( !mLockPreviousSnapshotMode )
749     {
750       // mPreviousSnapshotModeEnabled stores the snapshot mode value before SetScrollEnabled( true ) is
751       // called. However, if SetSnapshotModeEnabled() is called after SetScrollEnabled() then the stored value
752       // is updated.
753       // As SetSnapshotModeEnabled() is also called from SetScrollEnabled(), the mLockPreviousSnapshotMode prevents
754       // to smash the stored value.
755       mPreviousSnapshotModeEnabled = enable;
756     }
757
758     if( mVisualParameters.mSnapshotModeEnabled )
759     {
760       // Create a root actor and an image actor for offscreen rendering.
761       mOffscreenRootActor = Layer::New();
762       mOffscreenImageActor = ImageActor::New();
763
764       mOffscreenRootActor.SetColorMode( USE_OWN_COLOR );
765       mOffscreenRootActor.SetPositionInheritanceMode( DONT_INHERIT_POSITION );
766       mOffscreenRootActor.SetInheritOrientation( false );
767       mOffscreenRootActor.SetInheritScale( false );
768       mOffscreenRootActor.SetDepthTestDisabled( true );
769
770       mOffscreenRootActor.SetPosition( 0.f, 0.f, 0.f );
771
772       mOffscreenImageActor.SetAnchorPoint( ParentOrigin::CENTER );
773       mOffscreenImageActor.SetParentOrigin( ParentOrigin::CENTER );
774       mOffscreenImageActor.SetBlendFunc( BlendingFactor::ONE, BlendingFactor::ONE_MINUS_SRC_ALPHA,
775                                          BlendingFactor::ONE, BlendingFactor::ONE );
776
777       Actor self = Self();
778       self.Add( mOffscreenRootActor );
779       self.Add( mOffscreenImageActor );
780       mOffscreenImageActor.SetScale( Vector3( 1.f, -1.f, 1.f ) );
781     }
782     else
783     {
784       Actor self = Self();
785
786       if( mOffscreenRootActor )
787       {
788         self.Remove( mOffscreenRootActor );
789       }
790
791       if( mOffscreenImageActor )
792       {
793         self.Remove( mOffscreenImageActor );
794       }
795
796       DestroyOffscreenRenderingResources();
797     }
798
799     if( RELAYOUT_ALL != mRelayoutOperations )
800     {
801       mRelayoutOperations = static_cast<RelayoutOperationMask>( mRelayoutOperations |
802                                                                 RELAYOUT_REMOVE_TEXT_ACTORS |
803                                                                 RELAYOUT_TEXT_ACTOR_UPDATE |
804                                                                 RELAYOUT_INSERT_TO_TEXT_VIEW );
805     }
806     RelayoutRequest();
807   }
808 }
809
810 bool TextView::IsSnapshotModeEnabled() const
811 {
812   return mVisualParameters.mSnapshotModeEnabled;
813 }
814
815 void TextView::SetMarkupProcessingEnabled( bool enable )
816 {
817   mMarkUpEnabled = enable;
818 }
819
820 bool TextView::IsMarkupProcessingEnabled() const
821 {
822   return mMarkUpEnabled;
823 }
824
825 void TextView::SetScrollEnabled( bool enable )
826 {
827   if( enable != mVisualParameters.mScrollEnabled )
828   {
829     mVisualParameters.mScrollEnabled = enable;
830
831     if( mVisualParameters.mScrollEnabled )
832     {
833       // Offscreen rendering is needed to enable text scroll.
834
835       // Stores previous value of the snapshot mode.
836       mPreviousSnapshotModeEnabled = IsSnapshotModeEnabled();
837
838       {
839         // SetSnapshotModeEnabled() modifies the mPreviousSnapshotModeEnabled just in case it's called after SetScrollEnabled(),
840         // this lock prevents to modify the mPreviousSnapshotModeEnabled when SetSnapshotModeEnabled() from this method.
841         Lock lock( mLockPreviousSnapshotMode );
842         SetSnapshotModeEnabled( true );
843       }
844
845       // Creates the pan gesture detector and attach the text-view.
846       mPanGestureDetector = PanGestureDetector::New();
847       mPanGestureDetector.DetectedSignal().Connect( this, &TextView::OnTextPan );
848       mPanGestureDetector.Attach( Self() );
849     }
850     else
851     {
852       // Removes the pan gesture detector.
853       if( mPanGestureDetector )
854       {
855         mPanGestureDetector.Detach( Self() );
856         mPanGestureDetector.DetectedSignal().Disconnect( this, &TextView::OnTextPan );
857         mPanGestureDetector.Reset();
858       }
859
860       // Restores the previous state for snapshot mode.
861       SetSnapshotModeEnabled( mPreviousSnapshotModeEnabled );
862     }
863   }
864 }
865
866 bool TextView::IsScrollEnabled() const
867 {
868   return mVisualParameters.mScrollEnabled;
869 }
870
871 void TextView::SetScrollPosition( const Vector2& position )
872 {
873   if( position != mVisualParameters.mCameraScrollPosition )
874   {
875     // Guard against destruction during signal emission
876     // Note that Emit() methods are called indirectly from within DoSetScrollPosition()
877     Toolkit::TextView handle( GetOwner() );
878
879     DoSetScrollPosition( position );
880
881     // Check if the new scroll position has been trimmed.
882     mVisualParameters.mScrollPositionTrimmed = ( position != mVisualParameters.mCameraScrollPosition );
883   }
884 }
885
886 const Vector2& TextView::GetScrollPosition() const
887 {
888   return mVisualParameters.mCameraScrollPosition;
889 }
890
891 bool TextView::IsScrollPositionTrimmed() const
892 {
893   return mVisualParameters.mScrollPositionTrimmed;
894 }
895
896 Toolkit::TextView::ScrolledSignalType& TextView::ScrolledSignal()
897 {
898   return mScrolledSignal;
899 }
900
901 bool TextView::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
902 {
903   Dali::BaseHandle handle( object );
904
905   bool connected( true );
906   Toolkit::TextView textView = Toolkit::TextView::DownCast( handle );
907
908   if( 0 == strcmp( signalName.c_str(), SIGNAL_TEXT_SCROLLED ) )
909   {
910     textView.ScrolledSignal().Connect( tracker, functor );
911   }
912   else
913   {
914     // signalName does not match any signal
915     connected = false;
916   }
917
918   return connected;
919 }
920
921 TextView::LayoutParameters::LayoutParameters()
922 : mMultilinePolicy( Toolkit::TextView::SplitByNewLineChar ),
923   mExceedPolicy( TextView::Original ),
924   mWidthExceedPolicy( Toolkit::TextView::Original ),
925   mHeightExceedPolicy( Toolkit::TextView::Original ),
926   mHorizontalAlignment( Toolkit::Alignment::HorizontalCenter ),
927   mVerticalAlignment( Toolkit::Alignment::VerticalCenter ),
928   mLineJustification( Toolkit::TextView::Left ),
929   mLineHeightOffset( 0.f ),
930   mMarkUpEnabled( false )
931 {
932 }
933
934 TextView::LayoutParameters::~LayoutParameters()
935 {
936 }
937
938 TextView::LayoutParameters::LayoutParameters( Toolkit::TextView::MultilinePolicy   multilinePolicy,
939                                               Toolkit::TextView::ExceedPolicy      widthExceedPolicy,
940                                               Toolkit::TextView::ExceedPolicy      heightExceedPolicy,
941                                               Toolkit::Alignment::Type             alignmentType,
942                                               Toolkit::TextView::LineJustification lineJustification,
943                                               float                                lineHeightOffset,
944                                               bool                                 markUpEnabled )
945 : mMultilinePolicy( multilinePolicy ),
946   mExceedPolicy( TextView::Original ),
947   mWidthExceedPolicy( widthExceedPolicy ),
948   mHeightExceedPolicy( heightExceedPolicy ),
949   mHorizontalAlignment(),
950   mVerticalAlignment(),
951   mLineJustification( lineJustification ),
952   mLineHeightOffset( lineHeightOffset ),
953   mMarkUpEnabled( markUpEnabled )
954 {
955   // Sets alignment
956   Toolkit::Alignment::Type horizontalAlignment( ( alignmentType & Toolkit::Alignment::HorizontalLeft ? Toolkit::Alignment::HorizontalLeft :
957                                                   ( alignmentType & Toolkit::Alignment::HorizontalCenter ? Toolkit::Alignment::HorizontalCenter :
958                                                     ( alignmentType & Toolkit::Alignment::HorizontalRight ? Toolkit::Alignment::HorizontalRight : Toolkit::Alignment::HorizontalCenter ) ) ) );
959   Toolkit::Alignment::Type verticalAlignment( ( alignmentType & Toolkit::Alignment::VerticalTop ? Toolkit::Alignment::VerticalTop :
960                                                 ( alignmentType & Toolkit::Alignment::VerticalCenter ? Toolkit::Alignment::VerticalCenter :
961                                                   ( alignmentType & Toolkit::Alignment::VerticalBottom ? Toolkit::Alignment::VerticalBottom : Toolkit::Alignment::VerticalCenter ) ) ) );
962
963   mHorizontalAlignment = horizontalAlignment;
964   mVerticalAlignment = verticalAlignment;
965 }
966
967 TextView::LayoutParameters::LayoutParameters( const TextView::LayoutParameters& layoutParameters )
968 : mMultilinePolicy( layoutParameters.mMultilinePolicy ),
969   mExceedPolicy( TextView::Original ),
970   mWidthExceedPolicy( layoutParameters.mWidthExceedPolicy ),
971   mHeightExceedPolicy( layoutParameters.mHeightExceedPolicy ),
972   mHorizontalAlignment( layoutParameters.mHorizontalAlignment ),
973   mVerticalAlignment( layoutParameters.mVerticalAlignment ),
974   mLineJustification( layoutParameters.mLineJustification ),
975   mLineHeightOffset( layoutParameters.mLineHeightOffset ),
976   mMarkUpEnabled( layoutParameters.mMarkUpEnabled )
977 {
978 }
979
980 TextView::LayoutParameters& TextView::LayoutParameters::operator=( const TextView::LayoutParameters& layoutParameters )
981 {
982   mMultilinePolicy = layoutParameters.mMultilinePolicy;
983   mWidthExceedPolicy = layoutParameters.mWidthExceedPolicy;
984   mHeightExceedPolicy = layoutParameters.mHeightExceedPolicy;
985   mHorizontalAlignment = layoutParameters.mHorizontalAlignment;
986   mVerticalAlignment = layoutParameters.mVerticalAlignment;
987   mLineJustification = layoutParameters.mLineJustification;
988   mLineHeightOffset = layoutParameters.mLineHeightOffset;
989   mMarkUpEnabled = layoutParameters.mMarkUpEnabled;
990
991   return *this;
992 }
993
994 TextView::VisualParameters::VisualParameters()
995 : mFadeBoundary(),
996   mSortModifier( 0.f ),
997   mCameraScrollPosition( 0.f, 0.f ),
998   mSnapshotModeEnabled( false ),
999   mScrollEnabled( false ),
1000   mScrollPositionTrimmed( false )
1001 {
1002 }
1003
1004 TextView::VisualParameters::VisualParameters( const VisualParameters& visualParameters )
1005 : mFadeBoundary( visualParameters.mFadeBoundary ),
1006   mSortModifier( visualParameters.mSortModifier ),
1007   mCameraScrollPosition( visualParameters.mCameraScrollPosition ),
1008   mSnapshotModeEnabled( visualParameters.mSnapshotModeEnabled ),
1009   mScrollEnabled( visualParameters.mScrollEnabled ),
1010   mScrollPositionTrimmed( visualParameters.mScrollPositionTrimmed )
1011 {
1012 }
1013
1014 TextView::VisualParameters& TextView::VisualParameters::operator=( const TextView::VisualParameters& visualParameters )
1015 {
1016   mFadeBoundary = visualParameters.mFadeBoundary;
1017   mSortModifier = visualParameters.mSortModifier;
1018   mCameraScrollPosition = visualParameters.mCameraScrollPosition;
1019   mSnapshotModeEnabled = visualParameters.mSnapshotModeEnabled;
1020   mScrollEnabled = visualParameters.mScrollEnabled;
1021   mScrollPositionTrimmed = visualParameters.mScrollPositionTrimmed;
1022
1023   return *this;
1024 }
1025
1026 TextView::RelayoutData::RelayoutData()
1027 : mTextViewSize(),
1028   mShrinkFactor( 1.f ),
1029   mTextLayoutInfo(),
1030   mCharacterLogicalToVisualMap(),
1031   mCharacterVisualToLogicalMap(),
1032   mGlyphActors(),
1033   mCharacterLayoutInfoTable(),
1034   mLines(),
1035   mTextSizeForRelayoutOption()
1036 {
1037 }
1038
1039 TextView::RelayoutData::RelayoutData( const TextView::RelayoutData& relayoutData )
1040 : mTextViewSize( relayoutData.mTextViewSize ),
1041   mShrinkFactor( relayoutData.mShrinkFactor ),
1042   mTextLayoutInfo( relayoutData.mTextLayoutInfo ),
1043   mCharacterLogicalToVisualMap( relayoutData.mCharacterLogicalToVisualMap ),
1044   mCharacterVisualToLogicalMap( relayoutData.mCharacterVisualToLogicalMap ),
1045   mGlyphActors( relayoutData.mGlyphActors ),
1046   mCharacterLayoutInfoTable( relayoutData.mCharacterLayoutInfoTable ),
1047   mLines( relayoutData.mLines ),
1048   mTextSizeForRelayoutOption( relayoutData.mTextSizeForRelayoutOption )
1049 {
1050 }
1051
1052 TextView::RelayoutData& TextView::RelayoutData::operator=( const TextView::RelayoutData& relayoutData )
1053 {
1054   mTextViewSize = relayoutData.mTextViewSize;
1055   mShrinkFactor = relayoutData.mShrinkFactor;
1056   mTextLayoutInfo = relayoutData.mTextLayoutInfo;
1057   mCharacterLogicalToVisualMap = relayoutData.mCharacterLogicalToVisualMap;
1058   mCharacterVisualToLogicalMap = relayoutData.mCharacterVisualToLogicalMap;
1059   mGlyphActors = relayoutData.mGlyphActors;
1060   mCharacterLayoutInfoTable = relayoutData.mCharacterLayoutInfoTable;
1061   mLines = relayoutData.mLines;
1062   mTextSizeForRelayoutOption = relayoutData.mTextSizeForRelayoutOption;
1063
1064   return *this;
1065 }
1066
1067 TextView::TextView()
1068 : Control( REQUIRES_STYLE_CHANGE_SIGNALS  ),
1069   mCurrentStyledText(),
1070   mTextViewProcessorOperations(),
1071   mLayoutParameters( Toolkit::TextView::SplitByNewLineChar,
1072                      Toolkit::TextView::Original,
1073                      Toolkit::TextView::Original,
1074                      static_cast<Toolkit::Alignment::Type>( Toolkit::Alignment::HorizontalCenter | Toolkit::Alignment::VerticalCenter ),
1075                      Toolkit::TextView::Left,
1076                      PointSize( 0.f ),
1077                      false ),
1078   mVisualParameters(),
1079   mRelayoutData(),
1080   mRelayoutOperations( NO_RELAYOUT ),
1081   mOffscreenRootActor(),
1082   mOffscreenImageActor(),
1083   mOffscreenCameraActor(),
1084   mCurrentOffscreenSize(),
1085   mFrameBufferImage(),
1086   mRenderTask(),
1087   mPanGestureDetector(),
1088   mLockPreviousSnapshotMode( false ),
1089   mPreviousSnapshotModeEnabled( false ),
1090   mMarkUpEnabled( false )
1091 {
1092   // Creates the ellipsis layout info.
1093   CreateEllipsizeLayout();
1094 }
1095
1096 TextView::~TextView()
1097 {
1098   // Destroys offscreen rendering resources.
1099   DestroyOffscreenRenderingResources();
1100
1101   // Destroys scroll pan gesture detector.
1102   if( mPanGestureDetector )
1103   {
1104     mPanGestureDetector.Reset();
1105   }
1106 }
1107
1108 Vector3 TextView::GetNaturalSize()
1109 {
1110   if( !mTextViewProcessorOperations.empty() )
1111   {
1112     // There are SetText, Inserts or Removes to do. It means the current layout info is not updated.
1113
1114     if( !mRelayoutData.mGlyphActors.empty() )
1115     {
1116       // Remove glyph-actors from the text-view as some text-operation like CreateTextInfo()
1117       // add them to the text-actor cache.
1118       TextViewRelayout::RemoveGlyphActors( GetRootActor(), mRelayoutData.mGlyphActors );
1119       mRelayoutData.mGlyphActors.clear();
1120
1121       mRelayoutOperations = static_cast<RelayoutOperationMask>( mRelayoutOperations | RELAYOUT_INSERT_TO_TEXT_VIEW );
1122     }
1123
1124     PerformTextViewProcessorOperations();
1125   }
1126
1127   return Vector3( mRelayoutData.mTextLayoutInfo.mWholeTextSize.width, mRelayoutData.mTextLayoutInfo.mWholeTextSize.height, 0.f );
1128 }
1129
1130 float TextView::GetHeightForWidth( float width )
1131 {
1132   float height = 0.f;
1133
1134   if( ( Toolkit::TextView::SplitByNewLineChar == mLayoutParameters.mMultilinePolicy ) &&
1135       ( Toolkit::TextView::Original == mLayoutParameters.mWidthExceedPolicy ) &&
1136       ( Toolkit::TextView::Original == mLayoutParameters.mHeightExceedPolicy ) )
1137   {
1138     // If multiline and exceed policies are 'SplitByNewLineChar' and 'Original' is better get the height from the
1139     // natural size. GetNaturalSize() for this configuration is faster than DoRelayOut().
1140     height = GetNaturalSize().height;
1141   }
1142   else
1143   {
1144     // Check if the given width is different than the current one.
1145     const bool differentWidth = ( fabsf( width - mRelayoutData.mTextViewSize.width ) > Math::MACHINE_EPSILON_1000 );
1146
1147     // Check if the text-view has glyph-actors.
1148     const bool hasGlyphActors = !mRelayoutData.mGlyphActors.empty();
1149
1150     // Check which layout operations need to be done.
1151     const bool relayoutSizeAndPositionNeeded = ( mRelayoutOperations & RELAYOUT_SIZE_POSITION ) || differentWidth;
1152
1153     if( relayoutSizeAndPositionNeeded )
1154     {
1155       if( hasGlyphActors )
1156       {
1157         // Remove glyph-actors from the text-view as some text-operation like CreateTextInfo()
1158         // add them to the text-actor cache.
1159         TextViewRelayout::RemoveGlyphActors( GetRootActor(), mRelayoutData.mGlyphActors );
1160         mRelayoutData.mGlyphActors.clear();
1161       }
1162
1163       // Use the given width.
1164       const Vector2 textViewSize( width, GetControlSize().height );
1165
1166       // Relays-out but doesn't add glyph-actors to the text-view.
1167       DoRelayOut( textViewSize, RELAYOUT_SIZE_POSITION );
1168     }
1169
1170     // Retrieve the text height after relayout the text.
1171     height = mRelayoutData.mTextSizeForRelayoutOption.height;
1172
1173     if( differentWidth )
1174     {
1175       // Revert the relayout operation mask
1176       mRelayoutOperations = static_cast<RelayoutOperationMask>( mRelayoutOperations | RELAYOUT_SIZE_POSITION );
1177     }
1178
1179     if( hasGlyphActors )
1180     {
1181       mRelayoutOperations = static_cast<RelayoutOperationMask>( mRelayoutOperations | RELAYOUT_INSERT_TO_TEXT_VIEW );
1182     }
1183
1184     if( differentWidth || hasGlyphActors )
1185     {
1186       RelayoutRequest();
1187     }
1188   }
1189
1190   return height;
1191 }
1192
1193 float TextView::GetWidthForHeight( float height )
1194 {
1195   // TODO: Needs implementing properly, for now just return the natural width.
1196   return GetNaturalSize().width;
1197 }
1198
1199
1200 void TextView::OnInitialize()
1201 {
1202 }
1203
1204
1205 void TextView::OnFontChange( bool defaultFontChange, bool defaultFontSizeChange )
1206 {
1207   // Creates the ellipsis layout info.
1208   CreateEllipsizeLayout();
1209
1210   SetText( mCurrentStyledText );
1211 }
1212
1213 void TextView::OnControlSizeSet( const Vector3& size )
1214 {
1215   if( size.GetVectorXY() != mRelayoutData.mTextViewSize )
1216   {
1217     // If a GetTextLayoutInfo() or GetHeightForWidth() arrives, relayout the text synchronously is needed in order to retrieve the right values.
1218     mRelayoutOperations = RELAYOUT_ALL;
1219
1220     // Request to be relaid out
1221     RelayoutRequest();
1222   }
1223 }
1224
1225 void TextView::OnRelayout( const Vector2& size, ActorSizeContainer& container )
1226 {
1227   if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
1228   {
1229     // Not worth to relayout if width or height is equal to zero.
1230     return;
1231   }
1232
1233   if( size != mRelayoutData.mTextViewSize )
1234   {
1235     // if new size is different than the prevoius one, set positions and maybe sizes of all glyph-actor is needed.
1236     if( RELAYOUT_ALL != mRelayoutOperations )
1237     {
1238       mRelayoutOperations = static_cast<RelayoutOperationMask>( mRelayoutOperations |
1239                                                                 RELAYOUT_REMOVE_TEXT_ACTORS |
1240                                                                 RELAYOUT_SIZE_POSITION |
1241                                                                 RELAYOUT_ALIGNMENT |
1242                                                                 RELAYOUT_VISIBILITY |
1243                                                                 RELAYOUT_TEXT_ACTOR_UPDATE |
1244                                                                 RELAYOUT_INSERT_TO_TEXT_VIEW );
1245     }
1246   }
1247
1248   if( ( Toolkit::TextView::Fade == mLayoutParameters.mWidthExceedPolicy ) ||
1249       ( Toolkit::TextView::Fade == mLayoutParameters.mHeightExceedPolicy ) )
1250   {
1251     if( mRelayoutOperations & RELAYOUT_ALIGNMENT )
1252     {
1253       // If the text of the alignment changes and a fade exceed policy is set,
1254       // some characters may need new TextActor.
1255       mRelayoutOperations = RELAYOUT_ALL;
1256     }
1257   }
1258
1259   // Remove glyph-actors from text-view
1260   if( !mRelayoutData.mGlyphActors.empty() && ( mRelayoutOperations & RELAYOUT_REMOVE_TEXT_ACTORS ) )
1261   {
1262     TextViewRelayout::RemoveGlyphActors( GetRootActor(), mRelayoutData.mGlyphActors );
1263     mRelayoutData.mGlyphActors.clear();
1264   }
1265
1266   if( NO_RELAYOUT != mRelayoutOperations )
1267   {
1268     // Relays-out and add glyph-actors to the text-view.
1269     DoRelayOut( size, mRelayoutOperations );
1270     ProcessSnapshot( size );
1271   }
1272
1273   // Quite likely the texts of the text-actors are not going to be reused, so clear them.
1274   mRelayoutData.mTextActorCache.ClearTexts();
1275 }
1276
1277 void TextView::PerformTextViewProcessorOperations()
1278 {
1279   // Traverse the relayout operation vector ...
1280
1281   // Optimizes some operations.
1282   OptimizeTextViewProcessorOperations();
1283
1284   for( std::vector<TextViewProcessorMetadata>::const_iterator it = mTextViewProcessorOperations.begin(), endIt = mTextViewProcessorOperations.end(); it != endIt; ++it )
1285   {
1286     const TextViewProcessorMetadata& relayoutMetadata( *it );
1287
1288     switch( relayoutMetadata.mType )
1289     {
1290       case TextView::TextSet:
1291       {
1292         TextViewProcessor::CreateTextInfo( relayoutMetadata.mText,
1293                                            mLayoutParameters,
1294                                            mRelayoutData );
1295         break;
1296       }
1297       case TextView::TextInserted:
1298       {
1299         TextViewProcessor::UpdateTextInfo( relayoutMetadata.mPosition,
1300                                            relayoutMetadata.mText,
1301                                            mLayoutParameters,
1302                                            mRelayoutData );
1303         break;
1304       }
1305       case TextView::TextReplaced:
1306       {
1307         TextViewProcessor::UpdateTextInfo( relayoutMetadata.mPosition,
1308                                            relayoutMetadata.mNumberOfCharacters,
1309                                            relayoutMetadata.mText,
1310                                            mLayoutParameters,
1311                                            mRelayoutData );
1312         break;
1313       }
1314       case TextView::TextRemoved:
1315       {
1316         TextViewProcessor::UpdateTextInfo( relayoutMetadata.mPosition,
1317                                            relayoutMetadata.mNumberOfCharacters,
1318                                            mLayoutParameters,
1319                                            mRelayoutData,
1320                                            TextViewProcessor::CLEAR_TEXT ); // clears the text of the text-actors.
1321         break;
1322       }
1323       case TextView::NewLineHeight:
1324       {
1325         TextViewProcessor::UpdateTextInfo( mLayoutParameters.mLineHeightOffset,
1326                                            mRelayoutData.mTextLayoutInfo );
1327         break;
1328       }
1329       case TextView::NewStyle:
1330       {
1331         TextViewProcessor::UpdateTextInfo( ( *relayoutMetadata.mText.begin() ).mStyle,
1332                                            relayoutMetadata.mStyleMask,
1333                                            mRelayoutData );
1334         break;
1335       }
1336     }
1337   }
1338
1339   // Clear all operations when they are done.
1340   mTextViewProcessorOperations.clear();
1341 }
1342
1343 void TextView::OptimizeTextViewProcessorOperations()
1344 {
1345   // TODO: check if some operation can be discarted. i.e. InsertTextAt( 0, "a" ); RemoveTextFrom( 0, 1 );
1346
1347   // At the moment it only replaces a 'remove 1 character' followed by 'insert 1 character' in the same position by a 'replace' operation.
1348   // This sequence is used by text-input with predictive text. Change this two operations by a replace allows the text-view processor to
1349   // use the cache without clearing the text-actors.
1350
1351   std::vector<TextViewProcessorMetadata> textViewProcessorOperations;
1352
1353   for( std::vector<TextViewProcessorMetadata>::const_iterator it = mTextViewProcessorOperations.begin(), endIt = mTextViewProcessorOperations.end(); it != endIt; ++it )
1354   {
1355     const TextViewProcessorMetadata& relayoutMetadata( *it );
1356
1357     switch( relayoutMetadata.mType )
1358     {
1359       case TextView::TextRemoved:
1360       {
1361         bool optimizationDone = false;
1362
1363         if( it + 1u != endIt )
1364         {
1365           const TextViewProcessorMetadata& nextRelayoutMetadata( *( it + 1u ) );
1366           if( TextView::TextInserted == nextRelayoutMetadata.mType )
1367           {
1368             if( relayoutMetadata.mPosition == nextRelayoutMetadata.mPosition )
1369             {
1370               optimizationDone = true;
1371               TextViewProcessorMetadata newRelayoutMetadata;
1372               newRelayoutMetadata.mType = TextView::TextReplaced;
1373               newRelayoutMetadata.mPosition = relayoutMetadata.mPosition;
1374               newRelayoutMetadata.mNumberOfCharacters = relayoutMetadata.mNumberOfCharacters;
1375               newRelayoutMetadata.mText = nextRelayoutMetadata.mText;
1376               textViewProcessorOperations.push_back( newRelayoutMetadata );
1377
1378               // do not access the TextInserted operation in next iteration.
1379               ++it;
1380             }
1381           }
1382         }
1383
1384         if( !optimizationDone )
1385         {
1386           textViewProcessorOperations.push_back( relayoutMetadata );
1387         }
1388         break;
1389       }
1390       default:
1391       {
1392         textViewProcessorOperations.push_back( relayoutMetadata );
1393       }
1394     }
1395   }
1396
1397   mTextViewProcessorOperations = textViewProcessorOperations;
1398 }
1399
1400 void TextView::DoRelayOut( const Size& textViewSize, RelayoutOperationMask relayoutOperationMask )
1401 {
1402   // Traverse the relayout operation vector. It fills the natural size, layout and glyph-actor data structures.
1403   if( !mTextViewProcessorOperations.empty() )
1404   {
1405     PerformTextViewProcessorOperations();
1406   }
1407
1408   CombineExceedPolicies();
1409
1410   Actor rootActor;
1411   if( mVisualParameters.mSnapshotModeEnabled )
1412   {
1413     rootActor = mOffscreenRootActor;
1414   }
1415   else
1416   {
1417     rootActor = Self();
1418   }
1419
1420   mRelayoutData.mTextViewSize = textViewSize;
1421   switch( mLayoutParameters.mMultilinePolicy )
1422   {
1423     case Toolkit::TextView::SplitByNewLineChar:              // multiline policy == SplitByNewLineChar.
1424     {
1425       SplitByNewLineChar::Relayout( rootActor, relayoutOperationMask, mLayoutParameters, mVisualParameters, mRelayoutData );
1426       break;
1427     } // SplitByNewLineChar
1428
1429     case Toolkit::TextView::SplitByWord:                     // multiline policy == SplitByWord.
1430     {
1431       SplitByWord::Relayout( rootActor, relayoutOperationMask, mLayoutParameters, mVisualParameters, mRelayoutData );
1432       break;
1433     } // SplitByWord
1434
1435     case Toolkit::TextView::SplitByChar:                     // multiline policy == SplitByChar.
1436     {
1437       SplitByChar::Relayout( rootActor, relayoutOperationMask, mLayoutParameters, mVisualParameters, mRelayoutData );
1438       break;
1439     } // SplitByChar
1440   } // switch( mMultilinePolicy )
1441
1442   // Remove done operations from the mask.
1443   mRelayoutOperations = static_cast<RelayoutOperationMask>( mRelayoutOperations & ~relayoutOperationMask );
1444 }
1445
1446 void TextView::ProcessSnapshot( const Size& textViewSize )
1447 {
1448   if( mVisualParameters.mSnapshotModeEnabled )
1449   {
1450     // If layout options change, it's needed generate a new image.
1451
1452     if( mOffscreenRootActor )
1453     {
1454       // Set the root actor visible.
1455       // The root actor is set to non visible after the render task is processed.
1456       mOffscreenRootActor.SetVisible( true );
1457
1458       // The offscreen root actor must have same size as text view. Otherwise, text alignment won't work.
1459       mOffscreenRootActor.SetSize( textViewSize );
1460     }
1461
1462     if( ( mRelayoutData.mTextSizeForRelayoutOption.width > Math::MACHINE_EPSILON_1000 ) &&
1463         ( mRelayoutData.mTextSizeForRelayoutOption.height > Math::MACHINE_EPSILON_1000 ) )
1464     {
1465       // Set the image actor visible.
1466       // The image actor is set to non visible if there is no text to render.
1467       mOffscreenImageActor.SetVisible( true );
1468
1469       // Calculates the offscreen image's size. It takes into account different points:
1470       // * If text has italics, add a small offset is needed in order to not to cut the text next to the right edge.
1471       // * There is a maximum texture size the graphic subsystem can load on the memory.
1472       // * If the scroll is enabled, the offscreen image's size is never bigger than the text-view's size.
1473
1474       const Size offscreenSize( std::min( MAX_OFFSCREEN_RENDERING_SIZE,
1475                                           mVisualParameters.mScrollEnabled ? textViewSize.width : std::max( mRelayoutData.mTextSizeForRelayoutOption.width, textViewSize.width ) + mRelayoutData.mTextLayoutInfo.mMaxItalicsOffset ),
1476                                 std::min( MAX_OFFSCREEN_RENDERING_SIZE,
1477                                           mVisualParameters.mScrollEnabled ? textViewSize.height : std::max( mRelayoutData.mTextSizeForRelayoutOption.height, textViewSize.height ) ) );
1478
1479       const bool sizeChanged = offscreenSize != mCurrentOffscreenSize;
1480
1481       if( sizeChanged )
1482       {
1483         // Creates a frame buffer for offscreen rendering when the size is negotiated.
1484         mFrameBufferImage = FrameBufferImage::New( offscreenSize.width,
1485                                                    offscreenSize.height,
1486                                                    Pixel::RGBA8888 );
1487
1488         // Stores current text-view size to avoid create new Dali resources if text changes.
1489         mCurrentOffscreenSize = offscreenSize;
1490
1491         if( !mOffscreenCameraActor )
1492         {
1493           // Creates a new camera actor.
1494           mOffscreenCameraActor = CameraActor::New();
1495           mOffscreenCameraActor.SetParentOrigin( ParentOrigin::CENTER );
1496           mOffscreenCameraActor.SetAnchorPoint( AnchorPoint::CENTER );
1497           mOffscreenCameraActor.SetOrientation(Degree(180.f), Vector3::YAXIS);
1498
1499           mOffscreenCameraActor.SetType( Dali::Camera::FREE_LOOK ); // Inherits position from the offscreen root actor.
1500
1501           mOffscreenRootActor.Add( mOffscreenCameraActor ); // camera to shoot the offscreen text
1502         }
1503
1504         // Calculate camera parameters for current text size.
1505         mOffscreenCameraActor.SetOrthographicProjection( offscreenSize );
1506       }
1507
1508       if( mVisualParameters.mScrollEnabled )
1509       {
1510         // Updates the offscreen camera position with the new scroll offset.
1511         mOffscreenCameraActor.SetX( mVisualParameters.mCameraScrollPosition.x );
1512         mOffscreenCameraActor.SetY( mVisualParameters.mCameraScrollPosition.y );
1513       }
1514       else
1515       {
1516         // Text's size could be bigger than text-view's size. In that case the camera must be aligned to cover the whole text.
1517         AlignOffscreenCameraActor( textViewSize, offscreenSize );
1518       }
1519
1520       if( !mRenderTask )
1521       {
1522         // Creates a new render task.
1523         mRenderTask = Stage::GetCurrent().GetRenderTaskList().CreateTask();
1524
1525         mRenderTask.SetSourceActor( mOffscreenRootActor );
1526         mRenderTask.SetInputEnabled( false );
1527         mRenderTask.SetClearColor( Color::TRANSPARENT );
1528         mRenderTask.SetClearEnabled( true );
1529         mRenderTask.SetExclusive( true );
1530
1531         // Connects the signal to the TextView::RenderTaskFinished method in order to make the root actor non visible when the render task is processed.
1532         mRenderTask.FinishedSignal().Connect( this, &TextView::RenderTaskFinished );
1533       }
1534
1535       if( sizeChanged )
1536       {
1537         mRenderTask.SetCameraActor( mOffscreenCameraActor );
1538         mRenderTask.SetTargetFrameBuffer( mFrameBufferImage );
1539       }
1540
1541       // Process the render task only once every time the text changes or the text-view's size canges.
1542       mRenderTask.SetRefreshRate( RenderTask::REFRESH_ONCE );
1543     }
1544     else
1545     {
1546       // If there is no text just make any previous generated image invisible instead to process a render task with no text.
1547       mOffscreenImageActor.SetVisible( false );
1548     }
1549   }
1550 }
1551
1552 void TextView::AlignOffscreenCameraActor( const Size& textViewSize, const Size& offscreenSize )
1553 {
1554   float xPosition = 0.f;
1555   float yPosition = 0.f;
1556   Vector3 parentOrigin = ParentOrigin::CENTER;
1557   Vector3 anchorPoint = AnchorPoint::CENTER;
1558
1559   switch( mLayoutParameters.mHorizontalAlignment )
1560   {
1561     case Toolkit::Alignment::HorizontalLeft:
1562     {
1563       xPosition = 0.5f * ( offscreenSize.width - textViewSize.width );
1564       parentOrigin.x = 0.f;
1565       anchorPoint.x = 0.f;
1566       break;
1567     }
1568     case Toolkit::Alignment::HorizontalCenter:
1569     {
1570       // nothing to do.
1571       break;
1572     }
1573     case Toolkit::Alignment::HorizontalRight:
1574     {
1575       xPosition = 0.5f * ( textViewSize.width - offscreenSize.width );
1576       parentOrigin.x = 1.f;
1577       anchorPoint.x = 1.f;
1578       break;
1579     }
1580     default:
1581     {
1582       DALI_ASSERT_ALWAYS( !"TextView::AlignOffscreenCameraActor: Invalid alignment option." )
1583     }
1584   }
1585
1586   switch( mLayoutParameters.mVerticalAlignment )
1587   {
1588     case Toolkit::Alignment::VerticalTop:
1589     {
1590       yPosition = 0.5f * ( offscreenSize.height - textViewSize.height );
1591       parentOrigin.y = 0.f;
1592       anchorPoint.y = 0.f;
1593       break;
1594     }
1595     case Toolkit::Alignment::VerticalCenter:
1596     {
1597       // nothing to do.
1598       break;
1599     }
1600     case Toolkit::Alignment::VerticalBottom:
1601     {
1602       yPosition = 0.5f * ( textViewSize.height - offscreenSize.height );
1603       parentOrigin.y = 1.f;
1604       anchorPoint.y = 1.f;
1605       break;
1606     }
1607     default:
1608     {
1609       DALI_ASSERT_ALWAYS( !"TextView::AlignOffscreenCameraActor: Invalid alignment option." )
1610     }
1611   }
1612
1613   mOffscreenCameraActor.SetX( xPosition );
1614   mOffscreenCameraActor.SetY( yPosition );
1615
1616   mOffscreenImageActor.SetParentOrigin( parentOrigin );
1617   mOffscreenImageActor.SetAnchorPoint( anchorPoint );
1618 }
1619
1620 void TextView::RenderTaskFinished( Dali::RenderTask& renderTask )
1621 {
1622   // not to process the offscreen root actor by setting its visibility to false.
1623   mOffscreenRootActor.SetVisible( false );
1624
1625   // Sets the new size and the new frame buffer to the image actor.
1626   // Image actor must have same size as text. Otherwise text can be truncated.
1627   mOffscreenImageActor.SetSize( mCurrentOffscreenSize );
1628   mOffscreenImageActor.SetImage( mFrameBufferImage );
1629 }
1630
1631 void TextView::DestroyOffscreenRenderingResources()
1632 {
1633   if( mRenderTask )
1634   {
1635     mRenderTask.FinishedSignal().Disconnect( this, &TextView::RenderTaskFinished );
1636
1637     if( Stage::IsInstalled() )
1638     {
1639       Stage::GetCurrent().GetRenderTaskList().RemoveTask( mRenderTask );
1640     }
1641
1642     mRenderTask.Reset();
1643   }
1644
1645   // Remove and reset the root actor, image actor and camera actor as text-view is not rendering offscreen.
1646   if( mOffscreenCameraActor )
1647   {
1648     mOffscreenRootActor.Remove( mOffscreenCameraActor );
1649
1650     mOffscreenCameraActor.Reset();
1651   }
1652
1653   if( mOffscreenRootActor )
1654   {
1655     mOffscreenRootActor.Reset();
1656   }
1657
1658   if( mOffscreenImageActor )
1659   {
1660     mOffscreenImageActor.Reset();
1661   }
1662
1663   mCurrentOffscreenSize = Size( 0.f, 0.f );
1664
1665   if( mFrameBufferImage )
1666   {
1667     mFrameBufferImage.Reset();
1668   }
1669 }
1670
1671 void TextView::OnTextPan( Actor actor, const PanGesture& gesture )
1672 {
1673   if( 1u == gesture.numberOfTouches )
1674   {
1675     DoSetScrollPosition( mVisualParameters.mCameraScrollPosition - gesture.displacement );
1676   }
1677 }
1678
1679 void TextView::TrimScrollPosition()
1680 {
1681   const Vector3& textViewSize = GetControlSize();
1682
1683   // Before use the text's size, relayout the text is needed to get the actual text size.
1684   GetTextLayoutInfo();
1685
1686   // Calculates the range within the text could be scrolled. (When the text is aligned in the center).
1687   float maxHorizontalDisplacement = std::max( 0.f, 0.5f * ( mRelayoutData.mTextSizeForRelayoutOption.width - textViewSize.width ) );
1688   float maxVerticalDisplacement = std::max( 0.f, 0.5f * ( mRelayoutData.mTextSizeForRelayoutOption.height - textViewSize.height ) );
1689   float minHorizontalDisplacement = -maxHorizontalDisplacement;
1690   float minVerticalDisplacement = -maxVerticalDisplacement;
1691
1692   // Updates the range if the text is aligned on the right or left.
1693   switch( mLayoutParameters.mHorizontalAlignment )
1694   {
1695     case Toolkit::Alignment::HorizontalLeft:
1696     {
1697       maxHorizontalDisplacement *= 2.f;
1698       minHorizontalDisplacement = 0.f;
1699       break;
1700     }
1701     case Toolkit::Alignment::HorizontalCenter:
1702     {
1703       // nothing to do.
1704       break;
1705     }
1706     case Toolkit::Alignment::HorizontalRight:
1707     {
1708       maxHorizontalDisplacement = 0.f;
1709       minHorizontalDisplacement *= 2.f;
1710       break;
1711     }
1712     default:
1713     {
1714       DALI_ASSERT_ALWAYS( !"TextView::TrimScrollPosition: Invalid alignment option." )
1715     }
1716   }
1717
1718   // Updates the range if the text is aligned on the top or bottom.
1719   switch( mLayoutParameters.mVerticalAlignment )
1720   {
1721     case Toolkit::Alignment::VerticalTop:
1722     {
1723       maxVerticalDisplacement *= 2.f;
1724       minVerticalDisplacement = 0.f;
1725       break;
1726     }
1727     case Toolkit::Alignment::VerticalCenter:
1728     {
1729       //nothing to do
1730       break;
1731     }
1732     case Toolkit::Alignment::VerticalBottom:
1733     {
1734       maxVerticalDisplacement = 0.f;
1735       minVerticalDisplacement *= 2.f;
1736       break;
1737     }
1738     default:
1739     {
1740       DALI_ASSERT_ALWAYS( !"TextView::TrimScrollPosition: Invalid alignment option." )
1741     }
1742   }
1743
1744   // Trims the scroll position to be within the range.
1745   mVisualParameters.mCameraScrollPosition.x = std::min( maxHorizontalDisplacement, mVisualParameters.mCameraScrollPosition.x );
1746   mVisualParameters.mCameraScrollPosition.x = std::max( minHorizontalDisplacement, mVisualParameters.mCameraScrollPosition.x );
1747
1748   mVisualParameters.mCameraScrollPosition.y = std::min( maxVerticalDisplacement, mVisualParameters.mCameraScrollPosition.y );
1749   mVisualParameters.mCameraScrollPosition.y = std::max( minVerticalDisplacement, mVisualParameters.mCameraScrollPosition.y );
1750 }
1751
1752 void TextView::DoSetScrollPosition( const Vector2& position )
1753 {
1754   // Stores old scroll position.
1755   Vector2 delta( mVisualParameters.mCameraScrollPosition );
1756
1757   // Updates the scroll position
1758   mVisualParameters.mCameraScrollPosition = position;
1759
1760   // Ensures the text-view is covered with text.
1761   TrimScrollPosition();
1762
1763   // Calculate the difference with the previous scroll position
1764   delta.x = mVisualParameters.mCameraScrollPosition.x - delta.x;
1765   delta.y = mVisualParameters.mCameraScrollPosition.y - delta.y;
1766
1767   if( mOffscreenRootActor )
1768   {
1769     // If there is a render-task it needs to be refreshed. Therefore glyph-actors need to be
1770     // set to visible.
1771     mOffscreenRootActor.SetVisible( true );
1772   }
1773
1774   if( mOffscreenCameraActor )
1775   {
1776     // Update the offscreen camera with the new scroll position.
1777     mOffscreenCameraActor.SetX( mVisualParameters.mCameraScrollPosition.x );
1778     mOffscreenCameraActor.SetY( mVisualParameters.mCameraScrollPosition.y );
1779   }
1780
1781   if( mRenderTask )
1782   {
1783     // Refresh the render-task.
1784     mRenderTask.SetRefreshRate( RenderTask::REFRESH_ONCE );
1785   }
1786
1787   // Emit the signal.
1788   Toolkit::TextView handle( GetOwner() );
1789   mScrolledSignal.Emit( handle, delta );
1790 }
1791
1792 void TextView::CombineExceedPolicies()
1793 {
1794   // Calculates the combination of exceed policies.
1795
1796   switch( mLayoutParameters.mWidthExceedPolicy )
1797   {
1798     case Toolkit::TextView::Original:
1799     {
1800       switch( mLayoutParameters.mHeightExceedPolicy )
1801       {
1802         case Toolkit::TextView::Original:
1803         {
1804           mLayoutParameters.mExceedPolicy = Original;
1805           break;
1806         }
1807         case Toolkit::TextView::Fade:
1808         {
1809           mLayoutParameters.mExceedPolicy = OriginalFade;
1810           break;
1811         }
1812         case Toolkit::TextView::ShrinkToFit:
1813         {
1814           mLayoutParameters.mExceedPolicy = OriginalShrink;
1815           break;
1816         }
1817         default:
1818         {
1819           DALI_ASSERT_ALWAYS( !"TextView::CombineExceedPolicies() Invalid width and height exceed policies combination" );
1820         }
1821       }
1822       break;
1823     }
1824     case Toolkit::TextView::Split:
1825     {
1826       switch( mLayoutParameters.mHeightExceedPolicy )
1827       {
1828         case Toolkit::TextView::Original:
1829         {
1830           mLayoutParameters.mExceedPolicy = SplitOriginal;
1831           break;
1832         }
1833         case Toolkit::TextView::Fade:
1834         {
1835           mLayoutParameters.mExceedPolicy = SplitFade;
1836           break;
1837         }
1838         case Toolkit::TextView::ShrinkToFit:
1839         {
1840           mLayoutParameters.mExceedPolicy = SplitShrink;
1841           break;
1842         }
1843         case Toolkit::TextView::EllipsizeEnd:
1844         {
1845           mLayoutParameters.mExceedPolicy = SplitEllipsizeEnd;
1846           break;
1847         }
1848         default:
1849         {
1850           DALI_ASSERT_ALWAYS( !"TextView::CombineExceedPolicies() Invalid width and height exceed policies combination" );
1851         }
1852       }
1853       break;
1854     }
1855     case Toolkit::TextView::Fade:
1856     {
1857       switch( mLayoutParameters.mHeightExceedPolicy )
1858       {
1859         case Toolkit::TextView::Original:
1860         {
1861           mLayoutParameters.mExceedPolicy = FadeOriginal;
1862           break;
1863         }
1864         case Toolkit::TextView::Fade:
1865         {
1866           mLayoutParameters.mExceedPolicy = Fade;
1867           break;
1868         }
1869         default:
1870         {
1871           DALI_ASSERT_ALWAYS( !"TextView::CombineExceedPolicies() Invalid width and height exceed policies combination" );
1872         }
1873       }
1874       break;
1875     }
1876     case Toolkit::TextView::ShrinkToFit:
1877     {
1878       switch( mLayoutParameters.mHeightExceedPolicy )
1879       {
1880         case Toolkit::TextView::Original:
1881         {
1882           mLayoutParameters.mExceedPolicy = ShrinkOriginal;
1883           break;
1884         }
1885         case Toolkit::TextView::Fade:
1886         {
1887           mLayoutParameters.mExceedPolicy = ShrinkFade;
1888           break;
1889         }
1890         case Toolkit::TextView::ShrinkToFit:
1891         {
1892           mLayoutParameters.mExceedPolicy = Shrink;
1893           break;
1894         }
1895         default:
1896         {
1897           DALI_ASSERT_ALWAYS( !"TextView::CombineExceedPolicies() Invalid width and height exceed policies combination" );
1898         }
1899       }
1900       break;
1901     }
1902     case Toolkit::TextView::EllipsizeEnd:
1903     {
1904       switch( mLayoutParameters.mHeightExceedPolicy )
1905       {
1906         case Toolkit::TextView::Original:
1907         {
1908           mLayoutParameters.mExceedPolicy = EllipsizeEndOriginal;
1909           break;
1910         }
1911         case Toolkit::TextView::EllipsizeEnd:
1912         {
1913           mLayoutParameters.mExceedPolicy = EllipsizeEnd;
1914           break;
1915         }
1916         default:
1917         {
1918           DALI_ASSERT_ALWAYS( !"TextView::CombineExceedPolicies() Invalid width and height exceed policies combination" );
1919         }
1920       }
1921       break;
1922     }
1923     default:
1924     {
1925       DALI_ASSERT_ALWAYS( !"TextView::CombineExceedPolicies() Invalid width exceed policy" );
1926     }
1927   }
1928 }
1929
1930 Actor TextView::GetRootActor() const
1931 {
1932   // Get the root actor, if text-view was rendering offscreen, or the text-view itself.
1933
1934   Actor rootActor;
1935
1936   if( mVisualParameters.mSnapshotModeEnabled )
1937   {
1938     rootActor = mOffscreenRootActor;
1939   }
1940   else
1941   {
1942     rootActor = Self();
1943   }
1944
1945   return rootActor;
1946 }
1947
1948 void TextView::CreateEllipsizeLayout()
1949 {
1950   // Creates the ellipsis layout info for the ellipsis text and styles.
1951   mRelayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo = TextViewProcessor::WordLayoutInfo();
1952   mRelayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mCharactersLayoutInfo.resize( mRelayoutData.mTextLayoutInfo.mEllipsisText.GetLength(), TextViewProcessor::CharacterLayoutInfo() );
1953   TextViewProcessor::CreateWordTextInfo( mRelayoutData.mTextLayoutInfo.mEllipsisText,
1954                                          mRelayoutData.mTextLayoutInfo.mEllipsisTextStyles,
1955                                          mRelayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo );
1956 }
1957
1958 void TextView::OnMarkupEnabledPeopertySet( Property::Value propertyValue )
1959 {
1960   bool newValue( propertyValue.Get<bool>() );
1961   if( newValue != IsMarkupProcessingEnabled() )
1962   {
1963     SetMarkupProcessingEnabled( newValue );
1964     if( newValue )
1965     {
1966       // If markup processing has been enabled, Ensure current text is reprocessed.
1967       const std::string& currentText( GetText() );
1968       if( ! currentText.empty() )
1969       {
1970         SetText( currentText );
1971       }
1972     }
1973   }
1974 }
1975
1976 void TextView::OnMultilinePolicyPropertySet( Property::Value propertyValue )
1977 {
1978   std::string policyName( propertyValue.Get<std::string>() );
1979   if(policyName == "SplitByNewLineChar")
1980   {
1981     SetMultilinePolicy(Toolkit::TextView::SplitByNewLineChar);
1982   }
1983   else if(policyName == "SplitByWord")
1984   {
1985     SetMultilinePolicy(Toolkit::TextView::SplitByWord);
1986   }
1987   else if(policyName == "SplitByChar")
1988   {
1989     SetMultilinePolicy(Toolkit::TextView::SplitByChar);
1990   }
1991   else
1992   {
1993     DALI_ASSERT_ALWAYS( !"TextView::OnMultilinePolicyPropertySet(). Invalid Property value." );
1994   }
1995 }
1996
1997 void TextView::OnWidthExceedPolicyPropertySet( Property::Value propertyValue )
1998 {
1999   std::string policyName( propertyValue.Get<std::string>() );
2000   if(policyName == "Original")
2001   {
2002     SetWidthExceedPolicy(Toolkit::TextView::Original);
2003   }
2004   else if(policyName == "Fade")
2005   {
2006     SetWidthExceedPolicy(Toolkit::TextView::Fade);
2007   }
2008   else if(policyName == "Split")
2009   {
2010     SetWidthExceedPolicy(Toolkit::TextView::Split);
2011   }
2012   else if(policyName == "ShrinkToFit")
2013   {
2014     SetWidthExceedPolicy(Toolkit::TextView::ShrinkToFit);
2015   }
2016   else if(policyName == "EllipsizeEnd")
2017   {
2018     SetWidthExceedPolicy(Toolkit::TextView::EllipsizeEnd);
2019   }
2020   else
2021   {
2022     DALI_ASSERT_ALWAYS( !"TextView::OnWidthExceedPolicyPropertySet(). Invalid Property value." );
2023   }
2024 }
2025
2026 void TextView::OnHeightExceedPolicyPropertySet( Property::Value propertyValue )
2027 {
2028   std::string policyName( propertyValue.Get<std::string>() );
2029   if(policyName == "Original")
2030   {
2031     SetHeightExceedPolicy(Toolkit::TextView::Original);
2032   }
2033   else if(policyName == "Fade")
2034   {
2035     SetHeightExceedPolicy(Toolkit::TextView::Fade);
2036   }
2037   else if(policyName == "Split")
2038   {
2039     SetHeightExceedPolicy(Toolkit::TextView::Split);
2040   }
2041   else if(policyName == "ShrinkToFit")
2042   {
2043     SetHeightExceedPolicy(Toolkit::TextView::ShrinkToFit);
2044   }
2045   else
2046   {
2047     DALI_ASSERT_ALWAYS( !"TextView::OnHeightExceedPolicyPropertySet(). Invalid Property value." );
2048   }
2049 }
2050
2051 void TextView::OnLineJustificationPropertySet( Property::Value propertyValue )
2052 {
2053   std::string policyName( propertyValue.Get<std::string>() );
2054   if(policyName == "Left")
2055   {
2056     SetLineJustification(Toolkit::TextView::Left);
2057   }
2058   else if(policyName == "Center")
2059   {
2060     SetLineJustification(Toolkit::TextView::Center);
2061   }
2062   else if(policyName == "Right")
2063   {
2064     SetLineJustification(Toolkit::TextView::Right);
2065   }
2066   else if(policyName == "Justified")
2067   {
2068     SetLineJustification(Toolkit::TextView::Justified);
2069   }
2070   else
2071   {
2072     DALI_ASSERT_ALWAYS( !"TextView::OnLineJustificationPropertySet(). Invalid Property value." );
2073   }
2074 }
2075
2076 void TextView::OnFadeBoundaryPropertySet( Property::Value propertyValue )
2077 {
2078   Vector4 value( propertyValue.Get<Vector4>() );
2079   DALI_ASSERT_ALWAYS( ( value.x >= 0.f ) && ( value.y >= 0.f ) && ( value.z >= 0.f ) && ( value.w >= 0.f )
2080                       && "TextView::OnFadeBoundaryPropertySet(). Negative value is invalid. "  );
2081
2082   Toolkit::TextView::FadeBoundary fadeBoundary( PixelSize( static_cast<unsigned int>( value.x ) ),
2083                                                 PixelSize( static_cast<unsigned int>( value.y ) ),
2084                                                 PixelSize( static_cast<unsigned int>( value.z ) ),
2085                                                 PixelSize( static_cast<unsigned int>( value.w ) ) );
2086
2087   SetFadeBoundary( fadeBoundary );
2088 }
2089
2090 void TextView::OnAlignmentPropertySet( Property::Index propertyIndex, Property::Value propertyValue )
2091 {
2092   std::string value( propertyValue.Get<std::string>() );
2093
2094   if( propertyIndex == Toolkit::TextView::Property::HORIZONTAL_ALIGNMENT )
2095   {
2096     if(value == "HorizontalLeft")
2097     {
2098       mLayoutParameters.mHorizontalAlignment = Toolkit::Alignment::HorizontalLeft;
2099     }
2100     else if( value == "HorizontalCenter")
2101     {
2102       mLayoutParameters.mHorizontalAlignment = Toolkit::Alignment::HorizontalCenter;
2103     }
2104     else if( value == "HorizontalRight")
2105     {
2106       mLayoutParameters.mHorizontalAlignment = Toolkit::Alignment::HorizontalRight;
2107     }
2108     else
2109     {
2110       DALI_ASSERT_ALWAYS( !"TextView::OnAlignmentPropertySet(). Invalid Property value." );
2111     }
2112   }
2113   else if( propertyIndex == Toolkit::TextView::Property::VERTICAL_ALIGNMENT )
2114   {
2115     if( value == "VerticalTop" )
2116     {
2117       mLayoutParameters.mVerticalAlignment = Toolkit::Alignment::VerticalTop;
2118     }
2119     else if( value == "VerticalCenter")
2120     {
2121       mLayoutParameters.mVerticalAlignment = Toolkit::Alignment::VerticalCenter;
2122     }
2123     else if( value == "VerticalBottom")
2124     {
2125       mLayoutParameters.mVerticalAlignment = Toolkit::Alignment::VerticalBottom;
2126     }
2127     else
2128     {
2129       DALI_ASSERT_ALWAYS( !"TextView::OnAlignmentPropertySet(). Invalid Property value." );
2130     }
2131   }
2132
2133   RelayoutRequest();
2134
2135   // If a GetTextLayoutInfo() or GetHeightForWidth() arrives, relayout the text synchronously is needed in order to retrieve the right values.
2136   if( RELAYOUT_ALL != mRelayoutOperations )
2137   {
2138     mRelayoutOperations = static_cast<RelayoutOperationMask>( mRelayoutOperations |
2139                                                               RELAYOUT_TEXT_ACTOR_UPDATE |
2140                                                               RELAYOUT_ALIGNMENT |
2141                                                               RELAYOUT_VISIBILITY );
2142   }
2143 }
2144
2145 std::string TextView::OnHorizontalAlignmentPropertyGet()
2146 {
2147   if( mLayoutParameters.mHorizontalAlignment == Toolkit::Alignment::HorizontalLeft )
2148   {
2149     return "HorizontalLeft";
2150   }
2151   else if( mLayoutParameters.mHorizontalAlignment == Toolkit::Alignment::HorizontalCenter )
2152   {
2153     return "HorizontalCenter";
2154   }
2155   else if( mLayoutParameters.mHorizontalAlignment == Toolkit::Alignment::HorizontalRight )
2156   {
2157     return "HorizontalRight";
2158   }
2159   else
2160   {
2161     DALI_ASSERT_ALWAYS( !"TextView::OnHorizontalAlignmentPropertyGet(). Invalid value." );
2162   }
2163 }
2164
2165 std::string TextView::OnVerticalAlignmentPropertyGet()
2166 {
2167   if( mLayoutParameters.mVerticalAlignment == Toolkit::Alignment::VerticalTop )
2168    {
2169      return "VerticalTop";
2170    }
2171    else if( mLayoutParameters.mVerticalAlignment == Toolkit::Alignment::VerticalCenter )
2172    {
2173      return "VerticalCenter";
2174    }
2175    else if( mLayoutParameters.mVerticalAlignment == Toolkit::Alignment::VerticalBottom )
2176    {
2177      return "VerticalBottom";
2178    }
2179    else
2180    {
2181      DALI_ASSERT_ALWAYS( !"TextView::OnVerticalAlignmentPropertyGet(). Invalid value." );
2182    }
2183 }
2184
2185 void TextView::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
2186 {
2187   Toolkit::TextView textView = Toolkit::TextView::DownCast( Dali::BaseHandle( object ) );
2188
2189   if( textView )
2190   {
2191     TextView& textViewImpl( GetImpl( textView ) );
2192     switch( index )
2193     {
2194       case Toolkit::TextView::Property::MARKUP_ENABLED:
2195       {
2196         textViewImpl.OnMarkupEnabledPeopertySet( value );
2197         break;
2198       }
2199       case Toolkit::TextView::Property::TEXT:
2200       {
2201         textViewImpl.SetText( value.Get<std::string>() );
2202         break;
2203       }
2204       case Toolkit::TextView::Property::MULTILINE_POLICY:
2205       {
2206         textViewImpl.OnMultilinePolicyPropertySet( value );
2207         break;
2208       }
2209       case Toolkit::TextView::Property::WIDTH_EXCEED_POLICY:
2210       {
2211         textViewImpl.OnWidthExceedPolicyPropertySet( value );
2212         break;
2213       }
2214       case Toolkit::TextView::Property::HEIGHT_EXCEED_POLICY:
2215       {
2216         textViewImpl.OnHeightExceedPolicyPropertySet( value );
2217         break;
2218       }
2219       case Toolkit::TextView::Property::LINE_JUSTIFICATION:
2220       {
2221         textViewImpl.OnLineJustificationPropertySet( value );
2222         break;
2223       }
2224       case Toolkit::TextView::Property::FADE_BOUNDARY:
2225       {
2226         textViewImpl.OnFadeBoundaryPropertySet( value );
2227         break;
2228       }
2229       case Toolkit::TextView::Property::LINE_HEIGHT_OFFSET:
2230       {
2231         Dali::PointSize pointSize( value.Get<float>() );
2232         textViewImpl.SetLineHeightOffset(pointSize);
2233         break;
2234       }
2235       case Toolkit::TextView::Property::HORIZONTAL_ALIGNMENT:
2236       case Toolkit::TextView::Property::VERTICAL_ALIGNMENT:
2237       {
2238         textViewImpl.OnAlignmentPropertySet( index, value );
2239         break;
2240       }
2241     }
2242   }
2243 }
2244
2245 Property::Value TextView::GetProperty( BaseObject* object, Property::Index index )
2246 {
2247   Property::Value value;
2248
2249   Toolkit::TextView textView = Toolkit::TextView::DownCast( Dali::BaseHandle( object ) );
2250
2251   if( textView )
2252   {
2253     TextView& textViewImpl( GetImpl( textView ) );
2254     switch( index )
2255     {
2256       case Toolkit::TextView::Property::MARKUP_ENABLED:
2257       {
2258         value = textViewImpl.IsMarkupProcessingEnabled();
2259         break;
2260       }
2261       case Toolkit::TextView::Property::TEXT:
2262       {
2263         value = textViewImpl.GetText();
2264         break;
2265       }
2266       case Toolkit::TextView::Property::MULTILINE_POLICY:
2267       {
2268         value = MULTILINE_POLICY_NAME[ textViewImpl.GetMultilinePolicy() ];
2269         break;
2270       }
2271       case Toolkit::TextView::Property::WIDTH_EXCEED_POLICY:
2272       {
2273         value = EXCEED_POLICY_NAME[ textViewImpl.GetWidthExceedPolicy() ];
2274         break;
2275       }
2276       case Toolkit::TextView::Property::HEIGHT_EXCEED_POLICY:
2277       {
2278         value = EXCEED_POLICY_NAME[ textViewImpl.GetHeightExceedPolicy() ];
2279         break;
2280       }
2281       case Toolkit::TextView::Property::LINE_JUSTIFICATION:
2282       {
2283         value = LINE_JUSTIFICATION_NAME[ textViewImpl.GetLineJustification() ];
2284         break;
2285       }
2286       case Toolkit::TextView::Property::FADE_BOUNDARY:
2287       {
2288         Toolkit::TextView::FadeBoundary boundary = textViewImpl.GetFadeBoundary();
2289         value = Vector4( static_cast<float>( boundary.mLeft.value ),
2290                          static_cast<float>( boundary.mRight.value ),
2291                          static_cast<float>( boundary.mTop.value ),
2292                          static_cast<float>( boundary.mBottom.value ) );
2293         break;
2294       }
2295       case Toolkit::TextView::Property::LINE_HEIGHT_OFFSET:
2296       {
2297         value = textViewImpl.GetLineHeightOffset().value;
2298         break;
2299       }
2300       case Toolkit::TextView::Property::HORIZONTAL_ALIGNMENT:
2301       {
2302         value = textViewImpl.OnHorizontalAlignmentPropertyGet();
2303         break;
2304       }
2305       case Toolkit::TextView::Property::VERTICAL_ALIGNMENT:
2306       {
2307         value = textViewImpl.OnVerticalAlignmentPropertyGet();
2308         break;
2309       }
2310     }
2311   }
2312   return value;
2313 }
2314
2315 } // namespace Internal
2316
2317 } // namespace Toolkit
2318
2319 } // namespace Dali