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