propagate unhandled key( DALI_KEY_SEARCH )
[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
29 // INTERNAL INCLUDES
30 #include <dali-toolkit/public-api/controls/text-controls/placeholder-properties.h>
31 #include <dali-toolkit/internal/text/bidirectional-support.h>
32 #include <dali-toolkit/internal/text/character-set-conversion.h>
33 #include <dali-toolkit/internal/text/layouts/layout-parameters.h>
34 #include <dali-toolkit/internal/text/markup-processor.h>
35 #include <dali-toolkit/internal/text/multi-language-support.h>
36 #include <dali-toolkit/internal/text/text-controller-impl.h>
37 #include <dali-toolkit/internal/text/text-editable-control-interface.h>
38 #include <dali-toolkit/internal/text/text-font-style.h>
39
40 namespace
41 {
42
43 #if defined(DEBUG_ENABLED)
44   Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
45 #endif
46
47 const float MAX_FLOAT = std::numeric_limits<float>::max();
48
49 const std::string EMPTY_STRING("");
50
51 const char * const PLACEHOLDER_TEXT = "text";
52 const char * const PLACEHOLDER_TEXT_FOCUSED = "textFocused";
53 const char * const PLACEHOLDER_COLOR = "color";
54 const char * const PLACEHOLDER_FONT_FAMILY = "fontFamily";
55 const char * const PLACEHOLDER_FONT_STYLE = "fontStyle";
56 const char * const PLACEHOLDER_POINT_SIZE = "pointSize";
57 const char * const PLACEHOLDER_PIXEL_SIZE = "pixelSize";
58 const char * const PLACEHOLDER_ELLIPSIS = "ellipsis";
59
60 float ConvertToEven( float value )
61 {
62   int intValue(static_cast<int>( value ));
63   return static_cast<float>(intValue % 2 == 0) ? intValue : (intValue + 1);
64 }
65
66 } // namespace
67
68 namespace Dali
69 {
70
71 namespace Toolkit
72 {
73
74 namespace Text
75 {
76
77 /**
78  * @brief Adds a new font description run for the selected text.
79  *
80  * The new font parameters are added after the call to this method.
81  *
82  * @param[in] eventData The event data pointer.
83  * @param[in] logicalModel The logical model where to add the new font description run.
84  * @param[out] startOfSelectedText Index to the first selected character.
85  * @param[out] lengthOfSelectedText Number of selected characters.
86  */
87 FontDescriptionRun& UpdateSelectionFontStyleRun( EventData* eventData,
88                                                  LogicalModelPtr logicalModel,
89                                                  CharacterIndex& startOfSelectedText,
90                                                  Length& lengthOfSelectedText )
91 {
92   const bool handlesCrossed = eventData->mLeftSelectionPosition > eventData->mRightSelectionPosition;
93
94   // Get start and end position of selection
95   startOfSelectedText = handlesCrossed ? eventData->mRightSelectionPosition : eventData->mLeftSelectionPosition;
96   lengthOfSelectedText = ( handlesCrossed ? eventData->mLeftSelectionPosition : eventData->mRightSelectionPosition ) - startOfSelectedText;
97
98   // Add the font run.
99   const VectorBase::SizeType numberOfRuns = logicalModel->mFontDescriptionRuns.Count();
100   logicalModel->mFontDescriptionRuns.Resize( numberOfRuns + 1u );
101
102   FontDescriptionRun& fontDescriptionRun = *( logicalModel->mFontDescriptionRuns.Begin() + numberOfRuns );
103
104   fontDescriptionRun.characterRun.characterIndex = startOfSelectedText;
105   fontDescriptionRun.characterRun.numberOfCharacters = lengthOfSelectedText;
106
107   // Recalculate the selection highlight as the metrics may have changed.
108   eventData->mUpdateLeftSelectionPosition = true;
109   eventData->mUpdateRightSelectionPosition = true;
110   eventData->mUpdateHighlightBox = true;
111
112   return fontDescriptionRun;
113 }
114
115 // public : Constructor.
116
117 ControllerPtr Controller::New()
118 {
119   return ControllerPtr( new Controller() );
120 }
121
122 ControllerPtr Controller::New( ControlInterface* controlInterface )
123 {
124   return ControllerPtr( new Controller( controlInterface ) );
125 }
126
127 ControllerPtr Controller::New( ControlInterface* controlInterface,
128                                EditableControlInterface* editableControlInterface )
129 {
130   return ControllerPtr( new Controller( controlInterface,
131                                         editableControlInterface ) );
132 }
133
134 // public : Configure the text controller.
135
136 void Controller::EnableTextInput( DecoratorPtr decorator )
137 {
138   if( !decorator )
139   {
140     delete mImpl->mEventData;
141     mImpl->mEventData = NULL;
142
143     // Nothing else to do.
144     return;
145   }
146
147   if( NULL == mImpl->mEventData )
148   {
149     mImpl->mEventData = new EventData( decorator );
150   }
151 }
152
153 void Controller::SetGlyphType( TextAbstraction::GlyphType glyphType )
154 {
155   // Metrics for bitmap & vector based glyphs are different
156   mImpl->mMetrics->SetGlyphType( glyphType );
157
158   // Clear the font-specific data
159   ClearFontData();
160
161   mImpl->RequestRelayout();
162 }
163
164 void Controller::SetMarkupProcessorEnabled( bool enable )
165 {
166   mImpl->mMarkupProcessorEnabled = enable;
167 }
168
169 bool Controller::IsMarkupProcessorEnabled() const
170 {
171   return mImpl->mMarkupProcessorEnabled;
172 }
173
174 void Controller::SetAutoScrollEnabled( bool enable )
175 {
176   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 );
177
178   if( mImpl->mLayoutEngine.GetLayout() == Layout::Engine::SINGLE_LINE_BOX )
179   {
180     if( enable )
181     {
182       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled for SINGLE_LINE_BOX\n" );
183       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
184                                                                LAYOUT                    |
185                                                                ALIGN                     |
186                                                                UPDATE_LAYOUT_SIZE        |
187                                                                UPDATE_DIRECTION          |
188                                                                REORDER );
189
190     }
191     else
192     {
193       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled Disabling autoscroll\n");
194       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
195                                                                LAYOUT                    |
196                                                                ALIGN                     |
197                                                                UPDATE_LAYOUT_SIZE        |
198                                                                REORDER );
199     }
200
201     mImpl->mIsAutoScrollEnabled = enable;
202     mImpl->RequestRelayout();
203   }
204   else
205   {
206     DALI_LOG_WARNING( "Attempted AutoScrolling on a non SINGLE_LINE_BOX, request ignored\n" );
207     mImpl->mIsAutoScrollEnabled = false;
208   }
209 }
210
211 bool Controller::IsAutoScrollEnabled() const
212 {
213   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::IsAutoScrollEnabled[%s]\n", mImpl->mIsAutoScrollEnabled?"true":"false" );
214
215   return mImpl->mIsAutoScrollEnabled;
216 }
217
218 CharacterDirection Controller::GetAutoScrollDirection() const
219 {
220   return mImpl->mAutoScrollDirectionRTL;
221 }
222
223 float Controller::GetAutoScrollLineAlignment() const
224 {
225   float offset = 0.f;
226
227   if( mImpl->mModel->mVisualModel &&
228       ( 0u != mImpl->mModel->mVisualModel->mLines.Count() ) )
229   {
230     offset = ( *mImpl->mModel->mVisualModel->mLines.Begin() ).alignmentOffset;
231   }
232
233   return offset;
234 }
235
236 void Controller::SetHorizontalScrollEnabled( bool enable )
237 {
238   if( ( NULL != mImpl->mEventData ) &&
239       mImpl->mEventData->mDecorator )
240   {
241     mImpl->mEventData->mDecorator->SetHorizontalScrollEnabled( enable );
242   }
243 }
244 bool Controller::IsHorizontalScrollEnabled() const
245 {
246   if( ( NULL != mImpl->mEventData ) &&
247       mImpl->mEventData->mDecorator )
248   {
249     return mImpl->mEventData->mDecorator->IsHorizontalScrollEnabled();
250   }
251
252   return false;
253 }
254
255 void Controller::SetVerticalScrollEnabled( bool enable )
256 {
257   if( ( NULL != mImpl->mEventData ) &&
258       mImpl->mEventData->mDecorator )
259   {
260     if( mImpl->mEventData->mDecorator )
261     {
262       mImpl->mEventData->mDecorator->SetVerticalScrollEnabled( enable );
263     }
264   }
265 }
266
267 bool Controller::IsVerticalScrollEnabled() const
268 {
269   if( ( NULL != mImpl->mEventData ) &&
270       mImpl->mEventData->mDecorator )
271   {
272     return mImpl->mEventData->mDecorator->IsVerticalScrollEnabled();
273   }
274
275   return false;
276 }
277
278 void Controller::SetSmoothHandlePanEnabled( bool enable )
279 {
280   if( ( NULL != mImpl->mEventData ) &&
281       mImpl->mEventData->mDecorator )
282   {
283     mImpl->mEventData->mDecorator->SetSmoothHandlePanEnabled( enable );
284   }
285 }
286
287 bool Controller::IsSmoothHandlePanEnabled() const
288 {
289   if( ( NULL != mImpl->mEventData ) &&
290       mImpl->mEventData->mDecorator )
291   {
292     return mImpl->mEventData->mDecorator->IsSmoothHandlePanEnabled();
293   }
294
295   return false;
296 }
297
298 void Controller::SetMaximumNumberOfCharacters( Length maxCharacters )
299 {
300   mImpl->mMaximumNumberOfCharacters = maxCharacters;
301 }
302
303 int Controller::GetMaximumNumberOfCharacters()
304 {
305   return mImpl->mMaximumNumberOfCharacters;
306 }
307
308 void Controller::SetEnableCursorBlink( bool enable )
309 {
310   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "TextInput disabled" );
311
312   if( NULL != mImpl->mEventData )
313   {
314     mImpl->mEventData->mCursorBlinkEnabled = enable;
315
316     if( !enable &&
317         mImpl->mEventData->mDecorator )
318     {
319       mImpl->mEventData->mDecorator->StopCursorBlink();
320     }
321   }
322 }
323
324 bool Controller::GetEnableCursorBlink() const
325 {
326   if( NULL != mImpl->mEventData )
327   {
328     return mImpl->mEventData->mCursorBlinkEnabled;
329   }
330
331   return false;
332 }
333
334 void Controller::SetMultiLineEnabled( bool enable )
335 {
336   const Layout::Engine::Type layout = enable ? Layout::Engine::MULTI_LINE_BOX : Layout::Engine::SINGLE_LINE_BOX;
337
338   if( layout != mImpl->mLayoutEngine.GetLayout() )
339   {
340     // Set the layout type.
341     mImpl->mLayoutEngine.SetLayout( layout );
342
343     // Set the flags to redo the layout operations
344     const OperationsMask layoutOperations =  static_cast<OperationsMask>( LAYOUT             |
345                                                                           UPDATE_LAYOUT_SIZE |
346                                                                           ALIGN              |
347                                                                           REORDER );
348
349     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | layoutOperations );
350
351     mImpl->RequestRelayout();
352   }
353 }
354
355 bool Controller::IsMultiLineEnabled() const
356 {
357   return Layout::Engine::MULTI_LINE_BOX == mImpl->mLayoutEngine.GetLayout();
358 }
359
360 void Controller::SetHorizontalAlignment( Text::HorizontalAlignment::Type alignment )
361 {
362   if( alignment != mImpl->mModel->mHorizontalAlignment )
363   {
364     // Set the alignment.
365     mImpl->mModel->mHorizontalAlignment = alignment;
366
367     // Set the flag to redo the alignment operation.
368     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | ALIGN );
369
370     mImpl->RequestRelayout();
371   }
372 }
373
374 Text::HorizontalAlignment::Type Controller::GetHorizontalAlignment() const
375 {
376   return mImpl->mModel->mHorizontalAlignment;
377 }
378
379 void Controller::SetVerticalAlignment( VerticalAlignment::Type alignment )
380 {
381   if( alignment != mImpl->mModel->mVerticalAlignment )
382   {
383     // Set the alignment.
384     mImpl->mModel->mVerticalAlignment = alignment;
385
386     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | ALIGN );
387
388     mImpl->RequestRelayout();
389   }
390 }
391
392 VerticalAlignment::Type Controller::GetVerticalAlignment() const
393 {
394   return mImpl->mModel->mVerticalAlignment;
395 }
396
397 void Controller::SetLineWrapMode( Text::LineWrap::Mode lineWrapMode )
398 {
399   if( lineWrapMode != mImpl->mModel->mLineWrapMode )
400   {
401     // Set the text wrap mode.
402     mImpl->mModel->mLineWrapMode = lineWrapMode;
403
404
405     // Update Text layout for applying wrap mode
406     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
407                                                              ALIGN                     |
408                                                              LAYOUT                    |
409                                                              UPDATE_LAYOUT_SIZE        |
410                                                              REORDER                   );
411     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
412     mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
413     mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
414
415     // Request relayout
416     mImpl->RequestRelayout();
417   }
418 }
419
420 Text::LineWrap::Mode Controller::GetLineWrapMode() const
421 {
422   return mImpl->mModel->mLineWrapMode;
423 }
424
425 void Controller::SetTextElideEnabled( bool enabled )
426 {
427   mImpl->mModel->mElideEnabled = enabled;
428 }
429
430 bool Controller::IsTextElideEnabled() const
431 {
432   return mImpl->mModel->mElideEnabled;
433 }
434
435 void Controller::SetPlaceholderTextElideEnabled( bool enabled )
436 {
437   mImpl->mEventData->mIsPlaceholderElideEnabled = enabled;
438   mImpl->mEventData->mPlaceholderEllipsisFlag = true;
439
440   // Update placeholder if there is no text
441   if( mImpl->IsShowingPlaceholderText() ||
442       ( 0u == mImpl->mModel->mLogicalModel->mText.Count() ) )
443   {
444     ShowPlaceholderText();
445   }
446 }
447
448 bool Controller::IsPlaceholderTextElideEnabled() const
449 {
450   return mImpl->mEventData->mIsPlaceholderElideEnabled;
451 }
452
453 void Controller::SetSelectionEnabled( bool enabled )
454 {
455   mImpl->mEventData->mSelectionEnabled = enabled;
456 }
457
458 bool Controller::IsSelectionEnabled() const
459 {
460   return mImpl->mEventData->mSelectionEnabled;
461 }
462
463 // public : Update
464
465 void Controller::SetText( const std::string& text )
466 {
467   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SetText\n" );
468
469   // Reset keyboard as text changed
470   mImpl->ResetImfManager();
471
472   // Remove the previously set text and style.
473   ResetText();
474
475   // Remove the style.
476   ClearStyleData();
477
478   CharacterIndex lastCursorIndex = 0u;
479
480   if( NULL != mImpl->mEventData )
481   {
482     // If popup shown then hide it by switching to Editing state
483     if( ( EventData::SELECTING == mImpl->mEventData->mState )          ||
484         ( EventData::EDITING_WITH_POPUP == mImpl->mEventData->mState ) ||
485         ( EventData::EDITING_WITH_GRAB_HANDLE == mImpl->mEventData->mState ) ||
486         ( EventData::EDITING_WITH_PASTE_POPUP == mImpl->mEventData->mState ) )
487     {
488       mImpl->ChangeState( EventData::EDITING );
489     }
490   }
491
492   if( !text.empty() )
493   {
494     mImpl->mModel->mVisualModel->SetTextColor( mImpl->mTextColor );
495
496     MarkupProcessData markupProcessData( mImpl->mModel->mLogicalModel->mColorRuns,
497                                          mImpl->mModel->mLogicalModel->mFontDescriptionRuns );
498
499     Length textSize = 0u;
500     const uint8_t* utf8 = NULL;
501     if( mImpl->mMarkupProcessorEnabled )
502     {
503       ProcessMarkupString( text, markupProcessData );
504       textSize = markupProcessData.markupProcessedText.size();
505
506       // This is a bit horrible but std::string returns a (signed) char*
507       utf8 = reinterpret_cast<const uint8_t*>( markupProcessData.markupProcessedText.c_str() );
508     }
509     else
510     {
511       textSize = text.size();
512
513       // This is a bit horrible but std::string returns a (signed) char*
514       utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
515     }
516
517     //  Convert text into UTF-32
518     Vector<Character>& utf32Characters = mImpl->mModel->mLogicalModel->mText;
519     utf32Characters.Resize( textSize );
520
521     // Transform a text array encoded in utf8 into an array encoded in utf32.
522     // It returns the actual number of characters.
523     Length characterCount = Utf8ToUtf32( utf8, textSize, utf32Characters.Begin() );
524     utf32Characters.Resize( characterCount );
525
526     DALI_ASSERT_DEBUG( textSize >= characterCount && "Invalid UTF32 conversion length" );
527     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SetText %p UTF8 size %d, UTF32 size %d\n", this, textSize, mImpl->mModel->mLogicalModel->mText.Count() );
528
529     // The characters to be added.
530     mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
531
532     // To reset the cursor position
533     lastCursorIndex = characterCount;
534
535     // Update the rest of the model during size negotiation
536     mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
537
538     // The natural size needs to be re-calculated.
539     mImpl->mRecalculateNaturalSize = true;
540
541     // Apply modifications to the model
542     mImpl->mOperationsPending = ALL_OPERATIONS;
543   }
544   else
545   {
546     ShowPlaceholderText();
547   }
548
549   // Resets the cursor position.
550   ResetCursorPosition( lastCursorIndex );
551
552   // Scrolls the text to make the cursor visible.
553   ResetScrollPosition();
554
555   mImpl->RequestRelayout();
556
557   if( NULL != mImpl->mEventData )
558   {
559     // Cancel previously queued events
560     mImpl->mEventData->mEventQueue.clear();
561   }
562
563   // Do this last since it provides callbacks into application code.
564   if( NULL != mImpl->mEditableControlInterface )
565   {
566     mImpl->mEditableControlInterface->TextChanged();
567   }
568 }
569
570 void Controller::GetText( std::string& text ) const
571 {
572   if( !mImpl->IsShowingPlaceholderText() )
573   {
574     // Retrieves the text string.
575     mImpl->GetText( 0u, text );
576   }
577   else
578   {
579     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::GetText %p empty (but showing placeholder)\n", this );
580   }
581 }
582
583 void Controller::SetPlaceholderText( PlaceholderType type, const std::string& text )
584 {
585   if( NULL != mImpl->mEventData )
586   {
587     if( PLACEHOLDER_TYPE_INACTIVE == type )
588     {
589       mImpl->mEventData->mPlaceholderTextInactive = text;
590     }
591     else
592     {
593       mImpl->mEventData->mPlaceholderTextActive = text;
594     }
595
596     // Update placeholder if there is no text
597     if( mImpl->IsShowingPlaceholderText() ||
598         ( 0u == mImpl->mModel->mLogicalModel->mText.Count() ) )
599     {
600       ShowPlaceholderText();
601     }
602   }
603 }
604
605 void Controller::GetPlaceholderText( PlaceholderType type, std::string& text ) const
606 {
607   if( NULL != mImpl->mEventData )
608   {
609     if( PLACEHOLDER_TYPE_INACTIVE == type )
610     {
611       text = mImpl->mEventData->mPlaceholderTextInactive;
612     }
613     else
614     {
615       text = mImpl->mEventData->mPlaceholderTextActive;
616     }
617   }
618 }
619
620 void Controller::UpdateAfterFontChange( const std::string& newDefaultFont )
621 {
622   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::UpdateAfterFontChange\n");
623
624   if( !mImpl->mFontDefaults->familyDefined ) // If user defined font then should not update when system font changes
625   {
626     DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::UpdateAfterFontChange newDefaultFont(%s)\n", newDefaultFont.c_str() );
627     mImpl->mFontDefaults->mFontDescription.family = newDefaultFont;
628
629     ClearFontData();
630
631     mImpl->RequestRelayout();
632   }
633 }
634
635 // public : Default style & Input style
636
637 void Controller::SetDefaultFontFamily( const std::string& defaultFontFamily )
638 {
639   if( NULL == mImpl->mFontDefaults )
640   {
641     mImpl->mFontDefaults = new FontDefaults();
642   }
643
644   mImpl->mFontDefaults->mFontDescription.family = defaultFontFamily;
645   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetDefaultFontFamily %s\n", defaultFontFamily.c_str());
646   mImpl->mFontDefaults->familyDefined = !defaultFontFamily.empty();
647
648   // Clear the font-specific data
649   ClearFontData();
650
651   mImpl->RequestRelayout();
652 }
653
654 const std::string& Controller::GetDefaultFontFamily() const
655 {
656   if( NULL != mImpl->mFontDefaults )
657   {
658     return mImpl->mFontDefaults->mFontDescription.family;
659   }
660
661   return EMPTY_STRING;
662 }
663
664 void Controller::SetPlaceholderFontFamily( const std::string& placeholderTextFontFamily )
665 {
666   if( NULL != mImpl->mEventData )
667   {
668     if( NULL == mImpl->mEventData->mPlaceholderFont )
669     {
670       mImpl->mEventData->mPlaceholderFont = new FontDefaults();
671     }
672
673     mImpl->mEventData->mPlaceholderFont->mFontDescription.family = placeholderTextFontFamily;
674     DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetPlaceholderFontFamily %s\n", placeholderTextFontFamily.c_str());
675     mImpl->mEventData->mPlaceholderFont->familyDefined = !placeholderTextFontFamily.empty();
676
677     mImpl->RequestRelayout();
678   }
679 }
680
681 const std::string& Controller::GetPlaceholderFontFamily() const
682 {
683   if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
684   {
685     return mImpl->mEventData->mPlaceholderFont->mFontDescription.family;
686   }
687
688   return EMPTY_STRING;
689 }
690
691 void Controller::SetDefaultFontWeight( FontWeight weight )
692 {
693   if( NULL == mImpl->mFontDefaults )
694   {
695     mImpl->mFontDefaults = new FontDefaults();
696   }
697
698   mImpl->mFontDefaults->mFontDescription.weight = weight;
699   mImpl->mFontDefaults->weightDefined = true;
700
701   // Clear the font-specific data
702   ClearFontData();
703
704   mImpl->RequestRelayout();
705 }
706
707 bool Controller::IsDefaultFontWeightDefined() const
708 {
709   if( NULL != mImpl->mFontDefaults )
710   {
711     return mImpl->mFontDefaults->weightDefined;
712   }
713
714   return false;
715 }
716
717 FontWeight Controller::GetDefaultFontWeight() const
718 {
719   if( NULL != mImpl->mFontDefaults )
720   {
721     return mImpl->mFontDefaults->mFontDescription.weight;
722   }
723
724   return TextAbstraction::FontWeight::NORMAL;
725 }
726
727 void Controller::SetPlaceholderTextFontWeight( FontWeight weight )
728 {
729   if( NULL != mImpl->mEventData )
730   {
731     if( NULL == mImpl->mEventData->mPlaceholderFont )
732     {
733       mImpl->mEventData->mPlaceholderFont = new FontDefaults();
734     }
735
736     mImpl->mEventData->mPlaceholderFont->mFontDescription.weight = weight;
737     mImpl->mEventData->mPlaceholderFont->weightDefined = true;
738
739     mImpl->RequestRelayout();
740   }
741 }
742
743 bool Controller::IsPlaceholderTextFontWeightDefined() const
744 {
745   if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
746   {
747     return mImpl->mEventData->mPlaceholderFont->weightDefined;
748   }
749   return false;
750 }
751
752 FontWeight Controller::GetPlaceholderTextFontWeight() const
753 {
754   if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
755   {
756     return mImpl->mEventData->mPlaceholderFont->mFontDescription.weight;
757   }
758
759   return TextAbstraction::FontWeight::NORMAL;
760 }
761
762 void Controller::SetDefaultFontWidth( FontWidth width )
763 {
764   if( NULL == mImpl->mFontDefaults )
765   {
766     mImpl->mFontDefaults = new FontDefaults();
767   }
768
769   mImpl->mFontDefaults->mFontDescription.width = width;
770   mImpl->mFontDefaults->widthDefined = true;
771
772   // Clear the font-specific data
773   ClearFontData();
774
775   mImpl->RequestRelayout();
776 }
777
778 bool Controller::IsDefaultFontWidthDefined() const
779 {
780   if( NULL != mImpl->mFontDefaults )
781   {
782     return mImpl->mFontDefaults->widthDefined;
783   }
784
785   return false;
786 }
787
788 FontWidth Controller::GetDefaultFontWidth() const
789 {
790   if( NULL != mImpl->mFontDefaults )
791   {
792     return mImpl->mFontDefaults->mFontDescription.width;
793   }
794
795   return TextAbstraction::FontWidth::NORMAL;
796 }
797
798 void Controller::SetPlaceholderTextFontWidth( FontWidth width )
799 {
800   if( NULL != mImpl->mEventData )
801   {
802     if( NULL == mImpl->mEventData->mPlaceholderFont )
803     {
804       mImpl->mEventData->mPlaceholderFont = new FontDefaults();
805     }
806
807     mImpl->mEventData->mPlaceholderFont->mFontDescription.width = width;
808     mImpl->mEventData->mPlaceholderFont->widthDefined = true;
809
810     mImpl->RequestRelayout();
811   }
812 }
813
814 bool Controller::IsPlaceholderTextFontWidthDefined() const
815 {
816   if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
817   {
818     return mImpl->mEventData->mPlaceholderFont->widthDefined;
819   }
820   return false;
821 }
822
823 FontWidth Controller::GetPlaceholderTextFontWidth() const
824 {
825   if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
826   {
827     return mImpl->mEventData->mPlaceholderFont->mFontDescription.width;
828   }
829
830   return TextAbstraction::FontWidth::NORMAL;
831 }
832
833 void Controller::SetDefaultFontSlant( FontSlant slant )
834 {
835   if( NULL == mImpl->mFontDefaults )
836   {
837     mImpl->mFontDefaults = new FontDefaults();
838   }
839
840   mImpl->mFontDefaults->mFontDescription.slant = slant;
841   mImpl->mFontDefaults->slantDefined = true;
842
843   // Clear the font-specific data
844   ClearFontData();
845
846   mImpl->RequestRelayout();
847 }
848
849 bool Controller::IsDefaultFontSlantDefined() const
850 {
851   if( NULL != mImpl->mFontDefaults )
852   {
853     return mImpl->mFontDefaults->slantDefined;
854   }
855   return false;
856 }
857
858 FontSlant Controller::GetDefaultFontSlant() const
859 {
860   if( NULL != mImpl->mFontDefaults )
861   {
862     return mImpl->mFontDefaults->mFontDescription.slant;
863   }
864
865   return TextAbstraction::FontSlant::NORMAL;
866 }
867
868 void Controller::SetPlaceholderTextFontSlant( FontSlant slant )
869 {
870   if( NULL != mImpl->mEventData )
871   {
872     if( NULL == mImpl->mEventData->mPlaceholderFont )
873     {
874       mImpl->mEventData->mPlaceholderFont = new FontDefaults();
875     }
876
877     mImpl->mEventData->mPlaceholderFont->mFontDescription.slant = slant;
878     mImpl->mEventData->mPlaceholderFont->slantDefined = true;
879
880     mImpl->RequestRelayout();
881   }
882 }
883
884 bool Controller::IsPlaceholderTextFontSlantDefined() const
885 {
886   if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
887   {
888     return mImpl->mEventData->mPlaceholderFont->slantDefined;
889   }
890   return false;
891 }
892
893 FontSlant Controller::GetPlaceholderTextFontSlant() const
894 {
895   if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
896   {
897     return mImpl->mEventData->mPlaceholderFont->mFontDescription.slant;
898   }
899
900   return TextAbstraction::FontSlant::NORMAL;
901 }
902
903 void Controller::SetDefaultFontSize( float fontSize, FontSizeType type )
904 {
905   if( NULL == mImpl->mFontDefaults )
906   {
907     mImpl->mFontDefaults = new FontDefaults();
908   }
909
910   switch( type )
911   {
912     case POINT_SIZE:
913     {
914       mImpl->mFontDefaults->mDefaultPointSize = fontSize;
915       mImpl->mFontDefaults->sizeDefined = true;
916       break;
917     }
918     case PIXEL_SIZE:
919     {
920       // Point size = Pixel size * 72.f / DPI
921       unsigned int horizontalDpi = 0u;
922       unsigned int verticalDpi = 0u;
923       TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
924       fontClient.GetDpi( horizontalDpi, verticalDpi );
925
926       mImpl->mFontDefaults->mDefaultPointSize = ( fontSize * 72.f ) / static_cast< float >( horizontalDpi );
927       mImpl->mFontDefaults->sizeDefined = true;
928       break;
929     }
930   }
931
932   // Clear the font-specific data
933   ClearFontData();
934
935   mImpl->RequestRelayout();
936 }
937
938 float Controller::GetDefaultFontSize( FontSizeType type ) const
939 {
940   float value = 0.0f;
941   if( NULL != mImpl->mFontDefaults )
942   {
943     switch( type )
944     {
945       case POINT_SIZE:
946       {
947         value = mImpl->mFontDefaults->mDefaultPointSize;
948         break;
949       }
950       case PIXEL_SIZE:
951       {
952         // Pixel size = Point size * DPI / 72.f
953         unsigned int horizontalDpi = 0u;
954         unsigned int verticalDpi = 0u;
955         TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
956         fontClient.GetDpi( horizontalDpi, verticalDpi );
957
958         value = mImpl->mFontDefaults->mDefaultPointSize * static_cast< float >( horizontalDpi ) / 72.f;
959         break;
960       }
961     }
962     return value;
963   }
964
965   return value;
966 }
967
968 void Controller::SetPlaceholderTextFontSize( float fontSize, FontSizeType type )
969 {
970   if( NULL != mImpl->mEventData )
971   {
972     if( NULL == mImpl->mEventData->mPlaceholderFont )
973     {
974       mImpl->mEventData->mPlaceholderFont = new FontDefaults();
975     }
976
977     switch( type )
978     {
979       case POINT_SIZE:
980       {
981         mImpl->mEventData->mPlaceholderFont->mDefaultPointSize = fontSize;
982         mImpl->mEventData->mPlaceholderFont->sizeDefined = true;
983         mImpl->mEventData->mIsPlaceholderPixelSize = false; // Font size flag
984         break;
985       }
986       case PIXEL_SIZE:
987       {
988         // Point size = Pixel size * 72.f / DPI
989         unsigned int horizontalDpi = 0u;
990         unsigned int verticalDpi = 0u;
991         TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
992         fontClient.GetDpi( horizontalDpi, verticalDpi );
993
994         mImpl->mEventData->mPlaceholderFont->mDefaultPointSize = ( fontSize * 72.f ) / static_cast< float >( horizontalDpi );
995         mImpl->mEventData->mPlaceholderFont->sizeDefined = true;
996         mImpl->mEventData->mIsPlaceholderPixelSize = true; // Font size flag
997         break;
998       }
999     }
1000
1001     mImpl->RequestRelayout();
1002   }
1003 }
1004
1005 float Controller::GetPlaceholderTextFontSize( FontSizeType type ) const
1006 {
1007   float value = 0.0f;
1008   if( NULL != mImpl->mEventData )
1009   {
1010     switch( type )
1011     {
1012       case POINT_SIZE:
1013       {
1014         if( NULL != mImpl->mEventData->mPlaceholderFont )
1015         {
1016           value = mImpl->mEventData->mPlaceholderFont->mDefaultPointSize;
1017         }
1018         else
1019         {
1020           // If the placeholder text font size is not set, then return the default font size.
1021           value = GetDefaultFontSize( POINT_SIZE );
1022         }
1023         break;
1024       }
1025       case PIXEL_SIZE:
1026       {
1027         if( NULL != mImpl->mEventData->mPlaceholderFont )
1028         {
1029           // Pixel size = Point size * DPI / 72.f
1030           unsigned int horizontalDpi = 0u;
1031           unsigned int verticalDpi = 0u;
1032           TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
1033           fontClient.GetDpi( horizontalDpi, verticalDpi );
1034
1035           value = mImpl->mEventData->mPlaceholderFont->mDefaultPointSize * static_cast< float >( horizontalDpi ) / 72.f;
1036         }
1037         else
1038         {
1039           // If the placeholder text font size is not set, then return the default font size.
1040           value = GetDefaultFontSize( PIXEL_SIZE );
1041         }
1042         break;
1043       }
1044     }
1045     return value;
1046   }
1047
1048   return value;
1049 }
1050
1051 void Controller::SetDefaultColor( const Vector4& color )
1052 {
1053   mImpl->mTextColor = color;
1054
1055   if( !mImpl->IsShowingPlaceholderText() )
1056   {
1057     mImpl->mModel->mVisualModel->SetTextColor( color );
1058
1059     mImpl->RequestRelayout();
1060   }
1061 }
1062
1063 const Vector4& Controller::GetDefaultColor() const
1064 {
1065   return mImpl->mTextColor;
1066 }
1067
1068 void Controller::SetPlaceholderTextColor( const Vector4& textColor )
1069 {
1070   if( NULL != mImpl->mEventData )
1071   {
1072     mImpl->mEventData->mPlaceholderTextColor = textColor;
1073   }
1074
1075   if( mImpl->IsShowingPlaceholderText() )
1076   {
1077     mImpl->mModel->mVisualModel->SetTextColor( textColor );
1078     mImpl->RequestRelayout();
1079   }
1080 }
1081
1082 const Vector4& Controller::GetPlaceholderTextColor() const
1083 {
1084   if( NULL != mImpl->mEventData )
1085   {
1086     return mImpl->mEventData->mPlaceholderTextColor;
1087   }
1088
1089   return Color::BLACK;
1090 }
1091
1092 void Controller::SetShadowOffset( const Vector2& shadowOffset )
1093 {
1094   mImpl->mModel->mVisualModel->SetShadowOffset( shadowOffset );
1095
1096   mImpl->RequestRelayout();
1097 }
1098
1099 const Vector2& Controller::GetShadowOffset() const
1100 {
1101   return mImpl->mModel->mVisualModel->GetShadowOffset();
1102 }
1103
1104 void Controller::SetShadowColor( const Vector4& shadowColor )
1105 {
1106   mImpl->mModel->mVisualModel->SetShadowColor( shadowColor );
1107
1108   mImpl->RequestRelayout();
1109 }
1110
1111 const Vector4& Controller::GetShadowColor() const
1112 {
1113   return mImpl->mModel->mVisualModel->GetShadowColor();
1114 }
1115
1116 void Controller::SetUnderlineColor( const Vector4& color )
1117 {
1118   mImpl->mModel->mVisualModel->SetUnderlineColor( color );
1119
1120   mImpl->RequestRelayout();
1121 }
1122
1123 const Vector4& Controller::GetUnderlineColor() const
1124 {
1125   return mImpl->mModel->mVisualModel->GetUnderlineColor();
1126 }
1127
1128 void Controller::SetUnderlineEnabled( bool enabled )
1129 {
1130   mImpl->mModel->mVisualModel->SetUnderlineEnabled( enabled );
1131
1132   mImpl->RequestRelayout();
1133 }
1134
1135 bool Controller::IsUnderlineEnabled() const
1136 {
1137   return mImpl->mModel->mVisualModel->IsUnderlineEnabled();
1138 }
1139
1140 void Controller::SetUnderlineHeight( float height )
1141 {
1142   mImpl->mModel->mVisualModel->SetUnderlineHeight( height );
1143
1144   mImpl->RequestRelayout();
1145 }
1146
1147 float Controller::GetUnderlineHeight() const
1148 {
1149   return mImpl->mModel->mVisualModel->GetUnderlineHeight();
1150 }
1151
1152 void Controller::SetOutlineColor( const Vector4& color )
1153 {
1154   mImpl->mModel->mVisualModel->SetOutlineColor( color );
1155
1156   mImpl->RequestRelayout();
1157 }
1158
1159 const Vector4& Controller::GetOutlineColor() const
1160 {
1161   return mImpl->mModel->mVisualModel->GetOutlineColor();
1162 }
1163
1164 void Controller::SetOutlineWidth( float width )
1165 {
1166   mImpl->mModel->mVisualModel->SetOutlineWidth( width );
1167
1168   mImpl->RequestRelayout();
1169 }
1170
1171 float Controller::GetOutlineWidth() const
1172 {
1173   return mImpl->mModel->mVisualModel->GetOutlineWidth();
1174 }
1175
1176 void Controller::SetDefaultEmbossProperties( const std::string& embossProperties )
1177 {
1178   if( NULL == mImpl->mEmbossDefaults )
1179   {
1180     mImpl->mEmbossDefaults = new EmbossDefaults();
1181   }
1182
1183   mImpl->mEmbossDefaults->properties = embossProperties;
1184 }
1185
1186 const std::string& Controller::GetDefaultEmbossProperties() const
1187 {
1188   if( NULL != mImpl->mEmbossDefaults )
1189   {
1190     return mImpl->mEmbossDefaults->properties;
1191   }
1192
1193   return EMPTY_STRING;
1194 }
1195
1196 void Controller::SetDefaultOutlineProperties( const std::string& outlineProperties )
1197 {
1198   if( NULL == mImpl->mOutlineDefaults )
1199   {
1200     mImpl->mOutlineDefaults = new OutlineDefaults();
1201   }
1202
1203   mImpl->mOutlineDefaults->properties = outlineProperties;
1204 }
1205
1206 const std::string& Controller::GetDefaultOutlineProperties() const
1207 {
1208   if( NULL != mImpl->mOutlineDefaults )
1209   {
1210     return mImpl->mOutlineDefaults->properties;
1211   }
1212
1213   return EMPTY_STRING;
1214 }
1215
1216 void Controller::SetDefaultLineSpacing( float lineSpacing )
1217 {
1218   //TODO finish implementation
1219   mImpl->mLayoutEngine.SetDefaultLineSpacing( lineSpacing );
1220 }
1221
1222 float Controller::GetDefaultLineSpacing() const
1223 {
1224   return mImpl->mLayoutEngine.GetDefaultLineSpacing();
1225 }
1226
1227 void Controller::SetInputColor( const Vector4& color )
1228 {
1229   if( NULL != mImpl->mEventData )
1230   {
1231     mImpl->mEventData->mInputStyle.textColor = color;
1232     mImpl->mEventData->mInputStyle.isDefaultColor = false;
1233
1234     if( EventData::SELECTING == mImpl->mEventData->mState )
1235     {
1236       const bool handlesCrossed = mImpl->mEventData->mLeftSelectionPosition > mImpl->mEventData->mRightSelectionPosition;
1237
1238       // Get start and end position of selection
1239       const CharacterIndex startOfSelectedText = handlesCrossed ? mImpl->mEventData->mRightSelectionPosition : mImpl->mEventData->mLeftSelectionPosition;
1240       const Length lengthOfSelectedText = ( handlesCrossed ? mImpl->mEventData->mLeftSelectionPosition : mImpl->mEventData->mRightSelectionPosition ) - startOfSelectedText;
1241
1242       // Add the color run.
1243       const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mColorRuns.Count();
1244       mImpl->mModel->mLogicalModel->mColorRuns.Resize( numberOfRuns + 1u );
1245
1246       ColorRun& colorRun = *( mImpl->mModel->mLogicalModel->mColorRuns.Begin() + numberOfRuns );
1247       colorRun.color = color;
1248       colorRun.characterRun.characterIndex = startOfSelectedText;
1249       colorRun.characterRun.numberOfCharacters = lengthOfSelectedText;
1250
1251       // Request to relayout.
1252       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | COLOR );
1253       mImpl->RequestRelayout();
1254
1255       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1256       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1257       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1258     }
1259   }
1260 }
1261
1262 const Vector4& Controller::GetInputColor() const
1263 {
1264   if( NULL != mImpl->mEventData )
1265   {
1266     return mImpl->mEventData->mInputStyle.textColor;
1267   }
1268
1269   // Return the default text's color if there is no EventData.
1270   return mImpl->mTextColor;
1271
1272 }
1273
1274 void Controller::SetInputFontFamily( const std::string& fontFamily )
1275 {
1276   if( NULL != mImpl->mEventData )
1277   {
1278     mImpl->mEventData->mInputStyle.familyName = fontFamily;
1279     mImpl->mEventData->mInputStyle.isFamilyDefined = true;
1280
1281     if( EventData::SELECTING == mImpl->mEventData->mState )
1282     {
1283       CharacterIndex startOfSelectedText = 0u;
1284       Length lengthOfSelectedText = 0u;
1285       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
1286                                                                             mImpl->mModel->mLogicalModel,
1287                                                                             startOfSelectedText,
1288                                                                             lengthOfSelectedText );
1289
1290       fontDescriptionRun.familyLength = fontFamily.size();
1291       fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
1292       memcpy( fontDescriptionRun.familyName, fontFamily.c_str(), fontDescriptionRun.familyLength );
1293       fontDescriptionRun.familyDefined = true;
1294
1295       // The memory allocated for the font family name is freed when the font description is removed from the logical model.
1296
1297       // Request to relayout.
1298       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1299                                                                VALIDATE_FONTS            |
1300                                                                SHAPE_TEXT                |
1301                                                                GET_GLYPH_METRICS         |
1302                                                                LAYOUT                    |
1303                                                                UPDATE_LAYOUT_SIZE        |
1304                                                                REORDER                   |
1305                                                                ALIGN );
1306       mImpl->mRecalculateNaturalSize = true;
1307       mImpl->RequestRelayout();
1308
1309       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1310       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1311       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1312
1313       // As the font changes, recalculate the handle positions is needed.
1314       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
1315       mImpl->mEventData->mUpdateRightSelectionPosition = true;
1316       mImpl->mEventData->mUpdateHighlightBox = true;
1317       mImpl->mEventData->mScrollAfterUpdatePosition = true;
1318     }
1319   }
1320 }
1321
1322 const std::string& Controller::GetInputFontFamily() const
1323 {
1324   if( NULL != mImpl->mEventData )
1325   {
1326     return mImpl->mEventData->mInputStyle.familyName;
1327   }
1328
1329   // Return the default font's family if there is no EventData.
1330   return GetDefaultFontFamily();
1331 }
1332
1333 void Controller::SetInputFontWeight( FontWeight weight )
1334 {
1335   if( NULL != mImpl->mEventData )
1336   {
1337     mImpl->mEventData->mInputStyle.weight = weight;
1338     mImpl->mEventData->mInputStyle.isWeightDefined = true;
1339
1340     if( EventData::SELECTING == mImpl->mEventData->mState )
1341     {
1342       CharacterIndex startOfSelectedText = 0u;
1343       Length lengthOfSelectedText = 0u;
1344       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
1345                                                                             mImpl->mModel->mLogicalModel,
1346                                                                             startOfSelectedText,
1347                                                                             lengthOfSelectedText );
1348
1349       fontDescriptionRun.weight = weight;
1350       fontDescriptionRun.weightDefined = true;
1351
1352       // Request to relayout.
1353       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1354                                                                VALIDATE_FONTS            |
1355                                                                SHAPE_TEXT                |
1356                                                                GET_GLYPH_METRICS         |
1357                                                                LAYOUT                    |
1358                                                                UPDATE_LAYOUT_SIZE        |
1359                                                                REORDER                   |
1360                                                                ALIGN );
1361       mImpl->mRecalculateNaturalSize = true;
1362       mImpl->RequestRelayout();
1363
1364       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1365       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1366       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1367
1368       // As the font might change, recalculate the handle positions is needed.
1369       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
1370       mImpl->mEventData->mUpdateRightSelectionPosition = true;
1371       mImpl->mEventData->mUpdateHighlightBox = true;
1372       mImpl->mEventData->mScrollAfterUpdatePosition = true;
1373     }
1374   }
1375 }
1376
1377 bool Controller::IsInputFontWeightDefined() const
1378 {
1379   bool defined = false;
1380
1381   if( NULL != mImpl->mEventData )
1382   {
1383     defined = mImpl->mEventData->mInputStyle.isWeightDefined;
1384   }
1385
1386   return defined;
1387 }
1388
1389 FontWeight Controller::GetInputFontWeight() const
1390 {
1391   if( NULL != mImpl->mEventData )
1392   {
1393     return mImpl->mEventData->mInputStyle.weight;
1394   }
1395
1396   return GetDefaultFontWeight();
1397 }
1398
1399 void Controller::SetInputFontWidth( FontWidth width )
1400 {
1401   if( NULL != mImpl->mEventData )
1402   {
1403     mImpl->mEventData->mInputStyle.width = width;
1404     mImpl->mEventData->mInputStyle.isWidthDefined = true;
1405
1406     if( EventData::SELECTING == mImpl->mEventData->mState )
1407     {
1408       CharacterIndex startOfSelectedText = 0u;
1409       Length lengthOfSelectedText = 0u;
1410       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
1411                                                                             mImpl->mModel->mLogicalModel,
1412                                                                             startOfSelectedText,
1413                                                                             lengthOfSelectedText );
1414
1415       fontDescriptionRun.width = width;
1416       fontDescriptionRun.widthDefined = true;
1417
1418       // Request to relayout.
1419       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1420                                                                VALIDATE_FONTS            |
1421                                                                SHAPE_TEXT                |
1422                                                                GET_GLYPH_METRICS         |
1423                                                                LAYOUT                    |
1424                                                                UPDATE_LAYOUT_SIZE        |
1425                                                                REORDER                   |
1426                                                                ALIGN );
1427       mImpl->mRecalculateNaturalSize = true;
1428       mImpl->RequestRelayout();
1429
1430       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1431       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1432       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1433
1434       // As the font might change, recalculate the handle positions is needed.
1435       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
1436       mImpl->mEventData->mUpdateRightSelectionPosition = true;
1437       mImpl->mEventData->mUpdateHighlightBox = true;
1438       mImpl->mEventData->mScrollAfterUpdatePosition = true;
1439     }
1440   }
1441 }
1442
1443 bool Controller::IsInputFontWidthDefined() const
1444 {
1445   bool defined = false;
1446
1447   if( NULL != mImpl->mEventData )
1448   {
1449     defined = mImpl->mEventData->mInputStyle.isWidthDefined;
1450   }
1451
1452   return defined;
1453 }
1454
1455 FontWidth Controller::GetInputFontWidth() const
1456 {
1457   if( NULL != mImpl->mEventData )
1458   {
1459     return mImpl->mEventData->mInputStyle.width;
1460   }
1461
1462   return GetDefaultFontWidth();
1463 }
1464
1465 void Controller::SetInputFontSlant( FontSlant slant )
1466 {
1467   if( NULL != mImpl->mEventData )
1468   {
1469     mImpl->mEventData->mInputStyle.slant = slant;
1470     mImpl->mEventData->mInputStyle.isSlantDefined = true;
1471
1472     if( EventData::SELECTING == mImpl->mEventData->mState )
1473     {
1474       CharacterIndex startOfSelectedText = 0u;
1475       Length lengthOfSelectedText = 0u;
1476       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
1477                                                                             mImpl->mModel->mLogicalModel,
1478                                                                             startOfSelectedText,
1479                                                                             lengthOfSelectedText );
1480
1481       fontDescriptionRun.slant = slant;
1482       fontDescriptionRun.slantDefined = true;
1483
1484       // Request to relayout.
1485       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1486                                                                VALIDATE_FONTS            |
1487                                                                SHAPE_TEXT                |
1488                                                                GET_GLYPH_METRICS         |
1489                                                                LAYOUT                    |
1490                                                                UPDATE_LAYOUT_SIZE        |
1491                                                                REORDER                   |
1492                                                                ALIGN );
1493       mImpl->mRecalculateNaturalSize = true;
1494       mImpl->RequestRelayout();
1495
1496       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1497       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1498       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1499
1500       // As the font might change, recalculate the handle positions is needed.
1501       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
1502       mImpl->mEventData->mUpdateRightSelectionPosition = true;
1503       mImpl->mEventData->mUpdateHighlightBox = true;
1504       mImpl->mEventData->mScrollAfterUpdatePosition = true;
1505     }
1506   }
1507 }
1508
1509 bool Controller::IsInputFontSlantDefined() const
1510 {
1511   bool defined = false;
1512
1513   if( NULL != mImpl->mEventData )
1514   {
1515     defined = mImpl->mEventData->mInputStyle.isSlantDefined;
1516   }
1517
1518   return defined;
1519 }
1520
1521 FontSlant Controller::GetInputFontSlant() const
1522 {
1523   if( NULL != mImpl->mEventData )
1524   {
1525     return mImpl->mEventData->mInputStyle.slant;
1526   }
1527
1528   return GetDefaultFontSlant();
1529 }
1530
1531 void Controller::SetInputFontPointSize( float size )
1532 {
1533   if( NULL != mImpl->mEventData )
1534   {
1535     mImpl->mEventData->mInputStyle.size = size;
1536     mImpl->mEventData->mInputStyle.isSizeDefined = true;
1537
1538     if( EventData::SELECTING == mImpl->mEventData->mState )
1539     {
1540       CharacterIndex startOfSelectedText = 0u;
1541       Length lengthOfSelectedText = 0u;
1542       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
1543                                                                             mImpl->mModel->mLogicalModel,
1544                                                                             startOfSelectedText,
1545                                                                             lengthOfSelectedText );
1546
1547       fontDescriptionRun.size = static_cast<PointSize26Dot6>( size * 64.f );
1548       fontDescriptionRun.sizeDefined = true;
1549
1550       // Request to relayout.
1551       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1552                                                                VALIDATE_FONTS            |
1553                                                                SHAPE_TEXT                |
1554                                                                GET_GLYPH_METRICS         |
1555                                                                LAYOUT                    |
1556                                                                UPDATE_LAYOUT_SIZE        |
1557                                                                REORDER                   |
1558                                                                ALIGN );
1559       mImpl->mRecalculateNaturalSize = true;
1560       mImpl->RequestRelayout();
1561
1562       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1563       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1564       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1565
1566       // As the font might change, recalculate the handle positions is needed.
1567       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
1568       mImpl->mEventData->mUpdateRightSelectionPosition = true;
1569       mImpl->mEventData->mUpdateHighlightBox = true;
1570       mImpl->mEventData->mScrollAfterUpdatePosition = true;
1571     }
1572   }
1573 }
1574
1575 float Controller::GetInputFontPointSize() const
1576 {
1577   if( NULL != mImpl->mEventData )
1578   {
1579     return mImpl->mEventData->mInputStyle.size;
1580   }
1581
1582   // Return the default font's point size if there is no EventData.
1583   return GetDefaultFontSize( Text::Controller::POINT_SIZE );
1584 }
1585
1586 void Controller::SetInputLineSpacing( float lineSpacing )
1587 {
1588   if( NULL != mImpl->mEventData )
1589   {
1590     mImpl->mEventData->mInputStyle.lineSpacing = lineSpacing;
1591     mImpl->mEventData->mInputStyle.isLineSpacingDefined = true;
1592   }
1593 }
1594
1595 float Controller::GetInputLineSpacing() const
1596 {
1597   if( NULL != mImpl->mEventData )
1598   {
1599     return mImpl->mEventData->mInputStyle.lineSpacing;
1600   }
1601
1602   return 0.f;
1603 }
1604
1605 void Controller::SetInputShadowProperties( const std::string& shadowProperties )
1606 {
1607   if( NULL != mImpl->mEventData )
1608   {
1609     mImpl->mEventData->mInputStyle.shadowProperties = shadowProperties;
1610   }
1611 }
1612
1613 const std::string& Controller::GetInputShadowProperties() const
1614 {
1615   if( NULL != mImpl->mEventData )
1616   {
1617     return mImpl->mEventData->mInputStyle.shadowProperties;
1618   }
1619
1620   return EMPTY_STRING;
1621 }
1622
1623 void Controller::SetInputUnderlineProperties( const std::string& underlineProperties )
1624 {
1625   if( NULL != mImpl->mEventData )
1626   {
1627     mImpl->mEventData->mInputStyle.underlineProperties = underlineProperties;
1628   }
1629 }
1630
1631 const std::string& Controller::GetInputUnderlineProperties() const
1632 {
1633   if( NULL != mImpl->mEventData )
1634   {
1635     return mImpl->mEventData->mInputStyle.underlineProperties;
1636   }
1637
1638   return EMPTY_STRING;
1639 }
1640
1641 void Controller::SetInputEmbossProperties( const std::string& embossProperties )
1642 {
1643   if( NULL != mImpl->mEventData )
1644   {
1645     mImpl->mEventData->mInputStyle.embossProperties = embossProperties;
1646   }
1647 }
1648
1649 const std::string& Controller::GetInputEmbossProperties() const
1650 {
1651   if( NULL != mImpl->mEventData )
1652   {
1653     return mImpl->mEventData->mInputStyle.embossProperties;
1654   }
1655
1656   return GetDefaultEmbossProperties();
1657 }
1658
1659 void Controller::SetInputOutlineProperties( const std::string& outlineProperties )
1660 {
1661   if( NULL != mImpl->mEventData )
1662   {
1663     mImpl->mEventData->mInputStyle.outlineProperties = outlineProperties;
1664   }
1665 }
1666
1667 const std::string& Controller::GetInputOutlineProperties() const
1668 {
1669   if( NULL != mImpl->mEventData )
1670   {
1671     return mImpl->mEventData->mInputStyle.outlineProperties;
1672   }
1673
1674   return GetDefaultOutlineProperties();
1675 }
1676
1677 void Controller::SetInputModePassword( bool passwordInput )
1678 {
1679   if( NULL != mImpl->mEventData )
1680   {
1681     mImpl->mEventData->mPasswordInput = passwordInput;
1682   }
1683 }
1684
1685 bool Controller::IsInputModePassword()
1686 {
1687   if( NULL != mImpl->mEventData )
1688   {
1689     return mImpl->mEventData->mPasswordInput;
1690   }
1691   return false;
1692 }
1693
1694 void Controller::SetNoTextDoubleTapAction( NoTextTap::Action action )
1695 {
1696   if( NULL != mImpl->mEventData )
1697   {
1698     mImpl->mEventData->mDoubleTapAction = action;
1699   }
1700 }
1701
1702 Controller::NoTextTap::Action Controller::GetNoTextDoubleTapAction() const
1703 {
1704   NoTextTap::Action action = NoTextTap::NO_ACTION;
1705
1706   if( NULL != mImpl->mEventData )
1707   {
1708     action = mImpl->mEventData->mDoubleTapAction;
1709   }
1710
1711   return action;
1712 }
1713
1714 void Controller::SetNoTextLongPressAction( NoTextTap::Action action )
1715 {
1716   if( NULL != mImpl->mEventData )
1717   {
1718     mImpl->mEventData->mLongPressAction = action;
1719   }
1720 }
1721
1722 Controller::NoTextTap::Action Controller::GetNoTextLongPressAction() const
1723 {
1724   NoTextTap::Action action = NoTextTap::NO_ACTION;
1725
1726   if( NULL != mImpl->mEventData )
1727   {
1728     action = mImpl->mEventData->mLongPressAction;
1729   }
1730
1731   return action;
1732 }
1733
1734 bool Controller::IsUnderlineSetByString()
1735 {
1736   return mImpl->mUnderlineSetByString;
1737 }
1738
1739 void Controller::UnderlineSetByString( bool setByString )
1740 {
1741   mImpl->mUnderlineSetByString = setByString;
1742 }
1743
1744 bool Controller::IsShadowSetByString()
1745 {
1746   return mImpl->mShadowSetByString;
1747 }
1748
1749 void Controller::ShadowSetByString( bool setByString )
1750 {
1751   mImpl->mShadowSetByString = setByString;
1752 }
1753
1754 bool Controller::IsOutlineSetByString()
1755 {
1756   return mImpl->mOutlineSetByString;
1757 }
1758
1759 void Controller::OutlineSetByString( bool setByString )
1760 {
1761   mImpl->mOutlineSetByString = setByString;
1762 }
1763
1764 bool Controller::IsFontStyleSetByString()
1765 {
1766   return mImpl->mFontStyleSetByString;
1767 }
1768
1769 void Controller::FontStyleSetByString( bool setByString )
1770 {
1771   mImpl->mFontStyleSetByString = setByString;
1772 }
1773
1774 // public : Queries & retrieves.
1775
1776 Layout::Engine& Controller::GetLayoutEngine()
1777 {
1778   return mImpl->mLayoutEngine;
1779 }
1780
1781 View& Controller::GetView()
1782 {
1783   return mImpl->mView;
1784 }
1785
1786 Vector3 Controller::GetNaturalSize()
1787 {
1788   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetNaturalSize\n" );
1789   Vector3 naturalSize;
1790
1791   // Make sure the model is up-to-date before layouting
1792   ProcessModifyEvents();
1793
1794   if( mImpl->mRecalculateNaturalSize )
1795   {
1796     // Operations that can be done only once until the text changes.
1797     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
1798                                                                            GET_SCRIPTS       |
1799                                                                            VALIDATE_FONTS    |
1800                                                                            GET_LINE_BREAKS   |
1801                                                                            GET_WORD_BREAKS   |
1802                                                                            BIDI_INFO         |
1803                                                                            SHAPE_TEXT        |
1804                                                                            GET_GLYPH_METRICS );
1805
1806     // Set the update info to relayout the whole text.
1807     mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
1808     mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
1809
1810     // Make sure the model is up-to-date before layouting
1811     mImpl->UpdateModel( onlyOnceOperations );
1812
1813     // Layout the text for the new width.
1814     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | LAYOUT | REORDER );
1815
1816     // Store the actual control's size to restore later.
1817     const Size actualControlSize = mImpl->mModel->mVisualModel->mControlSize;
1818
1819     DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
1820                 static_cast<OperationsMask>( onlyOnceOperations |
1821                                              LAYOUT | REORDER ),
1822                 naturalSize.GetVectorXY() );
1823
1824     // Do not do again the only once operations.
1825     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
1826
1827     // Do the size related operations again.
1828     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
1829                                                                         ALIGN  |
1830                                                                         REORDER );
1831     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
1832
1833     // Stores the natural size to avoid recalculate it again
1834     // unless the text/style changes.
1835     mImpl->mModel->mVisualModel->SetNaturalSize( naturalSize.GetVectorXY() );
1836
1837     mImpl->mRecalculateNaturalSize = false;
1838
1839     // Clear the update info. This info will be set the next time the text is updated.
1840     mImpl->mTextUpdateInfo.Clear();
1841
1842     // Restore the actual control's size.
1843     mImpl->mModel->mVisualModel->mControlSize = actualControlSize;
1844
1845     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize calculated %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z );
1846   }
1847   else
1848   {
1849     naturalSize = mImpl->mModel->mVisualModel->GetNaturalSize();
1850
1851     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize cached %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z );
1852   }
1853
1854   naturalSize.x = ConvertToEven( naturalSize.x );
1855   naturalSize.y = ConvertToEven( naturalSize.y );
1856
1857   return naturalSize;
1858 }
1859
1860 float Controller::GetHeightForWidth( float width )
1861 {
1862   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetHeightForWidth %p width %f\n", this, width );
1863   // Make sure the model is up-to-date before layouting
1864   ProcessModifyEvents();
1865
1866   Size layoutSize;
1867   if( fabsf( width - mImpl->mModel->mVisualModel->mControlSize.width ) > Math::MACHINE_EPSILON_1000 ||
1868                                                          mImpl->mTextUpdateInfo.mFullRelayoutNeeded ||
1869                                                          mImpl->mTextUpdateInfo.mClearAll            )
1870   {
1871     // Operations that can be done only once until the text changes.
1872     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
1873                                                                            GET_SCRIPTS       |
1874                                                                            VALIDATE_FONTS    |
1875                                                                            GET_LINE_BREAKS   |
1876                                                                            GET_WORD_BREAKS   |
1877                                                                            BIDI_INFO         |
1878                                                                            SHAPE_TEXT        |
1879                                                                            GET_GLYPH_METRICS );
1880
1881     // Set the update info to relayout the whole text.
1882     mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
1883     mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
1884
1885     // Make sure the model is up-to-date before layouting
1886     mImpl->UpdateModel( onlyOnceOperations );
1887
1888
1889     // Layout the text for the new width.
1890     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | LAYOUT );
1891
1892     // Store the actual control's width.
1893     const float actualControlWidth = mImpl->mModel->mVisualModel->mControlSize.width;
1894
1895     DoRelayout( Size( width, MAX_FLOAT ),
1896                 static_cast<OperationsMask>( onlyOnceOperations |
1897                                              LAYOUT ),
1898                 layoutSize );
1899
1900     // Do not do again the only once operations.
1901     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
1902
1903     // Do the size related operations again.
1904     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
1905                                                                         ALIGN  |
1906                                                                         REORDER );
1907
1908     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
1909
1910     // Clear the update info. This info will be set the next time the text is updated.
1911     mImpl->mTextUpdateInfo.Clear();
1912
1913     // Restore the actual control's width.
1914     mImpl->mModel->mVisualModel->mControlSize.width = actualControlWidth;
1915
1916     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth calculated %f\n", layoutSize.height );
1917   }
1918   else
1919   {
1920     layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
1921     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth cached %f\n", layoutSize.height );
1922   }
1923
1924   return layoutSize.height;
1925 }
1926
1927 int Controller::GetLineCount( float width )
1928 {
1929   GetHeightForWidth( width );
1930   int numberofLines = mImpl->mModel->GetNumberOfLines();
1931   return numberofLines;
1932 }
1933
1934 const ModelInterface* const Controller::GetTextModel() const
1935 {
1936   return mImpl->mModel.Get();
1937 }
1938
1939 float Controller::GetScrollAmountByUserInput()
1940 {
1941   float scrollAmount = 0.0f;
1942
1943   if (NULL != mImpl->mEventData && mImpl->mEventData->mCheckScrollAmount)
1944   {
1945     scrollAmount = mImpl->mModel->mScrollPosition.y -  mImpl->mModel->mScrollPositionLast.y;
1946     mImpl->mEventData->mCheckScrollAmount = false;
1947   }
1948   return scrollAmount;
1949 }
1950
1951 bool Controller::GetTextScrollInfo( float& scrollPosition, float& controlHeight, float& layoutHeight )
1952 {
1953   const Vector2& layout = mImpl->mModel->mVisualModel->GetLayoutSize();
1954   bool isScrolled;
1955
1956   controlHeight = mImpl->mModel->mVisualModel->mControlSize.height;
1957   layoutHeight = layout.height;
1958   scrollPosition = mImpl->mModel->mScrollPosition.y;
1959   isScrolled = !Equals( mImpl->mModel->mScrollPosition.y, mImpl->mModel->mScrollPositionLast.y, Math::MACHINE_EPSILON_1 );
1960   return isScrolled;
1961 }
1962
1963 void Controller::SetHiddenInputOption(const Property::Map& options )
1964 {
1965   if( NULL == mImpl->mHiddenInput )
1966   {
1967     mImpl->mHiddenInput = new HiddenText( this );
1968   }
1969   mImpl->mHiddenInput->SetProperties(options);
1970 }
1971
1972 void Controller::GetHiddenInputOption(Property::Map& options )
1973 {
1974   if( NULL != mImpl->mHiddenInput )
1975   {
1976     mImpl->mHiddenInput->GetProperties(options);
1977   }
1978 }
1979
1980 void Controller::SetPlaceholderProperty( const Property::Map& map )
1981 {
1982   const Property::Map::SizeType count = map.Count();
1983
1984   for( Property::Map::SizeType position = 0; position < count; ++position )
1985   {
1986     KeyValuePair keyValue = map.GetKeyValue( position );
1987     Property::Key& key = keyValue.first;
1988     Property::Value& value = keyValue.second;
1989
1990     if( key == Toolkit::Text::PlaceHolder::Property::TEXT  || key == PLACEHOLDER_TEXT )
1991     {
1992       std::string text = "";
1993       value.Get( text );
1994       SetPlaceholderText( Controller::PLACEHOLDER_TYPE_INACTIVE, text );
1995     }
1996     else if( key == Toolkit::Text::PlaceHolder::Property::TEXT_FOCUSED || key == PLACEHOLDER_TEXT_FOCUSED )
1997     {
1998       std::string text = "";
1999       value.Get( text );
2000       SetPlaceholderText( Controller::PLACEHOLDER_TYPE_ACTIVE, text );
2001     }
2002     else if( key == Toolkit::Text::PlaceHolder::Property::COLOR || key == PLACEHOLDER_COLOR )
2003     {
2004       Vector4 textColor;
2005       value.Get( textColor );
2006       if( GetPlaceholderTextColor() != textColor )
2007       {
2008         SetPlaceholderTextColor( textColor );
2009       }
2010     }
2011     else if( key == Toolkit::Text::PlaceHolder::Property::FONT_FAMILY || key == PLACEHOLDER_FONT_FAMILY )
2012     {
2013       std::string fontFamily = "";
2014       value.Get( fontFamily );
2015       SetPlaceholderFontFamily( fontFamily );
2016     }
2017     else if( key == Toolkit::Text::PlaceHolder::Property::FONT_STYLE || key == PLACEHOLDER_FONT_STYLE )
2018     {
2019       SetFontStyleProperty( this, value, Text::FontStyle::PLACEHOLDER );
2020     }
2021     else if( key == Toolkit::Text::PlaceHolder::Property::POINT_SIZE || key == PLACEHOLDER_POINT_SIZE )
2022     {
2023       float pointSize;
2024       value.Get( pointSize );
2025       if( !Equals( GetPlaceholderTextFontSize( Text::Controller::POINT_SIZE ), pointSize ) )
2026       {
2027         SetPlaceholderTextFontSize( pointSize, Text::Controller::POINT_SIZE );
2028       }
2029     }
2030     else if( key == Toolkit::Text::PlaceHolder::Property::PIXEL_SIZE || key == PLACEHOLDER_PIXEL_SIZE )
2031     {
2032       float pixelSize;
2033       value.Get( pixelSize );
2034       if( !Equals( GetPlaceholderTextFontSize( Text::Controller::PIXEL_SIZE ), pixelSize ) )
2035       {
2036         SetPlaceholderTextFontSize( pixelSize, Text::Controller::PIXEL_SIZE );
2037       }
2038     }
2039     else if( key == Toolkit::Text::PlaceHolder::Property::ELLIPSIS || key == PLACEHOLDER_ELLIPSIS )
2040     {
2041       bool ellipsis;
2042       value.Get( ellipsis );
2043       SetPlaceholderTextElideEnabled( ellipsis );
2044     }
2045   }
2046 }
2047
2048 void Controller::GetPlaceholderProperty( Property::Map& map )
2049 {
2050   if( NULL != mImpl->mEventData )
2051   {
2052     if( !mImpl->mEventData->mPlaceholderTextActive.empty() )
2053     {
2054       map[ Text::PlaceHolder::Property::TEXT_FOCUSED ] = mImpl->mEventData->mPlaceholderTextActive;
2055     }
2056     if( !mImpl->mEventData->mPlaceholderTextInactive.empty() )
2057     {
2058       map[ Text::PlaceHolder::Property::TEXT ] = mImpl->mEventData->mPlaceholderTextInactive;
2059     }
2060
2061     map[ Text::PlaceHolder::Property::COLOR ] = mImpl->mEventData->mPlaceholderTextColor;
2062     map[ Text::PlaceHolder::Property::FONT_FAMILY ] = GetPlaceholderFontFamily();
2063
2064     Property::Value fontStyleMapGet;
2065     GetFontStyleProperty( this, fontStyleMapGet, Text::FontStyle::PLACEHOLDER );
2066     map[ Text::PlaceHolder::Property::FONT_STYLE ] = fontStyleMapGet;
2067
2068     // Choose font size : POINT_SIZE or PIXEL_SIZE
2069     if( !mImpl->mEventData->mIsPlaceholderPixelSize )
2070     {
2071       map[ Text::PlaceHolder::Property::POINT_SIZE ] = GetPlaceholderTextFontSize( Text::Controller::POINT_SIZE );
2072     }
2073     else
2074     {
2075       map[ Text::PlaceHolder::Property::PIXEL_SIZE ] = GetPlaceholderTextFontSize( Text::Controller::PIXEL_SIZE );
2076     }
2077
2078     if( mImpl->mEventData->mPlaceholderEllipsisFlag )
2079     {
2080       map[ Text::PlaceHolder::Property::ELLIPSIS ] = IsPlaceholderTextElideEnabled();
2081     }
2082   }
2083 }
2084
2085 // public : Relayout.
2086
2087 Controller::UpdateTextType Controller::Relayout( const Size& size )
2088 {
2089   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::Relayout %p size %f,%f, autoScroll[%s]\n", this, size.width, size.height, mImpl->mIsAutoScrollEnabled ?"true":"false"  );
2090
2091   UpdateTextType updateTextType = NONE_UPDATED;
2092
2093   if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
2094   {
2095     if( 0u != mImpl->mModel->mVisualModel->mGlyphPositions.Count() )
2096     {
2097       mImpl->mModel->mVisualModel->mGlyphPositions.Clear();
2098       updateTextType = MODEL_UPDATED;
2099     }
2100
2101     // Clear the update info. This info will be set the next time the text is updated.
2102     mImpl->mTextUpdateInfo.Clear();
2103
2104     // Not worth to relayout if width or height is equal to zero.
2105     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout (skipped)\n" );
2106
2107     return updateTextType;
2108   }
2109
2110   // Whether a new size has been set.
2111   const bool newSize = ( size != mImpl->mModel->mVisualModel->mControlSize );
2112
2113   if( newSize )
2114   {
2115     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "new size (previous size %f,%f)\n", mImpl->mModel->mVisualModel->mControlSize.width, mImpl->mModel->mVisualModel->mControlSize.height );
2116
2117     // Layout operations that need to be done if the size changes.
2118     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
2119                                                              LAYOUT                    |
2120                                                              ALIGN                     |
2121                                                              UPDATE_LAYOUT_SIZE        |
2122                                                              REORDER );
2123     // Set the update info to relayout the whole text.
2124     mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
2125     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
2126
2127     // Store the size used to layout the text.
2128     mImpl->mModel->mVisualModel->mControlSize = size;
2129   }
2130
2131   // Whether there are modify events.
2132   if( 0u != mImpl->mModifyEvents.Count() )
2133   {
2134     // Style operations that need to be done if the text is modified.
2135     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
2136                                                              COLOR );
2137   }
2138
2139   // Set the update info to elide the text.
2140   if( mImpl->mModel->mElideEnabled ||
2141       ( ( NULL != mImpl->mEventData ) && mImpl->mEventData->mIsPlaceholderElideEnabled ) )
2142   {
2143     // Update Text layout for applying elided
2144     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
2145                                                              ALIGN                     |
2146                                                              LAYOUT                    |
2147                                                              UPDATE_LAYOUT_SIZE        |
2148                                                              REORDER );
2149     mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
2150     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
2151   }
2152
2153   // Make sure the model is up-to-date before layouting.
2154   ProcessModifyEvents();
2155   bool updated = mImpl->UpdateModel( mImpl->mOperationsPending );
2156
2157   // Layout the text.
2158   Size layoutSize;
2159   updated = DoRelayout( size,
2160                         mImpl->mOperationsPending,
2161                         layoutSize ) || updated;
2162
2163   if( updated )
2164   {
2165     updateTextType = MODEL_UPDATED;
2166   }
2167
2168   // Do not re-do any operation until something changes.
2169   mImpl->mOperationsPending = NO_OPERATION;
2170   mImpl->mModel->mScrollPositionLast = mImpl->mModel->mScrollPosition;
2171
2172   // Whether the text control is editable
2173   const bool isEditable = NULL != mImpl->mEventData;
2174
2175   // Keep the current offset as it will be used to update the decorator's positions (if the size changes).
2176   Vector2 offset;
2177   if( newSize && isEditable )
2178   {
2179     offset = mImpl->mModel->mScrollPosition;
2180   }
2181
2182   if( !isEditable || !IsMultiLineEnabled() )
2183   {
2184     // After doing the text layout, the vertical offset to place the actor in the desired position can be calculated.
2185     CalculateVerticalOffset( size );
2186   }
2187
2188   if( isEditable )
2189   {
2190     if( newSize )
2191     {
2192       // If there is a new size, the scroll position needs to be clamped.
2193       mImpl->ClampHorizontalScroll( layoutSize );
2194
2195       // Update the decorator's positions is needed if there is a new size.
2196       mImpl->mEventData->mDecorator->UpdatePositions( mImpl->mModel->mScrollPosition - offset );
2197     }
2198
2199     // Move the cursor, grab handle etc.
2200     if( mImpl->ProcessInputEvents() )
2201     {
2202       updateTextType = static_cast<UpdateTextType>( updateTextType | DECORATOR_UPDATED );
2203     }
2204   }
2205
2206   // Clear the update info. This info will be set the next time the text is updated.
2207   mImpl->mTextUpdateInfo.Clear();
2208   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout\n" );
2209
2210   return updateTextType;
2211 }
2212
2213 void Controller::RequestRelayout()
2214 {
2215   mImpl->RequestRelayout();
2216 }
2217
2218 // public : Input style change signals.
2219
2220 bool Controller::IsInputStyleChangedSignalsQueueEmpty()
2221 {
2222   return ( NULL == mImpl->mEventData ) || ( 0u == mImpl->mEventData->mInputStyleChangedQueue.Count() );
2223 }
2224
2225 void Controller::ProcessInputStyleChangedSignals()
2226 {
2227   if( NULL == mImpl->mEventData )
2228   {
2229     // Nothing to do.
2230     return;
2231   }
2232
2233   for( Vector<InputStyle::Mask>::ConstIterator it = mImpl->mEventData->mInputStyleChangedQueue.Begin(),
2234          endIt = mImpl->mEventData->mInputStyleChangedQueue.End();
2235        it != endIt;
2236        ++it )
2237   {
2238     const InputStyle::Mask mask = *it;
2239
2240     if( NULL != mImpl->mEditableControlInterface )
2241     {
2242       // Emit the input style changed signal.
2243       mImpl->mEditableControlInterface->InputStyleChanged( mask );
2244     }
2245   }
2246
2247   mImpl->mEventData->mInputStyleChangedQueue.Clear();
2248 }
2249
2250 // public : Text-input Event Queuing.
2251
2252 void Controller::KeyboardFocusGainEvent()
2253 {
2254   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusGainEvent" );
2255
2256   if( NULL != mImpl->mEventData )
2257   {
2258     if( ( EventData::INACTIVE == mImpl->mEventData->mState ) ||
2259         ( EventData::INTERRUPTED == mImpl->mEventData->mState ) )
2260     {
2261       mImpl->ChangeState( EventData::EDITING );
2262       mImpl->mEventData->mUpdateCursorPosition = true; //If editing started without tap event, cursor update must be triggered.
2263       mImpl->mEventData->mUpdateInputStyle = true;
2264     }
2265     mImpl->NotifyImfMultiLineStatus();
2266     if( mImpl->IsShowingPlaceholderText() )
2267     {
2268       // Show alternative placeholder-text when editing
2269       ShowPlaceholderText();
2270     }
2271
2272     mImpl->RequestRelayout();
2273   }
2274 }
2275
2276 void Controller::KeyboardFocusLostEvent()
2277 {
2278   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusLostEvent" );
2279
2280   if( NULL != mImpl->mEventData )
2281   {
2282     if( EventData::INTERRUPTED != mImpl->mEventData->mState )
2283     {
2284       mImpl->ChangeState( EventData::INACTIVE );
2285
2286       if( !mImpl->IsShowingRealText() )
2287       {
2288         // Revert to regular placeholder-text when not editing
2289         ShowPlaceholderText();
2290       }
2291     }
2292   }
2293   mImpl->RequestRelayout();
2294 }
2295
2296 bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
2297 {
2298   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyEvent" );
2299
2300   bool textChanged = false;
2301   bool relayoutNeeded = false;
2302
2303   if( ( NULL != mImpl->mEventData ) &&
2304       ( keyEvent.state == KeyEvent::Down ) )
2305   {
2306     int keyCode = keyEvent.keyCode;
2307     const std::string& keyString = keyEvent.keyPressed;
2308
2309     const bool isNullKey = ( 0 == keyCode ) && ( keyString.empty() );
2310
2311     // Pre-process to separate modifying events from non-modifying input events.
2312     if( isNullKey )
2313     {
2314       // In some platforms arrive key events with no key code.
2315       // Do nothing.
2316       return false;
2317     }
2318     else if( Dali::DALI_KEY_ESCAPE == keyCode || Dali::DALI_KEY_BACK == keyCode  || Dali::DALI_KEY_SEARCH == keyCode )
2319     {
2320       // Do nothing
2321       return false;
2322     }
2323     else if( ( Dali::DALI_KEY_CURSOR_LEFT  == keyCode ) ||
2324              ( Dali::DALI_KEY_CURSOR_RIGHT == keyCode ) ||
2325              ( Dali::DALI_KEY_CURSOR_UP    == keyCode ) ||
2326              ( Dali::DALI_KEY_CURSOR_DOWN  == keyCode ) )
2327     {
2328       // If don't have any text, do nothing.
2329       if( !mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters )
2330       {
2331         return false;
2332       }
2333
2334       uint32_t cursorPosition = mImpl->mEventData->mPrimaryCursorPosition;
2335       uint32_t numberOfCharacters = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
2336       uint32_t cursorLine = mImpl->mModel->mVisualModel->GetLineOfCharacter( cursorPosition );
2337       uint32_t numberOfLines = mImpl->mModel->GetNumberOfLines();
2338
2339       // Logic to determine whether this text control will lose focus or not.
2340       if( ( Dali::DALI_KEY_CURSOR_LEFT == keyCode && 0 == cursorPosition ) ||
2341           ( Dali::DALI_KEY_CURSOR_RIGHT == keyCode && numberOfCharacters == cursorPosition) ||
2342           ( Dali::DALI_KEY_CURSOR_DOWN == keyCode && cursorLine == numberOfLines -1 ) ||
2343           ( Dali::DALI_KEY_CURSOR_DOWN == keyCode && numberOfCharacters == cursorPosition && cursorLine -1 == numberOfLines -1 ) ||
2344           ( Dali::DALI_KEY_CURSOR_UP == keyCode && cursorLine == 0 ) ||
2345           ( Dali::DALI_KEY_CURSOR_UP == keyCode && numberOfCharacters == cursorPosition && cursorLine == 1 ) )
2346       {
2347         return false;
2348       }
2349
2350       mImpl->mEventData->mCheckScrollAmount = true;
2351       Event event( Event::CURSOR_KEY_EVENT );
2352       event.p1.mInt = keyCode;
2353       mImpl->mEventData->mEventQueue.push_back( event );
2354
2355       // Will request for relayout.
2356       relayoutNeeded = true;
2357     }
2358     else if( Dali::DALI_KEY_BACKSPACE == keyCode )
2359     {
2360       textChanged = BackspaceKeyEvent();
2361
2362       // Will request for relayout.
2363       relayoutNeeded = true;
2364     }
2365     else if( IsKey( keyEvent, Dali::DALI_KEY_POWER ) ||
2366              IsKey( keyEvent, Dali::DALI_KEY_MENU ) ||
2367              IsKey( keyEvent, Dali::DALI_KEY_HOME ) )
2368     {
2369       // Power key/Menu/Home key behaviour does not allow edit mode to resume.
2370       mImpl->ChangeState( EventData::INACTIVE );
2371
2372       // Will request for relayout.
2373       relayoutNeeded = true;
2374
2375       // This branch avoids calling the InsertText() method of the 'else' branch which can delete selected text.
2376     }
2377     else if( Dali::DALI_KEY_SHIFT_LEFT == keyCode )
2378     {
2379       // DALI_KEY_SHIFT_LEFT is the key code for the Left Shift. It's sent (by the imf?) when the predictive text is enabled
2380       // and a character is typed after the type of a upper case latin character.
2381
2382       // Do nothing.
2383       return false;
2384     }
2385     else if( ( Dali::DALI_KEY_VOLUME_UP == keyCode ) || ( Dali::DALI_KEY_VOLUME_DOWN == keyCode ) )
2386     {
2387       // This branch avoids calling the InsertText() method of the 'else' branch which can delete selected text.
2388       // Do nothing.
2389       return false;
2390     }
2391     else
2392     {
2393       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p keyString %s\n", this, keyString.c_str() );
2394
2395       // IMF manager is no longer handling key-events
2396       mImpl->ClearPreEditFlag();
2397
2398       InsertText( keyString, COMMIT );
2399       textChanged = true;
2400
2401       // Will request for relayout.
2402       relayoutNeeded = true;
2403     }
2404
2405     if ( ( mImpl->mEventData->mState != EventData::INTERRUPTED ) &&
2406          ( mImpl->mEventData->mState != EventData::INACTIVE ) &&
2407          ( !isNullKey ) &&
2408          ( Dali::DALI_KEY_SHIFT_LEFT != keyCode ) &&
2409          ( Dali::DALI_KEY_VOLUME_UP != keyCode ) &&
2410          ( Dali::DALI_KEY_VOLUME_DOWN != keyCode ) )
2411     {
2412       // Should not change the state if the key is the shift send by the imf manager.
2413       // Otherwise, when the state is SELECTING the text controller can't send the right
2414       // surrounding info to the imf.
2415       mImpl->ChangeState( EventData::EDITING );
2416
2417       // Will request for relayout.
2418       relayoutNeeded = true;
2419     }
2420
2421     if( relayoutNeeded )
2422     {
2423       mImpl->RequestRelayout();
2424     }
2425   }
2426
2427   if( textChanged &&
2428       ( NULL != mImpl->mEditableControlInterface ) )
2429   {
2430     // Do this last since it provides callbacks into application code
2431     mImpl->mEditableControlInterface->TextChanged();
2432   }
2433
2434   return true;
2435 }
2436
2437 void Controller::TapEvent( unsigned int tapCount, float x, float y )
2438 {
2439   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected TapEvent" );
2440
2441   if( NULL != mImpl->mEventData )
2442   {
2443     DALI_LOG_INFO( gLogFilter, Debug::Concise, "TapEvent state:%d \n", mImpl->mEventData->mState );
2444     EventData::State state( mImpl->mEventData->mState );
2445     bool relayoutNeeded( false );   // to avoid unnecessary relayouts when tapping an empty text-field
2446
2447     if( mImpl->IsClipboardVisible() )
2448     {
2449       if( EventData::INACTIVE == state || EventData::EDITING == state)
2450       {
2451         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );
2452       }
2453       relayoutNeeded = true;
2454     }
2455     else if( 1u == tapCount )
2456     {
2457       if( EventData::EDITING_WITH_POPUP == state || EventData::EDITING_WITH_PASTE_POPUP == state )
2458       {
2459         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );  // If Popup shown hide it here so can be shown again if required.
2460       }
2461
2462       if( mImpl->IsShowingRealText() && ( EventData::INACTIVE != state ) )
2463       {
2464         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );
2465         relayoutNeeded = true;
2466       }
2467       else
2468       {
2469         if( mImpl->IsShowingPlaceholderText() && !mImpl->IsFocusedPlaceholderAvailable() )
2470         {
2471           // Hide placeholder text
2472           ResetText();
2473         }
2474
2475         if( EventData::INACTIVE == state )
2476         {
2477           mImpl->ChangeState( EventData::EDITING );
2478         }
2479         else if( !mImpl->IsClipboardEmpty() )
2480         {
2481           mImpl->ChangeState( EventData::EDITING_WITH_POPUP );
2482         }
2483         relayoutNeeded = true;
2484       }
2485     }
2486     else if( 2u == tapCount )
2487     {
2488       if( mImpl->mEventData->mSelectionEnabled &&
2489           mImpl->IsShowingRealText() )
2490       {
2491         relayoutNeeded = true;
2492         mImpl->mEventData->mIsLeftHandleSelected = true;
2493         mImpl->mEventData->mIsRightHandleSelected = true;
2494       }
2495     }
2496
2497     // Handles & cursors must be repositioned after Relayout() i.e. after the Model has been updated
2498     if( relayoutNeeded )
2499     {
2500       Event event( Event::TAP_EVENT );
2501       event.p1.mUint = tapCount;
2502       event.p2.mFloat = x;
2503       event.p3.mFloat = y;
2504       mImpl->mEventData->mEventQueue.push_back( event );
2505
2506       mImpl->RequestRelayout();
2507     }
2508   }
2509
2510   // Reset keyboard as tap event has occurred.
2511   mImpl->ResetImfManager();
2512 }
2513
2514 void Controller::PanEvent( Gesture::State state, const Vector2& displacement )
2515 {
2516   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected PanEvent" );
2517
2518   if( NULL != mImpl->mEventData )
2519   {
2520     Event event( Event::PAN_EVENT );
2521     event.p1.mInt = state;
2522     event.p2.mFloat = displacement.x;
2523     event.p3.mFloat = displacement.y;
2524     mImpl->mEventData->mEventQueue.push_back( event );
2525
2526     mImpl->RequestRelayout();
2527   }
2528 }
2529
2530 void Controller::LongPressEvent( Gesture::State state, float x, float y  )
2531 {
2532   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected LongPressEvent" );
2533
2534   if( ( state == Gesture::Started ) &&
2535       ( NULL != mImpl->mEventData ) )
2536   {
2537     // The 1st long-press on inactive text-field is treated as tap
2538     if( EventData::INACTIVE == mImpl->mEventData->mState )
2539     {
2540       mImpl->ChangeState( EventData::EDITING );
2541
2542       Event event( Event::TAP_EVENT );
2543       event.p1.mUint = 1;
2544       event.p2.mFloat = x;
2545       event.p3.mFloat = y;
2546       mImpl->mEventData->mEventQueue.push_back( event );
2547
2548       mImpl->RequestRelayout();
2549     }
2550     else if( !mImpl->IsShowingRealText() )
2551     {
2552       Event event( Event::LONG_PRESS_EVENT );
2553       event.p1.mInt = state;
2554       event.p2.mFloat = x;
2555       event.p3.mFloat = y;
2556       mImpl->mEventData->mEventQueue.push_back( event );
2557       mImpl->RequestRelayout();
2558     }
2559     else if( !mImpl->IsClipboardVisible() )
2560     {
2561       // Reset the imf manager to commit the pre-edit before selecting the text.
2562       mImpl->ResetImfManager();
2563
2564       Event event( Event::LONG_PRESS_EVENT );
2565       event.p1.mInt = state;
2566       event.p2.mFloat = x;
2567       event.p3.mFloat = y;
2568       mImpl->mEventData->mEventQueue.push_back( event );
2569       mImpl->RequestRelayout();
2570
2571       mImpl->mEventData->mIsLeftHandleSelected = true;
2572       mImpl->mEventData->mIsRightHandleSelected = true;
2573     }
2574   }
2575 }
2576
2577 ImfManager::ImfCallbackData Controller::OnImfEvent( ImfManager& imfManager, const ImfManager::ImfEventData& imfEvent )
2578 {
2579   // Whether the text needs to be relaid-out.
2580   bool requestRelayout = false;
2581
2582   // Whether to retrieve the text and cursor position to be sent to the IMF manager.
2583   bool retrieveText = false;
2584   bool retrieveCursor = false;
2585
2586   switch( imfEvent.eventName )
2587   {
2588     case ImfManager::COMMIT:
2589     {
2590       InsertText( imfEvent.predictiveString, Text::Controller::COMMIT );
2591       requestRelayout = true;
2592       retrieveCursor = true;
2593       break;
2594     }
2595     case ImfManager::PREEDIT:
2596     {
2597       InsertText( imfEvent.predictiveString, Text::Controller::PRE_EDIT );
2598       requestRelayout = true;
2599       retrieveCursor = true;
2600       break;
2601     }
2602     case ImfManager::DELETESURROUNDING:
2603     {
2604       const bool textDeleted = RemoveText( imfEvent.cursorOffset,
2605                                            imfEvent.numberOfChars,
2606                                            DONT_UPDATE_INPUT_STYLE );
2607
2608       if( textDeleted )
2609       {
2610         if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) ||
2611             !mImpl->IsPlaceholderAvailable() )
2612         {
2613           mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
2614         }
2615         else
2616         {
2617           ShowPlaceholderText();
2618         }
2619         mImpl->mEventData->mUpdateCursorPosition = true;
2620         mImpl->mEventData->mScrollAfterDelete = true;
2621
2622         requestRelayout = true;
2623       }
2624       break;
2625     }
2626     case ImfManager::GETSURROUNDING:
2627     {
2628       retrieveText = true;
2629       retrieveCursor = true;
2630       break;
2631     }
2632     case ImfManager::PRIVATECOMMAND:
2633     {
2634       // PRIVATECOMMAND event is just for getting the private command message
2635       retrieveText = true;
2636       retrieveCursor = true;
2637       break;
2638     }
2639     case ImfManager::VOID:
2640     {
2641       // do nothing
2642       break;
2643     }
2644   } // end switch
2645
2646   if( requestRelayout )
2647   {
2648     mImpl->mOperationsPending = ALL_OPERATIONS;
2649     mImpl->RequestRelayout();
2650   }
2651
2652   std::string text;
2653   CharacterIndex cursorPosition = 0u;
2654   Length numberOfWhiteSpaces = 0u;
2655
2656   if( retrieveCursor )
2657   {
2658     numberOfWhiteSpaces = mImpl->GetNumberOfWhiteSpaces( 0u );
2659
2660     cursorPosition = mImpl->GetLogicalCursorPosition();
2661
2662     if( cursorPosition < numberOfWhiteSpaces )
2663     {
2664       cursorPosition = 0u;
2665     }
2666     else
2667     {
2668       cursorPosition -= numberOfWhiteSpaces;
2669     }
2670   }
2671
2672   if( retrieveText )
2673   {
2674     mImpl->GetText( numberOfWhiteSpaces, text );
2675   }
2676
2677   ImfManager::ImfCallbackData callbackData( ( retrieveText || retrieveCursor ), cursorPosition, text, false );
2678
2679   if( requestRelayout &&
2680       ( NULL != mImpl->mEditableControlInterface ) )
2681   {
2682     // Do this last since it provides callbacks into application code
2683     mImpl->mEditableControlInterface->TextChanged();
2684   }
2685
2686   return callbackData;
2687 }
2688
2689 void Controller::PasteClipboardItemEvent()
2690 {
2691   // Retrieve the clipboard contents first
2692   ClipboardEventNotifier notifier( ClipboardEventNotifier::Get() );
2693   std::string stringToPaste( notifier.GetContent() );
2694
2695   // Commit the current pre-edit text; the contents of the clipboard should be appended
2696   mImpl->ResetImfManager();
2697
2698   // Temporary disable hiding clipboard
2699   mImpl->SetClipboardHideEnable( false );
2700
2701   // Paste
2702   PasteText( stringToPaste );
2703
2704   mImpl->SetClipboardHideEnable( true );
2705 }
2706
2707 // protected : Inherit from Text::Decorator::ControllerInterface.
2708
2709 void Controller::GetTargetSize( Vector2& targetSize )
2710 {
2711   targetSize = mImpl->mModel->mVisualModel->mControlSize;
2712 }
2713
2714 void Controller::AddDecoration( Actor& actor, bool needsClipping )
2715 {
2716   if( NULL != mImpl->mEditableControlInterface )
2717   {
2718     mImpl->mEditableControlInterface->AddDecoration( actor, needsClipping );
2719   }
2720 }
2721
2722 void Controller::DecorationEvent( HandleType handleType, HandleState state, float x, float y )
2723 {
2724   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected DecorationEvent" );
2725
2726   if( NULL != mImpl->mEventData )
2727   {
2728     switch( handleType )
2729     {
2730       case GRAB_HANDLE:
2731       {
2732         Event event( Event::GRAB_HANDLE_EVENT );
2733         event.p1.mUint  = state;
2734         event.p2.mFloat = x;
2735         event.p3.mFloat = y;
2736
2737         mImpl->mEventData->mEventQueue.push_back( event );
2738         break;
2739       }
2740       case LEFT_SELECTION_HANDLE:
2741       {
2742         Event event( Event::LEFT_SELECTION_HANDLE_EVENT );
2743         event.p1.mUint  = state;
2744         event.p2.mFloat = x;
2745         event.p3.mFloat = y;
2746
2747         mImpl->mEventData->mEventQueue.push_back( event );
2748         break;
2749       }
2750       case RIGHT_SELECTION_HANDLE:
2751       {
2752         Event event( Event::RIGHT_SELECTION_HANDLE_EVENT );
2753         event.p1.mUint  = state;
2754         event.p2.mFloat = x;
2755         event.p3.mFloat = y;
2756
2757         mImpl->mEventData->mEventQueue.push_back( event );
2758         break;
2759       }
2760       case LEFT_SELECTION_HANDLE_MARKER:
2761       case RIGHT_SELECTION_HANDLE_MARKER:
2762       {
2763         // Markers do not move the handles.
2764         break;
2765       }
2766       case HANDLE_TYPE_COUNT:
2767       {
2768         DALI_ASSERT_DEBUG( !"Controller::HandleEvent. Unexpected handle type" );
2769       }
2770     }
2771
2772     mImpl->RequestRelayout();
2773   }
2774 }
2775
2776 // protected : Inherit from TextSelectionPopup::TextPopupButtonCallbackInterface.
2777
2778 void Controller::TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::Buttons button )
2779 {
2780   if( NULL == mImpl->mEventData )
2781   {
2782     return;
2783   }
2784
2785   switch( button )
2786   {
2787     case Toolkit::TextSelectionPopup::CUT:
2788     {
2789       mImpl->SendSelectionToClipboard( true ); // Synchronous call to modify text
2790       mImpl->mOperationsPending = ALL_OPERATIONS;
2791
2792       if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) ||
2793           !mImpl->IsPlaceholderAvailable() )
2794       {
2795         mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
2796       }
2797       else
2798       {
2799         ShowPlaceholderText();
2800       }
2801
2802       mImpl->mEventData->mUpdateCursorPosition = true;
2803       mImpl->mEventData->mScrollAfterDelete = true;
2804
2805       mImpl->RequestRelayout();
2806
2807       if( NULL != mImpl->mEditableControlInterface )
2808       {
2809         mImpl->mEditableControlInterface->TextChanged();
2810       }
2811       break;
2812     }
2813     case Toolkit::TextSelectionPopup::COPY:
2814     {
2815       mImpl->SendSelectionToClipboard( false ); // Text not modified
2816
2817       mImpl->mEventData->mUpdateCursorPosition = true;
2818
2819       mImpl->RequestRelayout(); // Cursor, Handles, Selection Highlight, Popup
2820       break;
2821     }
2822     case Toolkit::TextSelectionPopup::PASTE:
2823     {
2824       mImpl->RequestGetTextFromClipboard(); // Request clipboard service to retrieve an item
2825       break;
2826     }
2827     case Toolkit::TextSelectionPopup::SELECT:
2828     {
2829       const Vector2& currentCursorPosition = mImpl->mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
2830
2831       if( mImpl->mEventData->mSelectionEnabled )
2832       {
2833         // Creates a SELECT event.
2834         SelectEvent( currentCursorPosition.x, currentCursorPosition.y, false );
2835       }
2836       break;
2837     }
2838     case Toolkit::TextSelectionPopup::SELECT_ALL:
2839     {
2840       // Creates a SELECT_ALL event
2841       SelectEvent( 0.f, 0.f, true );
2842       break;
2843     }
2844     case Toolkit::TextSelectionPopup::CLIPBOARD:
2845     {
2846       mImpl->ShowClipboard();
2847       break;
2848     }
2849     case Toolkit::TextSelectionPopup::NONE:
2850     {
2851       // Nothing to do.
2852       break;
2853     }
2854   }
2855 }
2856
2857 void Controller::DisplayTimeExpired()
2858 {
2859   mImpl->mEventData->mUpdateCursorPosition = true;
2860   // Apply modifications to the model
2861   mImpl->mOperationsPending = ALL_OPERATIONS;
2862
2863   mImpl->RequestRelayout();
2864 }
2865
2866 // private : Update.
2867
2868 void Controller::InsertText( const std::string& text, Controller::InsertType type )
2869 {
2870   bool removedPrevious = false;
2871   bool removedSelected = false;
2872   bool maxLengthReached = false;
2873
2874   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected InsertText" )
2875
2876   if( NULL == mImpl->mEventData )
2877   {
2878     return;
2879   }
2880
2881   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::InsertText %p %s (%s) mPrimaryCursorPosition %d mPreEditFlag %d mPreEditStartPosition %d mPreEditLength %d\n",
2882                  this, text.c_str(), (COMMIT == type ? "COMMIT" : "PRE_EDIT"),
2883                  mImpl->mEventData->mPrimaryCursorPosition, mImpl->mEventData->mPreEditFlag, mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
2884
2885   // TODO: At the moment the underline runs are only for pre-edit.
2886   mImpl->mModel->mVisualModel->mUnderlineRuns.Clear();
2887
2888   // Remove the previous IMF pre-edit.
2889   if( mImpl->mEventData->mPreEditFlag && ( 0u != mImpl->mEventData->mPreEditLength ) )
2890   {
2891     removedPrevious = RemoveText( -static_cast<int>( mImpl->mEventData->mPrimaryCursorPosition - mImpl->mEventData->mPreEditStartPosition ),
2892                                   mImpl->mEventData->mPreEditLength,
2893                                   DONT_UPDATE_INPUT_STYLE );
2894
2895     mImpl->mEventData->mPrimaryCursorPosition = mImpl->mEventData->mPreEditStartPosition;
2896     mImpl->mEventData->mPreEditLength = 0u;
2897   }
2898   else
2899   {
2900     // Remove the previous Selection.
2901     removedSelected = RemoveSelectedText();
2902
2903   }
2904
2905   Vector<Character> utf32Characters;
2906   Length characterCount = 0u;
2907
2908   if( !text.empty() )
2909   {
2910     //  Convert text into UTF-32
2911     utf32Characters.Resize( text.size() );
2912
2913     // This is a bit horrible but std::string returns a (signed) char*
2914     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
2915
2916     // Transform a text array encoded in utf8 into an array encoded in utf32.
2917     // It returns the actual number of characters.
2918     characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
2919     utf32Characters.Resize( characterCount );
2920
2921     DALI_ASSERT_DEBUG( text.size() >= utf32Characters.Count() && "Invalid UTF32 conversion length" );
2922     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "UTF8 size %d, UTF32 size %d\n", text.size(), utf32Characters.Count() );
2923   }
2924
2925   if( 0u != utf32Characters.Count() ) // Check if Utf8ToUtf32 conversion succeeded
2926   {
2927     // The placeholder text is no longer needed
2928     if( mImpl->IsShowingPlaceholderText() )
2929     {
2930       ResetText();
2931     }
2932
2933     mImpl->ChangeState( EventData::EDITING );
2934
2935     // Handle the IMF (predicitive text) state changes
2936     if( COMMIT == type )
2937     {
2938       // IMF manager is no longer handling key-events
2939       mImpl->ClearPreEditFlag();
2940     }
2941     else // PRE_EDIT
2942     {
2943       if( !mImpl->mEventData->mPreEditFlag )
2944       {
2945         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Entered PreEdit state\n" );
2946
2947         // Record the start of the pre-edit text
2948         mImpl->mEventData->mPreEditStartPosition = mImpl->mEventData->mPrimaryCursorPosition;
2949       }
2950
2951       mImpl->mEventData->mPreEditLength = utf32Characters.Count();
2952       mImpl->mEventData->mPreEditFlag = true;
2953
2954       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "mPreEditStartPosition %d mPreEditLength %d\n", mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
2955     }
2956
2957     const Length numberOfCharactersInModel = mImpl->mModel->mLogicalModel->mText.Count();
2958
2959     // Restrict new text to fit within Maximum characters setting.
2960     Length maxSizeOfNewText = std::min( ( mImpl->mMaximumNumberOfCharacters - numberOfCharactersInModel ), characterCount );
2961     maxLengthReached = ( characterCount > maxSizeOfNewText );
2962
2963     // The cursor position.
2964     CharacterIndex& cursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
2965
2966     // Update the text's style.
2967
2968     // Updates the text style runs by adding characters.
2969     mImpl->mModel->mLogicalModel->UpdateTextStyleRuns( cursorIndex, maxSizeOfNewText );
2970
2971     // Get the character index from the cursor index.
2972     const CharacterIndex styleIndex = ( cursorIndex > 0u ) ? cursorIndex - 1u : 0u;
2973
2974     // Retrieve the text's style for the given index.
2975     InputStyle style;
2976     mImpl->RetrieveDefaultInputStyle( style );
2977     mImpl->mModel->mLogicalModel->RetrieveStyle( styleIndex, style );
2978
2979     // Whether to add a new text color run.
2980     const bool addColorRun = ( style.textColor != mImpl->mEventData->mInputStyle.textColor );
2981
2982     // Whether to add a new font run.
2983     const bool addFontNameRun = style.familyName != mImpl->mEventData->mInputStyle.familyName;
2984     const bool addFontWeightRun = style.weight != mImpl->mEventData->mInputStyle.weight;
2985     const bool addFontWidthRun = style.width != mImpl->mEventData->mInputStyle.width;
2986     const bool addFontSlantRun = style.slant != mImpl->mEventData->mInputStyle.slant;
2987     const bool addFontSizeRun = style.size != mImpl->mEventData->mInputStyle.size;
2988
2989     // Add style runs.
2990     if( addColorRun )
2991     {
2992       const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mColorRuns.Count();
2993       mImpl->mModel->mLogicalModel->mColorRuns.Resize( numberOfRuns + 1u );
2994
2995       ColorRun& colorRun = *( mImpl->mModel->mLogicalModel->mColorRuns.Begin() + numberOfRuns );
2996       colorRun.color = mImpl->mEventData->mInputStyle.textColor;
2997       colorRun.characterRun.characterIndex = cursorIndex;
2998       colorRun.characterRun.numberOfCharacters = maxSizeOfNewText;
2999     }
3000
3001     if( addFontNameRun   ||
3002         addFontWeightRun ||
3003         addFontWidthRun  ||
3004         addFontSlantRun  ||
3005         addFontSizeRun )
3006     {
3007       const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Count();
3008       mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Resize( numberOfRuns + 1u );
3009
3010       FontDescriptionRun& fontDescriptionRun = *( mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Begin() + numberOfRuns );
3011
3012       if( addFontNameRun )
3013       {
3014         fontDescriptionRun.familyLength = mImpl->mEventData->mInputStyle.familyName.size();
3015         fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
3016         memcpy( fontDescriptionRun.familyName, mImpl->mEventData->mInputStyle.familyName.c_str(), fontDescriptionRun.familyLength );
3017         fontDescriptionRun.familyDefined = true;
3018
3019         // The memory allocated for the font family name is freed when the font description is removed from the logical model.
3020       }
3021
3022       if( addFontWeightRun )
3023       {
3024         fontDescriptionRun.weight = mImpl->mEventData->mInputStyle.weight;
3025         fontDescriptionRun.weightDefined = true;
3026       }
3027
3028       if( addFontWidthRun )
3029       {
3030         fontDescriptionRun.width = mImpl->mEventData->mInputStyle.width;
3031         fontDescriptionRun.widthDefined = true;
3032       }
3033
3034       if( addFontSlantRun )
3035       {
3036         fontDescriptionRun.slant = mImpl->mEventData->mInputStyle.slant;
3037         fontDescriptionRun.slantDefined = true;
3038       }
3039
3040       if( addFontSizeRun )
3041       {
3042         fontDescriptionRun.size = static_cast<PointSize26Dot6>( mImpl->mEventData->mInputStyle.size * 64.f );
3043         fontDescriptionRun.sizeDefined = true;
3044       }
3045
3046       fontDescriptionRun.characterRun.characterIndex = cursorIndex;
3047       fontDescriptionRun.characterRun.numberOfCharacters = maxSizeOfNewText;
3048     }
3049
3050     // Insert at current cursor position.
3051     Vector<Character>& modifyText = mImpl->mModel->mLogicalModel->mText;
3052
3053     if( cursorIndex < numberOfCharactersInModel )
3054     {
3055       modifyText.Insert( modifyText.Begin() + cursorIndex, utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
3056     }
3057     else
3058     {
3059       modifyText.Insert( modifyText.End(), utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
3060     }
3061
3062     // Mark the first paragraph to be updated.
3063     if( Layout::Engine::SINGLE_LINE_BOX == mImpl->mLayoutEngine.GetLayout() )
3064     {
3065       mImpl->mTextUpdateInfo.mCharacterIndex = 0;
3066       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3067       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = numberOfCharactersInModel + maxSizeOfNewText;
3068       mImpl->mTextUpdateInfo.mClearAll = true;
3069     }
3070     else
3071     {
3072       mImpl->mTextUpdateInfo.mCharacterIndex = std::min( cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex );
3073       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd += maxSizeOfNewText;
3074     }
3075
3076     // Update the cursor index.
3077     cursorIndex += maxSizeOfNewText;
3078
3079     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 );
3080   }
3081
3082   if( ( 0u == mImpl->mModel->mLogicalModel->mText.Count() ) &&
3083       mImpl->IsPlaceholderAvailable() )
3084   {
3085     // Show place-holder if empty after removing the pre-edit text
3086     ShowPlaceholderText();
3087     mImpl->mEventData->mUpdateCursorPosition = true;
3088     mImpl->ClearPreEditFlag();
3089   }
3090   else if( removedPrevious ||
3091            removedSelected ||
3092            ( 0 != utf32Characters.Count() ) )
3093   {
3094     // Queue an inserted event
3095     mImpl->QueueModifyEvent( ModifyEvent::TEXT_INSERTED );
3096
3097     mImpl->mEventData->mUpdateCursorPosition = true;
3098     if( removedSelected )
3099     {
3100       mImpl->mEventData->mScrollAfterDelete = true;
3101     }
3102     else
3103     {
3104       mImpl->mEventData->mScrollAfterUpdatePosition = true;
3105     }
3106   }
3107
3108   if( maxLengthReached )
3109   {
3110     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "MaxLengthReached (%d)\n", mImpl->mModel->mLogicalModel->mText.Count() );
3111
3112     mImpl->ResetImfManager();
3113
3114     if( NULL != mImpl->mEditableControlInterface )
3115     {
3116       // Do this last since it provides callbacks into application code
3117       mImpl->mEditableControlInterface->MaxLengthReached();
3118     }
3119   }
3120 }
3121
3122 void Controller::PasteText( const std::string& stringToPaste )
3123 {
3124   InsertText( stringToPaste, Text::Controller::COMMIT );
3125   mImpl->ChangeState( EventData::EDITING );
3126   mImpl->RequestRelayout();
3127
3128   if( NULL != mImpl->mEditableControlInterface )
3129   {
3130     // Do this last since it provides callbacks into application code
3131     mImpl->mEditableControlInterface->TextChanged();
3132   }
3133 }
3134
3135 bool Controller::RemoveText( int cursorOffset,
3136                              int numberOfCharacters,
3137                              UpdateInputStyleType type )
3138 {
3139   bool removed = false;
3140
3141   if( NULL == mImpl->mEventData )
3142   {
3143     return removed;
3144   }
3145
3146   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p mText.Count() %d cursor %d cursorOffset %d numberOfCharacters %d\n",
3147                  this, mImpl->mModel->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition, cursorOffset, numberOfCharacters );
3148
3149   if( !mImpl->IsShowingPlaceholderText() )
3150   {
3151     // Delete at current cursor position
3152     Vector<Character>& currentText = mImpl->mModel->mLogicalModel->mText;
3153     CharacterIndex& oldCursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
3154
3155     CharacterIndex cursorIndex = 0;
3156
3157     // Validate the cursor position & number of characters
3158     if( ( static_cast< int >( mImpl->mEventData->mPrimaryCursorPosition ) + cursorOffset ) >= 0 )
3159     {
3160       cursorIndex = mImpl->mEventData->mPrimaryCursorPosition + cursorOffset;
3161     }
3162
3163     if( ( cursorIndex + numberOfCharacters ) > currentText.Count() )
3164     {
3165       numberOfCharacters = currentText.Count() - cursorIndex;
3166     }
3167
3168     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.
3169         ( ( cursorIndex + numberOfCharacters ) <= mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters ) )
3170     {
3171       // Mark the paragraphs to be updated.
3172       if( Layout::Engine::SINGLE_LINE_BOX == mImpl->mLayoutEngine.GetLayout() )
3173       {
3174         mImpl->mTextUpdateInfo.mCharacterIndex = 0;
3175         mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3176         mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters - numberOfCharacters;
3177         mImpl->mTextUpdateInfo.mClearAll = true;