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