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