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