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