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