Calculate a new height when full relayout needed
[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                                                            mImpl->mTextUpdateInfo.mFullRelayoutNeeded )
1571   {
1572     // Operations that can be done only once until the text changes.
1573     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
1574                                                                            GET_SCRIPTS       |
1575                                                                            VALIDATE_FONTS    |
1576                                                                            GET_LINE_BREAKS   |
1577                                                                            GET_WORD_BREAKS   |
1578                                                                            BIDI_INFO         |
1579                                                                            SHAPE_TEXT        |
1580                                                                            GET_GLYPH_METRICS );
1581
1582     // Set the update info to relayout the whole text.
1583     mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
1584     mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
1585
1586     // Make sure the model is up-to-date before layouting
1587     mImpl->UpdateModel( onlyOnceOperations );
1588
1589
1590     // Layout the text for the new width.
1591     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | LAYOUT );
1592
1593     // Store the actual control's width.
1594     const float actualControlWidth = mImpl->mModel->mVisualModel->mControlSize.width;
1595
1596     DoRelayout( Size( width, MAX_FLOAT ),
1597                 static_cast<OperationsMask>( onlyOnceOperations |
1598                                              LAYOUT ),
1599                 layoutSize );
1600
1601     // Do not do again the only once operations.
1602     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
1603
1604     // Do the size related operations again.
1605     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
1606                                                                         ALIGN  |
1607                                                                         REORDER );
1608
1609     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
1610
1611     // Clear the update info. This info will be set the next time the text is updated.
1612     mImpl->mTextUpdateInfo.Clear();
1613
1614     // Restore the actual control's width.
1615     mImpl->mModel->mVisualModel->mControlSize.width = actualControlWidth;
1616
1617     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth calculated %f\n", layoutSize.height );
1618   }
1619   else
1620   {
1621     layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
1622     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth cached %f\n", layoutSize.height );
1623   }
1624
1625   return layoutSize.height;
1626 }
1627
1628 int Controller::GetLineCount( float width )
1629 {
1630   GetHeightForWidth( width );
1631   int numberofLines = mImpl->mModel->GetNumberOfLines();
1632   return numberofLines;
1633 }
1634
1635 const ModelInterface* const Controller::GetTextModel() const
1636 {
1637   return mImpl->mModel.Get();
1638 }
1639
1640 float Controller::GetScrollAmountByUserInput()
1641 {
1642   float scrollAmount = 0.0f;
1643
1644   if (NULL != mImpl->mEventData && mImpl->mEventData->mCheckScrollAmount)
1645   {
1646     scrollAmount = mImpl->mModel->mScrollPosition.y -  mImpl->mModel->mScrollPositionLast.y;
1647     mImpl->mEventData->mCheckScrollAmount = false;
1648   }
1649   return scrollAmount;
1650 }
1651
1652 bool Controller::GetTextScrollInfo( float& scrollPosition, float& controlHeight, float& layoutHeight )
1653 {
1654   const Vector2& layout = mImpl->mModel->mVisualModel->GetLayoutSize();
1655   bool isScrolled;
1656
1657   controlHeight = mImpl->mModel->mVisualModel->mControlSize.height;
1658   layoutHeight = layout.height;
1659   scrollPosition = mImpl->mModel->mScrollPosition.y;
1660   isScrolled = !Equals( mImpl->mModel->mScrollPosition.y, mImpl->mModel->mScrollPositionLast.y, Math::MACHINE_EPSILON_1 );
1661   return isScrolled;
1662 }
1663
1664 void Controller::SetHiddenInputOption(const Property::Map& options )
1665 {
1666   if( NULL == mImpl->mHiddenInput )
1667   {
1668     mImpl->mHiddenInput = new HiddenText( this );
1669   }
1670   mImpl->mHiddenInput->SetProperties(options);
1671 }
1672
1673 void Controller::GetHiddenInputOption(Property::Map& options )
1674 {
1675   if( NULL != mImpl->mHiddenInput )
1676   {
1677     mImpl->mHiddenInput->GetProperties(options);
1678   }
1679 }
1680
1681 // public : Relayout.
1682
1683 Controller::UpdateTextType Controller::Relayout( const Size& size )
1684 {
1685   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::Relayout %p size %f,%f, autoScroll[%s]\n", this, size.width, size.height, mImpl->mIsAutoScrollEnabled ?"true":"false"  );
1686
1687   UpdateTextType updateTextType = NONE_UPDATED;
1688
1689   if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
1690   {
1691     if( 0u != mImpl->mModel->mVisualModel->mGlyphPositions.Count() )
1692     {
1693       mImpl->mModel->mVisualModel->mGlyphPositions.Clear();
1694       updateTextType = MODEL_UPDATED;
1695     }
1696
1697     // Clear the update info. This info will be set the next time the text is updated.
1698     mImpl->mTextUpdateInfo.Clear();
1699
1700     // Not worth to relayout if width or height is equal to zero.
1701     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout (skipped)\n" );
1702
1703     return updateTextType;
1704   }
1705
1706   // Whether a new size has been set.
1707   const bool newSize = ( size != mImpl->mModel->mVisualModel->mControlSize );
1708
1709   if( newSize )
1710   {
1711     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "new size (previous size %f,%f)\n", mImpl->mModel->mVisualModel->mControlSize.width, mImpl->mModel->mVisualModel->mControlSize.height );
1712
1713     // Layout operations that need to be done if the size changes.
1714     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1715                                                              LAYOUT                    |
1716                                                              ALIGN                     |
1717                                                              UPDATE_LAYOUT_SIZE        |
1718                                                              REORDER );
1719     // Set the update info to relayout the whole text.
1720     mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
1721     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
1722
1723     // Store the size used to layout the text.
1724     mImpl->mModel->mVisualModel->mControlSize = size;
1725   }
1726
1727   // Whether there are modify events.
1728   if( 0u != mImpl->mModifyEvents.Count() )
1729   {
1730     // Style operations that need to be done if the text is modified.
1731     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1732                                                              COLOR );
1733   }
1734
1735   // Make sure the model is up-to-date before layouting.
1736   ProcessModifyEvents();
1737   bool updated = mImpl->UpdateModel( mImpl->mOperationsPending );
1738
1739   // Layout the text.
1740   Size layoutSize;
1741   updated = DoRelayout( size,
1742                         mImpl->mOperationsPending,
1743                         layoutSize ) || updated;
1744
1745   if( updated )
1746   {
1747     updateTextType = MODEL_UPDATED;
1748   }
1749
1750   // Do not re-do any operation until something changes.
1751   mImpl->mOperationsPending = NO_OPERATION;
1752   mImpl->mModel->mScrollPositionLast = mImpl->mModel->mScrollPosition;
1753
1754   // Whether the text control is editable
1755   const bool isEditable = NULL != mImpl->mEventData;
1756
1757   // Keep the current offset as it will be used to update the decorator's positions (if the size changes).
1758   Vector2 offset;
1759   if( newSize && isEditable )
1760   {
1761     offset = mImpl->mModel->mScrollPosition;
1762   }
1763
1764   if( !isEditable || !IsMultiLineEnabled() )
1765   {
1766     // After doing the text layout, the vertical offset to place the actor in the desired position can be calculated.
1767     CalculateVerticalOffset( size );
1768   }
1769
1770   if( isEditable )
1771   {
1772     if( newSize )
1773     {
1774       // If there is a new size, the scroll position needs to be clamped.
1775       mImpl->ClampHorizontalScroll( layoutSize );
1776
1777       // Update the decorator's positions is needed if there is a new size.
1778       mImpl->mEventData->mDecorator->UpdatePositions( mImpl->mModel->mScrollPosition - offset );
1779     }
1780
1781     // Move the cursor, grab handle etc.
1782     if( mImpl->ProcessInputEvents() )
1783     {
1784       updateTextType = static_cast<UpdateTextType>( updateTextType | DECORATOR_UPDATED );
1785     }
1786   }
1787
1788   // Clear the update info. This info will be set the next time the text is updated.
1789   mImpl->mTextUpdateInfo.Clear();
1790   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout\n" );
1791
1792   return updateTextType;
1793 }
1794
1795 void Controller::RequestRelayout()
1796 {
1797   mImpl->RequestRelayout();
1798 }
1799
1800 // public : Input style change signals.
1801
1802 bool Controller::IsInputStyleChangedSignalsQueueEmpty()
1803 {
1804   return ( NULL == mImpl->mEventData ) || ( 0u == mImpl->mEventData->mInputStyleChangedQueue.Count() );
1805 }
1806
1807 void Controller::ProcessInputStyleChangedSignals()
1808 {
1809   if( NULL == mImpl->mEventData )
1810   {
1811     // Nothing to do.
1812     return;
1813   }
1814
1815   for( Vector<InputStyle::Mask>::ConstIterator it = mImpl->mEventData->mInputStyleChangedQueue.Begin(),
1816          endIt = mImpl->mEventData->mInputStyleChangedQueue.End();
1817        it != endIt;
1818        ++it )
1819   {
1820     const InputStyle::Mask mask = *it;
1821
1822     if( NULL != mImpl->mEditableControlInterface )
1823     {
1824       // Emit the input style changed signal.
1825       mImpl->mEditableControlInterface->InputStyleChanged( mask );
1826     }
1827   }
1828
1829   mImpl->mEventData->mInputStyleChangedQueue.Clear();
1830 }
1831
1832 // public : Text-input Event Queuing.
1833
1834 void Controller::KeyboardFocusGainEvent()
1835 {
1836   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusGainEvent" );
1837
1838   if( NULL != mImpl->mEventData )
1839   {
1840     if( ( EventData::INACTIVE == mImpl->mEventData->mState ) ||
1841         ( EventData::INTERRUPTED == mImpl->mEventData->mState ) )
1842     {
1843       mImpl->ChangeState( EventData::EDITING );
1844       mImpl->mEventData->mUpdateCursorPosition = true; //If editing started without tap event, cursor update must be triggered.
1845       mImpl->mEventData->mUpdateInputStyle = true;
1846     }
1847     mImpl->NotifyImfMultiLineStatus();
1848     if( mImpl->IsShowingPlaceholderText() )
1849     {
1850       // Show alternative placeholder-text when editing
1851       ShowPlaceholderText();
1852     }
1853
1854     mImpl->RequestRelayout();
1855   }
1856 }
1857
1858 void Controller::KeyboardFocusLostEvent()
1859 {
1860   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusLostEvent" );
1861
1862   if( NULL != mImpl->mEventData )
1863   {
1864     if( EventData::INTERRUPTED != mImpl->mEventData->mState )
1865     {
1866       mImpl->ChangeState( EventData::INACTIVE );
1867
1868       if( !mImpl->IsShowingRealText() )
1869       {
1870         // Revert to regular placeholder-text when not editing
1871         ShowPlaceholderText();
1872       }
1873     }
1874   }
1875   mImpl->RequestRelayout();
1876 }
1877
1878 bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
1879 {
1880   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyEvent" );
1881
1882   bool textChanged = false;
1883   bool relayoutNeeded = false;
1884
1885   if( ( NULL != mImpl->mEventData ) &&
1886       ( keyEvent.state == KeyEvent::Down ) )
1887   {
1888     int keyCode = keyEvent.keyCode;
1889     const std::string& keyString = keyEvent.keyPressed;
1890
1891     const bool isNullKey = ( 0 == keyCode ) && ( keyString.empty() );
1892
1893     // Pre-process to separate modifying events from non-modifying input events.
1894     if( isNullKey )
1895     {
1896       // In some platforms arrive key events with no key code.
1897       // Do nothing.
1898     }
1899     else if( Dali::DALI_KEY_ESCAPE == keyCode )
1900     {
1901       // Escape key is a special case which causes focus loss
1902       KeyboardFocusLostEvent();
1903
1904       // Will request for relayout.
1905       relayoutNeeded = true;
1906     }
1907     else if( ( Dali::DALI_KEY_CURSOR_LEFT  == keyCode ) ||
1908              ( Dali::DALI_KEY_CURSOR_RIGHT == keyCode ) ||
1909              ( Dali::DALI_KEY_CURSOR_UP    == keyCode ) ||
1910              ( Dali::DALI_KEY_CURSOR_DOWN  == keyCode ) )
1911     {
1912       // If don't have any text, do nothing.
1913       if( !mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters )
1914       {
1915         return false;
1916       }
1917
1918       uint32_t cursorPosition = mImpl->mEventData->mPrimaryCursorPosition;
1919       uint32_t numberOfCharacters = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
1920       uint32_t cursorLine = mImpl->mModel->mVisualModel->GetLineOfCharacter( cursorPosition );
1921       uint32_t numberOfLines = mImpl->mModel->GetNumberOfLines();
1922
1923       // Logic to determine whether this text control will lose focus or not.
1924       if( ( Dali::DALI_KEY_CURSOR_LEFT == keyCode && 0 == cursorPosition ) ||
1925           ( Dali::DALI_KEY_CURSOR_RIGHT == keyCode && numberOfCharacters == cursorPosition) ||
1926           ( Dali::DALI_KEY_CURSOR_DOWN == keyCode && cursorLine == numberOfLines -1 ) ||
1927           ( Dali::DALI_KEY_CURSOR_DOWN == keyCode && numberOfCharacters == cursorPosition && cursorLine -1 == numberOfLines -1 ) ||
1928           ( Dali::DALI_KEY_CURSOR_UP == keyCode && cursorLine == 0 ) ||
1929           ( Dali::DALI_KEY_CURSOR_UP == keyCode && numberOfCharacters == cursorPosition && cursorLine == 1 ) )
1930       {
1931         return false;
1932       }
1933
1934       mImpl->mEventData->mCheckScrollAmount = true;
1935       Event event( Event::CURSOR_KEY_EVENT );
1936       event.p1.mInt = keyCode;
1937       mImpl->mEventData->mEventQueue.push_back( event );
1938
1939       // Will request for relayout.
1940       relayoutNeeded = true;
1941     }
1942     else if( Dali::DALI_KEY_BACKSPACE == keyCode )
1943     {
1944       textChanged = BackspaceKeyEvent();
1945
1946       // Will request for relayout.
1947       relayoutNeeded = true;
1948     }
1949     else if( IsKey( keyEvent, Dali::DALI_KEY_POWER ) ||
1950              IsKey( keyEvent, Dali::DALI_KEY_MENU ) ||
1951              IsKey( keyEvent, Dali::DALI_KEY_HOME ) )
1952     {
1953       // Power key/Menu/Home key behaviour does not allow edit mode to resume.
1954       mImpl->ChangeState( EventData::INACTIVE );
1955
1956       // Will request for relayout.
1957       relayoutNeeded = true;
1958
1959       // This branch avoids calling the InsertText() method of the 'else' branch which can delete selected text.
1960     }
1961     else if( Dali::DALI_KEY_SHIFT_LEFT == keyCode )
1962     {
1963       // DALI_KEY_SHIFT_LEFT is the key code for the Left Shift. It's sent (by the imf?) when the predictive text is enabled
1964       // and a character is typed after the type of a upper case latin character.
1965
1966       // Do nothing.
1967     }
1968     else if( ( Dali::DALI_KEY_VOLUME_UP == keyCode ) || ( Dali::DALI_KEY_VOLUME_DOWN == keyCode ) )
1969     {
1970       // This branch avoids calling the InsertText() method of the 'else' branch which can delete selected text.
1971       // Do nothing.
1972     }
1973     else
1974     {
1975       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p keyString %s\n", this, keyString.c_str() );
1976
1977       // IMF manager is no longer handling key-events
1978       mImpl->ClearPreEditFlag();
1979
1980       InsertText( keyString, COMMIT );
1981       textChanged = true;
1982
1983       // Will request for relayout.
1984       relayoutNeeded = true;
1985     }
1986
1987     if ( ( mImpl->mEventData->mState != EventData::INTERRUPTED ) &&
1988          ( mImpl->mEventData->mState != EventData::INACTIVE ) &&
1989          ( !isNullKey ) &&
1990          ( Dali::DALI_KEY_SHIFT_LEFT != keyCode ) &&
1991          ( Dali::DALI_KEY_VOLUME_UP != keyCode ) &&
1992          ( Dali::DALI_KEY_VOLUME_DOWN != keyCode ) )
1993     {
1994       // Should not change the state if the key is the shift send by the imf manager.
1995       // Otherwise, when the state is SELECTING the text controller can't send the right
1996       // surrounding info to the imf.
1997       mImpl->ChangeState( EventData::EDITING );
1998
1999       // Will request for relayout.
2000       relayoutNeeded = true;
2001     }
2002
2003     if( relayoutNeeded )
2004     {
2005       mImpl->RequestRelayout();
2006     }
2007   }
2008
2009   if( textChanged &&
2010       ( NULL != mImpl->mEditableControlInterface ) )
2011   {
2012     // Do this last since it provides callbacks into application code
2013     mImpl->mEditableControlInterface->TextChanged();
2014   }
2015
2016   return true;
2017 }
2018
2019 void Controller::TapEvent( unsigned int tapCount, float x, float y )
2020 {
2021   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected TapEvent" );
2022
2023   if( NULL != mImpl->mEventData )
2024   {
2025     DALI_LOG_INFO( gLogFilter, Debug::Concise, "TapEvent state:%d \n", mImpl->mEventData->mState );
2026     EventData::State state( mImpl->mEventData->mState );
2027     bool relayoutNeeded( false );   // to avoid unnecessary relayouts when tapping an empty text-field
2028
2029     if( mImpl->IsClipboardVisible() )
2030     {
2031       if( EventData::INACTIVE == state || EventData::EDITING == state)
2032       {
2033         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );
2034       }
2035       relayoutNeeded = true;
2036     }
2037     else if( 1u == tapCount )
2038     {
2039       if( EventData::EDITING_WITH_POPUP == state || EventData::EDITING_WITH_PASTE_POPUP == state )
2040       {
2041         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );  // If Popup shown hide it here so can be shown again if required.
2042       }
2043
2044       if( mImpl->IsShowingRealText() && ( EventData::INACTIVE != state ) )
2045       {
2046         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );
2047         relayoutNeeded = true;
2048       }
2049       else
2050       {
2051         if( mImpl->IsShowingPlaceholderText() && !mImpl->IsFocusedPlaceholderAvailable() )
2052         {
2053           // Hide placeholder text
2054           ResetText();
2055         }
2056
2057         if( EventData::INACTIVE == state )
2058         {
2059           mImpl->ChangeState( EventData::EDITING );
2060         }
2061         else if( !mImpl->IsClipboardEmpty() )
2062         {
2063           mImpl->ChangeState( EventData::EDITING_WITH_POPUP );
2064         }
2065         relayoutNeeded = true;
2066       }
2067     }
2068     else if( 2u == tapCount )
2069     {
2070       if( mImpl->mEventData->mSelectionEnabled &&
2071           mImpl->IsShowingRealText() )
2072       {
2073         relayoutNeeded = true;
2074         mImpl->mEventData->mIsLeftHandleSelected = true;
2075         mImpl->mEventData->mIsRightHandleSelected = true;
2076       }
2077     }
2078
2079     // Handles & cursors must be repositioned after Relayout() i.e. after the Model has been updated
2080     if( relayoutNeeded )
2081     {
2082       Event event( Event::TAP_EVENT );
2083       event.p1.mUint = tapCount;
2084       event.p2.mFloat = x;
2085       event.p3.mFloat = y;
2086       mImpl->mEventData->mEventQueue.push_back( event );
2087
2088       mImpl->RequestRelayout();
2089     }
2090   }
2091
2092   // Reset keyboard as tap event has occurred.
2093   mImpl->ResetImfManager();
2094 }
2095
2096 void Controller::PanEvent( Gesture::State state, const Vector2& displacement )
2097 {
2098   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected PanEvent" );
2099
2100   if( NULL != mImpl->mEventData )
2101   {
2102     Event event( Event::PAN_EVENT );
2103     event.p1.mInt = state;
2104     event.p2.mFloat = displacement.x;
2105     event.p3.mFloat = displacement.y;
2106     mImpl->mEventData->mEventQueue.push_back( event );
2107
2108     mImpl->RequestRelayout();
2109   }
2110 }
2111
2112 void Controller::LongPressEvent( Gesture::State state, float x, float y  )
2113 {
2114   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected LongPressEvent" );
2115
2116   if( ( state == Gesture::Started ) &&
2117       ( NULL != mImpl->mEventData ) )
2118   {
2119     // The 1st long-press on inactive text-field is treated as tap
2120     if( EventData::INACTIVE == mImpl->mEventData->mState )
2121     {
2122       mImpl->ChangeState( EventData::EDITING );
2123
2124       Event event( Event::TAP_EVENT );
2125       event.p1.mUint = 1;
2126       event.p2.mFloat = x;
2127       event.p3.mFloat = y;
2128       mImpl->mEventData->mEventQueue.push_back( event );
2129
2130       mImpl->RequestRelayout();
2131     }
2132     else if( !mImpl->IsShowingRealText() )
2133     {
2134       Event event( Event::LONG_PRESS_EVENT );
2135       event.p1.mInt = state;
2136       event.p2.mFloat = x;
2137       event.p3.mFloat = y;
2138       mImpl->mEventData->mEventQueue.push_back( event );
2139       mImpl->RequestRelayout();
2140     }
2141     else if( !mImpl->IsClipboardVisible() )
2142     {
2143       // Reset the imf manager to commit the pre-edit before selecting the text.
2144       mImpl->ResetImfManager();
2145
2146       Event event( Event::LONG_PRESS_EVENT );
2147       event.p1.mInt = state;
2148       event.p2.mFloat = x;
2149       event.p3.mFloat = y;
2150       mImpl->mEventData->mEventQueue.push_back( event );
2151       mImpl->RequestRelayout();
2152
2153       mImpl->mEventData->mIsLeftHandleSelected = true;
2154       mImpl->mEventData->mIsRightHandleSelected = true;
2155     }
2156   }
2157 }
2158
2159 ImfManager::ImfCallbackData Controller::OnImfEvent( ImfManager& imfManager, const ImfManager::ImfEventData& imfEvent )
2160 {
2161   // Whether the text needs to be relaid-out.
2162   bool requestRelayout = false;
2163
2164   // Whether to retrieve the text and cursor position to be sent to the IMF manager.
2165   bool retrieveText = false;
2166   bool retrieveCursor = false;
2167
2168   switch( imfEvent.eventName )
2169   {
2170     case ImfManager::COMMIT:
2171     {
2172       InsertText( imfEvent.predictiveString, Text::Controller::COMMIT );
2173       requestRelayout = true;
2174       retrieveCursor = true;
2175       break;
2176     }
2177     case ImfManager::PREEDIT:
2178     {
2179       InsertText( imfEvent.predictiveString, Text::Controller::PRE_EDIT );
2180       requestRelayout = true;
2181       retrieveCursor = true;
2182       break;
2183     }
2184     case ImfManager::DELETESURROUNDING:
2185     {
2186       const bool textDeleted = RemoveText( imfEvent.cursorOffset,
2187                                            imfEvent.numberOfChars,
2188                                            DONT_UPDATE_INPUT_STYLE );
2189
2190       if( textDeleted )
2191       {
2192         if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) ||
2193             !mImpl->IsPlaceholderAvailable() )
2194         {
2195           mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
2196         }
2197         else
2198         {
2199           ShowPlaceholderText();
2200         }
2201         mImpl->mEventData->mUpdateCursorPosition = true;
2202         mImpl->mEventData->mScrollAfterDelete = true;
2203
2204         requestRelayout = true;
2205       }
2206       break;
2207     }
2208     case ImfManager::GETSURROUNDING:
2209     {
2210       retrieveText = true;
2211       retrieveCursor = true;
2212       break;
2213     }
2214     case ImfManager::PRIVATECOMMAND:
2215     {
2216       // PRIVATECOMMAND event is just for getting the private command message
2217       retrieveText = true;
2218       retrieveCursor = true;
2219       break;
2220     }
2221     case ImfManager::VOID:
2222     {
2223       // do nothing
2224       break;
2225     }
2226   } // end switch
2227
2228   if( requestRelayout )
2229   {
2230     mImpl->mOperationsPending = ALL_OPERATIONS;
2231     mImpl->RequestRelayout();
2232   }
2233
2234   std::string text;
2235   CharacterIndex cursorPosition = 0u;
2236   Length numberOfWhiteSpaces = 0u;
2237
2238   if( retrieveCursor )
2239   {
2240     numberOfWhiteSpaces = mImpl->GetNumberOfWhiteSpaces( 0u );
2241
2242     cursorPosition = mImpl->GetLogicalCursorPosition();
2243
2244     if( cursorPosition < numberOfWhiteSpaces )
2245     {
2246       cursorPosition = 0u;
2247     }
2248     else
2249     {
2250       cursorPosition -= numberOfWhiteSpaces;
2251     }
2252   }
2253
2254   if( retrieveText )
2255   {
2256     mImpl->GetText( numberOfWhiteSpaces, text );
2257   }
2258
2259   ImfManager::ImfCallbackData callbackData( ( retrieveText || retrieveCursor ), cursorPosition, text, false );
2260
2261   if( requestRelayout &&
2262       ( NULL != mImpl->mEditableControlInterface ) )
2263   {
2264     // Do this last since it provides callbacks into application code
2265     mImpl->mEditableControlInterface->TextChanged();
2266   }
2267
2268   return callbackData;
2269 }
2270
2271 void Controller::PasteClipboardItemEvent()
2272 {
2273   // Retrieve the clipboard contents first
2274   ClipboardEventNotifier notifier( ClipboardEventNotifier::Get() );
2275   std::string stringToPaste( notifier.GetContent() );
2276
2277   // Commit the current pre-edit text; the contents of the clipboard should be appended
2278   mImpl->ResetImfManager();
2279
2280   // Temporary disable hiding clipboard
2281   mImpl->SetClipboardHideEnable( false );
2282
2283   // Paste
2284   PasteText( stringToPaste );
2285
2286   mImpl->SetClipboardHideEnable( true );
2287 }
2288
2289 // protected : Inherit from Text::Decorator::ControllerInterface.
2290
2291 void Controller::GetTargetSize( Vector2& targetSize )
2292 {
2293   targetSize = mImpl->mModel->mVisualModel->mControlSize;
2294 }
2295
2296 void Controller::AddDecoration( Actor& actor, bool needsClipping )
2297 {
2298   if( NULL != mImpl->mEditableControlInterface )
2299   {
2300     mImpl->mEditableControlInterface->AddDecoration( actor, needsClipping );
2301   }
2302 }
2303
2304 void Controller::DecorationEvent( HandleType handleType, HandleState state, float x, float y )
2305 {
2306   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected DecorationEvent" );
2307
2308   if( NULL != mImpl->mEventData )
2309   {
2310     switch( handleType )
2311     {
2312       case GRAB_HANDLE:
2313       {
2314         Event event( Event::GRAB_HANDLE_EVENT );
2315         event.p1.mUint  = state;
2316         event.p2.mFloat = x;
2317         event.p3.mFloat = y;
2318
2319         mImpl->mEventData->mEventQueue.push_back( event );
2320         break;
2321       }
2322       case LEFT_SELECTION_HANDLE:
2323       {
2324         Event event( Event::LEFT_SELECTION_HANDLE_EVENT );
2325         event.p1.mUint  = state;
2326         event.p2.mFloat = x;
2327         event.p3.mFloat = y;
2328
2329         mImpl->mEventData->mEventQueue.push_back( event );
2330         break;
2331       }
2332       case RIGHT_SELECTION_HANDLE:
2333       {
2334         Event event( Event::RIGHT_SELECTION_HANDLE_EVENT );
2335         event.p1.mUint  = state;
2336         event.p2.mFloat = x;
2337         event.p3.mFloat = y;
2338
2339         mImpl->mEventData->mEventQueue.push_back( event );
2340         break;
2341       }
2342       case LEFT_SELECTION_HANDLE_MARKER:
2343       case RIGHT_SELECTION_HANDLE_MARKER:
2344       {
2345         // Markers do not move the handles.
2346         break;
2347       }
2348       case HANDLE_TYPE_COUNT:
2349       {
2350         DALI_ASSERT_DEBUG( !"Controller::HandleEvent. Unexpected handle type" );
2351       }
2352     }
2353
2354     mImpl->RequestRelayout();
2355   }
2356 }
2357
2358 // protected : Inherit from TextSelectionPopup::TextPopupButtonCallbackInterface.
2359
2360 void Controller::TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::Buttons button )
2361 {
2362   if( NULL == mImpl->mEventData )
2363   {
2364     return;
2365   }
2366
2367   switch( button )
2368   {
2369     case Toolkit::TextSelectionPopup::CUT:
2370     {
2371       mImpl->SendSelectionToClipboard( true ); // Synchronous call to modify text
2372       mImpl->mOperationsPending = ALL_OPERATIONS;
2373
2374       if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) ||
2375           !mImpl->IsPlaceholderAvailable() )
2376       {
2377         mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
2378       }
2379       else
2380       {
2381         ShowPlaceholderText();
2382       }
2383
2384       mImpl->mEventData->mUpdateCursorPosition = true;
2385       mImpl->mEventData->mScrollAfterDelete = true;
2386
2387       mImpl->RequestRelayout();
2388
2389       if( NULL != mImpl->mEditableControlInterface )
2390       {
2391         mImpl->mEditableControlInterface->TextChanged();
2392       }
2393       break;
2394     }
2395     case Toolkit::TextSelectionPopup::COPY:
2396     {
2397       mImpl->SendSelectionToClipboard( false ); // Text not modified
2398
2399       mImpl->mEventData->mUpdateCursorPosition = true;
2400
2401       mImpl->RequestRelayout(); // Cursor, Handles, Selection Highlight, Popup
2402       break;
2403     }
2404     case Toolkit::TextSelectionPopup::PASTE:
2405     {
2406       mImpl->RequestGetTextFromClipboard(); // Request clipboard service to retrieve an item
2407       break;
2408     }
2409     case Toolkit::TextSelectionPopup::SELECT:
2410     {
2411       const Vector2& currentCursorPosition = mImpl->mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
2412
2413       if( mImpl->mEventData->mSelectionEnabled )
2414       {
2415         // Creates a SELECT event.
2416         SelectEvent( currentCursorPosition.x, currentCursorPosition.y, false );
2417       }
2418       break;
2419     }
2420     case Toolkit::TextSelectionPopup::SELECT_ALL:
2421     {
2422       // Creates a SELECT_ALL event
2423       SelectEvent( 0.f, 0.f, true );
2424       break;
2425     }
2426     case Toolkit::TextSelectionPopup::CLIPBOARD:
2427     {
2428       mImpl->ShowClipboard();
2429       break;
2430     }
2431     case Toolkit::TextSelectionPopup::NONE:
2432     {
2433       // Nothing to do.
2434       break;
2435     }
2436   }
2437 }
2438
2439 void Controller::DisplayTimeExpired()
2440 {
2441   mImpl->mEventData->mUpdateCursorPosition = true;
2442   // Apply modifications to the model
2443   mImpl->mOperationsPending = ALL_OPERATIONS;
2444
2445   mImpl->RequestRelayout();
2446 }
2447
2448 // private : Update.
2449
2450 void Controller::InsertText( const std::string& text, Controller::InsertType type )
2451 {
2452   bool removedPrevious = false;
2453   bool removedSelected = false;
2454   bool maxLengthReached = false;
2455
2456   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected InsertText" )
2457
2458   if( NULL == mImpl->mEventData )
2459   {
2460     return;
2461   }
2462
2463   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::InsertText %p %s (%s) mPrimaryCursorPosition %d mPreEditFlag %d mPreEditStartPosition %d mPreEditLength %d\n",
2464                  this, text.c_str(), (COMMIT == type ? "COMMIT" : "PRE_EDIT"),
2465                  mImpl->mEventData->mPrimaryCursorPosition, mImpl->mEventData->mPreEditFlag, mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
2466
2467   // TODO: At the moment the underline runs are only for pre-edit.
2468   mImpl->mModel->mVisualModel->mUnderlineRuns.Clear();
2469
2470   // Remove the previous IMF pre-edit.
2471   if( mImpl->mEventData->mPreEditFlag && ( 0u != mImpl->mEventData->mPreEditLength ) )
2472   {
2473     removedPrevious = RemoveText( -static_cast<int>( mImpl->mEventData->mPrimaryCursorPosition - mImpl->mEventData->mPreEditStartPosition ),
2474                                   mImpl->mEventData->mPreEditLength,
2475                                   DONT_UPDATE_INPUT_STYLE );
2476
2477     mImpl->mEventData->mPrimaryCursorPosition = mImpl->mEventData->mPreEditStartPosition;
2478     mImpl->mEventData->mPreEditLength = 0u;
2479   }
2480   else
2481   {
2482     // Remove the previous Selection.
2483     removedSelected = RemoveSelectedText();
2484
2485   }
2486
2487   Vector<Character> utf32Characters;
2488   Length characterCount = 0u;
2489
2490   if( !text.empty() )
2491   {
2492     //  Convert text into UTF-32
2493     utf32Characters.Resize( text.size() );
2494
2495     // This is a bit horrible but std::string returns a (signed) char*
2496     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
2497
2498     // Transform a text array encoded in utf8 into an array encoded in utf32.
2499     // It returns the actual number of characters.
2500     characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
2501     utf32Characters.Resize( characterCount );
2502
2503     DALI_ASSERT_DEBUG( text.size() >= utf32Characters.Count() && "Invalid UTF32 conversion length" );
2504     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "UTF8 size %d, UTF32 size %d\n", text.size(), utf32Characters.Count() );
2505   }
2506
2507   if( 0u != utf32Characters.Count() ) // Check if Utf8ToUtf32 conversion succeeded
2508   {
2509     // The placeholder text is no longer needed
2510     if( mImpl->IsShowingPlaceholderText() )
2511     {
2512       ResetText();
2513     }
2514
2515     mImpl->ChangeState( EventData::EDITING );
2516
2517     // Handle the IMF (predicitive text) state changes
2518     if( COMMIT == type )
2519     {
2520       // IMF manager is no longer handling key-events
2521       mImpl->ClearPreEditFlag();
2522     }
2523     else // PRE_EDIT
2524     {
2525       if( !mImpl->mEventData->mPreEditFlag )
2526       {
2527         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Entered PreEdit state\n" );
2528
2529         // Record the start of the pre-edit text
2530         mImpl->mEventData->mPreEditStartPosition = mImpl->mEventData->mPrimaryCursorPosition;
2531       }
2532
2533       mImpl->mEventData->mPreEditLength = utf32Characters.Count();
2534       mImpl->mEventData->mPreEditFlag = true;
2535
2536       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "mPreEditStartPosition %d mPreEditLength %d\n", mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
2537     }
2538
2539     const Length numberOfCharactersInModel = mImpl->mModel->mLogicalModel->mText.Count();
2540
2541     // Restrict new text to fit within Maximum characters setting.
2542     Length maxSizeOfNewText = std::min( ( mImpl->mMaximumNumberOfCharacters - numberOfCharactersInModel ), characterCount );
2543     maxLengthReached = ( characterCount > maxSizeOfNewText );
2544
2545     // The cursor position.
2546     CharacterIndex& cursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
2547
2548     // Update the text's style.
2549
2550     // Updates the text style runs by adding characters.
2551     mImpl->mModel->mLogicalModel->UpdateTextStyleRuns( cursorIndex, maxSizeOfNewText );
2552
2553     // Get the character index from the cursor index.
2554     const CharacterIndex styleIndex = ( cursorIndex > 0u ) ? cursorIndex - 1u : 0u;
2555
2556     // Retrieve the text's style for the given index.
2557     InputStyle style;
2558     mImpl->RetrieveDefaultInputStyle( style );
2559     mImpl->mModel->mLogicalModel->RetrieveStyle( styleIndex, style );
2560
2561     // Whether to add a new text color run.
2562     const bool addColorRun = ( style.textColor != mImpl->mEventData->mInputStyle.textColor );
2563
2564     // Whether to add a new font run.
2565     const bool addFontNameRun = style.familyName != mImpl->mEventData->mInputStyle.familyName;
2566     const bool addFontWeightRun = style.weight != mImpl->mEventData->mInputStyle.weight;
2567     const bool addFontWidthRun = style.width != mImpl->mEventData->mInputStyle.width;
2568     const bool addFontSlantRun = style.slant != mImpl->mEventData->mInputStyle.slant;
2569     const bool addFontSizeRun = style.size != mImpl->mEventData->mInputStyle.size;
2570
2571     // Add style runs.
2572     if( addColorRun )
2573     {
2574       const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mColorRuns.Count();
2575       mImpl->mModel->mLogicalModel->mColorRuns.Resize( numberOfRuns + 1u );
2576
2577       ColorRun& colorRun = *( mImpl->mModel->mLogicalModel->mColorRuns.Begin() + numberOfRuns );
2578       colorRun.color = mImpl->mEventData->mInputStyle.textColor;
2579       colorRun.characterRun.characterIndex = cursorIndex;
2580       colorRun.characterRun.numberOfCharacters = maxSizeOfNewText;
2581     }
2582
2583     if( addFontNameRun   ||
2584         addFontWeightRun ||
2585         addFontWidthRun  ||
2586         addFontSlantRun  ||
2587         addFontSizeRun )
2588     {
2589       const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Count();
2590       mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Resize( numberOfRuns + 1u );
2591
2592       FontDescriptionRun& fontDescriptionRun = *( mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Begin() + numberOfRuns );
2593
2594       if( addFontNameRun )
2595       {
2596         fontDescriptionRun.familyLength = mImpl->mEventData->mInputStyle.familyName.size();
2597         fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
2598         memcpy( fontDescriptionRun.familyName, mImpl->mEventData->mInputStyle.familyName.c_str(), fontDescriptionRun.familyLength );
2599         fontDescriptionRun.familyDefined = true;
2600
2601         // The memory allocated for the font family name is freed when the font description is removed from the logical model.
2602       }
2603
2604       if( addFontWeightRun )
2605       {
2606         fontDescriptionRun.weight = mImpl->mEventData->mInputStyle.weight;
2607         fontDescriptionRun.weightDefined = true;
2608       }
2609
2610       if( addFontWidthRun )
2611       {
2612         fontDescriptionRun.width = mImpl->mEventData->mInputStyle.width;
2613         fontDescriptionRun.widthDefined = true;
2614       }
2615
2616       if( addFontSlantRun )
2617       {
2618         fontDescriptionRun.slant = mImpl->mEventData->mInputStyle.slant;
2619         fontDescriptionRun.slantDefined = true;
2620       }
2621
2622       if( addFontSizeRun )
2623       {
2624         fontDescriptionRun.size = static_cast<PointSize26Dot6>( mImpl->mEventData->mInputStyle.size * 64.f );
2625         fontDescriptionRun.sizeDefined = true;
2626       }
2627
2628       fontDescriptionRun.characterRun.characterIndex = cursorIndex;
2629       fontDescriptionRun.characterRun.numberOfCharacters = maxSizeOfNewText;
2630     }
2631
2632     // Insert at current cursor position.
2633     Vector<Character>& modifyText = mImpl->mModel->mLogicalModel->mText;
2634
2635     if( cursorIndex < numberOfCharactersInModel )
2636     {
2637       modifyText.Insert( modifyText.Begin() + cursorIndex, utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
2638     }
2639     else
2640     {
2641       modifyText.Insert( modifyText.End(), utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
2642     }
2643
2644     // Mark the first paragraph to be updated.
2645     mImpl->mTextUpdateInfo.mCharacterIndex = std::min( cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex );
2646     mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd += maxSizeOfNewText;
2647
2648     // Update the cursor index.
2649     cursorIndex += maxSizeOfNewText;
2650
2651     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 );
2652   }
2653
2654   if( ( 0u == mImpl->mModel->mLogicalModel->mText.Count() ) &&
2655       mImpl->IsPlaceholderAvailable() )
2656   {
2657     // Show place-holder if empty after removing the pre-edit text
2658     ShowPlaceholderText();
2659     mImpl->mEventData->mUpdateCursorPosition = true;
2660     mImpl->ClearPreEditFlag();
2661   }
2662   else if( removedPrevious ||
2663            removedSelected ||
2664            ( 0 != utf32Characters.Count() ) )
2665   {
2666     // Queue an inserted event
2667     mImpl->QueueModifyEvent( ModifyEvent::TEXT_INSERTED );
2668
2669     mImpl->mEventData->mUpdateCursorPosition = true;
2670     if( removedSelected )
2671     {
2672       mImpl->mEventData->mScrollAfterDelete = true;
2673     }
2674     else
2675     {
2676       mImpl->mEventData->mScrollAfterUpdatePosition = true;
2677     }
2678   }
2679
2680   if( maxLengthReached )
2681   {
2682     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "MaxLengthReached (%d)\n", mImpl->mModel->mLogicalModel->mText.Count() );
2683
2684     mImpl->ResetImfManager();
2685
2686     if( NULL != mImpl->mEditableControlInterface )
2687     {
2688       // Do this last since it provides callbacks into application code
2689       mImpl->mEditableControlInterface->MaxLengthReached();
2690     }
2691   }
2692 }
2693
2694 void Controller::PasteText( const std::string& stringToPaste )
2695 {
2696   InsertText( stringToPaste, Text::Controller::COMMIT );
2697   mImpl->ChangeState( EventData::EDITING );
2698   mImpl->RequestRelayout();
2699
2700   if( NULL != mImpl->mEditableControlInterface )
2701   {
2702     // Do this last since it provides callbacks into application code
2703     mImpl->mEditableControlInterface->TextChanged();
2704   }
2705 }
2706
2707 bool Controller::RemoveText( int cursorOffset,
2708                              int numberOfCharacters,
2709                              UpdateInputStyleType type )
2710 {
2711   bool removed = false;
2712
2713   if( NULL == mImpl->mEventData )
2714   {
2715     return removed;
2716   }
2717
2718   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p mText.Count() %d cursor %d cursorOffset %d numberOfCharacters %d\n",
2719                  this, mImpl->mModel->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition, cursorOffset, numberOfCharacters );
2720
2721   if( !mImpl->IsShowingPlaceholderText() )
2722   {
2723     // Delete at current cursor position
2724     Vector<Character>& currentText = mImpl->mModel->mLogicalModel->mText;
2725     CharacterIndex& oldCursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
2726
2727     CharacterIndex cursorIndex = 0;
2728
2729     // Validate the cursor position & number of characters
2730     if( ( static_cast< int >( mImpl->mEventData->mPrimaryCursorPosition ) + cursorOffset ) >= 0 )
2731     {
2732       cursorIndex = mImpl->mEventData->mPrimaryCursorPosition + cursorOffset;
2733     }
2734
2735     if( ( cursorIndex + numberOfCharacters ) > currentText.Count() )
2736     {
2737       numberOfCharacters = currentText.Count() - cursorIndex;
2738     }
2739
2740     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.
2741         ( ( cursorIndex + numberOfCharacters ) <= mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters ) )
2742     {
2743       // Mark the paragraphs to be updated.
2744       mImpl->mTextUpdateInfo.mCharacterIndex = std::min( cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex );
2745       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove += numberOfCharacters;
2746
2747       // Update the input style and remove the text's style before removing the text.
2748
2749       if( UPDATE_INPUT_STYLE == type )
2750       {
2751         // Keep a copy of the current input style.
2752         InputStyle currentInputStyle;
2753         currentInputStyle.Copy( mImpl->mEventData->mInputStyle );
2754
2755         // Set first the default input style.
2756         mImpl->RetrieveDefaultInputStyle( mImpl->mEventData->mInputStyle );
2757
2758         // Update the input style.
2759         mImpl->mModel->mLogicalModel->RetrieveStyle( cursorIndex, mImpl->mEventData->mInputStyle );
2760
2761         // Compare if the input style has changed.
2762         const bool hasInputStyleChanged = !currentInputStyle.Equal( mImpl->mEventData->mInputStyle );
2763
2764         if( hasInputStyleChanged )
2765         {
2766           const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask( mImpl->mEventData->mInputStyle );
2767           // Queue the input style changed signal.
2768           mImpl->mEventData->mInputStyleChangedQueue.PushBack( styleChangedMask );
2769         }
2770       }
2771
2772       // Updates the text style runs by removing characters. Runs with no characters are removed.
2773       mImpl->mModel->mLogicalModel->UpdateTextStyleRuns( cursorIndex, -numberOfCharacters );
2774
2775       // Remove the characters.
2776       Vector<Character>::Iterator first = currentText.Begin() + cursorIndex;
2777       Vector<Character>::Iterator last  = first + numberOfCharacters;
2778
2779       currentText.Erase( first, last );
2780
2781       // Cursor position retreat
2782       oldCursorIndex = cursorIndex;
2783
2784       mImpl->mEventData->mScrollAfterDelete = true;
2785
2786       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p removed %d\n", this, numberOfCharacters );
2787       removed = true;
2788     }
2789   }
2790
2791   return removed;
2792 }
2793
2794 bool Controller::RemoveSelectedText()
2795 {
2796   bool textRemoved( false );
2797
2798   if( EventData::SELECTING == mImpl->mEventData->mState )
2799   {
2800     std::string removedString;
2801     mImpl->RetrieveSelection( removedString, true );
2802
2803     if( !removedString.empty() )
2804     {
2805       textRemoved = true;
2806       mImpl->ChangeState( EventData::EDITING );
2807     }
2808   }
2809
2810   return textRemoved;
2811 }
2812
2813 // private : Relayout.
2814
2815 bool Controller::DoRelayout( const Size& size,
2816                              OperationsMask operationsRequired,
2817                              Size& layoutSize )
2818 {
2819   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::DoRelayout %p size %f,%f\n", this, size.width, size.height );
2820   bool viewUpdated( false );
2821
2822   // Calculate the operations to be done.
2823   const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
2824
2825   const CharacterIndex startIndex = mImpl->mTextUpdateInfo.mParagraphCharacterIndex;
2826   const Length requestedNumberOfCharacters = mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters;
2827
2828   // Get the current layout size.
2829   layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
2830
2831   if( NO_OPERATION != ( LAYOUT & operations ) )
2832   {
2833     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::DoRelayout LAYOUT & operations\n");
2834
2835     // Some vectors with data needed to layout and reorder may be void
2836     // after the first time the text has been laid out.
2837     // Fill the vectors again.
2838
2839     // Calculate the number of glyphs to layout.
2840     const Vector<GlyphIndex>& charactersToGlyph = mImpl->mModel->mVisualModel->mCharactersToGlyph;
2841     const Vector<Length>& glyphsPerCharacter = mImpl->mModel->mVisualModel->mGlyphsPerCharacter;
2842     const GlyphIndex* const charactersToGlyphBuffer = charactersToGlyph.Begin();
2843     const Length* const glyphsPerCharacterBuffer = glyphsPerCharacter.Begin();
2844
2845     const CharacterIndex lastIndex = startIndex + ( ( requestedNumberOfCharacters > 0u ) ? requestedNumberOfCharacters - 1u : 0u );
2846     const GlyphIndex startGlyphIndex = mImpl->mTextUpdateInfo.mStartGlyphIndex;
2847     const Length numberOfGlyphs = ( requestedNumberOfCharacters > 0u ) ? *( charactersToGlyphBuffer + lastIndex ) + *( glyphsPerCharacterBuffer + lastIndex ) - startGlyphIndex : 0u;
2848     const Length totalNumberOfGlyphs = mImpl->mModel->mVisualModel->mGlyphs.Count();
2849
2850     if( 0u == totalNumberOfGlyphs )
2851     {
2852       if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) )
2853       {
2854         mImpl->mModel->mVisualModel->SetLayoutSize( Size::ZERO );
2855       }
2856
2857       // Nothing else to do if there is no glyphs.
2858       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout no glyphs, view updated true\n" );
2859       return true;
2860     }
2861
2862     const Vector<LineBreakInfo>& lineBreakInfo = mImpl->mModel->mLogicalModel->mLineBreakInfo;
2863     const Vector<WordBreakInfo>& wordBreakInfo = mImpl->mModel->mLogicalModel->mWordBreakInfo;
2864     const Vector<CharacterDirection>& characterDirection = mImpl->mModel->mLogicalModel->mCharacterDirections;
2865     const Vector<GlyphInfo>& glyphs = mImpl->mModel->mVisualModel->mGlyphs;
2866     const Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mModel->mVisualModel->mGlyphsToCharacters;
2867     const Vector<Length>& charactersPerGlyph = mImpl->mModel->mVisualModel->mCharactersPerGlyph;
2868     const Character* const textBuffer = mImpl->mModel->mLogicalModel->mText.Begin();
2869
2870     // Set the layout parameters.
2871     Layout::Parameters layoutParameters( size,
2872                                          textBuffer,
2873                                          lineBreakInfo.Begin(),
2874                                          wordBreakInfo.Begin(),
2875                                          ( 0u != characterDirection.Count() ) ? characterDirection.Begin() : NULL,
2876                                          glyphs.Begin(),
2877                                          glyphsToCharactersMap.Begin(),
2878                                          charactersPerGlyph.Begin(),
2879                                          charactersToGlyphBuffer,
2880                                          glyphsPerCharacterBuffer,
2881                                          totalNumberOfGlyphs,
2882                                          mImpl->mModel->mHorizontalAlignment );
2883
2884     // Resize the vector of positions to have the same size than the vector of glyphs.
2885     Vector<Vector2>& glyphPositions = mImpl->mModel->mVisualModel->mGlyphPositions;
2886     glyphPositions.Resize( totalNumberOfGlyphs );
2887
2888     // Whether the last character is a new paragraph character.
2889     mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph =  TextAbstraction::IsNewParagraph( *( textBuffer + ( mImpl->mModel->mLogicalModel->mText.Count() - 1u ) ) );
2890     layoutParameters.isLastNewParagraph = mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph;
2891
2892     // The initial glyph and the number of glyphs to layout.
2893     layoutParameters.startGlyphIndex = startGlyphIndex;
2894     layoutParameters.numberOfGlyphs = numberOfGlyphs;
2895     layoutParameters.startLineIndex = mImpl->mTextUpdateInfo.mStartLineIndex;
2896     layoutParameters.estimatedNumberOfLines = mImpl->mTextUpdateInfo.mEstimatedNumberOfLines;
2897
2898     // Update the visual model.
2899     Size newLayoutSize;
2900     viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
2901                                                    glyphPositions,
2902                                                    mImpl->mModel->mVisualModel->mLines,
2903                                                    newLayoutSize,
2904                                                    mImpl->mModel->mElideEnabled );
2905
2906     viewUpdated = viewUpdated || ( newLayoutSize != layoutSize );
2907
2908     if( viewUpdated )
2909     {
2910       layoutSize = newLayoutSize;
2911
2912       if( NO_OPERATION != ( UPDATE_DIRECTION & operations ) )
2913       {
2914         mImpl->mAutoScrollDirectionRTL = false;
2915       }
2916
2917       // Reorder the lines
2918       if( NO_OPERATION != ( REORDER & operations ) )
2919       {
2920         Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mImpl->mModel->mLogicalModel->mBidirectionalParagraphInfo;
2921         Vector<BidirectionalLineInfoRun>& bidirectionalLineInfo = mImpl->mModel->mLogicalModel->mBidirectionalLineInfo;
2922
2923         // Check first if there are paragraphs with bidirectional info.
2924         if( 0u != bidirectionalInfo.Count() )
2925         {
2926           // Get the lines
2927           const Length numberOfLines = mImpl->mModel->mVisualModel->mLines.Count();
2928
2929           // Reorder the lines.
2930           bidirectionalLineInfo.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
2931           ReorderLines( bidirectionalInfo,
2932                         startIndex,
2933                         requestedNumberOfCharacters,
2934                         mImpl->mModel->mVisualModel->mLines,
2935                         bidirectionalLineInfo );
2936
2937           // Set the bidirectional info per line into the layout parameters.
2938           layoutParameters.lineBidirectionalInfoRunsBuffer = bidirectionalLineInfo.Begin();
2939           layoutParameters.numberOfBidirectionalInfoRuns = bidirectionalLineInfo.Count();
2940
2941           // Re-layout the text. Reorder those lines with right to left characters.
2942           mImpl->mLayoutEngine.ReLayoutRightToLeftLines( layoutParameters,
2943                                                          startIndex,
2944                                                          requestedNumberOfCharacters,
2945                                                          glyphPositions );
2946
2947           if ( ( NO_OPERATION != ( UPDATE_DIRECTION & operations ) ) && ( numberOfLines > 0 ) )
2948           {
2949             const LineRun* const firstline = mImpl->mModel->mVisualModel->mLines.Begin();
2950             if ( firstline )
2951             {
2952               mImpl->mAutoScrollDirectionRTL = firstline->direction;
2953             }
2954           }
2955         }
2956       } // REORDER
2957
2958       // Sets the layout size.
2959       if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) )
2960       {
2961         mImpl->mModel->mVisualModel->SetLayoutSize( layoutSize );
2962       }
2963     } // view updated
2964   }
2965
2966   if( NO_OPERATION != ( ALIGN & operations ) )
2967   {
2968     // The laid-out lines.
2969     Vector<LineRun>& lines = mImpl->mModel->mVisualModel->mLines;
2970
2971     // Need to align with the control's size as the text may contain lines
2972     // starting either with left to right text or right to left.
2973     mImpl->mLayoutEngine.Align( size,
2974                                 startIndex,
2975                                 requestedNumberOfCharacters,
2976                                 mImpl->mModel->mHorizontalAlignment,
2977                                 lines,
2978                                 mImpl->mModel->mAlignmentOffset );
2979
2980     viewUpdated = true;
2981   }
2982 #if defined(DEBUG_ENABLED)
2983   std::string currentText;
2984   GetText( currentText );
2985   DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::DoRelayout [%p] mImpl->mAutoScrollDirectionRTL[%s] [%s]\n", this, (mImpl->mAutoScrollDirectionRTL)?"true":"false",  currentText.c_str() );
2986 #endif
2987   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout, view updated %s\n", ( viewUpdated ? "true" : "false" ) );
2988   return viewUpdated;
2989 }
2990
2991 void Controller::CalculateVerticalOffset( const Size& controlSize )
2992 {
2993   Size layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
2994
2995   if( fabsf( layoutSize.height ) < Math::MACHINE_EPSILON_1000 )
2996   {
2997     // Get the line height of the default font.
2998     layoutSize.height = mImpl->GetDefaultFontLineHeight();
2999   }
3000
3001   switch( mImpl->mModel->mVerticalAlignment )
3002   {
3003     case Layout::VERTICAL_ALIGN_TOP:
3004     {
3005       mImpl->mModel->mScrollPosition.y = 0.f;
3006       break;
3007     }
3008     case Layout::VERTICAL_ALIGN_CENTER:
3009     {
3010       mImpl->mModel->mScrollPosition.y = floorf( 0.5f * ( controlSize.height - layoutSize.height ) ); // try to avoid pixel alignment.
3011       break;
3012     }
3013     case Layout::VERTICAL_ALIGN_BOTTOM:
3014     {
3015       mImpl->mModel->mScrollPosition.y = controlSize.height - layoutSize.height;
3016       break;
3017     }
3018   }
3019 }
3020
3021 // private : Events.
3022
3023 void Controller::ProcessModifyEvents()
3024 {
3025   Vector<ModifyEvent>& events = mImpl->mModifyEvents;
3026
3027   if( 0u == events.Count() )
3028   {
3029     // Nothing to do.
3030     return;
3031   }
3032
3033   for( Vector<ModifyEvent>::ConstIterator it = events.Begin(),
3034          endIt = events.End();
3035        it != endIt;
3036        ++it )
3037   {
3038     const ModifyEvent& event = *it;
3039
3040     if( ModifyEvent::TEXT_REPLACED == event.type )
3041     {
3042       // A (single) replace event should come first, otherwise we wasted time processing NOOP events
3043       DALI_ASSERT_DEBUG( it == events.Begin() && "Unexpected TEXT_REPLACED event" );
3044
3045       TextReplacedEvent();
3046     }
3047     else if( ModifyEvent::TEXT_INSERTED == event.type )
3048     {
3049       TextInsertedEvent();
3050     }
3051     else if( ModifyEvent::TEXT_DELETED == event.type )
3052     {
3053       // Placeholder-text cannot be deleted
3054       if( !mImpl->IsShowingPlaceholderText() )
3055       {
3056         TextDeletedEvent();
3057       }
3058     }
3059   }
3060
3061   if( NULL != mImpl->mEventData )
3062   {
3063     // When the text is being modified, delay cursor blinking
3064     mImpl->mEventData->mDecorator->DelayCursorBlink();
3065   }
3066
3067   // Discard temporary text
3068   events.Clear();
3069 }
3070
3071 void Controller::TextReplacedEvent()
3072 {
3073   // The natural size needs to be re-calculated.
3074   mImpl->mRecalculateNaturalSize = true;
3075
3076   // Apply modifications to the model
3077   mImpl->mOperationsPending = ALL_OPERATIONS;
3078 }
3079
3080 void Controller::TextInsertedEvent()
3081 {
3082   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextInsertedEvent" );
3083
3084   if( NULL == mImpl->mEventData )
3085   {
3086     return;
3087   }
3088
3089   mImpl->mEventData->mCheckScrollAmount = true;
3090
3091   // The natural size needs to be re-calculated.
3092   mImpl->mRecalculateNaturalSize = true;
3093
3094   // Apply modifications to the model; TODO - Optimize this
3095   mImpl->mOperationsPending = ALL_OPERATIONS;
3096 }
3097
3098 void Controller::TextDeletedEvent()
3099 {
3100   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextDeletedEvent" );
3101
3102   if( NULL == mImpl->mEventData )
3103   {
3104     return;
3105   }
3106
3107   mImpl->mEventData->mCheckScrollAmount = true;
3108
3109   // The natural size needs to be re-calculated.
3110   mImpl->mRecalculateNaturalSize = true;
3111
3112   // Apply modifications to the model; TODO - Optimize this
3113   mImpl->mOperationsPending = ALL_OPERATIONS;
3114 }
3115
3116 void Controller::SelectEvent( float x, float y, bool selectAll )
3117 {
3118   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SelectEvent\n" );
3119
3120   if( NULL != mImpl->mEventData )
3121   {
3122     if( selectAll )
3123     {
3124       Event event( Event::SELECT_ALL );
3125       mImpl->mEventData->mEventQueue.push_back( event );
3126     }
3127     else
3128     {
3129       Event event( Event::SELECT );
3130       event.p2.mFloat = x;
3131       event.p3.mFloat = y;
3132       mImpl->mEventData->mEventQueue.push_back( event );
3133     }
3134
3135     mImpl->mEventData->mCheckScrollAmount = true;
3136     mImpl->mEventData->mIsLeftHandleSelected = true;
3137     mImpl->mEventData->mIsRightHandleSelected = true;
3138     mImpl->RequestRelayout();
3139   }
3140 }
3141
3142 bool Controller::BackspaceKeyEvent()
3143 {
3144   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p DALI_KEY_BACKSPACE\n", this );
3145
3146   bool removed = false;
3147
3148   if( NULL == mImpl->mEventData )
3149   {
3150     return removed;
3151   }
3152
3153   // IMF manager is no longer handling key-events
3154   mImpl->ClearPreEditFlag();
3155
3156   if( EventData::SELECTING == mImpl->mEventData->mState )
3157   {
3158     removed = RemoveSelectedText();
3159   }
3160   else if( mImpl->mEventData->mPrimaryCursorPosition > 0 )
3161   {
3162     // Remove the character before the current cursor position
3163     removed = RemoveText( -1,
3164                           1,
3165                           UPDATE_INPUT_STYLE );
3166   }
3167
3168   if( removed )
3169   {
3170     if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) ||
3171         !mImpl->IsPlaceholderAvailable() )
3172     {
3173       mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
3174     }
3175     else
3176     {
3177       ShowPlaceholderText();
3178     }
3179     mImpl->mEventData->mUpdateCursorPosition = true;
3180     mImpl->mEventData->mScrollAfterDelete = true;
3181   }
3182
3183   return removed;
3184 }
3185
3186 // private : Helpers.
3187
3188 void Controller::ResetText()
3189 {
3190   // Reset buffers.
3191   mImpl->mModel->mLogicalModel->mText.Clear();
3192
3193   // We have cleared everything including the placeholder-text
3194   mImpl->PlaceholderCleared();
3195
3196   mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
3197   mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3198   mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = 0u;
3199
3200   // Clear any previous text.
3201   mImpl->mTextUpdateInfo.mClearAll = true;
3202
3203   // The natural size needs to be re-calculated.
3204   mImpl->mRecalculateNaturalSize = true;
3205
3206   // Apply modifications to the model
3207   mImpl->mOperationsPending = ALL_OPERATIONS;
3208 }
3209
3210 void Controller::ShowPlaceholderText()
3211 {
3212   if( mImpl->IsPlaceholderAvailable() )
3213   {
3214     DALI_ASSERT_DEBUG( mImpl->mEventData && "No placeholder text available" );
3215
3216     if( NULL == mImpl->mEventData )
3217     {
3218       return;
3219     }
3220
3221     mImpl->mEventData->mIsShowingPlaceholderText = true;
3222
3223     // Disable handles when showing place-holder text
3224     mImpl->mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
3225     mImpl->mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
3226     mImpl->mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
3227
3228     const char* text( NULL );
3229     size_t size( 0 );
3230
3231     if( !mImpl->mEventData->mPlaceholderTextActive.empty() || !mImpl->mEventData->mPlaceholderTextInactive.empty() )
3232     {
3233       if( ( EventData::INACTIVE != mImpl->mEventData->mState ) &&
3234           ( 0u != mImpl->mEventData->mPlaceholderTextActive.c_str() ) )
3235       {
3236         text = mImpl->mEventData->mPlaceholderTextActive.c_str();
3237         size = mImpl->mEventData->mPlaceholderTextActive.size();
3238       }
3239       else
3240       {
3241         text = mImpl->mEventData->mPlaceholderTextInactive.c_str();
3242         size = mImpl->mEventData->mPlaceholderTextInactive.size();
3243       }
3244     }
3245     else
3246     {
3247       if( 0u != mImpl->mEventData->mPlaceholderText.c_str() )
3248       {
3249         text = mImpl->mEventData->mPlaceholderText.c_str();
3250         size = mImpl->mEventData->mPlaceholderText.size();
3251       }
3252     }
3253
3254     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
3255     mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3256
3257     // Reset model for showing placeholder.
3258     mImpl->mModel->mLogicalModel->mText.Clear();
3259     mImpl->mModel->mVisualModel->SetTextColor( mImpl->mEventData->mPlaceholderTextColor );
3260
3261     // Convert text into UTF-32
3262     Vector<Character>& utf32Characters = mImpl->mModel->mLogicalModel->mText;
3263     utf32Characters.Resize( size );
3264
3265     // This is a bit horrible but std::string returns a (signed) char*
3266     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text );
3267
3268     // Transform a text array encoded in utf8 into an array encoded in utf32.
3269     // It returns the actual number of characters.
3270     const Length characterCount = Utf8ToUtf32( utf8, size, utf32Characters.Begin() );
3271     utf32Characters.Resize( characterCount );
3272
3273     // The characters to be added.
3274     mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = characterCount;
3275
3276     // Reset the cursor position
3277     mImpl->mEventData->mPrimaryCursorPosition = 0;
3278
3279     // The natural size needs to be re-calculated.
3280     mImpl->mRecalculateNaturalSize = true;
3281
3282     // Apply modifications to the model
3283     mImpl->mOperationsPending = ALL_OPERATIONS;
3284
3285     // Update the rest of the model during size negotiation
3286     mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
3287   }
3288 }
3289
3290 void Controller::ClearFontData()
3291 {
3292   if( mImpl->mFontDefaults )
3293   {
3294     mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
3295   }
3296
3297   // Set flags to update the model.
3298   mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
3299   mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3300   mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
3301
3302   mImpl->mTextUpdateInfo.mClearAll = true;
3303   mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
3304   mImpl->mRecalculateNaturalSize = true;
3305
3306   mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
3307                                                            VALIDATE_FONTS            |
3308                                                            SHAPE_TEXT                |
3309                                                            GET_GLYPH_METRICS         |
3310                                                            LAYOUT                    |
3311                                                            UPDATE_LAYOUT_SIZE        |
3312                                                            REORDER                   |
3313                                                            ALIGN );
3314 }
3315
3316 void Controller::ClearStyleData()
3317 {
3318   mImpl->mModel->mLogicalModel->mColorRuns.Clear();
3319   mImpl->mModel->mLogicalModel->ClearFontDescriptionRuns();
3320 }
3321
3322 void Controller::ResetCursorPosition( CharacterIndex cursorIndex )
3323 {
3324   // Reset the cursor position
3325   if( NULL != mImpl->mEventData )
3326   {
3327     mImpl->mEventData->mPrimaryCursorPosition = cursorIndex;
3328
3329     // Update the cursor if it's in editing mode.
3330     if( EventData::IsEditingState( mImpl->mEventData->mState )  )
3331     {
3332       mImpl->mEventData->mUpdateCursorPosition = true;
3333     }
3334   }
3335 }
3336
3337 void Controller::ResetScrollPosition()
3338 {
3339   if( NULL != mImpl->mEventData )
3340   {
3341     // Reset the scroll position.
3342     mImpl->mModel->mScrollPosition = Vector2::ZERO;
3343     mImpl->mEventData->mScrollAfterUpdatePosition = true;
3344   }
3345 }
3346
3347 // private : Private contructors & copy operator.
3348
3349 Controller::Controller()
3350 : mImpl( NULL )
3351 {
3352   mImpl = new Controller::Impl( NULL, NULL );
3353 }
3354
3355 Controller::Controller( ControlInterface* controlInterface )
3356 {
3357   mImpl = new Controller::Impl( controlInterface, NULL );
3358 }
3359
3360 Controller::Controller( ControlInterface* controlInterface,
3361                         EditableControlInterface* editableControlInterface )
3362 {
3363   mImpl = new Controller::Impl( controlInterface,
3364                                 editableControlInterface );
3365 }
3366
3367 // The copy constructor and operator are left unimplemented.
3368
3369 // protected : Destructor.
3370
3371 Controller::~Controller()
3372 {
3373   delete mImpl;
3374 }
3375
3376 } // namespace Text
3377
3378 } // namespace Toolkit
3379
3380 } // namespace Dali