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