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