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