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