[4.0] Line spacing for TextLabel and vertical line alignment feature
[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 && !keyEvent.IsShiftModifier() ) ||
2423           ( Dali::DALI_KEY_CURSOR_RIGHT == keyCode && numberOfCharacters == cursorPosition && !keyEvent.IsShiftModifier() ) ||
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         // Release the active highlight.
2430         if( mImpl->mEventData->mState == EventData::SELECTING )
2431         {
2432           mImpl->ChangeState( EventData::EDITING );
2433
2434           // Update selection position.
2435           mImpl->mEventData->mLeftSelectionPosition = mImpl->mEventData->mPrimaryCursorPosition;
2436           mImpl->mEventData->mRightSelectionPosition = mImpl->mEventData->mPrimaryCursorPosition;
2437           mImpl->mEventData->mUpdateCursorPosition = true;
2438           mImpl->RequestRelayout();
2439         }
2440         return false;
2441       }
2442
2443       mImpl->mEventData->mCheckScrollAmount = true;
2444       Event event( Event::CURSOR_KEY_EVENT );
2445       event.p1.mInt = keyCode;
2446       event.p2.mBool = keyEvent.IsShiftModifier();
2447       mImpl->mEventData->mEventQueue.push_back( event );
2448
2449       // Will request for relayout.
2450       relayoutNeeded = true;
2451     }
2452     else if ( Dali::DevelKey::DALI_KEY_CONTROL_LEFT == keyCode || Dali::DevelKey::DALI_KEY_CONTROL_RIGHT == keyCode )
2453     {
2454       // Left or Right Control key event is received before Ctrl-C/V/X key event is received
2455       // If not handle it here, any selected text will be deleted
2456
2457       // Do nothing
2458       return false;
2459     }
2460     else if ( keyEvent.IsCtrlModifier() )
2461     {
2462       bool consumed = false;
2463       if (keyName == KEY_C_NAME)
2464       {
2465         // Ctrl-C to copy the selected text
2466         TextPopupButtonTouched( Toolkit::TextSelectionPopup::COPY );
2467         consumed = true;
2468       }
2469       else if (keyName == KEY_V_NAME)
2470       {
2471         // Ctrl-V to paste the copied text
2472         TextPopupButtonTouched( Toolkit::TextSelectionPopup::PASTE );
2473         consumed = true;
2474       }
2475       else if (keyName == KEY_X_NAME)
2476       {
2477         // Ctrl-X to cut the selected text
2478         TextPopupButtonTouched( Toolkit::TextSelectionPopup::CUT );
2479         consumed = true;
2480       }
2481       return consumed;
2482     }
2483     else if( ( Dali::DALI_KEY_BACKSPACE == keyCode ) ||
2484              ( Dali::DevelKey::DALI_KEY_DELETE == keyCode ) )
2485     {
2486       textChanged = DeleteEvent( keyCode );
2487
2488       // Will request for relayout.
2489       relayoutNeeded = true;
2490     }
2491     else if( IsKey( keyEvent, Dali::DALI_KEY_POWER ) ||
2492              IsKey( keyEvent, Dali::DALI_KEY_MENU )  ||
2493              IsKey( keyEvent, static_cast<Dali::KEY>(Dali::DevelKey::DALI_KEY_SOURCE) ) ||
2494              IsKey( keyEvent, Dali::DALI_KEY_HOME ) )
2495     {
2496       // Power key/Menu/Home key behaviour does not allow edit mode to resume.
2497       mImpl->ChangeState( EventData::INACTIVE );
2498
2499       // Will request for relayout.
2500       relayoutNeeded = true;
2501
2502       // This branch avoids calling the InsertText() method of the 'else' branch which can delete selected text.
2503     }
2504     else if( Dali::DALI_KEY_SHIFT_LEFT == keyCode )
2505     {
2506       // DALI_KEY_SHIFT_LEFT is the key code for the Left Shift. It's sent (by the imf?) when the predictive text is enabled
2507       // and a character is typed after the type of a upper case latin character.
2508
2509       // Do nothing.
2510       return false;
2511     }
2512     else if( ( Dali::DALI_KEY_VOLUME_UP == keyCode ) || ( Dali::DALI_KEY_VOLUME_DOWN == keyCode ) )
2513     {
2514       // This branch avoids calling the InsertText() method of the 'else' branch which can delete selected text.
2515       // Do nothing.
2516       return false;
2517     }
2518     else
2519     {
2520       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p keyString %s\n", this, keyString.c_str() );
2521
2522       // IMF manager is no longer handling key-events
2523       mImpl->ClearPreEditFlag();
2524
2525       InsertText( keyString, COMMIT );
2526       textChanged = true;
2527
2528       // Will request for relayout.
2529       relayoutNeeded = true;
2530     }
2531
2532     if ( ( mImpl->mEventData->mState != EventData::INTERRUPTED ) &&
2533          ( mImpl->mEventData->mState != EventData::INACTIVE ) &&
2534          ( !isNullKey ) &&
2535          ( Dali::DALI_KEY_SHIFT_LEFT != keyCode ) &&
2536          ( Dali::DALI_KEY_VOLUME_UP != keyCode ) &&
2537          ( Dali::DALI_KEY_VOLUME_DOWN != keyCode ) )
2538     {
2539       // Should not change the state if the key is the shift send by the imf manager.
2540       // Otherwise, when the state is SELECTING the text controller can't send the right
2541       // surrounding info to the imf.
2542       mImpl->ChangeState( EventData::EDITING );
2543
2544       // Will request for relayout.
2545       relayoutNeeded = true;
2546     }
2547
2548     if( relayoutNeeded )
2549     {
2550       mImpl->RequestRelayout();
2551     }
2552   }
2553
2554   if( textChanged &&
2555       ( NULL != mImpl->mEditableControlInterface ) )
2556   {
2557     // Do this last since it provides callbacks into application code
2558     mImpl->mEditableControlInterface->TextChanged();
2559   }
2560
2561   return true;
2562 }
2563
2564 void Controller::TapEvent( unsigned int tapCount, float x, float y )
2565 {
2566   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected TapEvent" );
2567
2568   if( NULL != mImpl->mEventData )
2569   {
2570     DALI_LOG_INFO( gLogFilter, Debug::Concise, "TapEvent state:%d \n", mImpl->mEventData->mState );
2571     EventData::State state( mImpl->mEventData->mState );
2572     bool relayoutNeeded( false );   // to avoid unnecessary relayouts when tapping an empty text-field
2573
2574     if( mImpl->IsClipboardVisible() )
2575     {
2576       if( EventData::INACTIVE == state || EventData::EDITING == state)
2577       {
2578         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );
2579       }
2580       relayoutNeeded = true;
2581     }
2582     else if( 1u == tapCount )
2583     {
2584       if( EventData::EDITING_WITH_POPUP == state || EventData::EDITING_WITH_PASTE_POPUP == state )
2585       {
2586         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );  // If Popup shown hide it here so can be shown again if required.
2587       }
2588
2589       if( mImpl->IsShowingRealText() && ( EventData::INACTIVE != state ) )
2590       {
2591         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );
2592         relayoutNeeded = true;
2593       }
2594       else
2595       {
2596         if( mImpl->IsShowingPlaceholderText() && !mImpl->IsFocusedPlaceholderAvailable() )
2597         {
2598           // Hide placeholder text
2599           ResetText();
2600         }
2601
2602         if( EventData::INACTIVE == state )
2603         {
2604           mImpl->ChangeState( EventData::EDITING );
2605         }
2606         else if( !mImpl->IsClipboardEmpty() )
2607         {
2608           mImpl->ChangeState( EventData::EDITING_WITH_POPUP );
2609         }
2610         relayoutNeeded = true;
2611       }
2612     }
2613     else if( 2u == tapCount )
2614     {
2615       if( mImpl->mEventData->mSelectionEnabled &&
2616           mImpl->IsShowingRealText() )
2617       {
2618         relayoutNeeded = true;
2619         mImpl->mEventData->mIsLeftHandleSelected = true;
2620         mImpl->mEventData->mIsRightHandleSelected = true;
2621       }
2622     }
2623
2624     // Handles & cursors must be repositioned after Relayout() i.e. after the Model has been updated
2625     if( relayoutNeeded )
2626     {
2627       Event event( Event::TAP_EVENT );
2628       event.p1.mUint = tapCount;
2629       event.p2.mFloat = x;
2630       event.p3.mFloat = y;
2631       mImpl->mEventData->mEventQueue.push_back( event );
2632
2633       mImpl->RequestRelayout();
2634     }
2635   }
2636
2637   // Reset keyboard as tap event has occurred.
2638   mImpl->ResetImfManager();
2639 }
2640
2641 void Controller::PanEvent( Gesture::State state, const Vector2& displacement )
2642 {
2643   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected PanEvent" );
2644
2645   if( NULL != mImpl->mEventData )
2646   {
2647     Event event( Event::PAN_EVENT );
2648     event.p1.mInt = state;
2649     event.p2.mFloat = displacement.x;
2650     event.p3.mFloat = displacement.y;
2651     mImpl->mEventData->mEventQueue.push_back( event );
2652
2653     mImpl->RequestRelayout();
2654   }
2655 }
2656
2657 void Controller::LongPressEvent( Gesture::State state, float x, float y  )
2658 {
2659   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected LongPressEvent" );
2660
2661   if( ( state == Gesture::Started ) &&
2662       ( NULL != mImpl->mEventData ) )
2663   {
2664     // The 1st long-press on inactive text-field is treated as tap
2665     if( EventData::INACTIVE == mImpl->mEventData->mState )
2666     {
2667       mImpl->ChangeState( EventData::EDITING );
2668
2669       Event event( Event::TAP_EVENT );
2670       event.p1.mUint = 1;
2671       event.p2.mFloat = x;
2672       event.p3.mFloat = y;
2673       mImpl->mEventData->mEventQueue.push_back( event );
2674
2675       mImpl->RequestRelayout();
2676     }
2677     else if( !mImpl->IsShowingRealText() )
2678     {
2679       Event event( Event::LONG_PRESS_EVENT );
2680       event.p1.mInt = state;
2681       event.p2.mFloat = x;
2682       event.p3.mFloat = y;
2683       mImpl->mEventData->mEventQueue.push_back( event );
2684       mImpl->RequestRelayout();
2685     }
2686     else if( !mImpl->IsClipboardVisible() )
2687     {
2688       // Reset the imf manager to commit the pre-edit before selecting the text.
2689       mImpl->ResetImfManager();
2690
2691       Event event( Event::LONG_PRESS_EVENT );
2692       event.p1.mInt = state;
2693       event.p2.mFloat = x;
2694       event.p3.mFloat = y;
2695       mImpl->mEventData->mEventQueue.push_back( event );
2696       mImpl->RequestRelayout();
2697
2698       mImpl->mEventData->mIsLeftHandleSelected = true;
2699       mImpl->mEventData->mIsRightHandleSelected = true;
2700     }
2701   }
2702 }
2703
2704 ImfManager::ImfCallbackData Controller::OnImfEvent( ImfManager& imfManager, const ImfManager::ImfEventData& imfEvent )
2705 {
2706   // Whether the text needs to be relaid-out.
2707   bool requestRelayout = false;
2708
2709   // Whether to retrieve the text and cursor position to be sent to the IMF manager.
2710   bool retrieveText = false;
2711   bool retrieveCursor = false;
2712
2713   switch( imfEvent.eventName )
2714   {
2715     case ImfManager::COMMIT:
2716     {
2717       InsertText( imfEvent.predictiveString, Text::Controller::COMMIT );
2718       requestRelayout = true;
2719       retrieveCursor = true;
2720       break;
2721     }
2722     case ImfManager::PREEDIT:
2723     {
2724       InsertText( imfEvent.predictiveString, Text::Controller::PRE_EDIT );
2725       requestRelayout = true;
2726       retrieveCursor = true;
2727       break;
2728     }
2729     case ImfManager::DELETESURROUNDING:
2730     {
2731       const bool textDeleted = RemoveText( imfEvent.cursorOffset,
2732                                            imfEvent.numberOfChars,
2733                                            DONT_UPDATE_INPUT_STYLE );
2734
2735       if( textDeleted )
2736       {
2737         if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) ||
2738             !mImpl->IsPlaceholderAvailable() )
2739         {
2740           mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
2741         }
2742         else
2743         {
2744           ShowPlaceholderText();
2745         }
2746         mImpl->mEventData->mUpdateCursorPosition = true;
2747         mImpl->mEventData->mScrollAfterDelete = true;
2748
2749         requestRelayout = true;
2750       }
2751       break;
2752     }
2753     case ImfManager::GETSURROUNDING:
2754     {
2755       retrieveText = true;
2756       retrieveCursor = true;
2757       break;
2758     }
2759     case ImfManager::PRIVATECOMMAND:
2760     {
2761       // PRIVATECOMMAND event is just for getting the private command message
2762       retrieveText = true;
2763       retrieveCursor = true;
2764       break;
2765     }
2766     case ImfManager::VOID:
2767     {
2768       // do nothing
2769       break;
2770     }
2771   } // end switch
2772
2773   if( requestRelayout )
2774   {
2775     mImpl->mOperationsPending = ALL_OPERATIONS;
2776     mImpl->RequestRelayout();
2777   }
2778
2779   std::string text;
2780   CharacterIndex cursorPosition = 0u;
2781   Length numberOfWhiteSpaces = 0u;
2782
2783   if( retrieveCursor )
2784   {
2785     numberOfWhiteSpaces = mImpl->GetNumberOfWhiteSpaces( 0u );
2786
2787     cursorPosition = mImpl->GetLogicalCursorPosition();
2788
2789     if( cursorPosition < numberOfWhiteSpaces )
2790     {
2791       cursorPosition = 0u;
2792     }
2793     else
2794     {
2795       cursorPosition -= numberOfWhiteSpaces;
2796     }
2797   }
2798
2799   if( retrieveText )
2800   {
2801     if( !mImpl->IsShowingPlaceholderText() )
2802     {
2803       // Retrieves the normal text string.
2804       mImpl->GetText( numberOfWhiteSpaces, text );
2805     }
2806     else
2807     {
2808       // When the current text is Placeholder Text, the surrounding text should be empty string.
2809       // It means DALi should send empty string ("") to IME.
2810       text = "";
2811     }
2812   }
2813
2814   ImfManager::ImfCallbackData callbackData( ( retrieveText || retrieveCursor ), cursorPosition, text, false );
2815
2816   if( requestRelayout &&
2817       ( NULL != mImpl->mEditableControlInterface ) )
2818   {
2819     // Do this last since it provides callbacks into application code
2820     mImpl->mEditableControlInterface->TextChanged();
2821   }
2822
2823   return callbackData;
2824 }
2825
2826 void Controller::PasteClipboardItemEvent()
2827 {
2828   // Retrieve the clipboard contents first
2829   ClipboardEventNotifier notifier( ClipboardEventNotifier::Get() );
2830   std::string stringToPaste( notifier.GetContent() );
2831
2832   // Commit the current pre-edit text; the contents of the clipboard should be appended
2833   mImpl->ResetImfManager();
2834
2835   // Temporary disable hiding clipboard
2836   mImpl->SetClipboardHideEnable( false );
2837
2838   // Paste
2839   PasteText( stringToPaste );
2840
2841   mImpl->SetClipboardHideEnable( true );
2842 }
2843
2844 // protected : Inherit from Text::Decorator::ControllerInterface.
2845
2846 void Controller::GetTargetSize( Vector2& targetSize )
2847 {
2848   targetSize = mImpl->mModel->mVisualModel->mControlSize;
2849 }
2850
2851 void Controller::AddDecoration( Actor& actor, bool needsClipping )
2852 {
2853   if( NULL != mImpl->mEditableControlInterface )
2854   {
2855     mImpl->mEditableControlInterface->AddDecoration( actor, needsClipping );
2856   }
2857 }
2858
2859 void Controller::DecorationEvent( HandleType handleType, HandleState state, float x, float y )
2860 {
2861   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected DecorationEvent" );
2862
2863   if( NULL != mImpl->mEventData )
2864   {
2865     switch( handleType )
2866     {
2867       case GRAB_HANDLE:
2868       {
2869         Event event( Event::GRAB_HANDLE_EVENT );
2870         event.p1.mUint  = state;
2871         event.p2.mFloat = x;
2872         event.p3.mFloat = y;
2873
2874         mImpl->mEventData->mEventQueue.push_back( event );
2875         break;
2876       }
2877       case LEFT_SELECTION_HANDLE:
2878       {
2879         Event event( Event::LEFT_SELECTION_HANDLE_EVENT );
2880         event.p1.mUint  = state;
2881         event.p2.mFloat = x;
2882         event.p3.mFloat = y;
2883
2884         mImpl->mEventData->mEventQueue.push_back( event );
2885         break;
2886       }
2887       case RIGHT_SELECTION_HANDLE:
2888       {
2889         Event event( Event::RIGHT_SELECTION_HANDLE_EVENT );
2890         event.p1.mUint  = state;
2891         event.p2.mFloat = x;
2892         event.p3.mFloat = y;
2893
2894         mImpl->mEventData->mEventQueue.push_back( event );
2895         break;
2896       }
2897       case LEFT_SELECTION_HANDLE_MARKER:
2898       case RIGHT_SELECTION_HANDLE_MARKER:
2899       {
2900         // Markers do not move the handles.
2901         break;
2902       }
2903       case HANDLE_TYPE_COUNT:
2904       {
2905         DALI_ASSERT_DEBUG( !"Controller::HandleEvent. Unexpected handle type" );
2906       }
2907     }
2908
2909     mImpl->RequestRelayout();
2910   }
2911 }
2912
2913 // protected : Inherit from TextSelectionPopup::TextPopupButtonCallbackInterface.
2914
2915 void Controller::TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::Buttons button )
2916 {
2917   if( NULL == mImpl->mEventData )
2918   {
2919     return;
2920   }
2921
2922   switch( button )
2923   {
2924     case Toolkit::TextSelectionPopup::CUT:
2925     {
2926       mImpl->SendSelectionToClipboard( true ); // Synchronous call to modify text
2927       mImpl->mOperationsPending = ALL_OPERATIONS;
2928
2929       if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) ||
2930           !mImpl->IsPlaceholderAvailable() )
2931       {
2932         mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
2933       }
2934       else
2935       {
2936         ShowPlaceholderText();
2937       }
2938
2939       mImpl->mEventData->mUpdateCursorPosition = true;
2940       mImpl->mEventData->mScrollAfterDelete = true;
2941
2942       mImpl->RequestRelayout();
2943
2944       if( NULL != mImpl->mEditableControlInterface )
2945       {
2946         mImpl->mEditableControlInterface->TextChanged();
2947       }
2948       break;
2949     }
2950     case Toolkit::TextSelectionPopup::COPY:
2951     {
2952       mImpl->SendSelectionToClipboard( false ); // Text not modified
2953
2954       mImpl->mEventData->mUpdateCursorPosition = true;
2955
2956       mImpl->RequestRelayout(); // Cursor, Handles, Selection Highlight, Popup
2957       break;
2958     }
2959     case Toolkit::TextSelectionPopup::PASTE:
2960     {
2961       mImpl->RequestGetTextFromClipboard(); // Request clipboard service to retrieve an item
2962       break;
2963     }
2964     case Toolkit::TextSelectionPopup::SELECT:
2965     {
2966       const Vector2& currentCursorPosition = mImpl->mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
2967
2968       if( mImpl->mEventData->mSelectionEnabled )
2969       {
2970         // Creates a SELECT event.
2971         SelectEvent( currentCursorPosition.x, currentCursorPosition.y, false );
2972       }
2973       break;
2974     }
2975     case Toolkit::TextSelectionPopup::SELECT_ALL:
2976     {
2977       // Creates a SELECT_ALL event
2978       SelectEvent( 0.f, 0.f, true );
2979       break;
2980     }
2981     case Toolkit::TextSelectionPopup::CLIPBOARD:
2982     {
2983       mImpl->ShowClipboard();
2984       break;
2985     }
2986     case Toolkit::TextSelectionPopup::NONE:
2987     {
2988       // Nothing to do.
2989       break;
2990     }
2991   }
2992 }
2993
2994 void Controller::DisplayTimeExpired()
2995 {
2996   mImpl->mEventData->mUpdateCursorPosition = true;
2997   // Apply modifications to the model
2998   mImpl->mOperationsPending = ALL_OPERATIONS;
2999
3000   mImpl->RequestRelayout();
3001 }
3002
3003 // private : Update.
3004
3005 void Controller::InsertText( const std::string& text, Controller::InsertType type )
3006 {
3007   bool removedPrevious = false;
3008   bool removedSelected = false;
3009   bool maxLengthReached = false;
3010
3011   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected InsertText" )
3012
3013   if( NULL == mImpl->mEventData )
3014   {
3015     return;
3016   }
3017
3018   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::InsertText %p %s (%s) mPrimaryCursorPosition %d mPreEditFlag %d mPreEditStartPosition %d mPreEditLength %d\n",
3019                  this, text.c_str(), (COMMIT == type ? "COMMIT" : "PRE_EDIT"),
3020                  mImpl->mEventData->mPrimaryCursorPosition, mImpl->mEventData->mPreEditFlag, mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
3021
3022   // TODO: At the moment the underline runs are only for pre-edit.
3023   mImpl->mModel->mVisualModel->mUnderlineRuns.Clear();
3024
3025   // Remove the previous IMF pre-edit.
3026   if( mImpl->mEventData->mPreEditFlag && ( 0u != mImpl->mEventData->mPreEditLength ) )
3027   {
3028     removedPrevious = RemoveText( -static_cast<int>( mImpl->mEventData->mPrimaryCursorPosition - mImpl->mEventData->mPreEditStartPosition ),
3029                                   mImpl->mEventData->mPreEditLength,
3030                                   DONT_UPDATE_INPUT_STYLE );
3031
3032     mImpl->mEventData->mPrimaryCursorPosition = mImpl->mEventData->mPreEditStartPosition;
3033     mImpl->mEventData->mPreEditLength = 0u;
3034   }
3035   else
3036   {
3037     // Remove the previous Selection.
3038     removedSelected = RemoveSelectedText();
3039
3040   }
3041
3042   Vector<Character> utf32Characters;
3043   Length characterCount = 0u;
3044
3045   if( !text.empty() )
3046   {
3047     //  Convert text into UTF-32
3048     utf32Characters.Resize( text.size() );
3049
3050     // This is a bit horrible but std::string returns a (signed) char*
3051     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
3052
3053     // Transform a text array encoded in utf8 into an array encoded in utf32.
3054     // It returns the actual number of characters.
3055     characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
3056     utf32Characters.Resize( characterCount );
3057
3058     DALI_ASSERT_DEBUG( text.size() >= utf32Characters.Count() && "Invalid UTF32 conversion length" );
3059     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "UTF8 size %d, UTF32 size %d\n", text.size(), utf32Characters.Count() );
3060   }
3061
3062   if( 0u != utf32Characters.Count() ) // Check if Utf8ToUtf32 conversion succeeded
3063   {
3064     // The placeholder text is no longer needed
3065     if( mImpl->IsShowingPlaceholderText() )
3066     {
3067       ResetText();
3068     }
3069
3070     mImpl->ChangeState( EventData::EDITING );
3071
3072     // Handle the IMF (predicitive text) state changes
3073     if( COMMIT == type )
3074     {
3075       // IMF manager is no longer handling key-events
3076       mImpl->ClearPreEditFlag();
3077     }
3078     else // PRE_EDIT
3079     {
3080       if( !mImpl->mEventData->mPreEditFlag )
3081       {
3082         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Entered PreEdit state\n" );
3083
3084         // Record the start of the pre-edit text
3085         mImpl->mEventData->mPreEditStartPosition = mImpl->mEventData->mPrimaryCursorPosition;
3086       }
3087
3088       mImpl->mEventData->mPreEditLength = utf32Characters.Count();
3089       mImpl->mEventData->mPreEditFlag = true;
3090
3091       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "mPreEditStartPosition %d mPreEditLength %d\n", mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
3092     }
3093
3094     const Length numberOfCharactersInModel = mImpl->mModel->mLogicalModel->mText.Count();
3095
3096     // Restrict new text to fit within Maximum characters setting.
3097     Length maxSizeOfNewText = std::min( ( mImpl->mMaximumNumberOfCharacters - numberOfCharactersInModel ), characterCount );
3098     maxLengthReached = ( characterCount > maxSizeOfNewText );
3099
3100     // The cursor position.
3101     CharacterIndex& cursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
3102
3103     // Update the text's style.
3104
3105     // Updates the text style runs by adding characters.
3106     mImpl->mModel->mLogicalModel->UpdateTextStyleRuns( cursorIndex, maxSizeOfNewText );
3107
3108     // Get the character index from the cursor index.
3109     const CharacterIndex styleIndex = ( cursorIndex > 0u ) ? cursorIndex - 1u : 0u;
3110
3111     // Retrieve the text's style for the given index.
3112     InputStyle style;
3113     mImpl->RetrieveDefaultInputStyle( style );
3114     mImpl->mModel->mLogicalModel->RetrieveStyle( styleIndex, style );
3115
3116     // Whether to add a new text color run.
3117     const bool addColorRun = ( style.textColor != mImpl->mEventData->mInputStyle.textColor );
3118
3119     // Whether to add a new font run.
3120     const bool addFontNameRun = style.familyName != mImpl->mEventData->mInputStyle.familyName;
3121     const bool addFontWeightRun = style.weight != mImpl->mEventData->mInputStyle.weight;
3122     const bool addFontWidthRun = style.width != mImpl->mEventData->mInputStyle.width;
3123     const bool addFontSlantRun = style.slant != mImpl->mEventData->mInputStyle.slant;
3124     const bool addFontSizeRun = style.size != mImpl->mEventData->mInputStyle.size;
3125
3126     // Add style runs.
3127     if( addColorRun )
3128     {
3129       const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mColorRuns.Count();
3130       mImpl->mModel->mLogicalModel->mColorRuns.Resize( numberOfRuns + 1u );
3131
3132       ColorRun& colorRun = *( mImpl->mModel->mLogicalModel->mColorRuns.Begin() + numberOfRuns );
3133       colorRun.color = mImpl->mEventData->mInputStyle.textColor;
3134       colorRun.characterRun.characterIndex = cursorIndex;
3135       colorRun.characterRun.numberOfCharacters = maxSizeOfNewText;
3136     }
3137
3138     if( addFontNameRun   ||
3139         addFontWeightRun ||
3140         addFontWidthRun  ||
3141         addFontSlantRun  ||
3142         addFontSizeRun )
3143     {
3144       const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Count();
3145       mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Resize( numberOfRuns + 1u );
3146
3147       FontDescriptionRun& fontDescriptionRun = *( mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Begin() + numberOfRuns );
3148
3149       if( addFontNameRun )
3150       {
3151         fontDescriptionRun.familyLength = mImpl->mEventData->mInputStyle.familyName.size();
3152         fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
3153         memcpy( fontDescriptionRun.familyName, mImpl->mEventData->mInputStyle.familyName.c_str(), fontDescriptionRun.familyLength );
3154         fontDescriptionRun.familyDefined = true;
3155
3156         // The memory allocated for the font family name is freed when the font description is removed from the logical model.
3157       }
3158
3159       if( addFontWeightRun )
3160       {
3161         fontDescriptionRun.weight = mImpl->mEventData->mInputStyle.weight;
3162         fontDescriptionRun.weightDefined = true;
3163       }
3164
3165       if( addFontWidthRun )
3166       {
3167         fontDescriptionRun.width = mImpl->mEventData->mInputStyle.width;
3168         fontDescriptionRun.widthDefined = true;
3169       }
3170
3171       if( addFontSlantRun )
3172       {
3173         fontDescriptionRun.slant = mImpl->mEventData->mInputStyle.slant;
3174         fontDescriptionRun.slantDefined = true;
3175       }
3176
3177       if( addFontSizeRun )
3178       {
3179         fontDescriptionRun.size = static_cast<PointSize26Dot6>( mImpl->mEventData->mInputStyle.size * 64.f );
3180         fontDescriptionRun.sizeDefined = true;
3181       }
3182
3183       fontDescriptionRun.characterRun.characterIndex = cursorIndex;
3184       fontDescriptionRun.characterRun.numberOfCharacters = maxSizeOfNewText;
3185     }
3186
3187     // Insert at current cursor position.
3188     Vector<Character>& modifyText = mImpl->mModel->mLogicalModel->mText;
3189
3190     if( cursorIndex < numberOfCharactersInModel )
3191     {
3192       modifyText.Insert( modifyText.Begin() + cursorIndex, utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
3193     }
3194     else
3195     {
3196       modifyText.Insert( modifyText.End(), utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
3197     }
3198
3199     // Mark the first paragraph to be updated.
3200     if( Layout::Engine::SINGLE_LINE_BOX == mImpl->mLayoutEngine.GetLayout() )
3201     {
3202       mImpl->mTextUpdateInfo.mCharacterIndex = 0;
3203       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3204       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = numberOfCharactersInModel + maxSizeOfNewText;
3205       mImpl->mTextUpdateInfo.mClearAll = true;
3206     }
3207     else
3208     {
3209       mImpl->mTextUpdateInfo.mCharacterIndex = std::min( cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex );
3210       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd += maxSizeOfNewText;
3211     }
3212
3213     // Update the cursor index.
3214     cursorIndex += maxSizeOfNewText;
3215
3216     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 );
3217   }
3218
3219   if( ( 0u == mImpl->mModel->mLogicalModel->mText.Count() ) &&
3220       mImpl->IsPlaceholderAvailable() )
3221   {
3222     // Show place-holder if empty after removing the pre-edit text
3223     ShowPlaceholderText();
3224     mImpl->mEventData->mUpdateCursorPosition = true;
3225     mImpl->ClearPreEditFlag();
3226   }
3227   else if( removedPrevious ||
3228            removedSelected ||
3229            ( 0 != utf32Characters.Count() ) )
3230   {
3231     // Queue an inserted event
3232     mImpl->QueueModifyEvent( ModifyEvent::TEXT_INSERTED );
3233
3234     mImpl->mEventData->mUpdateCursorPosition = true;
3235     if( removedSelected )
3236     {
3237       mImpl->mEventData->mScrollAfterDelete = true;
3238     }
3239     else
3240     {
3241       mImpl->mEventData->mScrollAfterUpdatePosition = true;
3242     }
3243   }
3244
3245   if( maxLengthReached )
3246   {
3247     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "MaxLengthReached (%d)\n", mImpl->mModel->mLogicalModel->mText.Count() );
3248
3249     mImpl->ResetImfManager();
3250
3251     if( NULL != mImpl->mEditableControlInterface )
3252     {
3253       // Do this last since it provides callbacks into application code
3254       mImpl->mEditableControlInterface->MaxLengthReached();
3255     }
3256   }
3257 }
3258
3259 void Controller::PasteText( const std::string& stringToPaste )
3260 {
3261   InsertText( stringToPaste, Text::Controller::COMMIT );
3262   mImpl->ChangeState( EventData::EDITING );
3263   mImpl->RequestRelayout();
3264
3265   if( NULL != mImpl->mEditableControlInterface )
3266   {
3267     // Do this last since it provides callbacks into application code
3268     mImpl->mEditableControlInterface->TextChanged();
3269   }
3270 }
3271
3272 bool Controller::RemoveText( int cursorOffset,
3273                              int numberOfCharacters,
3274                              UpdateInputStyleType type )
3275 {
3276   bool removed = false;
3277
3278   // When the users press "Delete All" button, the IME sends numberOfCharacters as '200000' value which means the max number of characters.
3279   const bool deleteAll = ( numberOfCharacters >= MAX_NUMBER_OF_CHARACTERS );
3280
3281   if( NULL == mImpl->mEventData )
3282   {
3283     return removed;
3284   }
3285
3286   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p mText.Count() %d cursor %d cursorOffset %d numberOfCharacters %d\n",
3287                  this, mImpl->mModel->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition, cursorOffset, numberOfCharacters );
3288
3289   if( !mImpl->IsShowingPlaceholderText() )
3290   {
3291     // Delete at current cursor position
3292     Vector<Character>& currentText = mImpl->mModel->mLogicalModel->mText;
3293     CharacterIndex& oldCursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
3294
3295     CharacterIndex cursorIndex = 0;
3296
3297     // Validate the cursor position & number of characters
3298     if( ( static_cast< int >( mImpl->mEventData->mPrimaryCursorPosition ) + cursorOffset ) >= 0 )
3299     {
3300       cursorIndex = mImpl->mEventData->mPrimaryCursorPosition + cursorOffset;
3301     }
3302
3303     if( ( cursorIndex + numberOfCharacters ) > currentText.Count() )
3304     {
3305       numberOfCharacters = currentText.Count() - cursorIndex;
3306     }
3307
3308     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.
3309         ( ( cursorIndex + numberOfCharacters ) <= mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters ) || deleteAll /*'Delete All' button clicked*/ )
3310     {
3311       // Mark the paragraphs to be updated.
3312       if( Layout::Engine::SINGLE_LINE_BOX == mImpl->mLayoutEngine.GetLayout() )
3313       {
3314         mImpl->mTextUpdateInfo.mCharacterIndex = 0;
3315         mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3316         mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters - numberOfCharacters;
3317         mImpl->mTextUpdateInfo.mClearAll = true;
3318       }
3319       else
3320       {
3321         mImpl->mTextUpdateInfo.mCharacterIndex = std::min( cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex );
3322         mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove += numberOfCharacters;
3323       }
3324
3325       // Update the input style and remove the text's style before removing the text.
3326
3327       if( UPDATE_INPUT_STYLE == type )
3328       {
3329         // Keep a copy of the current input style.
3330         InputStyle currentInputStyle;
3331         currentInputStyle.Copy( mImpl->mEventData->mInputStyle );
3332
3333         // Set first the default input style.
3334         mImpl->RetrieveDefaultInputStyle( mImpl->mEventData->mInputStyle );
3335
3336         // Update the input style.
3337         mImpl->mModel->mLogicalModel->RetrieveStyle( cursorIndex, mImpl->mEventData->mInputStyle );
3338
3339         // Compare if the input style has changed.
3340         const bool hasInputStyleChanged = !currentInputStyle.Equal( mImpl->mEventData->mInputStyle );
3341
3342         if( hasInputStyleChanged )
3343         {
3344           const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask( mImpl->mEventData->mInputStyle );
3345           // Queue the input style changed signal.
3346           mImpl->mEventData->mInputStyleChangedQueue.PushBack( styleChangedMask );
3347         }
3348       }
3349
3350       // Updates the text style runs by removing characters. Runs with no characters are removed.
3351       mImpl->mModel->mLogicalModel->UpdateTextStyleRuns( cursorIndex, -numberOfCharacters );
3352
3353       // Remove the characters.
3354       Vector<Character>::Iterator first = currentText.Begin() + cursorIndex;
3355       Vector<Character>::Iterator last  = first + numberOfCharacters;
3356
3357       currentText.Erase( first, last );
3358
3359       // Cursor position retreat
3360       oldCursorIndex = cursorIndex;
3361
3362       mImpl->mEventData->mScrollAfterDelete = true;
3363
3364       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p removed %d\n", this, numberOfCharacters );
3365       removed = true;
3366     }
3367   }
3368
3369   return removed;
3370 }
3371
3372 bool Controller::RemoveSelectedText()
3373 {
3374   bool textRemoved( false );
3375
3376   if( EventData::SELECTING == mImpl->mEventData->mState )
3377   {
3378     std::string removedString;
3379     mImpl->RetrieveSelection( removedString, true );
3380
3381     if( !removedString.empty() )
3382     {
3383       textRemoved = true;
3384       mImpl->ChangeState( EventData::EDITING );
3385     }
3386   }
3387
3388   return textRemoved;
3389 }
3390
3391 // private : Relayout.
3392
3393 bool Controller::DoRelayout( const Size& size,
3394                              OperationsMask operationsRequired,
3395                              Size& layoutSize )
3396 {
3397   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::DoRelayout %p size %f,%f\n", this, size.width, size.height );
3398   bool viewUpdated( false );
3399
3400   // Calculate the operations to be done.
3401   const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
3402
3403   const CharacterIndex startIndex = mImpl->mTextUpdateInfo.mParagraphCharacterIndex;
3404   const Length requestedNumberOfCharacters = mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters;
3405
3406   // Get the current layout size.
3407   layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
3408
3409   if( NO_OPERATION != ( LAYOUT & operations ) )
3410   {
3411     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::DoRelayout LAYOUT & operations\n");
3412
3413     // Some vectors with data needed to layout and reorder may be void
3414     // after the first time the text has been laid out.
3415     // Fill the vectors again.
3416
3417     // Calculate the number of glyphs to layout.
3418     const Vector<GlyphIndex>& charactersToGlyph = mImpl->mModel->mVisualModel->mCharactersToGlyph;
3419     const Vector<Length>& glyphsPerCharacter = mImpl->mModel->mVisualModel->mGlyphsPerCharacter;
3420     const GlyphIndex* const charactersToGlyphBuffer = charactersToGlyph.Begin();
3421     const Length* const glyphsPerCharacterBuffer = glyphsPerCharacter.Begin();
3422
3423     const CharacterIndex lastIndex = startIndex + ( ( requestedNumberOfCharacters > 0u ) ? requestedNumberOfCharacters - 1u : 0u );
3424     const GlyphIndex startGlyphIndex = mImpl->mTextUpdateInfo.mStartGlyphIndex;
3425     const Length numberOfGlyphs = ( requestedNumberOfCharacters > 0u ) ? *( charactersToGlyphBuffer + lastIndex ) + *( glyphsPerCharacterBuffer + lastIndex ) - startGlyphIndex : 0u;
3426     const Length totalNumberOfGlyphs = mImpl->mModel->mVisualModel->mGlyphs.Count();
3427
3428     if( 0u == totalNumberOfGlyphs )
3429     {
3430       if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) )
3431       {
3432         mImpl->mModel->mVisualModel->SetLayoutSize( Size::ZERO );
3433       }
3434
3435       // Nothing else to do if there is no glyphs.
3436       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout no glyphs, view updated true\n" );
3437       return true;
3438     }
3439
3440     const Vector<LineBreakInfo>& lineBreakInfo = mImpl->mModel->mLogicalModel->mLineBreakInfo;
3441     const Vector<WordBreakInfo>& wordBreakInfo = mImpl->mModel->mLogicalModel->mWordBreakInfo;
3442     const Vector<CharacterDirection>& characterDirection = mImpl->mModel->mLogicalModel->mCharacterDirections;
3443     const Vector<GlyphInfo>& glyphs = mImpl->mModel->mVisualModel->mGlyphs;
3444     const Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mModel->mVisualModel->mGlyphsToCharacters;
3445     const Vector<Length>& charactersPerGlyph = mImpl->mModel->mVisualModel->mCharactersPerGlyph;
3446     const Character* const textBuffer = mImpl->mModel->mLogicalModel->mText.Begin();
3447     const float outlineWidth = static_cast<float>( mImpl->mModel->GetOutlineWidth() );
3448
3449     // Set the layout parameters.
3450     Layout::Parameters layoutParameters( size,
3451                                          textBuffer,
3452                                          lineBreakInfo.Begin(),
3453                                          wordBreakInfo.Begin(),
3454                                          ( 0u != characterDirection.Count() ) ? characterDirection.Begin() : NULL,
3455                                          glyphs.Begin(),
3456                                          glyphsToCharactersMap.Begin(),
3457                                          charactersPerGlyph.Begin(),
3458                                          charactersToGlyphBuffer,
3459                                          glyphsPerCharacterBuffer,
3460                                          totalNumberOfGlyphs,
3461                                          mImpl->mModel->mHorizontalAlignment,
3462                                          mImpl->mModel->mLineWrapMode,
3463                                          outlineWidth );
3464
3465     // Resize the vector of positions to have the same size than the vector of glyphs.
3466     Vector<Vector2>& glyphPositions = mImpl->mModel->mVisualModel->mGlyphPositions;
3467     glyphPositions.Resize( totalNumberOfGlyphs );
3468
3469     // Whether the last character is a new paragraph character.
3470     mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph =  TextAbstraction::IsNewParagraph( *( textBuffer + ( mImpl->mModel->mLogicalModel->mText.Count() - 1u ) ) );
3471     layoutParameters.isLastNewParagraph = mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph;
3472
3473     // The initial glyph and the number of glyphs to layout.
3474     layoutParameters.startGlyphIndex = startGlyphIndex;
3475     layoutParameters.numberOfGlyphs = numberOfGlyphs;
3476     layoutParameters.startLineIndex = mImpl->mTextUpdateInfo.mStartLineIndex;
3477     layoutParameters.estimatedNumberOfLines = mImpl->mTextUpdateInfo.mEstimatedNumberOfLines;
3478
3479     // Update the ellipsis
3480     bool elideTextEnabled = mImpl->mModel->mElideEnabled;
3481
3482     if( NULL != mImpl->mEventData )
3483     {
3484       if( mImpl->mEventData->mPlaceholderEllipsisFlag && mImpl->IsShowingPlaceholderText() )
3485       {
3486         elideTextEnabled = mImpl->mEventData->mIsPlaceholderElideEnabled;
3487       }
3488       else if( EventData::INACTIVE != mImpl->mEventData->mState )
3489       {
3490         // Disable ellipsis when editing
3491         elideTextEnabled = false;
3492       }
3493
3494       // Reset the scroll position in inactive state
3495       if( elideTextEnabled && ( mImpl->mEventData->mState == EventData::INACTIVE ) )
3496       {
3497         ResetScrollPosition();
3498       }
3499     }
3500
3501     // Update the visual model.
3502     Size newLayoutSize;
3503     viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
3504                                                    glyphPositions,
3505                                                    mImpl->mModel->mVisualModel->mLines,
3506                                                    newLayoutSize,
3507                                                    elideTextEnabled );
3508
3509     viewUpdated = viewUpdated || ( newLayoutSize != layoutSize );
3510
3511     if( viewUpdated )
3512     {
3513       layoutSize = newLayoutSize;
3514
3515       if( NO_OPERATION != ( UPDATE_DIRECTION & operations ) )
3516       {
3517         mImpl->mAutoScrollDirectionRTL = false;
3518       }
3519
3520       // Reorder the lines
3521       if( NO_OPERATION != ( REORDER & operations ) )
3522       {
3523         Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mImpl->mModel->mLogicalModel->mBidirectionalParagraphInfo;
3524         Vector<BidirectionalLineInfoRun>& bidirectionalLineInfo = mImpl->mModel->mLogicalModel->mBidirectionalLineInfo;
3525
3526         // Check first if there are paragraphs with bidirectional info.
3527         if( 0u != bidirectionalInfo.Count() )
3528         {
3529           // Get the lines
3530           const Length numberOfLines = mImpl->mModel->mVisualModel->mLines.Count();
3531
3532           // Reorder the lines.
3533           bidirectionalLineInfo.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
3534           ReorderLines( bidirectionalInfo,
3535                         startIndex,
3536                         requestedNumberOfCharacters,
3537                         mImpl->mModel->mVisualModel->mLines,
3538                         bidirectionalLineInfo );
3539
3540           // Set the bidirectional info per line into the layout parameters.
3541           layoutParameters.lineBidirectionalInfoRunsBuffer = bidirectionalLineInfo.Begin();
3542           layoutParameters.numberOfBidirectionalInfoRuns = bidirectionalLineInfo.Count();
3543
3544           // Re-layout the text. Reorder those lines with right to left characters.
3545           mImpl->mLayoutEngine.ReLayoutRightToLeftLines( layoutParameters,
3546                                                          startIndex,
3547                                                          requestedNumberOfCharacters,
3548                                                          glyphPositions );
3549
3550           if ( ( NO_OPERATION != ( UPDATE_DIRECTION & operations ) ) && ( numberOfLines > 0 ) )
3551           {
3552             const LineRun* const firstline = mImpl->mModel->mVisualModel->mLines.Begin();
3553             if ( firstline )
3554             {
3555               mImpl->mAutoScrollDirectionRTL = firstline->direction;
3556             }
3557           }
3558         }
3559       } // REORDER
3560
3561       // Sets the layout size.
3562       if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) )
3563       {
3564         mImpl->mModel->mVisualModel->SetLayoutSize( layoutSize );
3565       }
3566     } // view updated
3567   }
3568
3569   if( NO_OPERATION != ( ALIGN & operations ) )
3570   {
3571     // The laid-out lines.
3572     Vector<LineRun>& lines = mImpl->mModel->mVisualModel->mLines;
3573
3574     // Need to align with the control's size as the text may contain lines
3575     // starting either with left to right text or right to left.
3576     mImpl->mLayoutEngine.Align( size,
3577                                 startIndex,
3578                                 requestedNumberOfCharacters,
3579                                 mImpl->mModel->mHorizontalAlignment,
3580                                 lines,
3581                                 mImpl->mModel->mAlignmentOffset );
3582
3583     viewUpdated = true;
3584   }
3585 #if defined(DEBUG_ENABLED)
3586   std::string currentText;
3587   GetText( currentText );
3588   DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::DoRelayout [%p] mImpl->mAutoScrollDirectionRTL[%s] [%s]\n", this, (mImpl->mAutoScrollDirectionRTL)?"true":"false",  currentText.c_str() );
3589 #endif
3590   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout, view updated %s\n", ( viewUpdated ? "true" : "false" ) );
3591   return viewUpdated;
3592 }
3593
3594 void Controller::CalculateVerticalOffset( const Size& controlSize )
3595 {
3596   Size layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
3597
3598   if( fabsf( layoutSize.height ) < Math::MACHINE_EPSILON_1000 )
3599   {
3600     // Get the line height of the default font.
3601     layoutSize.height = mImpl->GetDefaultFontLineHeight();
3602   }
3603
3604   switch( mImpl->mModel->mVerticalAlignment )
3605   {
3606     case VerticalAlignment::TOP:
3607     {
3608       mImpl->mModel->mScrollPosition.y = 0.f;
3609       break;
3610     }
3611     case VerticalAlignment::CENTER:
3612     {
3613       mImpl->mModel->mScrollPosition.y = floorf( 0.5f * ( controlSize.height - layoutSize.height ) ); // try to avoid pixel alignment.
3614       break;
3615     }
3616     case VerticalAlignment::BOTTOM:
3617     {
3618       mImpl->mModel->mScrollPosition.y = controlSize.height - layoutSize.height;
3619       break;
3620     }
3621   }
3622 }
3623
3624 // private : Events.
3625
3626 void Controller::ProcessModifyEvents()
3627 {
3628   Vector<ModifyEvent>& events = mImpl->mModifyEvents;
3629
3630   if( 0u == events.Count() )
3631   {
3632     // Nothing to do.
3633     return;
3634   }
3635
3636   for( Vector<ModifyEvent>::ConstIterator it = events.Begin(),
3637          endIt = events.End();
3638        it != endIt;
3639        ++it )
3640   {
3641     const ModifyEvent& event = *it;
3642
3643     if( ModifyEvent::TEXT_REPLACED == event.type )
3644     {
3645       // A (single) replace event should come first, otherwise we wasted time processing NOOP events
3646       DALI_ASSERT_DEBUG( it == events.Begin() && "Unexpected TEXT_REPLACED event" );
3647
3648       TextReplacedEvent();
3649     }
3650     else if( ModifyEvent::TEXT_INSERTED == event.type )
3651     {
3652       TextInsertedEvent();
3653     }
3654     else if( ModifyEvent::TEXT_DELETED == event.type )
3655     {
3656       // Placeholder-text cannot be deleted
3657       if( !mImpl->IsShowingPlaceholderText() )
3658       {
3659         TextDeletedEvent();
3660       }
3661     }
3662   }
3663
3664   if( NULL != mImpl->mEventData )
3665   {
3666     // When the text is being modified, delay cursor blinking
3667     mImpl->mEventData->mDecorator->DelayCursorBlink();
3668
3669     // Update selection position after modifying the text
3670     mImpl->mEventData->mLeftSelectionPosition = mImpl->mEventData->mPrimaryCursorPosition;
3671     mImpl->mEventData->mRightSelectionPosition = mImpl->mEventData->mPrimaryCursorPosition;
3672   }
3673
3674   // Discard temporary text
3675   events.Clear();
3676 }
3677
3678 void Controller::TextReplacedEvent()
3679 {
3680   // The natural size needs to be re-calculated.
3681   mImpl->mRecalculateNaturalSize = true;
3682
3683   // Apply modifications to the model
3684   mImpl->mOperationsPending = ALL_OPERATIONS;
3685 }
3686
3687 void Controller::TextInsertedEvent()
3688 {
3689   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextInsertedEvent" );
3690
3691   if( NULL == mImpl->mEventData )
3692   {
3693     return;
3694   }
3695
3696   mImpl->mEventData->mCheckScrollAmount = true;
3697
3698   // The natural size needs to be re-calculated.
3699   mImpl->mRecalculateNaturalSize = true;
3700
3701   // Apply modifications to the model; TODO - Optimize this
3702   mImpl->mOperationsPending = ALL_OPERATIONS;
3703 }
3704
3705 void Controller::TextDeletedEvent()
3706 {
3707   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextDeletedEvent" );
3708
3709   if( NULL == mImpl->mEventData )
3710   {
3711     return;
3712   }
3713
3714   mImpl->mEventData->mCheckScrollAmount = true;
3715
3716   // The natural size needs to be re-calculated.
3717   mImpl->mRecalculateNaturalSize = true;
3718
3719   // Apply modifications to the model; TODO - Optimize this
3720   mImpl->mOperationsPending = ALL_OPERATIONS;
3721 }
3722
3723 void Controller::SelectEvent( float x, float y, bool selectAll )
3724 {
3725   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SelectEvent\n" );
3726
3727   if( NULL != mImpl->mEventData )
3728   {
3729     if( selectAll )
3730     {
3731       Event event( Event::SELECT_ALL );
3732       mImpl->mEventData->mEventQueue.push_back( event );
3733     }
3734     else
3735     {
3736       Event event( Event::SELECT );
3737       event.p2.mFloat = x;
3738       event.p3.mFloat = y;
3739       mImpl->mEventData->mEventQueue.push_back( event );
3740     }
3741
3742     mImpl->mEventData->mCheckScrollAmount = true;
3743     mImpl->mEventData->mIsLeftHandleSelected = true;
3744     mImpl->mEventData->mIsRightHandleSelected = true;
3745     mImpl->RequestRelayout();
3746   }
3747 }
3748
3749 bool Controller::DeleteEvent( int keyCode )
3750 {
3751   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p KeyCode : %d \n", this, keyCode );
3752
3753   bool removed = false;
3754
3755   if( NULL == mImpl->mEventData )
3756   {
3757     return removed;
3758   }
3759
3760   // IMF manager is no longer handling key-events
3761   mImpl->ClearPreEditFlag();
3762
3763   if( EventData::SELECTING == mImpl->mEventData->mState )
3764   {
3765     removed = RemoveSelectedText();
3766   }
3767   else if( ( mImpl->mEventData->mPrimaryCursorPosition > 0 ) && ( keyCode == Dali::DALI_KEY_BACKSPACE) )
3768   {
3769     // Remove the character before the current cursor position
3770     removed = RemoveText( -1,
3771                           1,
3772                           UPDATE_INPUT_STYLE );
3773   }
3774   else if( keyCode == Dali::DevelKey::DALI_KEY_DELETE )
3775   {
3776     // Remove the character after the current cursor position
3777     removed = RemoveText( 0,
3778                           1,
3779                           UPDATE_INPUT_STYLE );
3780   }
3781
3782   if( removed )
3783   {
3784     if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) ||
3785         !mImpl->IsPlaceholderAvailable() )
3786     {
3787       mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
3788     }
3789     else
3790     {
3791       ShowPlaceholderText();
3792     }
3793     mImpl->mEventData->mUpdateCursorPosition = true;
3794     mImpl->mEventData->mScrollAfterDelete = true;
3795   }
3796
3797   return removed;
3798 }
3799
3800 // private : Helpers.
3801
3802 void Controller::ResetText()
3803 {
3804   // Reset buffers.
3805   mImpl->mModel->mLogicalModel->mText.Clear();
3806
3807   // We have cleared everything including the placeholder-text
3808   mImpl->PlaceholderCleared();
3809
3810   mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
3811   mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3812   mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = 0u;
3813
3814   // Clear any previous text.
3815   mImpl->mTextUpdateInfo.mClearAll = true;
3816
3817   // The natural size needs to be re-calculated.
3818   mImpl->mRecalculateNaturalSize = true;
3819
3820   // Apply modifications to the model
3821   mImpl->mOperationsPending = ALL_OPERATIONS;
3822 }
3823
3824 void Controller::ShowPlaceholderText()
3825 {
3826   if( mImpl->IsPlaceholderAvailable() )
3827   {
3828     DALI_ASSERT_DEBUG( mImpl->mEventData && "No placeholder text available" );
3829
3830     if( NULL == mImpl->mEventData )
3831     {
3832       return;
3833     }
3834
3835     mImpl->mEventData->mIsShowingPlaceholderText = true;
3836
3837     // Disable handles when showing place-holder text
3838     mImpl->mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
3839     mImpl->mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
3840     mImpl->mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
3841
3842     const char* text( NULL );
3843     size_t size( 0 );
3844
3845     // TODO - Switch Placeholder text when changing state
3846     if( ( EventData::INACTIVE != mImpl->mEventData->mState ) &&
3847         ( 0u != mImpl->mEventData->mPlaceholderTextActive.c_str() ) )
3848     {
3849       text = mImpl->mEventData->mPlaceholderTextActive.c_str();
3850       size = mImpl->mEventData->mPlaceholderTextActive.size();
3851     }
3852     else
3853     {
3854       text = mImpl->mEventData->mPlaceholderTextInactive.c_str();
3855       size = mImpl->mEventData->mPlaceholderTextInactive.size();
3856     }
3857
3858     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
3859     mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3860
3861     // Reset model for showing placeholder.
3862     mImpl->mModel->mLogicalModel->mText.Clear();
3863     mImpl->mModel->mVisualModel->SetTextColor( mImpl->mEventData->mPlaceholderTextColor );
3864
3865     // Convert text into UTF-32
3866     Vector<Character>& utf32Characters = mImpl->mModel->mLogicalModel->mText;
3867     utf32Characters.Resize( size );
3868
3869     // This is a bit horrible but std::string returns a (signed) char*
3870     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text );
3871
3872     // Transform a text array encoded in utf8 into an array encoded in utf32.
3873     // It returns the actual number of characters.
3874     const Length characterCount = Utf8ToUtf32( utf8, size, utf32Characters.Begin() );
3875     utf32Characters.Resize( characterCount );
3876
3877     // The characters to be added.
3878     mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = characterCount;
3879
3880     // Reset the cursor position
3881     mImpl->mEventData->mPrimaryCursorPosition = 0;
3882
3883     // The natural size needs to be re-calculated.
3884     mImpl->mRecalculateNaturalSize = true;
3885
3886     // Apply modifications to the model
3887     mImpl->mOperationsPending = ALL_OPERATIONS;
3888
3889     // Update the rest of the model during size negotiation
3890     mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
3891   }
3892 }
3893
3894 void Controller::ClearFontData()
3895 {
3896   if( mImpl->mFontDefaults )
3897   {
3898     mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
3899   }
3900
3901   // Set flags to update the model.
3902   mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
3903   mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3904   mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
3905
3906   mImpl->mTextUpdateInfo.mClearAll = true;
3907   mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
3908   mImpl->mRecalculateNaturalSize = true;
3909
3910   mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
3911                                                            VALIDATE_FONTS            |
3912                                                            SHAPE_TEXT                |
3913                                                            BIDI_INFO                 |
3914                                                            GET_GLYPH_METRICS         |
3915                                                            LAYOUT                    |
3916                                                            UPDATE_LAYOUT_SIZE        |
3917                                                            REORDER                   |
3918                                                            ALIGN );
3919 }
3920
3921 void Controller::ClearStyleData()
3922 {
3923   mImpl->mModel->mLogicalModel->mColorRuns.Clear();
3924   mImpl->mModel->mLogicalModel->ClearFontDescriptionRuns();
3925 }
3926
3927 void Controller::ResetCursorPosition( CharacterIndex cursorIndex )
3928 {
3929   // Reset the cursor position
3930   if( NULL != mImpl->mEventData )
3931   {
3932     mImpl->mEventData->mPrimaryCursorPosition = cursorIndex;
3933
3934     // Update the cursor if it's in editing mode.
3935     if( EventData::IsEditingState( mImpl->mEventData->mState )  )
3936     {
3937       mImpl->mEventData->mUpdateCursorPosition = true;
3938     }
3939   }
3940 }
3941
3942 void Controller::ResetScrollPosition()
3943 {
3944   if( NULL != mImpl->mEventData )
3945   {
3946     // Reset the scroll position.
3947     mImpl->mModel->mScrollPosition = Vector2::ZERO;
3948     mImpl->mEventData->mScrollAfterUpdatePosition = true;
3949   }
3950 }
3951
3952 void Controller::SetControlInterface( ControlInterface* controlInterface )
3953 {
3954   mImpl->mControlInterface = controlInterface;
3955 }
3956
3957 bool Controller::ShouldClearFocusOnEscape() const
3958 {
3959   return mImpl->mShouldClearFocusOnEscape;
3960 }
3961
3962 // private : Private contructors & copy operator.
3963
3964 Controller::Controller()
3965 : mImpl( NULL )
3966 {
3967   mImpl = new Controller::Impl( NULL, NULL );
3968 }
3969
3970 Controller::Controller( ControlInterface* controlInterface )
3971 {
3972   mImpl = new Controller::Impl( controlInterface, NULL );
3973 }
3974
3975 Controller::Controller( ControlInterface* controlInterface,
3976                         EditableControlInterface* editableControlInterface )
3977 {
3978   mImpl = new Controller::Impl( controlInterface,
3979                                 editableControlInterface );
3980 }
3981
3982 // The copy constructor and operator are left unimplemented.
3983
3984 // protected : Destructor.
3985
3986 Controller::~Controller()
3987 {
3988   delete mImpl;
3989 }
3990
3991 } // namespace Text
3992
3993 } // namespace Toolkit
3994
3995 } // namespace Dali