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