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