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