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