ca90f55fab8d34098909daf3da74f3141a847b40
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-controller.cpp
1 /*
2  * Copyright (c) 2016 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/text/text-controller.h>
20
21 // EXTERNAL INCLUDES
22 #include <limits>
23 #include <memory.h>
24 #include <dali/public-api/adaptor-framework/key.h>
25 #include <dali/integration-api/debug.h>
26 #include <dali/devel-api/adaptor-framework/clipboard-event-notifier.h>
27
28 // INTERNAL INCLUDES
29 #include <dali-toolkit/internal/text/bidirectional-support.h>
30 #include <dali-toolkit/internal/text/character-set-conversion.h>
31 #include <dali-toolkit/internal/text/layouts/layout-parameters.h>
32 #include <dali-toolkit/internal/text/markup-processor.h>
33 #include <dali-toolkit/internal/text/text-controller-impl.h>
34
35 namespace
36 {
37
38 #if defined(DEBUG_ENABLED)
39   Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
40 #endif
41
42 const float MAX_FLOAT = std::numeric_limits<float>::max();
43
44 const std::string EMPTY_STRING("");
45
46 float ConvertToEven( float value )
47 {
48   int intValue(static_cast<int>( value ));
49   return static_cast<float>(intValue % 2 == 0) ? intValue : (intValue + 1);
50 }
51
52 } // namespace
53
54 namespace Dali
55 {
56
57 namespace Toolkit
58 {
59
60 namespace Text
61 {
62
63 /**
64  * @brief Adds a new font description run for the selected text.
65  *
66  * The new font parameters are added after the call to this method.
67  *
68  * @param[in] eventData The event data pointer.
69  * @param[in] logicalModel The logical model where to add the new font description run.
70  * @param[out] startOfSelectedText Index to the first selected character.
71  * @param[out] lengthOfSelectedText Number of selected characters.
72  */
73 FontDescriptionRun& UpdateSelectionFontStyleRun( EventData* eventData,
74                                                  LogicalModelPtr logicalModel,
75                                                  CharacterIndex& startOfSelectedText,
76                                                  Length& lengthOfSelectedText )
77 {
78   const bool handlesCrossed = eventData->mLeftSelectionPosition > eventData->mRightSelectionPosition;
79
80   // Get start and end position of selection
81   startOfSelectedText = handlesCrossed ? eventData->mRightSelectionPosition : eventData->mLeftSelectionPosition;
82   lengthOfSelectedText = ( handlesCrossed ? eventData->mLeftSelectionPosition : eventData->mRightSelectionPosition ) - startOfSelectedText;
83
84   // Add the font run.
85   const VectorBase::SizeType numberOfRuns = logicalModel->mFontDescriptionRuns.Count();
86   logicalModel->mFontDescriptionRuns.Resize( numberOfRuns + 1u );
87
88   FontDescriptionRun& fontDescriptionRun = *( logicalModel->mFontDescriptionRuns.Begin() + numberOfRuns );
89
90   fontDescriptionRun.characterRun.characterIndex = startOfSelectedText;
91   fontDescriptionRun.characterRun.numberOfCharacters = lengthOfSelectedText;
92
93   // Recalculate the selection highlight as the metrics may have changed.
94   eventData->mUpdateLeftSelectionPosition = true;
95   eventData->mUpdateRightSelectionPosition = true;
96   eventData->mUpdateHighlightBox = true;
97
98   return fontDescriptionRun;
99 }
100
101 // public : Constructor.
102
103 ControllerPtr Controller::New( ControlInterface& controlInterface )
104 {
105   return ControllerPtr( new Controller( controlInterface ) );
106 }
107
108 // public : Configure the text controller.
109
110 void Controller::EnableTextInput( DecoratorPtr decorator )
111 {
112   if( NULL == mImpl->mEventData )
113   {
114     mImpl->mEventData = new EventData( decorator );
115   }
116 }
117
118 void Controller::SetGlyphType( TextAbstraction::GlyphType glyphType )
119 {
120   // Metrics for bitmap & vector based glyphs are different
121   mImpl->mMetrics->SetGlyphType( glyphType );
122
123   // Clear the font-specific data
124   ClearFontData();
125
126   mImpl->RequestRelayout();
127 }
128
129 void Controller::SetMarkupProcessorEnabled( bool enable )
130 {
131   mImpl->mMarkupProcessorEnabled = enable;
132 }
133
134 bool Controller::IsMarkupProcessorEnabled() const
135 {
136   return mImpl->mMarkupProcessorEnabled;
137 }
138
139 void Controller::SetAutoScrollEnabled( bool enable )
140 {
141   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled[%s] SingleBox[%s]-> [%p]\n", (enable)?"true":"false", ( mImpl->mLayoutEngine.GetLayout() == LayoutEngine::SINGLE_LINE_BOX)?"true":"false", this );
142
143   if ( mImpl->mLayoutEngine.GetLayout() == LayoutEngine::SINGLE_LINE_BOX )
144   {
145     if ( enable )
146     {
147       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled for SINGLE_LINE_BOX\n" );
148       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
149                                                                LAYOUT                    |
150                                                                ALIGN                     |
151                                                                UPDATE_LAYOUT_SIZE        |
152                                                                UPDATE_DIRECTION          |
153                                                                REORDER );
154
155     }
156     else
157     {
158       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled Disabling autoscroll\n");
159       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
160                                                                LAYOUT                    |
161                                                                ALIGN                     |
162                                                                UPDATE_LAYOUT_SIZE        |
163                                                                REORDER );
164     }
165
166     mImpl->mAutoScrollEnabled = enable;
167     mImpl->RequestRelayout();
168   }
169   else
170   {
171     DALI_LOG_WARNING( "Attempted AutoScrolling on a non SINGLE_LINE_BOX, request ignored\n" );
172     mImpl->mAutoScrollEnabled = false;
173   }
174 }
175
176 bool Controller::IsAutoScrollEnabled() const
177 {
178   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::IsAutoScrollEnabled[%s]\n", (mImpl->mAutoScrollEnabled)?"true":"false" );
179
180   return mImpl->mAutoScrollEnabled;
181 }
182
183 CharacterDirection Controller::GetAutoScrollDirection() const
184 {
185   return mImpl->mAutoScrollDirectionRTL;
186 }
187
188 float Controller::GetAutoScrollLineAlignment() const
189 {
190   float offset = 0.f;
191
192   if( mImpl->mVisualModel &&
193       ( 0u != mImpl->mVisualModel->mLines.Count() ) )
194   {
195     offset = ( *mImpl->mVisualModel->mLines.Begin() ).alignmentOffset;
196   }
197
198   return offset;
199 }
200
201 void Controller::SetHorizontalScrollEnabled( bool enable )
202 {
203   if( ( NULL != mImpl->mEventData ) &&
204       mImpl->mEventData->mDecorator )
205   {
206     mImpl->mEventData->mDecorator->SetHorizontalScrollEnabled( enable );
207   }
208 }
209
210 bool Controller::IsHorizontalScrollEnabled() const
211 {
212   if( ( NULL != mImpl->mEventData ) &&
213       mImpl->mEventData->mDecorator )
214   {
215     return mImpl->mEventData->mDecorator->IsHorizontalScrollEnabled();
216   }
217
218   return false;
219 }
220
221 void Controller::SetVerticalScrollEnabled( bool enable )
222 {
223   if( ( NULL != mImpl->mEventData ) &&
224       mImpl->mEventData->mDecorator )
225   {
226     if( mImpl->mEventData->mDecorator )
227     {
228       mImpl->mEventData->mDecorator->SetVerticalScrollEnabled( enable );
229     }
230   }
231 }
232
233 bool Controller::IsVerticalScrollEnabled() const
234 {
235   if( ( NULL != mImpl->mEventData ) &&
236       mImpl->mEventData->mDecorator )
237   {
238     return mImpl->mEventData->mDecorator->IsVerticalScrollEnabled();
239   }
240
241   return false;
242 }
243
244 void Controller::SetSmoothHandlePanEnabled( bool enable )
245 {
246   if( ( NULL != mImpl->mEventData ) &&
247       mImpl->mEventData->mDecorator )
248   {
249     mImpl->mEventData->mDecorator->SetSmoothHandlePanEnabled( enable );
250   }
251 }
252
253 bool Controller::IsSmoothHandlePanEnabled() const
254 {
255   if( ( NULL != mImpl->mEventData ) &&
256       mImpl->mEventData->mDecorator )
257   {
258     return mImpl->mEventData->mDecorator->IsSmoothHandlePanEnabled();
259   }
260
261   return false;
262 }
263
264 void Controller::SetMaximumNumberOfCharacters( Length maxCharacters )
265 {
266   mImpl->mMaximumNumberOfCharacters = maxCharacters;
267 }
268
269 int Controller::GetMaximumNumberOfCharacters()
270 {
271   return mImpl->mMaximumNumberOfCharacters;
272 }
273
274 void Controller::SetEnableCursorBlink( bool enable )
275 {
276   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "TextInput disabled" );
277
278   if( NULL != mImpl->mEventData )
279   {
280     mImpl->mEventData->mCursorBlinkEnabled = enable;
281
282     if( !enable &&
283         mImpl->mEventData->mDecorator )
284     {
285       mImpl->mEventData->mDecorator->StopCursorBlink();
286     }
287   }
288 }
289
290 bool Controller::GetEnableCursorBlink() const
291 {
292   if( NULL != mImpl->mEventData )
293   {
294     return mImpl->mEventData->mCursorBlinkEnabled;
295   }
296
297   return false;
298 }
299
300 void Controller::SetMultiLineEnabled( bool enable )
301 {
302   const LayoutEngine::Layout layout = enable ? LayoutEngine::MULTI_LINE_BOX : LayoutEngine::SINGLE_LINE_BOX;
303
304   if( layout != mImpl->mLayoutEngine.GetLayout() )
305   {
306     // Set the layout type.
307     mImpl->mLayoutEngine.SetLayout( layout );
308
309     // Set the flags to redo the layout operations
310     const OperationsMask layoutOperations =  static_cast<OperationsMask>( LAYOUT             |
311                                                                           UPDATE_LAYOUT_SIZE |
312                                                                           ALIGN              |
313                                                                           REORDER );
314
315     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | layoutOperations );
316
317     mImpl->RequestRelayout();
318   }
319 }
320
321 bool Controller::IsMultiLineEnabled() const
322 {
323   return LayoutEngine::MULTI_LINE_BOX == mImpl->mLayoutEngine.GetLayout();
324 }
325
326 void Controller::SetHorizontalAlignment( LayoutEngine::HorizontalAlignment alignment )
327 {
328   if( alignment != mImpl->mLayoutEngine.GetHorizontalAlignment() )
329   {
330     // Set the alignment.
331     mImpl->mLayoutEngine.SetHorizontalAlignment( alignment );
332
333     // Set the flag to redo the alignment operation.
334     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | ALIGN );
335
336     mImpl->RequestRelayout();
337   }
338 }
339
340 LayoutEngine::HorizontalAlignment Controller::GetHorizontalAlignment() const
341 {
342   return mImpl->mLayoutEngine.GetHorizontalAlignment();
343 }
344
345 void Controller::SetVerticalAlignment( LayoutEngine::VerticalAlignment alignment )
346 {
347   if( alignment != mImpl->mLayoutEngine.GetVerticalAlignment() )
348   {
349     // Set the alignment.
350     mImpl->mLayoutEngine.SetVerticalAlignment( alignment );
351
352     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | ALIGN );
353
354     mImpl->RequestRelayout();
355   }
356 }
357
358 LayoutEngine::VerticalAlignment Controller::GetVerticalAlignment() const
359 {
360   return mImpl->mLayoutEngine.GetVerticalAlignment();
361 }
362
363 // public : Update
364
365 void Controller::SetText( const std::string& text )
366 {
367   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SetText\n" );
368
369   // Reset keyboard as text changed
370   mImpl->ResetImfManager();
371
372   // Remove the previously set text and style.
373   ResetText();
374
375   // Remove the style.
376   ClearStyleData();
377
378   CharacterIndex lastCursorIndex = 0u;
379
380   if( NULL != mImpl->mEventData )
381   {
382     // If popup shown then hide it by switching to Editing state
383     if( ( EventData::SELECTING == mImpl->mEventData->mState )          ||
384         ( EventData::EDITING_WITH_POPUP == mImpl->mEventData->mState ) ||
385         ( EventData::EDITING_WITH_GRAB_HANDLE == mImpl->mEventData->mState ) ||
386         ( EventData::EDITING_WITH_PASTE_POPUP == mImpl->mEventData->mState ) )
387     {
388       mImpl->ChangeState( EventData::EDITING );
389     }
390   }
391
392   if( !text.empty() )
393   {
394     mImpl->mVisualModel->SetTextColor( mImpl->mTextColor );
395
396     MarkupProcessData markupProcessData( mImpl->mLogicalModel->mColorRuns,
397                                          mImpl->mLogicalModel->mFontDescriptionRuns );
398
399     Length textSize = 0u;
400     const uint8_t* utf8 = NULL;
401     if( mImpl->mMarkupProcessorEnabled )
402     {
403       ProcessMarkupString( text, markupProcessData );
404       textSize = markupProcessData.markupProcessedText.size();
405
406       // This is a bit horrible but std::string returns a (signed) char*
407       utf8 = reinterpret_cast<const uint8_t*>( markupProcessData.markupProcessedText.c_str() );
408     }
409     else
410     {
411       textSize = text.size();
412
413       // This is a bit horrible but std::string returns a (signed) char*
414       utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
415     }
416
417     //  Convert text into UTF-32
418     Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
419     utf32Characters.Resize( textSize );
420
421     // Transform a text array encoded in utf8 into an array encoded in utf32.
422     // It returns the actual number of characters.
423     Length characterCount = Utf8ToUtf32( utf8, textSize, utf32Characters.Begin() );
424     utf32Characters.Resize( characterCount );
425
426     DALI_ASSERT_DEBUG( textSize >= characterCount && "Invalid UTF32 conversion length" );
427     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SetText %p UTF8 size %d, UTF32 size %d\n", this, textSize, mImpl->mLogicalModel->mText.Count() );
428
429     // The characters to be added.
430     mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mLogicalModel->mText.Count();
431
432     // To reset the cursor position
433     lastCursorIndex = characterCount;
434
435     // Update the rest of the model during size negotiation
436     mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
437
438     // The natural size needs to be re-calculated.
439     mImpl->mRecalculateNaturalSize = true;
440
441     // Apply modifications to the model
442     mImpl->mOperationsPending = ALL_OPERATIONS;
443   }
444   else
445   {
446     ShowPlaceholderText();
447   }
448
449   // Resets the cursor position.
450   ResetCursorPosition( lastCursorIndex );
451
452   // Scrolls the text to make the cursor visible.
453   ResetScrollPosition();
454
455   mImpl->RequestRelayout();
456
457   if( NULL != mImpl->mEventData )
458   {
459     // Cancel previously queued events
460     mImpl->mEventData->mEventQueue.clear();
461   }
462
463   // Do this last since it provides callbacks into application code
464   mImpl->mControlInterface.TextChanged();
465 }
466
467 void Controller::GetText( std::string& text ) const
468 {
469   if( !mImpl->IsShowingPlaceholderText() )
470   {
471     // Retrieves the text string.
472     mImpl->GetText( 0u, text );
473   }
474   else
475   {
476     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::GetText %p empty (but showing placeholder)\n", this );
477   }
478 }
479
480 void Controller::SetPlaceholderText( PlaceholderType type, const std::string& text )
481 {
482   if( NULL != mImpl->mEventData )
483   {
484     if( PLACEHOLDER_TYPE_INACTIVE == type )
485     {
486       mImpl->mEventData->mPlaceholderTextInactive = text;
487     }
488     else
489     {
490       mImpl->mEventData->mPlaceholderTextActive = text;
491     }
492
493     // Update placeholder if there is no text
494     if( mImpl->IsShowingPlaceholderText() ||
495         ( 0u == mImpl->mLogicalModel->mText.Count() ) )
496     {
497       ShowPlaceholderText();
498     }
499   }
500 }
501
502 void Controller::GetPlaceholderText( PlaceholderType type, std::string& text ) const
503 {
504   if( NULL != mImpl->mEventData )
505   {
506     if( PLACEHOLDER_TYPE_INACTIVE == type )
507     {
508       text = mImpl->mEventData->mPlaceholderTextInactive;
509     }
510     else
511     {
512       text = mImpl->mEventData->mPlaceholderTextActive;
513     }
514   }
515 }
516
517 void Controller::UpdateAfterFontChange( const std::string& newDefaultFont )
518 {
519   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::UpdateAfterFontChange\n");
520
521   if( !mImpl->mFontDefaults->familyDefined ) // If user defined font then should not update when system font changes
522   {
523     DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::UpdateAfterFontChange newDefaultFont(%s)\n", newDefaultFont.c_str() );
524     mImpl->mFontDefaults->mFontDescription.family = newDefaultFont;
525
526     ClearFontData();
527
528     mImpl->RequestRelayout();
529   }
530 }
531
532 // public : Default style & Input style
533
534 void Controller::SetDefaultFontFamily( const std::string& defaultFontFamily )
535 {
536   if( NULL == mImpl->mFontDefaults )
537   {
538     mImpl->mFontDefaults = new FontDefaults();
539   }
540
541   mImpl->mFontDefaults->mFontDescription.family = defaultFontFamily;
542   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetDefaultFontFamily %s\n", defaultFontFamily.c_str());
543   mImpl->mFontDefaults->familyDefined = !defaultFontFamily.empty();
544
545   // Clear the font-specific data
546   ClearFontData();
547
548   mImpl->RequestRelayout();
549 }
550
551 const std::string& Controller::GetDefaultFontFamily() const
552 {
553   if( NULL != mImpl->mFontDefaults )
554   {
555     return mImpl->mFontDefaults->mFontDescription.family;
556   }
557
558   return EMPTY_STRING;
559 }
560
561 void Controller::SetDefaultFontWeight( FontWeight weight )
562 {
563   if( NULL == mImpl->mFontDefaults )
564   {
565     mImpl->mFontDefaults = new FontDefaults();
566   }
567
568   mImpl->mFontDefaults->mFontDescription.weight = weight;
569   mImpl->mFontDefaults->weightDefined = true;
570
571   // Clear the font-specific data
572   ClearFontData();
573
574   mImpl->RequestRelayout();
575 }
576
577 bool Controller::IsDefaultFontWeightDefined() const
578 {
579   return mImpl->mFontDefaults->weightDefined;
580 }
581
582 FontWeight Controller::GetDefaultFontWeight() const
583 {
584   if( NULL != mImpl->mFontDefaults )
585   {
586     return mImpl->mFontDefaults->mFontDescription.weight;
587   }
588
589   return TextAbstraction::FontWeight::NORMAL;
590 }
591
592 void Controller::SetDefaultFontWidth( FontWidth width )
593 {
594   if( NULL == mImpl->mFontDefaults )
595   {
596     mImpl->mFontDefaults = new FontDefaults();
597   }
598
599   mImpl->mFontDefaults->mFontDescription.width = width;
600   mImpl->mFontDefaults->widthDefined = true;
601
602   // Clear the font-specific data
603   ClearFontData();
604
605   mImpl->RequestRelayout();
606 }
607
608 bool Controller::IsDefaultFontWidthDefined() const
609 {
610   return mImpl->mFontDefaults->widthDefined;
611 }
612
613 FontWidth Controller::GetDefaultFontWidth() const
614 {
615   if( NULL != mImpl->mFontDefaults )
616   {
617     return mImpl->mFontDefaults->mFontDescription.width;
618   }
619
620   return TextAbstraction::FontWidth::NORMAL;
621 }
622
623 void Controller::SetDefaultFontSlant( FontSlant slant )
624 {
625   if( NULL == mImpl->mFontDefaults )
626   {
627     mImpl->mFontDefaults = new FontDefaults();
628   }
629
630   mImpl->mFontDefaults->mFontDescription.slant = slant;
631   mImpl->mFontDefaults->slantDefined = true;
632
633   // Clear the font-specific data
634   ClearFontData();
635
636   mImpl->RequestRelayout();
637 }
638
639 bool Controller::IsDefaultFontSlantDefined() const
640 {
641   return mImpl->mFontDefaults->slantDefined;
642 }
643
644 FontSlant Controller::GetDefaultFontSlant() const
645 {
646   if( NULL != mImpl->mFontDefaults )
647   {
648     return mImpl->mFontDefaults->mFontDescription.slant;
649   }
650
651   return TextAbstraction::FontSlant::NORMAL;
652 }
653
654 void Controller::SetDefaultPointSize( float pointSize )
655 {
656   if( NULL == mImpl->mFontDefaults )
657   {
658     mImpl->mFontDefaults = new FontDefaults();
659   }
660
661   mImpl->mFontDefaults->mDefaultPointSize = pointSize;
662   mImpl->mFontDefaults->sizeDefined = true;
663
664   // Clear the font-specific data
665   ClearFontData();
666
667   mImpl->RequestRelayout();
668 }
669
670 float Controller::GetDefaultPointSize() const
671 {
672   if( NULL != mImpl->mFontDefaults )
673   {
674     return mImpl->mFontDefaults->mDefaultPointSize;
675   }
676
677   return 0.0f;
678 }
679
680 void Controller::SetTextColor( const Vector4& textColor )
681 {
682   mImpl->mTextColor = textColor;
683
684   if( !mImpl->IsShowingPlaceholderText() )
685   {
686     mImpl->mVisualModel->SetTextColor( textColor );
687
688     mImpl->RequestRelayout();
689   }
690 }
691
692 const Vector4& Controller::GetTextColor() const
693 {
694   return mImpl->mTextColor;
695 }
696
697 void Controller::SetPlaceholderTextColor( const Vector4& textColor )
698 {
699   if( NULL != mImpl->mEventData )
700   {
701     mImpl->mEventData->mPlaceholderTextColor = textColor;
702   }
703
704   if( mImpl->IsShowingPlaceholderText() )
705   {
706     mImpl->mVisualModel->SetTextColor( textColor );
707     mImpl->RequestRelayout();
708   }
709 }
710
711 const Vector4& Controller::GetPlaceholderTextColor() const
712 {
713   if( NULL != mImpl->mEventData )
714   {
715     return mImpl->mEventData->mPlaceholderTextColor;
716   }
717
718   return Color::BLACK;
719 }
720
721 void Controller::SetShadowOffset( const Vector2& shadowOffset )
722 {
723   mImpl->mVisualModel->SetShadowOffset( shadowOffset );
724
725   mImpl->RequestRelayout();
726 }
727
728 const Vector2& Controller::GetShadowOffset() const
729 {
730   return mImpl->mVisualModel->GetShadowOffset();
731 }
732
733 void Controller::SetShadowColor( const Vector4& shadowColor )
734 {
735   mImpl->mVisualModel->SetShadowColor( shadowColor );
736
737   mImpl->RequestRelayout();
738 }
739
740 const Vector4& Controller::GetShadowColor() const
741 {
742   return mImpl->mVisualModel->GetShadowColor();
743 }
744
745 void Controller::SetDefaultShadowProperties( const std::string& shadowProperties )
746 {
747   if( NULL == mImpl->mShadowDefaults )
748   {
749     mImpl->mShadowDefaults = new ShadowDefaults();
750   }
751
752   mImpl->mShadowDefaults->properties = shadowProperties;
753 }
754
755 const std::string& Controller::GetDefaultShadowProperties() const
756 {
757   if( NULL != mImpl->mShadowDefaults )
758   {
759     return mImpl->mShadowDefaults->properties;
760   }
761
762   return EMPTY_STRING;
763 }
764
765 void Controller::SetUnderlineColor( const Vector4& color )
766 {
767   mImpl->mVisualModel->SetUnderlineColor( color );
768
769   mImpl->RequestRelayout();
770 }
771
772 const Vector4& Controller::GetUnderlineColor() const
773 {
774   return mImpl->mVisualModel->GetUnderlineColor();
775 }
776
777 void Controller::SetUnderlineEnabled( bool enabled )
778 {
779   mImpl->mVisualModel->SetUnderlineEnabled( enabled );
780
781   mImpl->RequestRelayout();
782 }
783
784 bool Controller::IsUnderlineEnabled() const
785 {
786   return mImpl->mVisualModel->IsUnderlineEnabled();
787 }
788
789 void Controller::SetUnderlineHeight( float height )
790 {
791   mImpl->mVisualModel->SetUnderlineHeight( height );
792
793   mImpl->RequestRelayout();
794 }
795
796 float Controller::GetUnderlineHeight() const
797 {
798   return mImpl->mVisualModel->GetUnderlineHeight();
799 }
800
801 void Controller::SetDefaultUnderlineProperties( const std::string& underlineProperties )
802 {
803   if( NULL == mImpl->mUnderlineDefaults )
804   {
805     mImpl->mUnderlineDefaults = new UnderlineDefaults();
806   }
807
808   mImpl->mUnderlineDefaults->properties = underlineProperties;
809 }
810
811 const std::string& Controller::GetDefaultUnderlineProperties() const
812 {
813   if( NULL != mImpl->mUnderlineDefaults )
814   {
815     return mImpl->mUnderlineDefaults->properties;
816   }
817
818   return EMPTY_STRING;
819 }
820
821 void Controller::SetDefaultEmbossProperties( const std::string& embossProperties )
822 {
823   if( NULL == mImpl->mEmbossDefaults )
824   {
825     mImpl->mEmbossDefaults = new EmbossDefaults();
826   }
827
828   mImpl->mEmbossDefaults->properties = embossProperties;
829 }
830
831 const std::string& Controller::GetDefaultEmbossProperties() const
832 {
833   if( NULL != mImpl->mEmbossDefaults )
834   {
835     return mImpl->mEmbossDefaults->properties;
836   }
837
838   return EMPTY_STRING;
839 }
840
841 void Controller::SetDefaultOutlineProperties( const std::string& outlineProperties )
842 {
843   if( NULL == mImpl->mOutlineDefaults )
844   {
845     mImpl->mOutlineDefaults = new OutlineDefaults();
846   }
847
848   mImpl->mOutlineDefaults->properties = outlineProperties;
849 }
850
851 const std::string& Controller::GetDefaultOutlineProperties() const
852 {
853   if( NULL != mImpl->mOutlineDefaults )
854   {
855     return mImpl->mOutlineDefaults->properties;
856   }
857
858   return EMPTY_STRING;
859 }
860
861 void Controller::SetDefaultLineSpacing( float lineSpacing )
862 {
863   //TODO finish implementation
864   mImpl->mLayoutEngine.SetDefaultLineSpacing( lineSpacing );
865 }
866
867 float Controller::GetDefaultLineSpacing() const
868 {
869   return mImpl->mLayoutEngine.GetDefaultLineSpacing();
870 }
871
872 void Controller::SetInputColor( const Vector4& color )
873 {
874   if( NULL != mImpl->mEventData )
875   {
876     mImpl->mEventData->mInputStyle.textColor = color;
877     mImpl->mEventData->mInputStyle.isDefaultColor = false;
878
879     if( EventData::SELECTING == mImpl->mEventData->mState )
880     {
881       const bool handlesCrossed = mImpl->mEventData->mLeftSelectionPosition > mImpl->mEventData->mRightSelectionPosition;
882
883       // Get start and end position of selection
884       const CharacterIndex startOfSelectedText = handlesCrossed ? mImpl->mEventData->mRightSelectionPosition : mImpl->mEventData->mLeftSelectionPosition;
885       const Length lengthOfSelectedText = ( handlesCrossed ? mImpl->mEventData->mLeftSelectionPosition : mImpl->mEventData->mRightSelectionPosition ) - startOfSelectedText;
886
887       // Add the color run.
888       const VectorBase::SizeType numberOfRuns = mImpl->mLogicalModel->mColorRuns.Count();
889       mImpl->mLogicalModel->mColorRuns.Resize( numberOfRuns + 1u );
890
891       ColorRun& colorRun = *( mImpl->mLogicalModel->mColorRuns.Begin() + numberOfRuns );
892       colorRun.color = color;
893       colorRun.characterRun.characterIndex = startOfSelectedText;
894       colorRun.characterRun.numberOfCharacters = lengthOfSelectedText;
895
896       // Request to relayout.
897       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | COLOR );
898       mImpl->RequestRelayout();
899
900       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
901       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
902       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
903     }
904   }
905 }
906
907 const Vector4& Controller::GetInputColor() const
908 {
909   if( NULL != mImpl->mEventData )
910   {
911     return mImpl->mEventData->mInputStyle.textColor;
912   }
913
914   // Return the default text's color if there is no EventData.
915   return mImpl->mTextColor;
916
917 }
918
919 void Controller::SetInputFontFamily( const std::string& fontFamily )
920 {
921   if( NULL != mImpl->mEventData )
922   {
923     mImpl->mEventData->mInputStyle.familyName = fontFamily;
924     mImpl->mEventData->mInputStyle.isFamilyDefined = true;
925
926     if( EventData::SELECTING == mImpl->mEventData->mState )
927     {
928       CharacterIndex startOfSelectedText = 0u;
929       Length lengthOfSelectedText = 0u;
930       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
931                                                                             mImpl->mLogicalModel,
932                                                                             startOfSelectedText,
933                                                                             lengthOfSelectedText );
934
935       fontDescriptionRun.familyLength = fontFamily.size();
936       fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
937       memcpy( fontDescriptionRun.familyName, fontFamily.c_str(), fontDescriptionRun.familyLength );
938       fontDescriptionRun.familyDefined = true;
939
940       // The memory allocated for the font family name is freed when the font description is removed from the logical model.
941
942       // Request to relayout.
943       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
944                                                                VALIDATE_FONTS            |
945                                                                SHAPE_TEXT                |
946                                                                GET_GLYPH_METRICS         |
947                                                                LAYOUT                    |
948                                                                UPDATE_LAYOUT_SIZE        |
949                                                                REORDER                   |
950                                                                ALIGN );
951       mImpl->mRecalculateNaturalSize = true;
952       mImpl->RequestRelayout();
953
954       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
955       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
956       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
957
958       // As the font changes, recalculate the handle positions is needed.
959       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
960       mImpl->mEventData->mUpdateRightSelectionPosition = true;
961       mImpl->mEventData->mUpdateHighlightBox = true;
962       mImpl->mEventData->mScrollAfterUpdatePosition = true;
963     }
964   }
965 }
966
967 const std::string& Controller::GetInputFontFamily() const
968 {
969   if( NULL != mImpl->mEventData )
970   {
971     return mImpl->mEventData->mInputStyle.familyName;
972   }
973
974   // Return the default font's family if there is no EventData.
975   return GetDefaultFontFamily();
976 }
977
978 void Controller::SetInputFontWeight( FontWeight weight )
979 {
980   if( NULL != mImpl->mEventData )
981   {
982     mImpl->mEventData->mInputStyle.weight = weight;
983     mImpl->mEventData->mInputStyle.isWeightDefined = true;
984
985     if( EventData::SELECTING == mImpl->mEventData->mState )
986     {
987       CharacterIndex startOfSelectedText = 0u;
988       Length lengthOfSelectedText = 0u;
989       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
990                                                                             mImpl->mLogicalModel,
991                                                                             startOfSelectedText,
992                                                                             lengthOfSelectedText );
993
994       fontDescriptionRun.weight = weight;
995       fontDescriptionRun.weightDefined = true;
996
997       // Request to relayout.
998       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
999                                                                VALIDATE_FONTS            |
1000                                                                SHAPE_TEXT                |
1001                                                                GET_GLYPH_METRICS         |
1002                                                                LAYOUT                    |
1003                                                                UPDATE_LAYOUT_SIZE        |
1004                                                                REORDER                   |
1005                                                                ALIGN );
1006       mImpl->mRecalculateNaturalSize = true;
1007       mImpl->RequestRelayout();
1008
1009       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1010       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1011       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1012
1013       // As the font might change, recalculate the handle positions is needed.
1014       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
1015       mImpl->mEventData->mUpdateRightSelectionPosition = true;
1016       mImpl->mEventData->mUpdateHighlightBox = true;
1017       mImpl->mEventData->mScrollAfterUpdatePosition = true;
1018     }
1019   }
1020 }
1021
1022 bool Controller::IsInputFontWeightDefined() const
1023 {
1024   bool defined = false;
1025
1026   if( NULL != mImpl->mEventData )
1027   {
1028     defined = mImpl->mEventData->mInputStyle.isWeightDefined;
1029   }
1030
1031   return defined;
1032 }
1033
1034 FontWeight Controller::GetInputFontWeight() const
1035 {
1036   if( NULL != mImpl->mEventData )
1037   {
1038     return mImpl->mEventData->mInputStyle.weight;
1039   }
1040
1041   return GetDefaultFontWeight();
1042 }
1043
1044 void Controller::SetInputFontWidth( FontWidth width )
1045 {
1046   if( NULL != mImpl->mEventData )
1047   {
1048     mImpl->mEventData->mInputStyle.width = width;
1049     mImpl->mEventData->mInputStyle.isWidthDefined = true;
1050
1051     if( EventData::SELECTING == mImpl->mEventData->mState )
1052     {
1053       CharacterIndex startOfSelectedText = 0u;
1054       Length lengthOfSelectedText = 0u;
1055       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
1056                                                                             mImpl->mLogicalModel,
1057                                                                             startOfSelectedText,
1058                                                                             lengthOfSelectedText );
1059
1060       fontDescriptionRun.width = width;
1061       fontDescriptionRun.widthDefined = true;
1062
1063       // Request to relayout.
1064       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1065                                                                VALIDATE_FONTS            |
1066                                                                SHAPE_TEXT                |
1067                                                                GET_GLYPH_METRICS         |
1068                                                                LAYOUT                    |
1069                                                                UPDATE_LAYOUT_SIZE        |
1070                                                                REORDER                   |
1071                                                                ALIGN );
1072       mImpl->mRecalculateNaturalSize = true;
1073       mImpl->RequestRelayout();
1074
1075       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1076       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1077       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1078
1079       // As the font might change, recalculate the handle positions is needed.
1080       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
1081       mImpl->mEventData->mUpdateRightSelectionPosition = true;
1082       mImpl->mEventData->mUpdateHighlightBox = true;
1083       mImpl->mEventData->mScrollAfterUpdatePosition = true;
1084     }
1085   }
1086 }
1087
1088 bool Controller::IsInputFontWidthDefined() const
1089 {
1090   bool defined = false;
1091
1092   if( NULL != mImpl->mEventData )
1093   {
1094     defined = mImpl->mEventData->mInputStyle.isWidthDefined;
1095   }
1096
1097   return defined;
1098 }
1099
1100 FontWidth Controller::GetInputFontWidth() const
1101 {
1102   if( NULL != mImpl->mEventData )
1103   {
1104     return mImpl->mEventData->mInputStyle.width;
1105   }
1106
1107   return GetDefaultFontWidth();
1108 }
1109
1110 void Controller::SetInputFontSlant( FontSlant slant )
1111 {
1112   if( NULL != mImpl->mEventData )
1113   {
1114     mImpl->mEventData->mInputStyle.slant = slant;
1115     mImpl->mEventData->mInputStyle.isSlantDefined = true;
1116
1117     if( EventData::SELECTING == mImpl->mEventData->mState )
1118     {
1119       CharacterIndex startOfSelectedText = 0u;
1120       Length lengthOfSelectedText = 0u;
1121       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
1122                                                                             mImpl->mLogicalModel,
1123                                                                             startOfSelectedText,
1124                                                                             lengthOfSelectedText );
1125
1126       fontDescriptionRun.slant = slant;
1127       fontDescriptionRun.slantDefined = true;
1128
1129       // Request to relayout.
1130       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1131                                                                VALIDATE_FONTS            |
1132                                                                SHAPE_TEXT                |
1133                                                                GET_GLYPH_METRICS         |
1134                                                                LAYOUT                    |
1135                                                                UPDATE_LAYOUT_SIZE        |
1136                                                                REORDER                   |
1137                                                                ALIGN );
1138       mImpl->mRecalculateNaturalSize = true;
1139       mImpl->RequestRelayout();
1140
1141       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1142       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1143       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1144
1145       // As the font might change, recalculate the handle positions is needed.
1146       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
1147       mImpl->mEventData->mUpdateRightSelectionPosition = true;
1148       mImpl->mEventData->mUpdateHighlightBox = true;
1149       mImpl->mEventData->mScrollAfterUpdatePosition = true;
1150     }
1151   }
1152 }
1153
1154 bool Controller::IsInputFontSlantDefined() const
1155 {
1156   bool defined = false;
1157
1158   if( NULL != mImpl->mEventData )
1159   {
1160     defined = mImpl->mEventData->mInputStyle.isSlantDefined;
1161   }
1162
1163   return defined;
1164 }
1165
1166 FontSlant Controller::GetInputFontSlant() const
1167 {
1168   if( NULL != mImpl->mEventData )
1169   {
1170     return mImpl->mEventData->mInputStyle.slant;
1171   }
1172
1173   return GetDefaultFontSlant();
1174 }
1175
1176 void Controller::SetInputFontPointSize( float size )
1177 {
1178   if( NULL != mImpl->mEventData )
1179   {
1180     mImpl->mEventData->mInputStyle.size = size;
1181     mImpl->mEventData->mInputStyle.isSizeDefined = true;
1182
1183     if( EventData::SELECTING == mImpl->mEventData->mState )
1184     {
1185       CharacterIndex startOfSelectedText = 0u;
1186       Length lengthOfSelectedText = 0u;
1187       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
1188                                                                             mImpl->mLogicalModel,
1189                                                                             startOfSelectedText,
1190                                                                             lengthOfSelectedText );
1191
1192       fontDescriptionRun.size = static_cast<PointSize26Dot6>( size * 64.f );
1193       fontDescriptionRun.sizeDefined = true;
1194
1195       // Request to relayout.
1196       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1197                                                                VALIDATE_FONTS            |
1198                                                                SHAPE_TEXT                |
1199                                                                GET_GLYPH_METRICS         |
1200                                                                LAYOUT                    |
1201                                                                UPDATE_LAYOUT_SIZE        |
1202                                                                REORDER                   |
1203                                                                ALIGN );
1204       mImpl->mRecalculateNaturalSize = true;
1205       mImpl->RequestRelayout();
1206
1207       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1208       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1209       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1210
1211       // As the font might change, recalculate the handle positions is needed.
1212       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
1213       mImpl->mEventData->mUpdateRightSelectionPosition = true;
1214       mImpl->mEventData->mUpdateHighlightBox = true;
1215       mImpl->mEventData->mScrollAfterUpdatePosition = true;
1216     }
1217   }
1218 }
1219
1220 float Controller::GetInputFontPointSize() const
1221 {
1222   if( NULL != mImpl->mEventData )
1223   {
1224     return mImpl->mEventData->mInputStyle.size;
1225   }
1226
1227   // Return the default font's point size if there is no EventData.
1228   return GetDefaultPointSize();
1229 }
1230
1231 void Controller::SetInputLineSpacing( float lineSpacing )
1232 {
1233   if( NULL != mImpl->mEventData )
1234   {
1235     mImpl->mEventData->mInputStyle.lineSpacing = lineSpacing;
1236     mImpl->mEventData->mInputStyle.isLineSpacingDefined = true;
1237   }
1238 }
1239
1240 float Controller::GetInputLineSpacing() const
1241 {
1242   if( NULL != mImpl->mEventData )
1243   {
1244     return mImpl->mEventData->mInputStyle.lineSpacing;
1245   }
1246
1247   return 0.f;
1248 }
1249
1250 void Controller::SetInputShadowProperties( const std::string& shadowProperties )
1251 {
1252   if( NULL != mImpl->mEventData )
1253   {
1254     mImpl->mEventData->mInputStyle.shadowProperties = shadowProperties;
1255   }
1256 }
1257
1258 const std::string& Controller::GetInputShadowProperties() const
1259 {
1260   if( NULL != mImpl->mEventData )
1261   {
1262     return mImpl->mEventData->mInputStyle.shadowProperties;
1263   }
1264
1265   return GetDefaultShadowProperties();
1266 }
1267
1268 void Controller::SetInputUnderlineProperties( const std::string& underlineProperties )
1269 {
1270   if( NULL != mImpl->mEventData )
1271   {
1272     mImpl->mEventData->mInputStyle.underlineProperties = underlineProperties;
1273   }
1274 }
1275
1276 const std::string& Controller::GetInputUnderlineProperties() const
1277 {
1278   if( NULL != mImpl->mEventData )
1279   {
1280     return mImpl->mEventData->mInputStyle.underlineProperties;
1281   }
1282
1283   return GetDefaultUnderlineProperties();
1284 }
1285
1286 void Controller::SetInputEmbossProperties( const std::string& embossProperties )
1287 {
1288   if( NULL != mImpl->mEventData )
1289   {
1290     mImpl->mEventData->mInputStyle.embossProperties = embossProperties;
1291   }
1292 }
1293
1294 const std::string& Controller::GetInputEmbossProperties() const
1295 {
1296   if( NULL != mImpl->mEventData )
1297   {
1298     return mImpl->mEventData->mInputStyle.embossProperties;
1299   }
1300
1301   return GetDefaultEmbossProperties();
1302 }
1303
1304 void Controller::SetInputOutlineProperties( const std::string& outlineProperties )
1305 {
1306   if( NULL != mImpl->mEventData )
1307   {
1308     mImpl->mEventData->mInputStyle.outlineProperties = outlineProperties;
1309   }
1310 }
1311
1312 const std::string& Controller::GetInputOutlineProperties() const
1313 {
1314   if( NULL != mImpl->mEventData )
1315   {
1316     return mImpl->mEventData->mInputStyle.outlineProperties;
1317   }
1318
1319   return GetDefaultOutlineProperties();
1320 }
1321
1322 // public : Queries & retrieves.
1323
1324 LayoutEngine& Controller::GetLayoutEngine()
1325 {
1326   return mImpl->mLayoutEngine;
1327 }
1328
1329 View& Controller::GetView()
1330 {
1331   return mImpl->mView;
1332 }
1333
1334 const Vector2& Controller::GetScrollPosition() const
1335 {
1336   return mImpl->mScrollPosition;
1337 }
1338
1339 Vector3 Controller::GetNaturalSize()
1340 {
1341   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetNaturalSize\n" );
1342   Vector3 naturalSize;
1343
1344   // Make sure the model is up-to-date before layouting
1345   ProcessModifyEvents();
1346
1347   if( mImpl->mRecalculateNaturalSize )
1348   {
1349     // Operations that can be done only once until the text changes.
1350     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
1351                                                                            GET_SCRIPTS       |
1352                                                                            VALIDATE_FONTS    |
1353                                                                            GET_LINE_BREAKS   |
1354                                                                            GET_WORD_BREAKS   |
1355                                                                            BIDI_INFO         |
1356                                                                            SHAPE_TEXT        |
1357                                                                            GET_GLYPH_METRICS );
1358     // Make sure the model is up-to-date before layouting
1359     mImpl->UpdateModel( onlyOnceOperations );
1360
1361     // Layout the text for the new width.
1362     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | LAYOUT );
1363
1364     // Set the update info to relayout the whole text.
1365     mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
1366     mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mLogicalModel->mText.Count();
1367
1368     // Store the actual control's size to restore later.
1369     const Size actualControlSize = mImpl->mVisualModel->mControlSize;
1370
1371     DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
1372                 static_cast<OperationsMask>( onlyOnceOperations |
1373                                              LAYOUT ),
1374                 naturalSize.GetVectorXY() );
1375
1376     // Do not do again the only once operations.
1377     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
1378
1379     // Do the size related operations again.
1380     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
1381                                                                         ALIGN  |
1382                                                                         REORDER );
1383     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
1384
1385     // Stores the natural size to avoid recalculate it again
1386     // unless the text/style changes.
1387     mImpl->mVisualModel->SetNaturalSize( naturalSize.GetVectorXY() );
1388
1389     mImpl->mRecalculateNaturalSize = false;
1390
1391     // Clear the update info. This info will be set the next time the text is updated.
1392     mImpl->mTextUpdateInfo.Clear();
1393
1394     // Restore the actual control's size.
1395     mImpl->mVisualModel->mControlSize = actualControlSize;
1396
1397     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize calculated %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z );
1398   }
1399   else
1400   {
1401     naturalSize = mImpl->mVisualModel->GetNaturalSize();
1402
1403     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize cached %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z );
1404   }
1405
1406   naturalSize.x = ConvertToEven( naturalSize.x );
1407   naturalSize.y = ConvertToEven( naturalSize.y );
1408
1409   return naturalSize;
1410 }
1411
1412 float Controller::GetHeightForWidth( float width )
1413 {
1414   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetHeightForWidth %p width %f\n", this, width );
1415   // Make sure the model is up-to-date before layouting
1416   ProcessModifyEvents();
1417
1418   Size layoutSize;
1419   if( fabsf( width - mImpl->mVisualModel->mControlSize.width ) > Math::MACHINE_EPSILON_1000 )
1420   {
1421     // Operations that can be done only once until the text changes.
1422     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
1423                                                                            GET_SCRIPTS       |
1424                                                                            VALIDATE_FONTS    |
1425                                                                            GET_LINE_BREAKS   |
1426                                                                            GET_WORD_BREAKS   |
1427                                                                            BIDI_INFO         |
1428                                                                            SHAPE_TEXT        |
1429                                                                            GET_GLYPH_METRICS );
1430     // Make sure the model is up-to-date before layouting
1431     mImpl->UpdateModel( onlyOnceOperations );
1432
1433
1434     // Layout the text for the new width.
1435     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | LAYOUT );
1436
1437     // Set the update info to relayout the whole text.
1438     mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
1439     mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mLogicalModel->mText.Count();
1440
1441     // Store the actual control's width.
1442     const float actualControlWidth = mImpl->mVisualModel->mControlSize.width;
1443
1444     DoRelayout( Size( width, MAX_FLOAT ),
1445                 static_cast<OperationsMask>( onlyOnceOperations |
1446                                              LAYOUT ),
1447                 layoutSize );
1448
1449     // Do not do again the only once operations.
1450     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
1451
1452     // Do the size related operations again.
1453     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
1454                                                                         ALIGN  |
1455                                                                         REORDER );
1456
1457     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
1458
1459     // Clear the update info. This info will be set the next time the text is updated.
1460     mImpl->mTextUpdateInfo.Clear();
1461
1462     // Restore the actual control's width.
1463     mImpl->mVisualModel->mControlSize.width = actualControlWidth;
1464
1465     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth calculated %f\n", layoutSize.height );
1466   }
1467   else
1468   {
1469     layoutSize = mImpl->mVisualModel->GetLayoutSize();
1470     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth cached %f\n", layoutSize.height );
1471   }
1472
1473   return layoutSize.height;
1474 }
1475
1476 // public : Relayout.
1477
1478 Controller::UpdateTextType Controller::Relayout( const Size& size )
1479 {
1480   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::Relayout %p size %f,%f, autoScroll[%s]\n", this, size.width, size.height, (mImpl->mAutoScrollEnabled)?"true":"false"  );
1481
1482   UpdateTextType updateTextType = NONE_UPDATED;
1483
1484   if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
1485   {
1486     if( 0u != mImpl->mVisualModel->mGlyphPositions.Count() )
1487     {
1488       mImpl->mVisualModel->mGlyphPositions.Clear();
1489       updateTextType = MODEL_UPDATED;
1490     }
1491
1492     // Clear the update info. This info will be set the next time the text is updated.
1493     mImpl->mTextUpdateInfo.Clear();
1494
1495     // Not worth to relayout if width or height is equal to zero.
1496     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout (skipped)\n" );
1497
1498     return updateTextType;
1499   }
1500
1501   // Whether a new size has been set.
1502   const bool newSize = ( size != mImpl->mVisualModel->mControlSize );
1503
1504   if( newSize )
1505   {
1506     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "new size (previous size %f,%f)\n", mImpl->mVisualModel->mControlSize.width, mImpl->mVisualModel->mControlSize.height );
1507
1508     // Layout operations that need to be done if the size changes.
1509     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1510                                                              LAYOUT                    |
1511                                                              ALIGN                     |
1512                                                              UPDATE_LAYOUT_SIZE        |
1513                                                              REORDER );
1514     // Set the update info to relayout the whole text.
1515     mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
1516     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
1517   }
1518
1519   // Whether there are modify events.
1520   if( 0u != mImpl->mModifyEvents.Count() )
1521   {
1522     // Style operations that need to be done if the text is modified.
1523     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1524                                                              COLOR );
1525   }
1526
1527   // Make sure the model is up-to-date before layouting.
1528   ProcessModifyEvents();
1529   bool updated = mImpl->UpdateModel( mImpl->mOperationsPending );
1530
1531   // Layout the text.
1532   Size layoutSize;
1533   updated = DoRelayout( size,
1534                         mImpl->mOperationsPending,
1535                         layoutSize ) || updated;
1536
1537   if( updated )
1538   {
1539     updateTextType = MODEL_UPDATED;
1540   }
1541
1542   // Do not re-do any operation until something changes.
1543   mImpl->mOperationsPending = NO_OPERATION;
1544
1545   // Whether the text control is editable
1546   const bool isEditable = NULL != mImpl->mEventData;
1547
1548   // Keep the current offset as it will be used to update the decorator's positions (if the size changes).
1549   Vector2 offset;
1550   if( newSize && isEditable )
1551   {
1552     offset = mImpl->mScrollPosition;
1553   }
1554
1555   if( !isEditable || !IsMultiLineEnabled() )
1556   {
1557     // After doing the text layout, the vertical offset to place the actor in the desired position can be calculated.
1558     CalculateVerticalOffset( size );
1559   }
1560
1561   if( isEditable )
1562   {
1563     if( newSize )
1564     {
1565       // If there is a new size, the scroll position needs to be clamped.
1566       mImpl->ClampHorizontalScroll( layoutSize );
1567
1568       // Update the decorator's positions is needed if there is a new size.
1569       mImpl->mEventData->mDecorator->UpdatePositions( mImpl->mScrollPosition - offset );
1570     }
1571
1572     // Move the cursor, grab handle etc.
1573     if( mImpl->ProcessInputEvents() )
1574     {
1575       updateTextType = static_cast<UpdateTextType>( updateTextType | DECORATOR_UPDATED );
1576     }
1577   }
1578
1579   // Clear the update info. This info will be set the next time the text is updated.
1580   mImpl->mTextUpdateInfo.Clear();
1581   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout\n" );
1582
1583   return updateTextType;
1584 }
1585
1586 // public : Input style change signals.
1587
1588 bool Controller::IsInputStyleChangedSignalsQueueEmpty()
1589 {
1590   return ( NULL == mImpl->mEventData ) || ( 0u == mImpl->mEventData->mInputStyleChangedQueue.Count() );
1591 }
1592
1593 void Controller::ProcessInputStyleChangedSignals()
1594 {
1595   if( NULL == mImpl->mEventData )
1596   {
1597     // Nothing to do.
1598     return;
1599   }
1600
1601   for( Vector<InputStyle::Mask>::ConstIterator it = mImpl->mEventData->mInputStyleChangedQueue.Begin(),
1602          endIt = mImpl->mEventData->mInputStyleChangedQueue.End();
1603        it != endIt;
1604        ++it )
1605   {
1606     const InputStyle::Mask mask = *it;
1607
1608     // Emit the input style changed signal.
1609     mImpl->mControlInterface.InputStyleChanged( mask );
1610   }
1611
1612   mImpl->mEventData->mInputStyleChangedQueue.Clear();
1613 }
1614
1615 // public : Text-input Event Queuing.
1616
1617 void Controller::KeyboardFocusGainEvent()
1618 {
1619   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusGainEvent" );
1620
1621   if( NULL != mImpl->mEventData )
1622   {
1623     if( ( EventData::INACTIVE == mImpl->mEventData->mState ) ||
1624         ( EventData::INTERRUPTED == mImpl->mEventData->mState ) )
1625     {
1626       mImpl->ChangeState( EventData::EDITING );
1627       mImpl->mEventData->mUpdateCursorPosition = true; //If editing started without tap event, cursor update must be triggered.
1628       mImpl->mEventData->mUpdateInputStyle = true;
1629     }
1630     mImpl->NotifyImfMultiLineStatus();
1631     if( mImpl->IsShowingPlaceholderText() )
1632     {
1633       // Show alternative placeholder-text when editing
1634       ShowPlaceholderText();
1635     }
1636
1637     mImpl->RequestRelayout();
1638   }
1639 }
1640
1641 void Controller::KeyboardFocusLostEvent()
1642 {
1643   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusLostEvent" );
1644
1645   if( NULL != mImpl->mEventData )
1646   {
1647     if( EventData::INTERRUPTED != mImpl->mEventData->mState )
1648     {
1649       mImpl->ChangeState( EventData::INACTIVE );
1650
1651       if( !mImpl->IsShowingRealText() )
1652       {
1653         // Revert to regular placeholder-text when not editing
1654         ShowPlaceholderText();
1655       }
1656     }
1657   }
1658   mImpl->RequestRelayout();
1659 }
1660
1661 bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
1662 {
1663   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyEvent" );
1664
1665   bool textChanged( false );
1666
1667   if( ( NULL != mImpl->mEventData ) &&
1668       ( keyEvent.state == KeyEvent::Down ) )
1669   {
1670     int keyCode = keyEvent.keyCode;
1671     const std::string& keyString = keyEvent.keyPressed;
1672
1673     // Pre-process to separate modifying events from non-modifying input events.
1674     if( Dali::DALI_KEY_ESCAPE == keyCode )
1675     {
1676       // Escape key is a special case which causes focus loss
1677       KeyboardFocusLostEvent();
1678     }
1679     else if( ( Dali::DALI_KEY_CURSOR_LEFT  == keyCode ) ||
1680              ( Dali::DALI_KEY_CURSOR_RIGHT == keyCode ) ||
1681              ( Dali::DALI_KEY_CURSOR_UP    == keyCode ) ||
1682              ( Dali::DALI_KEY_CURSOR_DOWN  == keyCode ) )
1683     {
1684       Event event( Event::CURSOR_KEY_EVENT );
1685       event.p1.mInt = keyCode;
1686       mImpl->mEventData->mEventQueue.push_back( event );
1687     }
1688     else if( Dali::DALI_KEY_BACKSPACE == keyCode )
1689     {
1690       textChanged = BackspaceKeyEvent();
1691     }
1692     else if( IsKey( keyEvent,  Dali::DALI_KEY_POWER ) )
1693     {
1694       mImpl->ChangeState( EventData::INTERRUPTED ); // State is not INACTIVE as expect to return to edit mode.
1695       // Avoids calling the InsertText() method which can delete selected text
1696     }
1697     else if( IsKey( keyEvent, Dali::DALI_KEY_MENU ) ||
1698              IsKey( keyEvent, Dali::DALI_KEY_HOME ) )
1699     {
1700       mImpl->ChangeState( EventData::INACTIVE );
1701       // Menu/Home key behaviour does not allow edit mode to resume like Power key
1702       // Avoids calling the InsertText() method which can delete selected text
1703     }
1704     else if( Dali::DALI_KEY_SHIFT_LEFT == keyCode )
1705     {
1706       // DALI_KEY_SHIFT_LEFT is the key code for the Left Shift. It's sent (by the imf?) when the predictive text is enabled
1707       // and a character is typed after the type of a upper case latin character.
1708
1709       // Do nothing.
1710     }
1711     else
1712     {
1713       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p keyString %s\n", this, keyString.c_str() );
1714
1715       // IMF manager is no longer handling key-events
1716       mImpl->ClearPreEditFlag();
1717
1718       InsertText( keyString, COMMIT );
1719       textChanged = true;
1720     }
1721
1722     if ( ( mImpl->mEventData->mState != EventData::INTERRUPTED ) &&
1723          ( mImpl->mEventData->mState != EventData::INACTIVE ) &&
1724          ( Dali::DALI_KEY_SHIFT_LEFT != keyCode ) )
1725     {
1726       // Should not change the state if the key is the shift send by the imf manager.
1727       // Otherwise, when the state is SELECTING the text controller can't send the right
1728       // surrounding info to the imf.
1729       mImpl->ChangeState( EventData::EDITING );
1730     }
1731
1732     mImpl->RequestRelayout();
1733   }
1734
1735   if( textChanged )
1736   {
1737     // Do this last since it provides callbacks into application code
1738     mImpl->mControlInterface.TextChanged();
1739   }
1740
1741   return true;
1742 }
1743
1744 void Controller::TapEvent( unsigned int tapCount, float x, float y )
1745 {
1746   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected TapEvent" );
1747
1748   if( NULL != mImpl->mEventData )
1749   {
1750     DALI_LOG_INFO( gLogFilter, Debug::Concise, "TapEvent state:%d \n", mImpl->mEventData->mState );
1751     EventData::State state( mImpl->mEventData->mState );
1752     bool relayoutNeeded( false );   // to avoid unnecessary relayouts when tapping an empty text-field
1753
1754     if( mImpl->IsClipboardVisible() )
1755     {
1756       if( EventData::INACTIVE == state || EventData::EDITING == state)
1757       {
1758         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );
1759       }
1760       relayoutNeeded = true;
1761     }
1762     else if( 1u == tapCount )
1763     {
1764       if( EventData::EDITING_WITH_POPUP == state || EventData::EDITING_WITH_PASTE_POPUP == state )
1765       {
1766         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );  // If Popup shown hide it here so can be shown again if required.
1767       }
1768
1769       if( mImpl->IsShowingRealText() && ( EventData::INACTIVE != state ) )
1770       {
1771         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );
1772         relayoutNeeded = true;
1773       }
1774       else
1775       {
1776         if( mImpl->IsShowingPlaceholderText() && !mImpl->IsFocusedPlaceholderAvailable() )
1777         {
1778           // Hide placeholder text
1779           ResetText();
1780         }
1781
1782         if( EventData::INACTIVE == state )
1783         {
1784           mImpl->ChangeState( EventData::EDITING );
1785         }
1786         else if( !mImpl->IsClipboardEmpty() )
1787         {
1788           mImpl->ChangeState( EventData::EDITING_WITH_POPUP );
1789         }
1790         relayoutNeeded = true;
1791       }
1792     }
1793     else if( 2u == tapCount )
1794     {
1795       if( mImpl->mEventData->mSelectionEnabled &&
1796           mImpl->IsShowingRealText() )
1797       {
1798         SelectEvent( x, y, false );
1799       }
1800     }
1801     // Handles & cursors must be repositioned after Relayout() i.e. after the Model has been updated
1802     if( relayoutNeeded )
1803     {
1804       Event event( Event::TAP_EVENT );
1805       event.p1.mUint = tapCount;
1806       event.p2.mFloat = x;
1807       event.p3.mFloat = y;
1808       mImpl->mEventData->mEventQueue.push_back( event );
1809
1810       mImpl->RequestRelayout();
1811     }
1812   }
1813
1814   // Reset keyboard as tap event has occurred.
1815   mImpl->ResetImfManager();
1816 }
1817
1818 void Controller::PanEvent( Gesture::State state, const Vector2& displacement )
1819 {
1820   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected PanEvent" );
1821
1822   if( NULL != mImpl->mEventData )
1823   {
1824     Event event( Event::PAN_EVENT );
1825     event.p1.mInt = state;
1826     event.p2.mFloat = displacement.x;
1827     event.p3.mFloat = displacement.y;
1828     mImpl->mEventData->mEventQueue.push_back( event );
1829
1830     mImpl->RequestRelayout();
1831   }
1832 }
1833
1834 void Controller::LongPressEvent( Gesture::State state, float x, float y  )
1835 {
1836   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected LongPressEvent" );
1837
1838   if( ( state == Gesture::Started ) &&
1839       ( NULL != mImpl->mEventData ) )
1840   {
1841     if( !mImpl->IsShowingRealText() )
1842     {
1843       Event event( Event::LONG_PRESS_EVENT );
1844       event.p1.mInt = state;
1845       mImpl->mEventData->mEventQueue.push_back( event );
1846       mImpl->RequestRelayout();
1847     }
1848     else
1849     {
1850       // The 1st long-press on inactive text-field is treated as tap
1851       if( EventData::INACTIVE == mImpl->mEventData->mState )
1852       {
1853         mImpl->ChangeState( EventData::EDITING );
1854
1855         Event event( Event::TAP_EVENT );
1856         event.p1.mUint = 1;
1857         event.p2.mFloat = x;
1858         event.p3.mFloat = y;
1859         mImpl->mEventData->mEventQueue.push_back( event );
1860
1861         mImpl->RequestRelayout();
1862       }
1863       else if( !mImpl->IsClipboardVisible() )
1864       {
1865         // Reset the imf manger to commit the pre-edit before selecting the text.
1866         mImpl->ResetImfManager();
1867
1868         SelectEvent( x, y, false );
1869       }
1870     }
1871   }
1872 }
1873
1874 ImfManager::ImfCallbackData Controller::OnImfEvent( ImfManager& imfManager, const ImfManager::ImfEventData& imfEvent )
1875 {
1876   // Whether the text needs to be relaid-out.
1877   bool requestRelayout = false;
1878
1879   // Whether to retrieve the text and cursor position to be sent to the IMF manager.
1880   bool retrieveText = false;
1881   bool retrieveCursor = false;
1882
1883   switch( imfEvent.eventName )
1884   {
1885     case ImfManager::COMMIT:
1886     {
1887       InsertText( imfEvent.predictiveString, Text::Controller::COMMIT );
1888       requestRelayout = true;
1889       retrieveCursor = true;
1890       break;
1891     }
1892     case ImfManager::PREEDIT:
1893     {
1894       InsertText( imfEvent.predictiveString, Text::Controller::PRE_EDIT );
1895       requestRelayout = true;
1896       retrieveCursor = true;
1897       break;
1898     }
1899     case ImfManager::DELETESURROUNDING:
1900     {
1901       const bool textDeleted = RemoveText( imfEvent.cursorOffset,
1902                                            imfEvent.numberOfChars,
1903                                            DONT_UPDATE_INPUT_STYLE );
1904
1905       if( textDeleted )
1906       {
1907         if( ( 0u != mImpl->mLogicalModel->mText.Count() ) ||
1908             !mImpl->IsPlaceholderAvailable() )
1909         {
1910           mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
1911         }
1912         else
1913         {
1914           ShowPlaceholderText();
1915         }
1916         mImpl->mEventData->mUpdateCursorPosition = true;
1917         mImpl->mEventData->mScrollAfterDelete = true;
1918
1919         requestRelayout = true;
1920       }
1921       break;
1922     }
1923     case ImfManager::GETSURROUNDING:
1924     {
1925       retrieveText = true;
1926       retrieveCursor = true;
1927       break;
1928     }
1929     case ImfManager::VOID:
1930     {
1931       // do nothing
1932       break;
1933     }
1934   } // end switch
1935
1936   if( requestRelayout )
1937   {
1938     mImpl->mOperationsPending = ALL_OPERATIONS;
1939     mImpl->RequestRelayout();
1940   }
1941
1942   std::string text;
1943   CharacterIndex cursorPosition = 0u;
1944   Length numberOfWhiteSpaces = 0u;
1945
1946   if( retrieveCursor )
1947   {
1948     numberOfWhiteSpaces = mImpl->GetNumberOfWhiteSpaces( 0u );
1949
1950     cursorPosition = mImpl->GetLogicalCursorPosition();
1951
1952     if( cursorPosition < numberOfWhiteSpaces )
1953     {
1954       cursorPosition = 0u;
1955     }
1956     else
1957     {
1958       cursorPosition -= numberOfWhiteSpaces;
1959     }
1960   }
1961
1962   if( retrieveText )
1963   {
1964     mImpl->GetText( numberOfWhiteSpaces, text );
1965   }
1966
1967   ImfManager::ImfCallbackData callbackData( ( retrieveText || retrieveCursor ), cursorPosition, text, false );
1968
1969   if( requestRelayout )
1970   {
1971     // Do this last since it provides callbacks into application code
1972     mImpl->mControlInterface.TextChanged();
1973   }
1974
1975   return callbackData;
1976 }
1977
1978 void Controller::PasteClipboardItemEvent()
1979 {
1980   // Retrieve the clipboard contents first
1981   ClipboardEventNotifier notifier( ClipboardEventNotifier::Get() );
1982   std::string stringToPaste( notifier.GetContent() );
1983
1984   // Commit the current pre-edit text; the contents of the clipboard should be appended
1985   mImpl->ResetImfManager();
1986
1987   // Temporary disable hiding clipboard
1988   mImpl->SetClipboardHideEnable( false );
1989
1990   // Paste
1991   PasteText( stringToPaste );
1992
1993   mImpl->SetClipboardHideEnable( true );
1994 }
1995
1996 // protected : Inherit from Text::Decorator::ControllerInterface.
1997
1998 void Controller::GetTargetSize( Vector2& targetSize )
1999 {
2000   targetSize = mImpl->mVisualModel->mControlSize;
2001 }
2002
2003 void Controller::AddDecoration( Actor& actor, bool needsClipping )
2004 {
2005   mImpl->mControlInterface.AddDecoration( actor, needsClipping );
2006 }
2007
2008 void Controller::DecorationEvent( HandleType handleType, HandleState state, float x, float y )
2009 {
2010   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected DecorationEvent" );
2011
2012   if( NULL != mImpl->mEventData )
2013   {
2014     switch( handleType )
2015     {
2016       case GRAB_HANDLE:
2017       {
2018         Event event( Event::GRAB_HANDLE_EVENT );
2019         event.p1.mUint  = state;
2020         event.p2.mFloat = x;
2021         event.p3.mFloat = y;
2022
2023         mImpl->mEventData->mEventQueue.push_back( event );
2024         break;
2025       }
2026       case LEFT_SELECTION_HANDLE:
2027       {
2028         Event event( Event::LEFT_SELECTION_HANDLE_EVENT );
2029         event.p1.mUint  = state;
2030         event.p2.mFloat = x;
2031         event.p3.mFloat = y;
2032
2033         mImpl->mEventData->mEventQueue.push_back( event );
2034         break;
2035       }
2036       case RIGHT_SELECTION_HANDLE:
2037       {
2038         Event event( Event::RIGHT_SELECTION_HANDLE_EVENT );
2039         event.p1.mUint  = state;
2040         event.p2.mFloat = x;
2041         event.p3.mFloat = y;
2042
2043         mImpl->mEventData->mEventQueue.push_back( event );
2044         break;
2045       }
2046       case LEFT_SELECTION_HANDLE_MARKER:
2047       case RIGHT_SELECTION_HANDLE_MARKER:
2048       {
2049         // Markers do not move the handles.
2050         break;
2051       }
2052       case HANDLE_TYPE_COUNT:
2053       {
2054         DALI_ASSERT_DEBUG( !"Controller::HandleEvent. Unexpected handle type" );
2055       }
2056     }
2057
2058     mImpl->RequestRelayout();
2059   }
2060 }
2061
2062 // protected : Inherit from TextSelectionPopup::TextPopupButtonCallbackInterface.
2063
2064 void Controller::TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::Buttons button )
2065 {
2066   if( NULL == mImpl->mEventData )
2067   {
2068     return;
2069   }
2070
2071   switch( button )
2072   {
2073     case Toolkit::TextSelectionPopup::CUT:
2074     {
2075       mImpl->SendSelectionToClipboard( true ); // Synchronous call to modify text
2076       mImpl->mOperationsPending = ALL_OPERATIONS;
2077
2078       if( ( 0u != mImpl->mLogicalModel->mText.Count() ) ||
2079           !mImpl->IsPlaceholderAvailable() )
2080       {
2081         mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
2082       }
2083       else
2084       {
2085         ShowPlaceholderText();
2086       }
2087
2088       mImpl->mEventData->mUpdateCursorPosition = true;
2089       mImpl->mEventData->mScrollAfterDelete = true;
2090
2091       mImpl->RequestRelayout();
2092       mImpl->mControlInterface.TextChanged();
2093       break;
2094     }
2095     case Toolkit::TextSelectionPopup::COPY:
2096     {
2097       mImpl->SendSelectionToClipboard( false ); // Text not modified
2098
2099       mImpl->mEventData->mUpdateCursorPosition = true;
2100
2101       mImpl->RequestRelayout(); // Cursor, Handles, Selection Highlight, Popup
2102       break;
2103     }
2104     case Toolkit::TextSelectionPopup::PASTE:
2105     {
2106       mImpl->RequestGetTextFromClipboard(); // Request clipboard service to retrieve an item
2107       break;
2108     }
2109     case Toolkit::TextSelectionPopup::SELECT:
2110     {
2111       const Vector2& currentCursorPosition = mImpl->mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
2112
2113       if( mImpl->mEventData->mSelectionEnabled )
2114       {
2115         // Creates a SELECT event.
2116         SelectEvent( currentCursorPosition.x, currentCursorPosition.y, false );
2117       }
2118       break;
2119     }
2120     case Toolkit::TextSelectionPopup::SELECT_ALL:
2121     {
2122       // Creates a SELECT_ALL event
2123       SelectEvent( 0.f, 0.f, true );
2124       break;
2125     }
2126     case Toolkit::TextSelectionPopup::CLIPBOARD:
2127     {
2128       mImpl->ShowClipboard();
2129       break;
2130     }
2131     case Toolkit::TextSelectionPopup::NONE:
2132     {
2133       // Nothing to do.
2134       break;
2135     }
2136   }
2137 }
2138
2139 // private : Update.
2140
2141 void Controller::InsertText( const std::string& text, Controller::InsertType type )
2142 {
2143   bool removedPrevious( false );
2144   bool maxLengthReached( false );
2145
2146   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected InsertText" )
2147
2148   if( NULL == mImpl->mEventData )
2149   {
2150     return;
2151   }
2152
2153   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::InsertText %p %s (%s) mPrimaryCursorPosition %d mPreEditFlag %d mPreEditStartPosition %d mPreEditLength %d\n",
2154                  this, text.c_str(), (COMMIT == type ? "COMMIT" : "PRE_EDIT"),
2155                  mImpl->mEventData->mPrimaryCursorPosition, mImpl->mEventData->mPreEditFlag, mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
2156
2157   // TODO: At the moment the underline runs are only for pre-edit.
2158   mImpl->mVisualModel->mUnderlineRuns.Clear();
2159
2160   // Keep the current number of characters.
2161   const Length currentNumberOfCharacters = mImpl->IsShowingRealText() ? mImpl->mLogicalModel->mText.Count() : 0u;
2162
2163   // Remove the previous IMF pre-edit.
2164   if( mImpl->mEventData->mPreEditFlag && ( 0u != mImpl->mEventData->mPreEditLength ) )
2165   {
2166     removedPrevious = RemoveText( -static_cast<int>( mImpl->mEventData->mPrimaryCursorPosition - mImpl->mEventData->mPreEditStartPosition ),
2167                                   mImpl->mEventData->mPreEditLength,
2168                                   DONT_UPDATE_INPUT_STYLE );
2169
2170     mImpl->mEventData->mPrimaryCursorPosition = mImpl->mEventData->mPreEditStartPosition;
2171     mImpl->mEventData->mPreEditLength = 0u;
2172   }
2173   else
2174   {
2175     // Remove the previous Selection.
2176     removedPrevious = RemoveSelectedText();
2177   }
2178
2179   Vector<Character> utf32Characters;
2180   Length characterCount = 0u;
2181
2182   if( !text.empty() )
2183   {
2184     //  Convert text into UTF-32
2185     utf32Characters.Resize( text.size() );
2186
2187     // This is a bit horrible but std::string returns a (signed) char*
2188     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
2189
2190     // Transform a text array encoded in utf8 into an array encoded in utf32.
2191     // It returns the actual number of characters.
2192     characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
2193     utf32Characters.Resize( characterCount );
2194
2195     DALI_ASSERT_DEBUG( text.size() >= utf32Characters.Count() && "Invalid UTF32 conversion length" );
2196     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "UTF8 size %d, UTF32 size %d\n", text.size(), utf32Characters.Count() );
2197   }
2198
2199   if( 0u != utf32Characters.Count() ) // Check if Utf8ToUtf32 conversion succeeded
2200   {
2201     // The placeholder text is no longer needed
2202     if( mImpl->IsShowingPlaceholderText() )
2203     {
2204       ResetText();
2205     }
2206
2207     mImpl->ChangeState( EventData::EDITING );
2208
2209     // Handle the IMF (predicitive text) state changes
2210     if( COMMIT == type )
2211     {
2212       // IMF manager is no longer handling key-events
2213       mImpl->ClearPreEditFlag();
2214     }
2215     else // PRE_EDIT
2216     {
2217       if( !mImpl->mEventData->mPreEditFlag )
2218       {
2219         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Entered PreEdit state\n" );
2220
2221         // Record the start of the pre-edit text
2222         mImpl->mEventData->mPreEditStartPosition = mImpl->mEventData->mPrimaryCursorPosition;
2223       }
2224
2225       mImpl->mEventData->mPreEditLength = utf32Characters.Count();
2226       mImpl->mEventData->mPreEditFlag = true;
2227
2228       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "mPreEditStartPosition %d mPreEditLength %d\n", mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
2229     }
2230
2231     const Length numberOfCharactersInModel = mImpl->mLogicalModel->mText.Count();
2232
2233     // Restrict new text to fit within Maximum characters setting.
2234     Length maxSizeOfNewText = std::min( ( mImpl->mMaximumNumberOfCharacters - numberOfCharactersInModel ), characterCount );
2235     maxLengthReached = ( characterCount > maxSizeOfNewText );
2236
2237     // The cursor position.
2238     CharacterIndex& cursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
2239
2240     // Update the text's style.
2241
2242     // Updates the text style runs by adding characters.
2243     mImpl->mLogicalModel->UpdateTextStyleRuns( cursorIndex, maxSizeOfNewText );
2244
2245     // Get the character index from the cursor index.
2246     const CharacterIndex styleIndex = ( cursorIndex > 0u ) ? cursorIndex - 1u : 0u;
2247
2248     // Retrieve the text's style for the given index.
2249     InputStyle style;
2250     mImpl->RetrieveDefaultInputStyle( style );
2251     mImpl->mLogicalModel->RetrieveStyle( styleIndex, style );
2252
2253     // Whether to add a new text color run.
2254     const bool addColorRun = ( style.textColor != mImpl->mEventData->mInputStyle.textColor );
2255
2256     // Whether to add a new font run.
2257     const bool addFontNameRun = style.familyName != mImpl->mEventData->mInputStyle.familyName;
2258     const bool addFontWeightRun = style.weight != mImpl->mEventData->mInputStyle.weight;
2259     const bool addFontWidthRun = style.width != mImpl->mEventData->mInputStyle.width;
2260     const bool addFontSlantRun = style.slant != mImpl->mEventData->mInputStyle.slant;
2261     const bool addFontSizeRun = style.size != mImpl->mEventData->mInputStyle.size;
2262
2263     // Add style runs.
2264     if( addColorRun )
2265     {
2266       const VectorBase::SizeType numberOfRuns = mImpl->mLogicalModel->mColorRuns.Count();
2267       mImpl->mLogicalModel->mColorRuns.Resize( numberOfRuns + 1u );
2268
2269       ColorRun& colorRun = *( mImpl->mLogicalModel->mColorRuns.Begin() + numberOfRuns );
2270       colorRun.color = mImpl->mEventData->mInputStyle.textColor;
2271       colorRun.characterRun.characterIndex = cursorIndex;
2272       colorRun.characterRun.numberOfCharacters = maxSizeOfNewText;
2273     }
2274
2275     if( addFontNameRun   ||
2276         addFontWeightRun ||
2277         addFontWidthRun  ||
2278         addFontSlantRun  ||
2279         addFontSizeRun )
2280     {
2281       const VectorBase::SizeType numberOfRuns = mImpl->mLogicalModel->mFontDescriptionRuns.Count();
2282       mImpl->mLogicalModel->mFontDescriptionRuns.Resize( numberOfRuns + 1u );
2283
2284       FontDescriptionRun& fontDescriptionRun = *( mImpl->mLogicalModel->mFontDescriptionRuns.Begin() + numberOfRuns );
2285
2286       if( addFontNameRun )
2287       {
2288         fontDescriptionRun.familyLength = mImpl->mEventData->mInputStyle.familyName.size();
2289         fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
2290         memcpy( fontDescriptionRun.familyName, mImpl->mEventData->mInputStyle.familyName.c_str(), fontDescriptionRun.familyLength );
2291         fontDescriptionRun.familyDefined = true;
2292
2293         // The memory allocated for the font family name is freed when the font description is removed from the logical model.
2294       }
2295
2296       if( addFontWeightRun )
2297       {
2298         fontDescriptionRun.weight = mImpl->mEventData->mInputStyle.weight;
2299         fontDescriptionRun.weightDefined = true;
2300       }
2301
2302       if( addFontWidthRun )
2303       {
2304         fontDescriptionRun.width = mImpl->mEventData->mInputStyle.width;
2305         fontDescriptionRun.widthDefined = true;
2306       }
2307
2308       if( addFontSlantRun )
2309       {
2310         fontDescriptionRun.slant = mImpl->mEventData->mInputStyle.slant;
2311         fontDescriptionRun.slantDefined = true;
2312       }
2313
2314       if( addFontSizeRun )
2315       {
2316         fontDescriptionRun.size = static_cast<PointSize26Dot6>( mImpl->mEventData->mInputStyle.size * 64.f );
2317         fontDescriptionRun.sizeDefined = true;
2318       }
2319
2320       fontDescriptionRun.characterRun.characterIndex = cursorIndex;
2321       fontDescriptionRun.characterRun.numberOfCharacters = maxSizeOfNewText;
2322     }
2323
2324     // Insert at current cursor position.
2325     Vector<Character>& modifyText = mImpl->mLogicalModel->mText;
2326
2327     if( cursorIndex < numberOfCharactersInModel )
2328     {
2329       modifyText.Insert( modifyText.Begin() + cursorIndex, utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
2330     }
2331     else
2332     {
2333       modifyText.Insert( modifyText.End(), utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
2334     }
2335
2336     // Mark the first paragraph to be updated.
2337     mImpl->mTextUpdateInfo.mCharacterIndex = std::min( cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex );
2338     mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd += maxSizeOfNewText;
2339
2340     // Update the cursor index.
2341     cursorIndex += maxSizeOfNewText;
2342
2343     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Inserted %d characters, new size %d new cursor %d\n", maxSizeOfNewText, mImpl->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition );
2344   }
2345
2346   const Length numberOfCharacters = mImpl->IsShowingRealText() ? mImpl->mLogicalModel->mText.Count() : 0u;
2347
2348   if( ( 0u == mImpl->mLogicalModel->mText.Count() ) &&
2349       mImpl->IsPlaceholderAvailable() )
2350   {
2351     // Show place-holder if empty after removing the pre-edit text
2352     ShowPlaceholderText();
2353     mImpl->mEventData->mUpdateCursorPosition = true;
2354     mImpl->ClearPreEditFlag();
2355   }
2356   else if( removedPrevious ||
2357            ( 0 != utf32Characters.Count() ) )
2358   {
2359     // Queue an inserted event
2360     mImpl->QueueModifyEvent( ModifyEvent::TEXT_INSERTED );
2361
2362     mImpl->mEventData->mUpdateCursorPosition = true;
2363     if( numberOfCharacters < currentNumberOfCharacters )
2364     {
2365       mImpl->mEventData->mScrollAfterDelete = true;
2366     }
2367     else
2368     {
2369       mImpl->mEventData->mScrollAfterUpdatePosition = true;
2370     }
2371   }
2372
2373   if( maxLengthReached )
2374   {
2375     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "MaxLengthReached (%d)\n", mImpl->mLogicalModel->mText.Count() );
2376
2377     mImpl->ResetImfManager();
2378
2379     // Do this last since it provides callbacks into application code
2380     mImpl->mControlInterface.MaxLengthReached();
2381   }
2382 }
2383
2384 void Controller::PasteText( const std::string& stringToPaste )
2385 {
2386   InsertText( stringToPaste, Text::Controller::COMMIT );
2387   mImpl->ChangeState( EventData::EDITING );
2388   mImpl->RequestRelayout();
2389
2390   // Do this last since it provides callbacks into application code
2391   mImpl->mControlInterface.TextChanged();
2392 }
2393
2394 bool Controller::RemoveText( int cursorOffset,
2395                              int numberOfCharacters,
2396                              UpdateInputStyleType type )
2397 {
2398   bool removed = false;
2399
2400   if( NULL == mImpl->mEventData )
2401   {
2402     return removed;
2403   }
2404
2405   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p mText.Count() %d cursor %d cursorOffset %d numberOfCharacters %d\n",
2406                  this, mImpl->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition, cursorOffset, numberOfCharacters );
2407
2408   if( !mImpl->IsShowingPlaceholderText() )
2409   {
2410     // Delete at current cursor position
2411     Vector<Character>& currentText = mImpl->mLogicalModel->mText;
2412     CharacterIndex& oldCursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
2413
2414     CharacterIndex cursorIndex = oldCursorIndex;
2415
2416     // Validate the cursor position & number of characters
2417     if( static_cast< CharacterIndex >( std::abs( cursorOffset ) ) <= cursorIndex )
2418     {
2419       cursorIndex = oldCursorIndex + cursorOffset;
2420     }
2421
2422     if( ( cursorIndex + numberOfCharacters ) > currentText.Count() )
2423     {
2424       numberOfCharacters = currentText.Count() - cursorIndex;
2425     }
2426
2427     if( ( cursorIndex + numberOfCharacters ) <= mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters )
2428     {
2429       // Mark the paragraphs to be updated.
2430       mImpl->mTextUpdateInfo.mCharacterIndex = std::min( cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex );
2431       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove += numberOfCharacters;
2432
2433       // Update the input style and remove the text's style before removing the text.
2434
2435       if( UPDATE_INPUT_STYLE == type )
2436       {
2437         // Keep a copy of the current input style.
2438         InputStyle currentInputStyle;
2439         currentInputStyle.Copy( mImpl->mEventData->mInputStyle );
2440
2441         // Set first the default input style.
2442         mImpl->RetrieveDefaultInputStyle( mImpl->mEventData->mInputStyle );
2443
2444         // Update the input style.
2445         mImpl->mLogicalModel->RetrieveStyle( cursorIndex, mImpl->mEventData->mInputStyle );
2446
2447         // Compare if the input style has changed.
2448         const bool hasInputStyleChanged = !currentInputStyle.Equal( mImpl->mEventData->mInputStyle );
2449
2450         if( hasInputStyleChanged )
2451         {
2452           const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask( mImpl->mEventData->mInputStyle );
2453           // Queue the input style changed signal.
2454           mImpl->mEventData->mInputStyleChangedQueue.PushBack( styleChangedMask );
2455         }
2456       }
2457
2458       // Updates the text style runs by removing characters. Runs with no characters are removed.
2459       mImpl->mLogicalModel->UpdateTextStyleRuns( cursorIndex, -numberOfCharacters );
2460
2461       // Remove the characters.
2462       Vector<Character>::Iterator first = currentText.Begin() + cursorIndex;
2463       Vector<Character>::Iterator last  = first + numberOfCharacters;
2464
2465       currentText.Erase( first, last );
2466
2467       // Cursor position retreat
2468       oldCursorIndex = cursorIndex;
2469
2470       mImpl->mEventData->mScrollAfterDelete = true;
2471
2472       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p removed %d\n", this, numberOfCharacters );
2473       removed = true;
2474     }
2475   }
2476
2477   return removed;
2478 }
2479
2480 bool Controller::RemoveSelectedText()
2481 {
2482   bool textRemoved( false );
2483
2484   if( EventData::SELECTING == mImpl->mEventData->mState )
2485   {
2486     std::string removedString;
2487     mImpl->RetrieveSelection( removedString, true );
2488
2489     if( !removedString.empty() )
2490     {
2491       textRemoved = true;
2492       mImpl->ChangeState( EventData::EDITING );
2493     }
2494   }
2495
2496   return textRemoved;
2497 }
2498
2499 // private : Relayout.
2500
2501 bool Controller::DoRelayout( const Size& size,
2502                              OperationsMask operationsRequired,
2503                              Size& layoutSize )
2504 {
2505   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::DoRelayout %p size %f,%f\n", this, size.width, size.height );
2506   bool viewUpdated( false );
2507
2508   // Calculate the operations to be done.
2509   const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
2510
2511   const CharacterIndex startIndex = mImpl->mTextUpdateInfo.mParagraphCharacterIndex;
2512   const Length requestedNumberOfCharacters = mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters;
2513
2514   // Get the current layout size.
2515   layoutSize = mImpl->mVisualModel->GetLayoutSize();
2516
2517   if( NO_OPERATION != ( LAYOUT & operations ) )
2518   {
2519     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::DoRelayout LAYOUT & operations\n");
2520
2521     // Some vectors with data needed to layout and reorder may be void
2522     // after the first time the text has been laid out.
2523     // Fill the vectors again.
2524
2525     // Calculate the number of glyphs to layout.
2526     const Vector<GlyphIndex>& charactersToGlyph = mImpl->mVisualModel->mCharactersToGlyph;
2527     const Vector<Length>& glyphsPerCharacter = mImpl->mVisualModel->mGlyphsPerCharacter;
2528     const GlyphIndex* const charactersToGlyphBuffer = charactersToGlyph.Begin();
2529     const Length* const glyphsPerCharacterBuffer = glyphsPerCharacter.Begin();
2530
2531     const CharacterIndex lastIndex = startIndex + ( ( requestedNumberOfCharacters > 0u ) ? requestedNumberOfCharacters - 1u : 0u );
2532     const GlyphIndex startGlyphIndex = mImpl->mTextUpdateInfo.mStartGlyphIndex;
2533     const Length numberOfGlyphs = ( requestedNumberOfCharacters > 0u ) ? *( charactersToGlyphBuffer + lastIndex ) + *( glyphsPerCharacterBuffer + lastIndex ) - startGlyphIndex : 0u;
2534     const Length totalNumberOfGlyphs = mImpl->mVisualModel->mGlyphs.Count();
2535
2536     if( 0u == totalNumberOfGlyphs )
2537     {
2538       if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) )
2539       {
2540         mImpl->mVisualModel->SetLayoutSize( Size::ZERO );
2541       }
2542
2543       // Nothing else to do if there is no glyphs.
2544       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout no glyphs, view updated true\n" );
2545       return true;
2546     }
2547
2548     const Vector<LineBreakInfo>& lineBreakInfo = mImpl->mLogicalModel->mLineBreakInfo;
2549     const Vector<WordBreakInfo>& wordBreakInfo = mImpl->mLogicalModel->mWordBreakInfo;
2550     const Vector<CharacterDirection>& characterDirection = mImpl->mLogicalModel->mCharacterDirections;
2551     const Vector<GlyphInfo>& glyphs = mImpl->mVisualModel->mGlyphs;
2552     const Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mVisualModel->mGlyphsToCharacters;
2553     const Vector<Length>& charactersPerGlyph = mImpl->mVisualModel->mCharactersPerGlyph;
2554     const Character* const textBuffer = mImpl->mLogicalModel->mText.Begin();
2555
2556     // Set the layout parameters.
2557     LayoutParameters layoutParameters( size,
2558                                        textBuffer,
2559                                        lineBreakInfo.Begin(),
2560                                        wordBreakInfo.Begin(),
2561                                        ( 0u != characterDirection.Count() ) ? characterDirection.Begin() : NULL,
2562                                        glyphs.Begin(),
2563                                        glyphsToCharactersMap.Begin(),
2564                                        charactersPerGlyph.Begin(),
2565                                        charactersToGlyphBuffer,
2566                                        glyphsPerCharacterBuffer,
2567                                        totalNumberOfGlyphs );
2568
2569     // Resize the vector of positions to have the same size than the vector of glyphs.
2570     Vector<Vector2>& glyphPositions = mImpl->mVisualModel->mGlyphPositions;
2571     glyphPositions.Resize( totalNumberOfGlyphs );
2572
2573     // Whether the last character is a new paragraph character.
2574     mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph =  TextAbstraction::IsNewParagraph( *( textBuffer + ( mImpl->mLogicalModel->mText.Count() - 1u ) ) );
2575     layoutParameters.isLastNewParagraph = mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph;
2576
2577     // The initial glyph and the number of glyphs to layout.
2578     layoutParameters.startGlyphIndex = startGlyphIndex;
2579     layoutParameters.numberOfGlyphs = numberOfGlyphs;
2580     layoutParameters.startLineIndex = mImpl->mTextUpdateInfo.mStartLineIndex;
2581     layoutParameters.estimatedNumberOfLines = mImpl->mTextUpdateInfo.mEstimatedNumberOfLines;
2582
2583     // Update the visual model.
2584     Size newLayoutSize;
2585     viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
2586                                                    glyphPositions,
2587                                                    mImpl->mVisualModel->mLines,
2588                                                    newLayoutSize );
2589
2590     viewUpdated = viewUpdated || ( newLayoutSize != layoutSize );
2591
2592     if( viewUpdated )
2593     {
2594       layoutSize = newLayoutSize;
2595
2596       if ( NO_OPERATION != ( UPDATE_DIRECTION & operations ) )
2597       {
2598         mImpl->mAutoScrollDirectionRTL = false;
2599       }
2600
2601       // Reorder the lines
2602       if( NO_OPERATION != ( REORDER & operations ) )
2603       {
2604         Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mImpl->mLogicalModel->mBidirectionalParagraphInfo;
2605         Vector<BidirectionalLineInfoRun>& bidirectionalLineInfo = mImpl->mLogicalModel->mBidirectionalLineInfo;
2606
2607         // Check first if there are paragraphs with bidirectional info.
2608         if( 0u != bidirectionalInfo.Count() )
2609         {
2610           // Get the lines
2611           const Length numberOfLines = mImpl->mVisualModel->mLines.Count();
2612
2613           // Reorder the lines.
2614           bidirectionalLineInfo.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
2615           ReorderLines( bidirectionalInfo,
2616                         startIndex,
2617                         requestedNumberOfCharacters,
2618                         mImpl->mVisualModel->mLines,
2619                         bidirectionalLineInfo );
2620
2621           // Set the bidirectional info per line into the layout parameters.
2622           layoutParameters.lineBidirectionalInfoRunsBuffer = bidirectionalLineInfo.Begin();
2623           layoutParameters.numberOfBidirectionalInfoRuns = bidirectionalLineInfo.Count();
2624
2625           // Re-layout the text. Reorder those lines with right to left characters.
2626           mImpl->mLayoutEngine.ReLayoutRightToLeftLines( layoutParameters,
2627                                                          startIndex,
2628                                                          requestedNumberOfCharacters,
2629                                                          glyphPositions );
2630
2631           if ( ( NO_OPERATION != ( UPDATE_DIRECTION & operations ) ) && ( numberOfLines > 0 ) )
2632           {
2633             const LineRun* const firstline = mImpl->mVisualModel->mLines.Begin();
2634             if ( firstline )
2635             {
2636               mImpl->mAutoScrollDirectionRTL = firstline->direction;
2637             }
2638           }
2639         }
2640       } // REORDER
2641
2642       // Sets the layout size.
2643       if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) )
2644       {
2645         mImpl->mVisualModel->SetLayoutSize( layoutSize );
2646       }
2647     } // view updated
2648
2649     // Store the size used to layout the text.
2650     mImpl->mVisualModel->mControlSize = size;
2651   }
2652
2653   if( NO_OPERATION != ( ALIGN & operations ) )
2654   {
2655     // The laid-out lines.
2656     Vector<LineRun>& lines = mImpl->mVisualModel->mLines;
2657
2658     mImpl->mLayoutEngine.Align( size,
2659                                 startIndex,
2660                                 requestedNumberOfCharacters,
2661                                 lines );
2662
2663     viewUpdated = true;
2664   }
2665 #if defined(DEBUG_ENABLED)
2666   std::string currentText;
2667   GetText( currentText );
2668   DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::DoRelayout [%p] mImpl->mAutoScrollDirectionRTL[%s] [%s]\n", this, (mImpl->mAutoScrollDirectionRTL)?"true":"false",  currentText.c_str() );
2669 #endif
2670   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout, view updated %s\n", ( viewUpdated ? "true" : "false" ) );
2671   return viewUpdated;
2672 }
2673
2674 void Controller::CalculateVerticalOffset( const Size& controlSize )
2675 {
2676   Size layoutSize = mImpl->mVisualModel->GetLayoutSize();
2677
2678   if( fabsf( layoutSize.height ) < Math::MACHINE_EPSILON_1000 )
2679   {
2680     // Get the line height of the default font.
2681     layoutSize.height = mImpl->GetDefaultFontLineHeight();
2682   }
2683
2684   switch( mImpl->mLayoutEngine.GetVerticalAlignment() )
2685   {
2686     case LayoutEngine::VERTICAL_ALIGN_TOP:
2687     {
2688       mImpl->mScrollPosition.y = 0.f;
2689       break;
2690     }
2691     case LayoutEngine::VERTICAL_ALIGN_CENTER:
2692     {
2693       mImpl->mScrollPosition.y = floorf( 0.5f * ( controlSize.height - layoutSize.height ) ); // try to avoid pixel alignment.
2694       break;
2695     }
2696     case LayoutEngine::VERTICAL_ALIGN_BOTTOM:
2697     {
2698       mImpl->mScrollPosition.y = controlSize.height - layoutSize.height;
2699       break;
2700     }
2701   }
2702 }
2703
2704 // private : Events.
2705
2706 void Controller::ProcessModifyEvents()
2707 {
2708   Vector<ModifyEvent>& events = mImpl->mModifyEvents;
2709
2710   if( 0u == events.Count() )
2711   {
2712     // Nothing to do.
2713     return;
2714   }
2715
2716   for( Vector<ModifyEvent>::ConstIterator it = events.Begin(),
2717          endIt = events.End();
2718        it != endIt;
2719        ++it )
2720   {
2721     const ModifyEvent& event = *it;
2722
2723     if( ModifyEvent::TEXT_REPLACED == event.type )
2724     {
2725       // A (single) replace event should come first, otherwise we wasted time processing NOOP events
2726       DALI_ASSERT_DEBUG( it == events.Begin() && "Unexpected TEXT_REPLACED event" );
2727
2728       TextReplacedEvent();
2729     }
2730     else if( ModifyEvent::TEXT_INSERTED == event.type )
2731     {
2732       TextInsertedEvent();
2733     }
2734     else if( ModifyEvent::TEXT_DELETED == event.type )
2735     {
2736       // Placeholder-text cannot be deleted
2737       if( !mImpl->IsShowingPlaceholderText() )
2738       {
2739         TextDeletedEvent();
2740       }
2741     }
2742   }
2743
2744   if( NULL != mImpl->mEventData )
2745   {
2746     // When the text is being modified, delay cursor blinking
2747     mImpl->mEventData->mDecorator->DelayCursorBlink();
2748   }
2749
2750   // Discard temporary text
2751   events.Clear();
2752 }
2753
2754 void Controller::TextReplacedEvent()
2755 {
2756   // The natural size needs to be re-calculated.
2757   mImpl->mRecalculateNaturalSize = true;
2758
2759   // Apply modifications to the model
2760   mImpl->mOperationsPending = ALL_OPERATIONS;
2761 }
2762
2763 void Controller::TextInsertedEvent()
2764 {
2765   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextInsertedEvent" );
2766
2767   if( NULL == mImpl->mEventData )
2768   {
2769     return;
2770   }
2771
2772   // The natural size needs to be re-calculated.
2773   mImpl->mRecalculateNaturalSize = true;
2774
2775   // Apply modifications to the model; TODO - Optimize this
2776   mImpl->mOperationsPending = ALL_OPERATIONS;
2777 }
2778
2779 void Controller::TextDeletedEvent()
2780 {
2781   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextDeletedEvent" );
2782
2783   if( NULL == mImpl->mEventData )
2784   {
2785     return;
2786   }
2787
2788   // The natural size needs to be re-calculated.
2789   mImpl->mRecalculateNaturalSize = true;
2790
2791   // Apply modifications to the model; TODO - Optimize this
2792   mImpl->mOperationsPending = ALL_OPERATIONS;
2793 }
2794
2795 void Controller::SelectEvent( float x, float y, bool selectAll )
2796 {
2797   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SelectEvent\n" );
2798
2799   if( NULL != mImpl->mEventData )
2800   {
2801     if( selectAll )
2802     {
2803       Event event( Event::SELECT_ALL );
2804       mImpl->mEventData->mEventQueue.push_back( event );
2805     }
2806     else
2807     {
2808       Event event( Event::SELECT );
2809       event.p2.mFloat = x;
2810       event.p3.mFloat = y;
2811       mImpl->mEventData->mEventQueue.push_back( event );
2812     }
2813
2814     mImpl->RequestRelayout();
2815   }
2816 }
2817
2818 bool Controller::BackspaceKeyEvent()
2819 {
2820   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p DALI_KEY_BACKSPACE\n", this );
2821
2822   bool removed = false;
2823
2824   if( NULL == mImpl->mEventData )
2825   {
2826     return removed;
2827   }
2828
2829   // IMF manager is no longer handling key-events
2830   mImpl->ClearPreEditFlag();
2831
2832   if( EventData::SELECTING == mImpl->mEventData->mState )
2833   {
2834     removed = RemoveSelectedText();
2835   }
2836   else if( mImpl->mEventData->mPrimaryCursorPosition > 0 )
2837   {
2838     // Remove the character before the current cursor position
2839     removed = RemoveText( -1,
2840                           1,
2841                           UPDATE_INPUT_STYLE );
2842   }
2843
2844   if( removed )
2845   {
2846     if( ( 0u != mImpl->mLogicalModel->mText.Count() ) ||
2847         !mImpl->IsPlaceholderAvailable() )
2848     {
2849       mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
2850     }
2851     else
2852     {
2853       ShowPlaceholderText();
2854     }
2855     mImpl->mEventData->mUpdateCursorPosition = true;
2856     mImpl->mEventData->mScrollAfterDelete = true;
2857   }
2858
2859   return removed;
2860 }
2861
2862 // private : Helpers.
2863
2864 void Controller::ResetText()
2865 {
2866   // Reset buffers.
2867   mImpl->mLogicalModel->mText.Clear();
2868
2869   // We have cleared everything including the placeholder-text
2870   mImpl->PlaceholderCleared();
2871
2872   mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
2873   mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
2874   mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = 0u;
2875
2876   // Clear any previous text.
2877   mImpl->mTextUpdateInfo.mClearAll = true;
2878
2879   // The natural size needs to be re-calculated.
2880   mImpl->mRecalculateNaturalSize = true;
2881
2882   // Apply modifications to the model
2883   mImpl->mOperationsPending = ALL_OPERATIONS;
2884 }
2885
2886 void Controller::ShowPlaceholderText()
2887 {
2888   if( mImpl->IsPlaceholderAvailable() )
2889   {
2890     DALI_ASSERT_DEBUG( mImpl->mEventData && "No placeholder text available" );
2891
2892     if( NULL == mImpl->mEventData )
2893     {
2894       return;
2895     }
2896
2897     mImpl->mEventData->mIsShowingPlaceholderText = true;
2898
2899     // Disable handles when showing place-holder text
2900     mImpl->mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
2901     mImpl->mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2902     mImpl->mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2903
2904     const char* text( NULL );
2905     size_t size( 0 );
2906
2907     // TODO - Switch placeholder text styles when changing state
2908     if( ( EventData::INACTIVE != mImpl->mEventData->mState ) &&
2909         ( 0u != mImpl->mEventData->mPlaceholderTextActive.c_str() ) )
2910     {
2911       text = mImpl->mEventData->mPlaceholderTextActive.c_str();
2912       size = mImpl->mEventData->mPlaceholderTextActive.size();
2913     }
2914     else
2915     {
2916       text = mImpl->mEventData->mPlaceholderTextInactive.c_str();
2917       size = mImpl->mEventData->mPlaceholderTextInactive.size();
2918     }
2919
2920     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
2921     mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
2922
2923     // Reset model for showing placeholder.
2924     mImpl->mLogicalModel->mText.Clear();
2925     mImpl->mVisualModel->SetTextColor( mImpl->mEventData->mPlaceholderTextColor );
2926
2927     // Convert text into UTF-32
2928     Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
2929     utf32Characters.Resize( size );
2930
2931     // This is a bit horrible but std::string returns a (signed) char*
2932     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text );
2933
2934     // Transform a text array encoded in utf8 into an array encoded in utf32.
2935     // It returns the actual number of characters.
2936     const Length characterCount = Utf8ToUtf32( utf8, size, utf32Characters.Begin() );
2937     utf32Characters.Resize( characterCount );
2938
2939     // The characters to be added.
2940     mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = characterCount;
2941
2942     // Reset the cursor position
2943     mImpl->mEventData->mPrimaryCursorPosition = 0;
2944
2945     // The natural size needs to be re-calculated.
2946     mImpl->mRecalculateNaturalSize = true;
2947
2948     // Apply modifications to the model
2949     mImpl->mOperationsPending = ALL_OPERATIONS;
2950
2951     // Update the rest of the model during size negotiation
2952     mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
2953   }
2954 }
2955
2956 void Controller::ClearFontData()
2957 {
2958   if( mImpl->mFontDefaults )
2959   {
2960     mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
2961   }
2962
2963   // Set flags to update the model.
2964   mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
2965   mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
2966   mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mLogicalModel->mText.Count();
2967
2968   mImpl->mTextUpdateInfo.mClearAll = true;
2969   mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
2970   mImpl->mRecalculateNaturalSize = true;
2971
2972   mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
2973                                                            VALIDATE_FONTS            |
2974                                                            SHAPE_TEXT                |
2975                                                            GET_GLYPH_METRICS         |
2976                                                            LAYOUT                    |
2977                                                            UPDATE_LAYOUT_SIZE        |
2978                                                            REORDER                   |
2979                                                            ALIGN );
2980 }
2981
2982 void Controller::ClearStyleData()
2983 {
2984   mImpl->mLogicalModel->mColorRuns.Clear();
2985   mImpl->mLogicalModel->ClearFontDescriptionRuns();
2986 }
2987
2988 void Controller::ResetCursorPosition( CharacterIndex cursorIndex )
2989 {
2990   // Reset the cursor position
2991   if( NULL != mImpl->mEventData )
2992   {
2993     mImpl->mEventData->mPrimaryCursorPosition = cursorIndex;
2994
2995     // Update the cursor if it's in editing mode.
2996     if( EventData::IsEditingState( mImpl->mEventData->mState )  )
2997     {
2998       mImpl->mEventData->mUpdateCursorPosition = true;
2999     }
3000   }
3001 }
3002
3003 void Controller::ResetScrollPosition()
3004 {
3005   if( NULL != mImpl->mEventData )
3006   {
3007     // Reset the scroll position.
3008     mImpl->mScrollPosition = Vector2::ZERO;
3009     mImpl->mEventData->mScrollAfterUpdatePosition = true;
3010   }
3011 }
3012
3013 // private : Private contructors & copy operator.
3014
3015 Controller::Controller( ControlInterface& controlInterface )
3016 : mImpl( NULL )
3017 {
3018   mImpl = new Controller::Impl( controlInterface );
3019 }
3020
3021 // The copy constructor and operator are left unimplemented.
3022
3023 // protected : Destructor.
3024
3025 Controller::~Controller()
3026 {
3027   delete mImpl;
3028 }
3029
3030 } // namespace Text
3031
3032 } // namespace Toolkit
3033
3034 } // namespace Dali