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