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