a3d77d4caa9088ae093eb16126bb68a2e41d63f4
[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 ) )
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;