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