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