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