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