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