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