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