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