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