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