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