Add Text input style changed signal.
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-controller.cpp
1 /*
2  * Copyright (c) 2016 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
28 // INTERNAL INCLUDES
29 #include <dali-toolkit/internal/text/bidirectional-support.h>
30 #include <dali-toolkit/internal/text/character-set-conversion.h>
31 #include <dali-toolkit/internal/text/layouts/layout-parameters.h>
32 #include <dali-toolkit/internal/text/markup-processor.h>
33 #include <dali-toolkit/internal/text/text-controller-impl.h>
34
35 namespace
36 {
37
38 #if defined(DEBUG_ENABLED)
39   Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
40 #endif
41
42 const float MAX_FLOAT = std::numeric_limits<float>::max();
43
44 const std::string EMPTY_STRING("");
45
46 float ConvertToEven( float value )
47 {
48   int intValue(static_cast<int>( value ));
49   return static_cast<float>(intValue % 2 == 0) ? intValue : (intValue + 1);
50 }
51
52 } // namespace
53
54 namespace Dali
55 {
56
57 namespace Toolkit
58 {
59
60 namespace Text
61 {
62
63 /**
64  * @brief Adds a new font description run for the selected text.
65  *
66  * The new font parameters are added after the call to this method.
67  *
68  * @param[in] eventData The event data pointer.
69  * @param[in] logicalModel The logical model where to add the new font description run.
70  * @param[out] startOfSelectedText Index to the first selected character.
71  * @param[out] lengthOfSelectedText Number of selected characters.
72  */
73 FontDescriptionRun& UpdateSelectionFontStyleRun( EventData* eventData,
74                                                  LogicalModelPtr logicalModel,
75                                                  CharacterIndex& startOfSelectedText,
76                                                  Length& lengthOfSelectedText )
77 {
78   const bool handlesCrossed = eventData->mLeftSelectionPosition > eventData->mRightSelectionPosition;
79
80   // Get start and end position of selection
81   startOfSelectedText = handlesCrossed ? eventData->mRightSelectionPosition : eventData->mLeftSelectionPosition;
82   lengthOfSelectedText = ( handlesCrossed ? eventData->mLeftSelectionPosition : eventData->mRightSelectionPosition ) - startOfSelectedText;
83
84   // Add the font run.
85   const VectorBase::SizeType numberOfRuns = logicalModel->mFontDescriptionRuns.Count();
86   logicalModel->mFontDescriptionRuns.Resize( numberOfRuns + 1u );
87
88   FontDescriptionRun& fontDescriptionRun = *( logicalModel->mFontDescriptionRuns.Begin() + numberOfRuns );
89
90   fontDescriptionRun.characterRun.characterIndex = startOfSelectedText;
91   fontDescriptionRun.characterRun.numberOfCharacters = lengthOfSelectedText;
92
93   // Recalculate the selection highlight as the metrics may have changed.
94   eventData->mUpdateLeftSelectionPosition = true;
95   eventData->mUpdateRightSelectionPosition = true;
96   eventData->mUpdateHighlightBox = true;
97
98   return fontDescriptionRun;
99 }
100
101 ControllerPtr Controller::New( ControlInterface& controlInterface )
102 {
103   return ControllerPtr( new Controller( controlInterface ) );
104 }
105
106 void Controller::EnableTextInput( DecoratorPtr decorator )
107 {
108   if( NULL == mImpl->mEventData )
109   {
110     mImpl->mEventData = new EventData( decorator );
111   }
112 }
113
114 void Controller::SetGlyphType( TextAbstraction::GlyphType glyphType )
115 {
116   // Metrics for bitmap & vector based glyphs are different
117   mImpl->mMetrics->SetGlyphType( glyphType );
118
119   // Clear the font-specific data
120   ClearFontData();
121
122   mImpl->RequestRelayout();
123 }
124
125 void Controller::SetMarkupProcessorEnabled( bool enable )
126 {
127   mImpl->mMarkupProcessorEnabled = enable;
128 }
129
130 bool Controller::IsMarkupProcessorEnabled() const
131 {
132   return mImpl->mMarkupProcessorEnabled;
133 }
134
135 void Controller::SetAutoScrollEnabled( bool enable )
136 {
137   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled[%s] SingleBox[%s]-> [%p]\n", (enable)?"true":"false", ( mImpl->mLayoutEngine.GetLayout() == LayoutEngine::SINGLE_LINE_BOX)?"true":"false", this );
138
139   if ( mImpl->mLayoutEngine.GetLayout() == LayoutEngine::SINGLE_LINE_BOX )
140   {
141     if ( enable )
142     {
143       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled for SINGLE_LINE_BOX\n" );
144       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
145                                                                LAYOUT                    |
146                                                                ALIGN                     |
147                                                                UPDATE_LAYOUT_SIZE        |
148                                                                UPDATE_DIRECTION          |
149                                                                REORDER );
150
151     }
152     else
153     {
154       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled Disabling autoscroll\n");
155       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
156                                                                LAYOUT                    |
157                                                                ALIGN                     |
158                                                                UPDATE_LAYOUT_SIZE        |
159                                                                REORDER );
160     }
161
162     mImpl->mAutoScrollEnabled = enable;
163     mImpl->RequestRelayout();
164   }
165   else
166   {
167     DALI_LOG_WARNING( "Attempted AutoScrolling on a non SINGLE_LINE_BOX, request ignored\n" );
168     mImpl->mAutoScrollEnabled = false;
169   }
170 }
171
172 bool Controller::IsAutoScrollEnabled() const
173 {
174   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::IsAutoScrollEnabled[%s]\n", (mImpl->mAutoScrollEnabled)?"true":"false" );
175
176   return mImpl->mAutoScrollEnabled;
177 }
178
179 CharacterDirection Controller::GetAutoScrollDirection() const
180 {
181   return mImpl->mAutoScrollDirectionRTL;
182 }
183
184 float Controller::GetAutoScrollLineAlignment() const
185 {
186   float offset = 0.f;
187
188   if( mImpl->mVisualModel &&
189       ( 0u != mImpl->mVisualModel->mLines.Count() ) )
190   {
191     offset = ( *mImpl->mVisualModel->mLines.Begin() ).alignmentOffset;
192   }
193
194   return offset;
195 }
196
197 void Controller::SetHorizontalScrollEnabled( bool enable )
198 {
199   if( ( NULL != mImpl->mEventData ) &&
200       mImpl->mEventData->mDecorator )
201   {
202     mImpl->mEventData->mDecorator->SetHorizontalScrollEnabled( enable );
203   }
204 }
205
206 bool Controller::IsHorizontalScrollEnabled() const
207 {
208   if( ( NULL != mImpl->mEventData ) &&
209       mImpl->mEventData->mDecorator )
210   {
211     return mImpl->mEventData->mDecorator->IsHorizontalScrollEnabled();
212   }
213
214   return false;
215 }
216
217 void Controller::SetVerticalScrollEnabled( bool enable )
218 {
219   if( ( NULL != mImpl->mEventData ) &&
220       mImpl->mEventData->mDecorator )
221   {
222     if( mImpl->mEventData->mDecorator )
223     {
224       mImpl->mEventData->mDecorator->SetVerticalScrollEnabled( enable );
225     }
226   }
227 }
228
229 bool Controller::IsVerticalScrollEnabled() const
230 {
231   if( ( NULL != mImpl->mEventData ) &&
232       mImpl->mEventData->mDecorator )
233   {
234     return mImpl->mEventData->mDecorator->IsVerticalScrollEnabled();
235   }
236
237   return false;
238 }
239
240 void Controller::SetSmoothHandlePanEnabled( bool enable )
241 {
242   if( ( NULL != mImpl->mEventData ) &&
243       mImpl->mEventData->mDecorator )
244   {
245     mImpl->mEventData->mDecorator->SetSmoothHandlePanEnabled( enable );
246   }
247 }
248
249 bool Controller::IsSmoothHandlePanEnabled() const
250 {
251   if( ( NULL != mImpl->mEventData ) &&
252       mImpl->mEventData->mDecorator )
253   {
254     return mImpl->mEventData->mDecorator->IsSmoothHandlePanEnabled();
255   }
256
257   return false;
258 }
259
260 void Controller::SetText( const std::string& text )
261 {
262   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SetText\n" );
263
264   // Reset keyboard as text changed
265   mImpl->ResetImfManager();
266
267   // Remove the previously set text and style.
268   ResetText();
269
270   // Remove the style.
271   ClearStyleData();
272
273   CharacterIndex lastCursorIndex = 0u;
274
275   if( NULL != mImpl->mEventData )
276   {
277     // If popup shown then hide it by switching to Editing state
278     if( ( EventData::SELECTING == mImpl->mEventData->mState )          ||
279         ( EventData::EDITING_WITH_POPUP == mImpl->mEventData->mState ) ||
280         ( EventData::EDITING_WITH_GRAB_HANDLE == mImpl->mEventData->mState ) ||
281         ( EventData::EDITING_WITH_PASTE_POPUP == mImpl->mEventData->mState ) )
282     {
283       mImpl->ChangeState( EventData::EDITING );
284     }
285   }
286
287   if( !text.empty() )
288   {
289     mImpl->mVisualModel->SetTextColor( mImpl->mTextColor );
290
291     MarkupProcessData markupProcessData( mImpl->mLogicalModel->mColorRuns,
292                                          mImpl->mLogicalModel->mFontDescriptionRuns );
293
294     Length textSize = 0u;
295     const uint8_t* utf8 = NULL;
296     if( mImpl->mMarkupProcessorEnabled )
297     {
298       ProcessMarkupString( text, markupProcessData );
299       textSize = markupProcessData.markupProcessedText.size();
300
301       // This is a bit horrible but std::string returns a (signed) char*
302       utf8 = reinterpret_cast<const uint8_t*>( markupProcessData.markupProcessedText.c_str() );
303     }
304     else
305     {
306       textSize = text.size();
307
308       // This is a bit horrible but std::string returns a (signed) char*
309       utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
310     }
311
312     //  Convert text into UTF-32
313     Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
314     utf32Characters.Resize( textSize );
315
316     // Transform a text array encoded in utf8 into an array encoded in utf32.
317     // It returns the actual number of characters.
318     Length characterCount = Utf8ToUtf32( utf8, textSize, utf32Characters.Begin() );
319     utf32Characters.Resize( characterCount );
320
321     DALI_ASSERT_DEBUG( textSize >= characterCount && "Invalid UTF32 conversion length" );
322     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SetText %p UTF8 size %d, UTF32 size %d\n", this, textSize, mImpl->mLogicalModel->mText.Count() );
323
324     // The characters to be added.
325     mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mLogicalModel->mText.Count();
326
327     // To reset the cursor position
328     lastCursorIndex = characterCount;
329
330     // Update the rest of the model during size negotiation
331     mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
332
333     // The natural size needs to be re-calculated.
334     mImpl->mRecalculateNaturalSize = true;
335
336     // Apply modifications to the model
337     mImpl->mOperationsPending = ALL_OPERATIONS;
338   }
339   else
340   {
341     ShowPlaceholderText();
342   }
343
344   // Resets the cursor position.
345   ResetCursorPosition( lastCursorIndex );
346
347   // Scrolls the text to make the cursor visible.
348   ResetScrollPosition();
349
350   mImpl->RequestRelayout();
351
352   if( NULL != mImpl->mEventData )
353   {
354     // Cancel previously queued events
355     mImpl->mEventData->mEventQueue.clear();
356   }
357
358   // Do this last since it provides callbacks into application code
359   mImpl->mControlInterface.TextChanged();
360 }
361
362 void Controller::GetText( std::string& text ) const
363 {
364   if( !mImpl->IsShowingPlaceholderText() )
365   {
366     // Retrieves the text string.
367     mImpl->GetText( 0u, text );
368   }
369   else
370   {
371     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::GetText %p empty (but showing placeholder)\n", this );
372   }
373 }
374
375 void Controller::SetPlaceholderText( PlaceholderType type, const std::string& text )
376 {
377   if( NULL != mImpl->mEventData )
378   {
379     if( PLACEHOLDER_TYPE_INACTIVE == type )
380     {
381       mImpl->mEventData->mPlaceholderTextInactive = text;
382     }
383     else
384     {
385       mImpl->mEventData->mPlaceholderTextActive = text;
386     }
387
388     // Update placeholder if there is no text
389     if( mImpl->IsShowingPlaceholderText() ||
390         ( 0u == mImpl->mLogicalModel->mText.Count() ) )
391     {
392       ShowPlaceholderText();
393     }
394   }
395 }
396
397 void Controller::GetPlaceholderText( PlaceholderType type, std::string& text ) const
398 {
399   if( NULL != mImpl->mEventData )
400   {
401     if( PLACEHOLDER_TYPE_INACTIVE == type )
402     {
403       text = mImpl->mEventData->mPlaceholderTextInactive;
404     }
405     else
406     {
407       text = mImpl->mEventData->mPlaceholderTextActive;
408     }
409   }
410 }
411
412 void Controller::SetMaximumNumberOfCharacters( Length maxCharacters )
413 {
414   mImpl->mMaximumNumberOfCharacters = maxCharacters;
415 }
416
417 int Controller::GetMaximumNumberOfCharacters()
418 {
419   return mImpl->mMaximumNumberOfCharacters;
420 }
421
422 void Controller::SetDefaultFontFamily( const std::string& defaultFontFamily )
423 {
424   if( NULL == mImpl->mFontDefaults )
425   {
426     mImpl->mFontDefaults = new FontDefaults();
427   }
428
429   mImpl->mFontDefaults->mFontDescription.family = defaultFontFamily;
430   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetDefaultFontFamily %s\n", defaultFontFamily.c_str());
431   mImpl->mFontDefaults->familyDefined = !defaultFontFamily.empty();
432
433   // Clear the font-specific data
434   ClearFontData();
435
436   mImpl->RequestRelayout();
437 }
438
439 const std::string& Controller::GetDefaultFontFamily() const
440 {
441   if( NULL != mImpl->mFontDefaults )
442   {
443     return mImpl->mFontDefaults->mFontDescription.family;
444   }
445
446   return EMPTY_STRING;
447 }
448
449 void Controller::SetDefaultFontWeight( FontWeight weight )
450 {
451   if( NULL == mImpl->mFontDefaults )
452   {
453     mImpl->mFontDefaults = new FontDefaults();
454   }
455
456   mImpl->mFontDefaults->mFontDescription.weight = weight;
457   mImpl->mFontDefaults->weightDefined = true;
458
459   // Clear the font-specific data
460   ClearFontData();
461
462   mImpl->RequestRelayout();
463 }
464
465 bool Controller::IsDefaultFontWeightDefined() const
466 {
467   return mImpl->mFontDefaults->weightDefined;
468 }
469
470 FontWeight Controller::GetDefaultFontWeight() const
471 {
472   if( NULL != mImpl->mFontDefaults )
473   {
474     return mImpl->mFontDefaults->mFontDescription.weight;
475   }
476
477   return TextAbstraction::FontWeight::NORMAL;
478 }
479
480 void Controller::SetDefaultFontWidth( FontWidth width )
481 {
482   if( NULL == mImpl->mFontDefaults )
483   {
484     mImpl->mFontDefaults = new FontDefaults();
485   }
486
487   mImpl->mFontDefaults->mFontDescription.width = width;
488   mImpl->mFontDefaults->widthDefined = true;
489
490   // Clear the font-specific data
491   ClearFontData();
492
493   mImpl->RequestRelayout();
494 }
495
496 bool Controller::IsDefaultFontWidthDefined() const
497 {
498   return mImpl->mFontDefaults->widthDefined;
499 }
500
501 FontWidth Controller::GetDefaultFontWidth() const
502 {
503   if( NULL != mImpl->mFontDefaults )
504   {
505     return mImpl->mFontDefaults->mFontDescription.width;
506   }
507
508   return TextAbstraction::FontWidth::NORMAL;
509 }
510
511 void Controller::SetDefaultFontSlant( FontSlant slant )
512 {
513   if( NULL == mImpl->mFontDefaults )
514   {
515     mImpl->mFontDefaults = new FontDefaults();
516   }
517
518   mImpl->mFontDefaults->mFontDescription.slant = slant;
519   mImpl->mFontDefaults->slantDefined = true;
520
521   // Clear the font-specific data
522   ClearFontData();
523
524   mImpl->RequestRelayout();
525 }
526
527 bool Controller::IsDefaultFontSlantDefined() const
528 {
529   return mImpl->mFontDefaults->slantDefined;
530 }
531
532 FontSlant Controller::GetDefaultFontSlant() const
533 {
534   if( NULL != mImpl->mFontDefaults )
535   {
536     return mImpl->mFontDefaults->mFontDescription.slant;
537   }
538
539   return TextAbstraction::FontSlant::NORMAL;
540 }
541
542 void Controller::SetDefaultPointSize( float pointSize )
543 {
544   if( NULL == mImpl->mFontDefaults )
545   {
546     mImpl->mFontDefaults = new FontDefaults();
547   }
548
549   mImpl->mFontDefaults->mDefaultPointSize = pointSize;
550   mImpl->mFontDefaults->sizeDefined = true;
551
552   // Clear the font-specific data
553   ClearFontData();
554
555   mImpl->RequestRelayout();
556 }
557
558 float Controller::GetDefaultPointSize() const
559 {
560   if( NULL != mImpl->mFontDefaults )
561   {
562     return mImpl->mFontDefaults->mDefaultPointSize;
563   }
564
565   return 0.0f;
566 }
567
568 void Controller::UpdateAfterFontChange( const std::string& newDefaultFont )
569 {
570   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::UpdateAfterFontChange\n");
571
572   if( !mImpl->mFontDefaults->familyDefined ) // If user defined font then should not update when system font changes
573   {
574     DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::UpdateAfterFontChange newDefaultFont(%s)\n", newDefaultFont.c_str() );
575     mImpl->mFontDefaults->mFontDescription.family = newDefaultFont;
576
577     ClearFontData();
578
579     mImpl->RequestRelayout();
580   }
581 }
582
583 void Controller::SetTextColor( const Vector4& textColor )
584 {
585   mImpl->mTextColor = textColor;
586
587   if( !mImpl->IsShowingPlaceholderText() )
588   {
589     mImpl->mVisualModel->SetTextColor( textColor );
590
591     mImpl->RequestRelayout();
592   }
593 }
594
595 const Vector4& Controller::GetTextColor() const
596 {
597   return mImpl->mTextColor;
598 }
599
600 bool Controller::RemoveText( int cursorOffset,
601                              int numberOfCharacters,
602                              UpdateInputStyleType type )
603 {
604   bool removed = false;
605
606   if( NULL == mImpl->mEventData )
607   {
608     return removed;
609   }
610
611   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p mText.Count() %d cursor %d cursorOffset %d numberOfCharacters %d\n",
612                  this, mImpl->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition, cursorOffset, numberOfCharacters );
613
614   if( !mImpl->IsShowingPlaceholderText() )
615   {
616     // Delete at current cursor position
617     Vector<Character>& currentText = mImpl->mLogicalModel->mText;
618     CharacterIndex& oldCursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
619
620     CharacterIndex cursorIndex = oldCursorIndex;
621
622     // Validate the cursor position & number of characters
623     if( static_cast< CharacterIndex >( std::abs( cursorOffset ) ) <= cursorIndex )
624     {
625       cursorIndex = oldCursorIndex + cursorOffset;
626     }
627
628     if( ( cursorIndex + numberOfCharacters ) > currentText.Count() )
629     {
630       numberOfCharacters = currentText.Count() - cursorIndex;
631     }
632
633     if( ( cursorIndex + numberOfCharacters ) <= mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters )
634     {
635       // Mark the paragraphs to be updated.
636       mImpl->mTextUpdateInfo.mCharacterIndex = std::min( cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex );
637       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove += numberOfCharacters;
638
639       // Update the input style and remove the text's style before removing the text.
640
641       if( UPDATE_INPUT_STYLE == type )
642       {
643         // Keep a copy of the current input style.
644         InputStyle currentInputStyle;
645         currentInputStyle.Copy( mImpl->mEventData->mInputStyle );
646
647         // Set first the default input style.
648         mImpl->RetrieveDefaultInputStyle( mImpl->mEventData->mInputStyle );
649
650         // Update the input style.
651         mImpl->mLogicalModel->RetrieveStyle( cursorIndex, mImpl->mEventData->mInputStyle );
652
653         // Compare if the input style has changed.
654         const bool hasInputStyleChanged = !currentInputStyle.Equal( mImpl->mEventData->mInputStyle );
655
656         if( hasInputStyleChanged )
657         {
658           const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask( mImpl->mEventData->mInputStyle );
659           // Queue the input style changed signal.
660           mImpl->mEventData->mInputStyleChangedQueue.PushBack( styleChangedMask );
661         }
662       }
663
664       // Updates the text style runs by removing characters. Runs with no characters are removed.
665       mImpl->mLogicalModel->UpdateTextStyleRuns( cursorIndex, -numberOfCharacters );
666
667       // Remove the characters.
668       Vector<Character>::Iterator first = currentText.Begin() + cursorIndex;
669       Vector<Character>::Iterator last  = first + numberOfCharacters;
670
671       currentText.Erase( first, last );
672
673       // Cursor position retreat
674       oldCursorIndex = cursorIndex;
675
676       mImpl->mEventData->mScrollAfterDelete = true;
677
678       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p removed %d\n", this, numberOfCharacters );
679       removed = true;
680     }
681   }
682
683   return removed;
684 }
685
686 void Controller::SetPlaceholderTextColor( const Vector4& textColor )
687 {
688   if( NULL != mImpl->mEventData )
689   {
690     mImpl->mEventData->mPlaceholderTextColor = textColor;
691   }
692
693   if( mImpl->IsShowingPlaceholderText() )
694   {
695     mImpl->mVisualModel->SetTextColor( textColor );
696     mImpl->RequestRelayout();
697   }
698 }
699
700 const Vector4& Controller::GetPlaceholderTextColor() const
701 {
702   if( NULL != mImpl->mEventData )
703   {
704     return mImpl->mEventData->mPlaceholderTextColor;
705   }
706
707   return Color::BLACK;
708 }
709
710 void Controller::SetShadowOffset( const Vector2& shadowOffset )
711 {
712   mImpl->mVisualModel->SetShadowOffset( shadowOffset );
713
714   mImpl->RequestRelayout();
715 }
716
717 const Vector2& Controller::GetShadowOffset() const
718 {
719   return mImpl->mVisualModel->GetShadowOffset();
720 }
721
722 void Controller::SetShadowColor( const Vector4& shadowColor )
723 {
724   mImpl->mVisualModel->SetShadowColor( shadowColor );
725
726   mImpl->RequestRelayout();
727 }
728
729 const Vector4& Controller::GetShadowColor() const
730 {
731   return mImpl->mVisualModel->GetShadowColor();
732 }
733
734 void Controller::SetDefaultShadowProperties( const std::string& shadowProperties )
735 {
736   if( NULL == mImpl->mShadowDefaults )
737   {
738     mImpl->mShadowDefaults = new ShadowDefaults();
739   }
740
741   mImpl->mShadowDefaults->properties = shadowProperties;
742 }
743
744 const std::string& Controller::GetDefaultShadowProperties() const
745 {
746   if( NULL != mImpl->mShadowDefaults )
747   {
748     return mImpl->mShadowDefaults->properties;
749   }
750
751   return EMPTY_STRING;
752 }
753
754 void Controller::SetUnderlineColor( const Vector4& color )
755 {
756   mImpl->mVisualModel->SetUnderlineColor( color );
757
758   mImpl->RequestRelayout();
759 }
760
761 const Vector4& Controller::GetUnderlineColor() const
762 {
763   return mImpl->mVisualModel->GetUnderlineColor();
764 }
765
766 void Controller::SetUnderlineEnabled( bool enabled )
767 {
768   mImpl->mVisualModel->SetUnderlineEnabled( enabled );
769
770   mImpl->RequestRelayout();
771 }
772
773 bool Controller::IsUnderlineEnabled() const
774 {
775   return mImpl->mVisualModel->IsUnderlineEnabled();
776 }
777
778 void Controller::SetUnderlineHeight( float height )
779 {
780   mImpl->mVisualModel->SetUnderlineHeight( height );
781
782   mImpl->RequestRelayout();
783 }
784
785 float Controller::GetUnderlineHeight() const
786 {
787   return mImpl->mVisualModel->GetUnderlineHeight();
788 }
789
790 void Controller::SetDefaultUnderlineProperties( const std::string& underlineProperties )
791 {
792   if( NULL == mImpl->mUnderlineDefaults )
793   {
794     mImpl->mUnderlineDefaults = new UnderlineDefaults();
795   }
796
797   mImpl->mUnderlineDefaults->properties = underlineProperties;
798 }
799
800 const std::string& Controller::GetDefaultUnderlineProperties() const
801 {
802   if( NULL != mImpl->mUnderlineDefaults )
803   {
804     return mImpl->mUnderlineDefaults->properties;
805   }
806
807   return EMPTY_STRING;
808 }
809
810 void Controller::SetDefaultEmbossProperties( const std::string& embossProperties )
811 {
812   if( NULL == mImpl->mEmbossDefaults )
813   {
814     mImpl->mEmbossDefaults = new EmbossDefaults();
815   }
816
817   mImpl->mEmbossDefaults->properties = embossProperties;
818 }
819
820 const std::string& Controller::GetDefaultEmbossProperties() const
821 {
822   if( NULL != mImpl->mEmbossDefaults )
823   {
824     return mImpl->mEmbossDefaults->properties;
825   }
826
827   return EMPTY_STRING;
828 }
829
830 void Controller::SetDefaultOutlineProperties( const std::string& outlineProperties )
831 {
832   if( NULL == mImpl->mOutlineDefaults )
833   {
834     mImpl->mOutlineDefaults = new OutlineDefaults();
835   }
836
837   mImpl->mOutlineDefaults->properties = outlineProperties;
838 }
839
840 const std::string& Controller::GetDefaultOutlineProperties() const
841 {
842   if( NULL != mImpl->mOutlineDefaults )
843   {
844     return mImpl->mOutlineDefaults->properties;
845   }
846
847   return EMPTY_STRING;
848 }
849
850 void Controller::SetDefaultLineSpacing( float lineSpacing )
851 {
852   //TODO finish implementation
853   mImpl->mLayoutEngine.SetDefaultLineSpacing( lineSpacing );
854 }
855
856 float Controller::GetDefaultLineSpacing() const
857 {
858   return mImpl->mLayoutEngine.GetDefaultLineSpacing();
859 }
860
861 void Controller::SetInputColor( const Vector4& color )
862 {
863   if( NULL != mImpl->mEventData )
864   {
865     mImpl->mEventData->mInputStyle.textColor = color;
866     mImpl->mEventData->mInputStyle.isDefaultColor = false;
867
868     if( EventData::SELECTING == mImpl->mEventData->mState )
869     {
870       const bool handlesCrossed = mImpl->mEventData->mLeftSelectionPosition > mImpl->mEventData->mRightSelectionPosition;
871
872       // Get start and end position of selection
873       const CharacterIndex startOfSelectedText = handlesCrossed ? mImpl->mEventData->mRightSelectionPosition : mImpl->mEventData->mLeftSelectionPosition;
874       const Length lengthOfSelectedText = ( handlesCrossed ? mImpl->mEventData->mLeftSelectionPosition : mImpl->mEventData->mRightSelectionPosition ) - startOfSelectedText;
875
876       // Add the color run.
877       const VectorBase::SizeType numberOfRuns = mImpl->mLogicalModel->mColorRuns.Count();
878       mImpl->mLogicalModel->mColorRuns.Resize( numberOfRuns + 1u );
879
880       ColorRun& colorRun = *( mImpl->mLogicalModel->mColorRuns.Begin() + numberOfRuns );
881       colorRun.color = color;
882       colorRun.characterRun.characterIndex = startOfSelectedText;
883       colorRun.characterRun.numberOfCharacters = lengthOfSelectedText;
884
885       // Request to relayout.
886       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | COLOR );
887       mImpl->RequestRelayout();
888
889       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
890       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
891       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
892     }
893   }
894 }
895
896 const Vector4& Controller::GetInputColor() const
897 {
898   if( NULL != mImpl->mEventData )
899   {
900     return mImpl->mEventData->mInputStyle.textColor;
901   }
902
903   // Return the default text's color if there is no EventData.
904   return mImpl->mTextColor;
905
906 }
907
908 void Controller::SetInputFontFamily( const std::string& fontFamily )
909 {
910   if( NULL != mImpl->mEventData )
911   {
912     mImpl->mEventData->mInputStyle.familyName = fontFamily;
913     mImpl->mEventData->mInputStyle.isFamilyDefined = true;
914
915     if( EventData::SELECTING == mImpl->mEventData->mState )
916     {
917       CharacterIndex startOfSelectedText = 0u;
918       Length lengthOfSelectedText = 0u;
919       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
920                                                                             mImpl->mLogicalModel,
921                                                                             startOfSelectedText,
922                                                                             lengthOfSelectedText );
923
924       fontDescriptionRun.familyLength = fontFamily.size();
925       fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
926       memcpy( fontDescriptionRun.familyName, fontFamily.c_str(), fontDescriptionRun.familyLength );
927       fontDescriptionRun.familyDefined = true;
928
929       // The memory allocated for the font family name is freed when the font description is removed from the logical model.
930
931       // Request to relayout.
932       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
933                                                                VALIDATE_FONTS            |
934                                                                SHAPE_TEXT                |
935                                                                GET_GLYPH_METRICS         |
936                                                                LAYOUT                    |
937                                                                UPDATE_LAYOUT_SIZE        |
938                                                                REORDER                   |
939                                                                ALIGN );
940       mImpl->mRecalculateNaturalSize = true;
941       mImpl->RequestRelayout();
942
943       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
944       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
945       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
946
947       // As the font changes, recalculate the handle positions is needed.
948       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
949       mImpl->mEventData->mUpdateRightSelectionPosition = true;
950       mImpl->mEventData->mUpdateHighlightBox = true;
951       mImpl->mEventData->mScrollAfterUpdatePosition = true;
952     }
953   }
954 }
955
956 const std::string& Controller::GetInputFontFamily() const
957 {
958   if( NULL != mImpl->mEventData )
959   {
960     return mImpl->mEventData->mInputStyle.familyName;
961   }
962
963   // Return the default font's family if there is no EventData.
964   return GetDefaultFontFamily();
965 }
966
967 void Controller::SetInputFontWeight( FontWeight weight )
968 {
969   if( NULL != mImpl->mEventData )
970   {
971     mImpl->mEventData->mInputStyle.weight = weight;
972     mImpl->mEventData->mInputStyle.isWeightDefined = true;
973
974     if( EventData::SELECTING == mImpl->mEventData->mState )
975     {
976       CharacterIndex startOfSelectedText = 0u;
977       Length lengthOfSelectedText = 0u;
978       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
979                                                                             mImpl->mLogicalModel,
980                                                                             startOfSelectedText,
981                                                                             lengthOfSelectedText );
982
983       fontDescriptionRun.weight = weight;
984       fontDescriptionRun.weightDefined = true;
985
986       // Request to relayout.
987       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
988                                                                VALIDATE_FONTS            |
989                                                                SHAPE_TEXT                |
990                                                                GET_GLYPH_METRICS         |
991                                                                LAYOUT                    |
992                                                                UPDATE_LAYOUT_SIZE        |
993                                                                REORDER                   |
994                                                                ALIGN );
995       mImpl->mRecalculateNaturalSize = true;
996       mImpl->RequestRelayout();
997
998       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
999       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1000       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1001
1002       // As the font might change, recalculate the handle positions is needed.
1003       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
1004       mImpl->mEventData->mUpdateRightSelectionPosition = true;
1005       mImpl->mEventData->mUpdateHighlightBox = true;
1006       mImpl->mEventData->mScrollAfterUpdatePosition = true;
1007     }
1008   }
1009 }
1010
1011 bool Controller::IsInputFontWeightDefined() const
1012 {
1013   bool defined = false;
1014
1015   if( NULL != mImpl->mEventData )
1016   {
1017     defined = mImpl->mEventData->mInputStyle.isWeightDefined;
1018   }
1019
1020   return defined;
1021 }
1022
1023 FontWeight Controller::GetInputFontWeight() const
1024 {
1025   if( NULL != mImpl->mEventData )
1026   {
1027     return mImpl->mEventData->mInputStyle.weight;
1028   }
1029
1030   return GetDefaultFontWeight();
1031 }
1032
1033 void Controller::SetInputFontWidth( FontWidth width )
1034 {
1035   if( NULL != mImpl->mEventData )
1036   {
1037     mImpl->mEventData->mInputStyle.width = width;
1038     mImpl->mEventData->mInputStyle.isWidthDefined = true;
1039
1040     if( EventData::SELECTING == mImpl->mEventData->mState )
1041     {
1042       CharacterIndex startOfSelectedText = 0u;
1043       Length lengthOfSelectedText = 0u;
1044       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
1045                                                                             mImpl->mLogicalModel,
1046                                                                             startOfSelectedText,
1047                                                                             lengthOfSelectedText );
1048
1049       fontDescriptionRun.width = width;
1050       fontDescriptionRun.widthDefined = true;
1051
1052       // Request to relayout.
1053       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1054                                                                VALIDATE_FONTS            |
1055                                                                SHAPE_TEXT                |
1056                                                                GET_GLYPH_METRICS         |
1057                                                                LAYOUT                    |
1058                                                                UPDATE_LAYOUT_SIZE        |
1059                                                                REORDER                   |
1060                                                                ALIGN );
1061       mImpl->mRecalculateNaturalSize = true;
1062       mImpl->RequestRelayout();
1063
1064       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1065       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1066       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1067
1068       // As the font might change, recalculate the handle positions is needed.
1069       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
1070       mImpl->mEventData->mUpdateRightSelectionPosition = true;
1071       mImpl->mEventData->mUpdateHighlightBox = true;
1072       mImpl->mEventData->mScrollAfterUpdatePosition = true;
1073     }
1074   }
1075 }
1076
1077 bool Controller::IsInputFontWidthDefined() const
1078 {
1079   bool defined = false;
1080
1081   if( NULL != mImpl->mEventData )
1082   {
1083     defined = mImpl->mEventData->mInputStyle.isWidthDefined;
1084   }
1085
1086   return defined;
1087 }
1088
1089 FontWidth Controller::GetInputFontWidth() const
1090 {
1091   if( NULL != mImpl->mEventData )
1092   {
1093     return mImpl->mEventData->mInputStyle.width;
1094   }
1095
1096   return GetDefaultFontWidth();
1097 }
1098
1099 void Controller::SetInputFontSlant( FontSlant slant )
1100 {
1101   if( NULL != mImpl->mEventData )
1102   {
1103     mImpl->mEventData->mInputStyle.slant = slant;
1104     mImpl->mEventData->mInputStyle.isSlantDefined = true;
1105
1106     if( EventData::SELECTING == mImpl->mEventData->mState )
1107     {
1108       CharacterIndex startOfSelectedText = 0u;
1109       Length lengthOfSelectedText = 0u;
1110       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
1111                                                                             mImpl->mLogicalModel,
1112                                                                             startOfSelectedText,
1113                                                                             lengthOfSelectedText );
1114
1115       fontDescriptionRun.slant = slant;
1116       fontDescriptionRun.slantDefined = true;
1117
1118       // Request to relayout.
1119       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1120                                                                VALIDATE_FONTS            |
1121                                                                SHAPE_TEXT                |
1122                                                                GET_GLYPH_METRICS         |
1123                                                                LAYOUT                    |
1124                                                                UPDATE_LAYOUT_SIZE        |
1125                                                                REORDER                   |
1126                                                                ALIGN );
1127       mImpl->mRecalculateNaturalSize = true;
1128       mImpl->RequestRelayout();
1129
1130       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1131       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1132       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1133
1134       // As the font might change, recalculate the handle positions is needed.
1135       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
1136       mImpl->mEventData->mUpdateRightSelectionPosition = true;
1137       mImpl->mEventData->mUpdateHighlightBox = true;
1138       mImpl->mEventData->mScrollAfterUpdatePosition = true;
1139     }
1140   }
1141 }
1142
1143 bool Controller::IsInputFontSlantDefined() const
1144 {
1145   bool defined = false;
1146
1147   if( NULL != mImpl->mEventData )
1148   {
1149     defined = mImpl->mEventData->mInputStyle.isSlantDefined;
1150   }
1151
1152   return defined;
1153 }
1154
1155 FontSlant Controller::GetInputFontSlant() const
1156 {
1157   if( NULL != mImpl->mEventData )
1158   {
1159     return mImpl->mEventData->mInputStyle.slant;
1160   }
1161
1162   return GetDefaultFontSlant();
1163 }
1164
1165 void Controller::SetInputFontPointSize( float size )
1166 {
1167   if( NULL != mImpl->mEventData )
1168   {
1169     mImpl->mEventData->mInputStyle.size = size;
1170     mImpl->mEventData->mInputStyle.isSizeDefined = true;
1171
1172     if( EventData::SELECTING == mImpl->mEventData->mState )
1173     {
1174       CharacterIndex startOfSelectedText = 0u;
1175       Length lengthOfSelectedText = 0u;
1176       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
1177                                                                             mImpl->mLogicalModel,
1178                                                                             startOfSelectedText,
1179                                                                             lengthOfSelectedText );
1180
1181       fontDescriptionRun.size = static_cast<PointSize26Dot6>( size * 64.f );
1182       fontDescriptionRun.sizeDefined = true;
1183
1184       // Request to relayout.
1185       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1186                                                                VALIDATE_FONTS            |
1187                                                                SHAPE_TEXT                |
1188                                                                GET_GLYPH_METRICS         |
1189                                                                LAYOUT                    |
1190                                                                UPDATE_LAYOUT_SIZE        |
1191                                                                REORDER                   |
1192                                                                ALIGN );
1193       mImpl->mRecalculateNaturalSize = true;
1194       mImpl->RequestRelayout();
1195
1196       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1197       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1198       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1199
1200       // As the font might change, recalculate the handle positions is needed.
1201       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
1202       mImpl->mEventData->mUpdateRightSelectionPosition = true;
1203       mImpl->mEventData->mUpdateHighlightBox = true;
1204       mImpl->mEventData->mScrollAfterUpdatePosition = true;
1205     }
1206   }
1207 }
1208
1209 float Controller::GetInputFontPointSize() const
1210 {
1211   if( NULL != mImpl->mEventData )
1212   {
1213     return mImpl->mEventData->mInputStyle.size;
1214   }
1215
1216   // Return the default font's point size if there is no EventData.
1217   return GetDefaultPointSize();
1218 }
1219
1220 void Controller::SetInputLineSpacing( float lineSpacing )
1221 {
1222   if( NULL != mImpl->mEventData )
1223   {
1224     mImpl->mEventData->mInputStyle.lineSpacing = lineSpacing;
1225     mImpl->mEventData->mInputStyle.isLineSpacingDefined = true;
1226   }
1227 }
1228
1229 float Controller::GetInputLineSpacing() const
1230 {
1231   if( NULL != mImpl->mEventData )
1232   {
1233     return mImpl->mEventData->mInputStyle.lineSpacing;
1234   }
1235
1236   return 0.f;
1237 }
1238
1239 void Controller::SetInputShadowProperties( const std::string& shadowProperties )
1240 {
1241   if( NULL != mImpl->mEventData )
1242   {
1243     mImpl->mEventData->mInputStyle.shadowProperties = shadowProperties;
1244   }
1245 }
1246
1247 const std::string& Controller::GetInputShadowProperties() const
1248 {
1249   if( NULL != mImpl->mEventData )
1250   {
1251     return mImpl->mEventData->mInputStyle.shadowProperties;
1252   }
1253
1254   return GetDefaultShadowProperties();
1255 }
1256
1257 void Controller::SetInputUnderlineProperties( const std::string& underlineProperties )
1258 {
1259   if( NULL != mImpl->mEventData )
1260   {
1261     mImpl->mEventData->mInputStyle.underlineProperties = underlineProperties;
1262   }
1263 }
1264
1265 const std::string& Controller::GetInputUnderlineProperties() const
1266 {
1267   if( NULL != mImpl->mEventData )
1268   {
1269     return mImpl->mEventData->mInputStyle.underlineProperties;
1270   }
1271
1272   return GetDefaultUnderlineProperties();
1273 }
1274
1275 void Controller::SetInputEmbossProperties( const std::string& embossProperties )
1276 {
1277   if( NULL != mImpl->mEventData )
1278   {
1279     mImpl->mEventData->mInputStyle.embossProperties = embossProperties;
1280   }
1281 }
1282
1283 const std::string& Controller::GetInputEmbossProperties() const
1284 {
1285   if( NULL != mImpl->mEventData )
1286   {
1287     return mImpl->mEventData->mInputStyle.embossProperties;
1288   }
1289
1290   return GetDefaultEmbossProperties();
1291 }
1292
1293 void Controller::SetInputOutlineProperties( const std::string& outlineProperties )
1294 {
1295   if( NULL != mImpl->mEventData )
1296   {
1297     mImpl->mEventData->mInputStyle.outlineProperties = outlineProperties;
1298   }
1299 }
1300
1301 const std::string& Controller::GetInputOutlineProperties() const
1302 {
1303   if( NULL != mImpl->mEventData )
1304   {
1305     return mImpl->mEventData->mInputStyle.outlineProperties;
1306   }
1307
1308   return GetDefaultOutlineProperties();
1309 }
1310
1311 void Controller::SetEnableCursorBlink( bool enable )
1312 {
1313   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "TextInput disabled" );
1314
1315   if( NULL != mImpl->mEventData )
1316   {
1317     mImpl->mEventData->mCursorBlinkEnabled = enable;
1318
1319     if( !enable &&
1320         mImpl->mEventData->mDecorator )
1321     {
1322       mImpl->mEventData->mDecorator->StopCursorBlink();
1323     }
1324   }
1325 }
1326
1327 bool Controller::GetEnableCursorBlink() const
1328 {
1329   if( NULL != mImpl->mEventData )
1330   {
1331     return mImpl->mEventData->mCursorBlinkEnabled;
1332   }
1333
1334   return false;
1335 }
1336
1337 const Vector2& Controller::GetScrollPosition() const
1338 {
1339   return mImpl->mScrollPosition;
1340 }
1341
1342 Vector3 Controller::GetNaturalSize()
1343 {
1344   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetNaturalSize\n" );
1345   Vector3 naturalSize;
1346
1347   // Make sure the model is up-to-date before layouting
1348   ProcessModifyEvents();
1349
1350   if( mImpl->mRecalculateNaturalSize )
1351   {
1352     // Operations that can be done only once until the text changes.
1353     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
1354                                                                            GET_SCRIPTS       |
1355                                                                            VALIDATE_FONTS    |
1356                                                                            GET_LINE_BREAKS   |
1357                                                                            GET_WORD_BREAKS   |
1358                                                                            BIDI_INFO         |
1359                                                                            SHAPE_TEXT        |
1360                                                                            GET_GLYPH_METRICS );
1361     // Make sure the model is up-to-date before layouting
1362     mImpl->UpdateModel( onlyOnceOperations );
1363
1364     // Layout the text for the new width.
1365     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | LAYOUT );
1366
1367     // Set the update info to relayout the whole text.
1368     mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
1369     mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mLogicalModel->mText.Count();
1370
1371     // Store the actual control's size to restore later.
1372     const Size actualControlSize = mImpl->mVisualModel->mControlSize;
1373
1374     DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
1375                 static_cast<OperationsMask>( onlyOnceOperations |
1376                                              LAYOUT ),
1377                 naturalSize.GetVectorXY() );
1378
1379     // Do not do again the only once operations.
1380     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
1381
1382     // Do the size related operations again.
1383     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
1384                                                                         ALIGN  |
1385                                                                         REORDER );
1386     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
1387
1388     // Stores the natural size to avoid recalculate it again
1389     // unless the text/style changes.
1390     mImpl->mVisualModel->SetNaturalSize( naturalSize.GetVectorXY() );
1391
1392     mImpl->mRecalculateNaturalSize = false;
1393
1394     // Clear the update info. This info will be set the next time the text is updated.
1395     mImpl->mTextUpdateInfo.Clear();
1396
1397     // Restore the actual control's size.
1398     mImpl->mVisualModel->mControlSize = actualControlSize;
1399
1400     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize calculated %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z );
1401   }
1402   else
1403   {
1404     naturalSize = mImpl->mVisualModel->GetNaturalSize();
1405
1406     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize cached %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z );
1407   }
1408
1409   naturalSize.x = ConvertToEven( naturalSize.x );
1410   naturalSize.y = ConvertToEven( naturalSize.y );
1411
1412   return naturalSize;
1413 }
1414
1415 float Controller::GetHeightForWidth( float width )
1416 {
1417   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetHeightForWidth %p width %f\n", this, width );
1418   // Make sure the model is up-to-date before layouting
1419   ProcessModifyEvents();
1420
1421   Size layoutSize;
1422   if( fabsf( width - mImpl->mVisualModel->mControlSize.width ) > Math::MACHINE_EPSILON_1000 )
1423   {
1424     // Operations that can be done only once until the text changes.
1425     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
1426                                                                            GET_SCRIPTS       |
1427                                                                            VALIDATE_FONTS    |
1428                                                                            GET_LINE_BREAKS   |
1429                                                                            GET_WORD_BREAKS   |
1430                                                                            BIDI_INFO         |
1431                                                                            SHAPE_TEXT        |
1432                                                                            GET_GLYPH_METRICS );
1433     // Make sure the model is up-to-date before layouting
1434     mImpl->UpdateModel( onlyOnceOperations );
1435
1436
1437     // Layout the text for the new width.
1438     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | LAYOUT );
1439
1440     // Set the update info to relayout the whole text.
1441     mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
1442     mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mLogicalModel->mText.Count();
1443
1444     // Store the actual control's width.
1445     const float actualControlWidth = mImpl->mVisualModel->mControlSize.width;
1446
1447     DoRelayout( Size( width, MAX_FLOAT ),
1448                 static_cast<OperationsMask>( onlyOnceOperations |
1449                                              LAYOUT ),
1450                 layoutSize );
1451
1452     // Do not do again the only once operations.
1453     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
1454
1455     // Do the size related operations again.
1456     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
1457                                                                         ALIGN  |
1458                                                                         REORDER );
1459
1460     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
1461
1462     // Clear the update info. This info will be set the next time the text is updated.
1463     mImpl->mTextUpdateInfo.Clear();
1464
1465     // Restore the actual control's width.
1466     mImpl->mVisualModel->mControlSize.width = actualControlWidth;
1467
1468     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth calculated %f\n", layoutSize.height );
1469   }
1470   else
1471   {
1472     layoutSize = mImpl->mVisualModel->GetLayoutSize();
1473     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth cached %f\n", layoutSize.height );
1474   }
1475
1476   return layoutSize.height;
1477 }
1478
1479 Controller::UpdateTextType Controller::Relayout( const Size& size )
1480 {
1481   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::Relayout %p size %f,%f, autoScroll[%s]\n", this, size.width, size.height, (mImpl->mAutoScrollEnabled)?"true":"false"  );
1482
1483   UpdateTextType updateTextType = NONE_UPDATED;
1484
1485   if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
1486   {
1487     if( 0u != mImpl->mVisualModel->mGlyphPositions.Count() )
1488     {
1489       mImpl->mVisualModel->mGlyphPositions.Clear();
1490       updateTextType = MODEL_UPDATED;
1491     }
1492
1493     // Clear the update info. This info will be set the next time the text is updated.
1494     mImpl->mTextUpdateInfo.Clear();
1495
1496     // Not worth to relayout if width or height is equal to zero.
1497     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout (skipped)\n" );
1498
1499     return updateTextType;
1500   }
1501
1502   // Whether a new size has been set.
1503   const bool newSize = ( size != mImpl->mVisualModel->mControlSize );
1504
1505   if( newSize )
1506   {
1507     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "new size (previous size %f,%f)\n", mImpl->mVisualModel->mControlSize.width, mImpl->mVisualModel->mControlSize.height );
1508
1509     // Layout operations that need to be done if the size changes.
1510     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1511                                                              LAYOUT                    |
1512                                                              ALIGN                     |
1513                                                              UPDATE_LAYOUT_SIZE        |
1514                                                              REORDER );
1515     // Set the update info to relayout the whole text.
1516     mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
1517     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
1518   }
1519
1520   // Whether there are modify events.
1521   if( 0u != mImpl->mModifyEvents.Count() )
1522   {
1523     // Style operations that need to be done if the text is modified.
1524     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1525                                                              COLOR );
1526   }
1527
1528   // Make sure the model is up-to-date before layouting.
1529   ProcessModifyEvents();
1530   bool updated = mImpl->UpdateModel( mImpl->mOperationsPending );
1531
1532   // Layout the text.
1533   Size layoutSize;
1534   updated = DoRelayout( size,
1535                         mImpl->mOperationsPending,
1536                         layoutSize ) || updated;
1537
1538   if( updated )
1539   {
1540     updateTextType = MODEL_UPDATED;
1541   }
1542
1543   // Do not re-do any operation until something changes.
1544   mImpl->mOperationsPending = NO_OPERATION;
1545
1546   // Whether the text control is editable
1547   const bool isEditable = NULL != mImpl->mEventData;
1548
1549   // Keep the current offset as it will be used to update the decorator's positions (if the size changes).
1550   Vector2 offset;
1551   if( newSize && isEditable )
1552   {
1553     offset = mImpl->mScrollPosition;
1554   }
1555
1556   if( !isEditable || !IsMultiLineEnabled() )
1557   {
1558     // After doing the text layout, the vertical offset to place the actor in the desired position can be calculated.
1559     CalculateVerticalOffset( size );
1560   }
1561
1562   if( isEditable )
1563   {
1564     if( newSize )
1565     {
1566       // If there is a new size, the scroll position needs to be clamped.
1567       mImpl->ClampHorizontalScroll( layoutSize );
1568
1569       // Update the decorator's positions is needed if there is a new size.
1570       mImpl->mEventData->mDecorator->UpdatePositions( mImpl->mScrollPosition - offset );
1571     }
1572
1573     // Move the cursor, grab handle etc.
1574     if( mImpl->ProcessInputEvents() )
1575     {
1576       updateTextType = static_cast<UpdateTextType>( updateTextType | DECORATOR_UPDATED );
1577     }
1578   }
1579
1580   // Clear the update info. This info will be set the next time the text is updated.
1581   mImpl->mTextUpdateInfo.Clear();
1582   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout\n" );
1583
1584   return updateTextType;
1585 }
1586
1587 void Controller::ProcessModifyEvents()
1588 {
1589   Vector<ModifyEvent>& events = mImpl->mModifyEvents;
1590
1591   if( 0u == events.Count() )
1592   {
1593     // Nothing to do.
1594     return;
1595   }
1596
1597   for( Vector<ModifyEvent>::ConstIterator it = events.Begin(),
1598          endIt = events.End();
1599        it != endIt;
1600        ++it )
1601   {
1602     const ModifyEvent& event = *it;
1603
1604     if( ModifyEvent::TEXT_REPLACED == event.type )
1605     {
1606       // A (single) replace event should come first, otherwise we wasted time processing NOOP events
1607       DALI_ASSERT_DEBUG( it == events.Begin() && "Unexpected TEXT_REPLACED event" );
1608
1609       TextReplacedEvent();
1610     }
1611     else if( ModifyEvent::TEXT_INSERTED == event.type )
1612     {
1613       TextInsertedEvent();
1614     }
1615     else if( ModifyEvent::TEXT_DELETED == event.type )
1616     {
1617       // Placeholder-text cannot be deleted
1618       if( !mImpl->IsShowingPlaceholderText() )
1619       {
1620         TextDeletedEvent();
1621       }
1622     }
1623   }
1624
1625   if( NULL != mImpl->mEventData )
1626   {
1627     // When the text is being modified, delay cursor blinking
1628     mImpl->mEventData->mDecorator->DelayCursorBlink();
1629   }
1630
1631   // Discard temporary text
1632   events.Clear();
1633 }
1634
1635 bool Controller::IsInputStyleChangedSignalsQueueEmpty()
1636 {
1637   return ( NULL == mImpl->mEventData ) || ( 0u == mImpl->mEventData->mInputStyleChangedQueue.Count() );
1638 }
1639
1640 void Controller::ProcessInputStyleChangedSignals()
1641 {
1642   if( NULL == mImpl->mEventData )
1643   {
1644     // Nothing to do.
1645     return;
1646   }
1647
1648   for( Vector<InputStyle::Mask>::ConstIterator it = mImpl->mEventData->mInputStyleChangedQueue.Begin(),
1649          endIt = mImpl->mEventData->mInputStyleChangedQueue.End();
1650        it != endIt;
1651        ++it )
1652   {
1653     const InputStyle::Mask mask = *it;
1654
1655     // Emit the input style changed signal.
1656     mImpl->mControlInterface.InputStyleChanged( mask );
1657   }
1658
1659   mImpl->mEventData->mInputStyleChangedQueue.Clear();
1660 }
1661
1662 void Controller::ResetText()
1663 {
1664   // Reset buffers.
1665   mImpl->mLogicalModel->mText.Clear();
1666
1667   // We have cleared everything including the placeholder-text
1668   mImpl->PlaceholderCleared();
1669
1670   mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
1671   mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
1672   mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = 0u;
1673
1674   // Clear any previous text.
1675   mImpl->mTextUpdateInfo.mClearAll = true;
1676
1677   // The natural size needs to be re-calculated.
1678   mImpl->mRecalculateNaturalSize = true;
1679
1680   // Apply modifications to the model
1681   mImpl->mOperationsPending = ALL_OPERATIONS;
1682 }
1683
1684 void Controller::ResetCursorPosition( CharacterIndex cursorIndex )
1685 {
1686   // Reset the cursor position
1687   if( NULL != mImpl->mEventData )
1688   {
1689     mImpl->mEventData->mPrimaryCursorPosition = cursorIndex;
1690
1691     // Update the cursor if it's in editing mode.
1692     if( EventData::IsEditingState( mImpl->mEventData->mState )  )
1693     {
1694       mImpl->mEventData->mUpdateCursorPosition = true;
1695     }
1696   }
1697 }
1698
1699 void Controller::ResetScrollPosition()
1700 {
1701   if( NULL != mImpl->mEventData )
1702   {
1703     // Reset the scroll position.
1704     mImpl->mScrollPosition = Vector2::ZERO;
1705     mImpl->mEventData->mScrollAfterUpdatePosition = true;
1706   }
1707 }
1708
1709 void Controller::TextReplacedEvent()
1710 {
1711   // The natural size needs to be re-calculated.
1712   mImpl->mRecalculateNaturalSize = true;
1713
1714   // Apply modifications to the model
1715   mImpl->mOperationsPending = ALL_OPERATIONS;
1716 }
1717
1718 void Controller::TextInsertedEvent()
1719 {
1720   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextInsertedEvent" );
1721
1722   if( NULL == mImpl->mEventData )
1723   {
1724     return;
1725   }
1726
1727   // The natural size needs to be re-calculated.
1728   mImpl->mRecalculateNaturalSize = true;
1729
1730   // Apply modifications to the model; TODO - Optimize this
1731   mImpl->mOperationsPending = ALL_OPERATIONS;
1732 }
1733
1734 void Controller::TextDeletedEvent()
1735 {
1736   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextDeletedEvent" );
1737
1738   if( NULL == mImpl->mEventData )
1739   {
1740     return;
1741   }
1742
1743   // The natural size needs to be re-calculated.
1744   mImpl->mRecalculateNaturalSize = true;
1745
1746   // Apply modifications to the model; TODO - Optimize this
1747   mImpl->mOperationsPending = ALL_OPERATIONS;
1748 }
1749
1750 bool Controller::DoRelayout( const Size& size,
1751                              OperationsMask operationsRequired,
1752                              Size& layoutSize )
1753 {
1754   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::DoRelayout %p size %f,%f\n", this, size.width, size.height );
1755   bool viewUpdated( false );
1756
1757   // Calculate the operations to be done.
1758   const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
1759
1760   const CharacterIndex startIndex = mImpl->mTextUpdateInfo.mParagraphCharacterIndex;
1761   const Length requestedNumberOfCharacters = mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters;
1762
1763   // Get the current layout size.
1764   layoutSize = mImpl->mVisualModel->GetLayoutSize();
1765
1766   if( NO_OPERATION != ( LAYOUT & operations ) )
1767   {
1768     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::DoRelayout LAYOUT & operations\n");
1769
1770     // Some vectors with data needed to layout and reorder may be void
1771     // after the first time the text has been laid out.
1772     // Fill the vectors again.
1773
1774     // Calculate the number of glyphs to layout.
1775     const Vector<GlyphIndex>& charactersToGlyph = mImpl->mVisualModel->mCharactersToGlyph;
1776     const Vector<Length>& glyphsPerCharacter = mImpl->mVisualModel->mGlyphsPerCharacter;
1777     const GlyphIndex* const charactersToGlyphBuffer = charactersToGlyph.Begin();
1778     const Length* const glyphsPerCharacterBuffer = glyphsPerCharacter.Begin();
1779
1780     const CharacterIndex lastIndex = startIndex + ( ( requestedNumberOfCharacters > 0u ) ? requestedNumberOfCharacters - 1u : 0u );
1781     const GlyphIndex startGlyphIndex = mImpl->mTextUpdateInfo.mStartGlyphIndex;
1782     const Length numberOfGlyphs = ( requestedNumberOfCharacters > 0u ) ? *( charactersToGlyphBuffer + lastIndex ) + *( glyphsPerCharacterBuffer + lastIndex ) - startGlyphIndex : 0u;
1783     const Length totalNumberOfGlyphs = mImpl->mVisualModel->mGlyphs.Count();
1784
1785     if( 0u == totalNumberOfGlyphs )
1786     {
1787       if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) )
1788       {
1789         mImpl->mVisualModel->SetLayoutSize( Size::ZERO );
1790       }
1791
1792       // Nothing else to do if there is no glyphs.
1793       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout no glyphs, view updated true\n" );
1794       return true;
1795     }
1796
1797     const Vector<LineBreakInfo>& lineBreakInfo = mImpl->mLogicalModel->mLineBreakInfo;
1798     const Vector<WordBreakInfo>& wordBreakInfo = mImpl->mLogicalModel->mWordBreakInfo;
1799     const Vector<CharacterDirection>& characterDirection = mImpl->mLogicalModel->mCharacterDirections;
1800     const Vector<GlyphInfo>& glyphs = mImpl->mVisualModel->mGlyphs;
1801     const Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mVisualModel->mGlyphsToCharacters;
1802     const Vector<Length>& charactersPerGlyph = mImpl->mVisualModel->mCharactersPerGlyph;
1803     const Character* const textBuffer = mImpl->mLogicalModel->mText.Begin();
1804
1805     // Set the layout parameters.
1806     LayoutParameters layoutParameters( size,
1807                                        textBuffer,
1808                                        lineBreakInfo.Begin(),
1809                                        wordBreakInfo.Begin(),
1810                                        ( 0u != characterDirection.Count() ) ? characterDirection.Begin() : NULL,
1811                                        glyphs.Begin(),
1812                                        glyphsToCharactersMap.Begin(),
1813                                        charactersPerGlyph.Begin(),
1814                                        charactersToGlyphBuffer,
1815                                        glyphsPerCharacterBuffer,
1816                                        totalNumberOfGlyphs );
1817
1818     // Resize the vector of positions to have the same size than the vector of glyphs.
1819     Vector<Vector2>& glyphPositions = mImpl->mVisualModel->mGlyphPositions;
1820     glyphPositions.Resize( totalNumberOfGlyphs );
1821
1822     // Whether the last character is a new paragraph character.
1823     mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph =  TextAbstraction::IsNewParagraph( *( textBuffer + ( mImpl->mLogicalModel->mText.Count() - 1u ) ) );
1824     layoutParameters.isLastNewParagraph = mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph;
1825
1826     // The initial glyph and the number of glyphs to layout.
1827     layoutParameters.startGlyphIndex = startGlyphIndex;
1828     layoutParameters.numberOfGlyphs = numberOfGlyphs;
1829     layoutParameters.startLineIndex = mImpl->mTextUpdateInfo.mStartLineIndex;
1830     layoutParameters.estimatedNumberOfLines = mImpl->mTextUpdateInfo.mEstimatedNumberOfLines;
1831
1832     // Update the visual model.
1833     Size newLayoutSize;
1834     viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
1835                                                    glyphPositions,
1836                                                    mImpl->mVisualModel->mLines,
1837                                                    newLayoutSize );
1838
1839     viewUpdated = viewUpdated || ( newLayoutSize != layoutSize );
1840
1841     if( viewUpdated )
1842     {
1843       layoutSize = newLayoutSize;
1844
1845       if ( NO_OPERATION != ( UPDATE_DIRECTION & operations ) )
1846       {
1847         mImpl->mAutoScrollDirectionRTL = false;
1848       }
1849
1850       // Reorder the lines
1851       if( NO_OPERATION != ( REORDER & operations ) )
1852       {
1853         Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mImpl->mLogicalModel->mBidirectionalParagraphInfo;
1854         Vector<BidirectionalLineInfoRun>& bidirectionalLineInfo = mImpl->mLogicalModel->mBidirectionalLineInfo;
1855
1856         // Check first if there are paragraphs with bidirectional info.
1857         if( 0u != bidirectionalInfo.Count() )
1858         {
1859           // Get the lines
1860           const Length numberOfLines = mImpl->mVisualModel->mLines.Count();
1861
1862           // Reorder the lines.
1863           bidirectionalLineInfo.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
1864           ReorderLines( bidirectionalInfo,
1865                         startIndex,
1866                         requestedNumberOfCharacters,
1867                         mImpl->mVisualModel->mLines,
1868                         bidirectionalLineInfo );
1869
1870           // Set the bidirectional info per line into the layout parameters.
1871           layoutParameters.lineBidirectionalInfoRunsBuffer = bidirectionalLineInfo.Begin();
1872           layoutParameters.numberOfBidirectionalInfoRuns = bidirectionalLineInfo.Count();
1873
1874           // Re-layout the text. Reorder those lines with right to left characters.
1875           mImpl->mLayoutEngine.ReLayoutRightToLeftLines( layoutParameters,
1876                                                          startIndex,
1877                                                          requestedNumberOfCharacters,
1878                                                          glyphPositions );
1879
1880           if ( ( NO_OPERATION != ( UPDATE_DIRECTION & operations ) ) && ( numberOfLines > 0 ) )
1881           {
1882             const LineRun* const firstline = mImpl->mVisualModel->mLines.Begin();
1883             if ( firstline )
1884             {
1885               mImpl->mAutoScrollDirectionRTL = firstline->direction;
1886             }
1887           }
1888         }
1889       } // REORDER
1890
1891       // Sets the layout size.
1892       if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) )
1893       {
1894         mImpl->mVisualModel->SetLayoutSize( layoutSize );
1895       }
1896     } // view updated
1897
1898     // Store the size used to layout the text.
1899     mImpl->mVisualModel->mControlSize = size;
1900   }
1901
1902   if( NO_OPERATION != ( ALIGN & operations ) )
1903   {
1904     // The laid-out lines.
1905     Vector<LineRun>& lines = mImpl->mVisualModel->mLines;
1906
1907     mImpl->mLayoutEngine.Align( size,
1908                                 startIndex,
1909                                 requestedNumberOfCharacters,
1910                                 lines );
1911
1912     viewUpdated = true;
1913   }
1914 #if defined(DEBUG_ENABLED)
1915   std::string currentText;
1916   GetText( currentText );
1917   DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::DoRelayout [%p] mImpl->mAutoScrollDirectionRTL[%s] [%s]\n", this, (mImpl->mAutoScrollDirectionRTL)?"true":"false",  currentText.c_str() );
1918 #endif
1919   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout, view updated %s\n", ( viewUpdated ? "true" : "false" ) );
1920   return viewUpdated;
1921 }
1922
1923 void Controller::SetMultiLineEnabled( bool enable )
1924 {
1925   const LayoutEngine::Layout layout = enable ? LayoutEngine::MULTI_LINE_BOX : LayoutEngine::SINGLE_LINE_BOX;
1926
1927   if( layout != mImpl->mLayoutEngine.GetLayout() )
1928   {
1929     // Set the layout type.
1930     mImpl->mLayoutEngine.SetLayout( layout );
1931
1932     // Set the flags to redo the layout operations
1933     const OperationsMask layoutOperations =  static_cast<OperationsMask>( LAYOUT             |
1934                                                                           UPDATE_LAYOUT_SIZE |
1935                                                                           ALIGN              |
1936                                                                           REORDER );
1937
1938     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | layoutOperations );
1939
1940     mImpl->RequestRelayout();
1941   }
1942 }
1943
1944 bool Controller::IsMultiLineEnabled() const
1945 {
1946   return LayoutEngine::MULTI_LINE_BOX == mImpl->mLayoutEngine.GetLayout();
1947 }
1948
1949 void Controller::SetHorizontalAlignment( LayoutEngine::HorizontalAlignment alignment )
1950 {
1951   if( alignment != mImpl->mLayoutEngine.GetHorizontalAlignment() )
1952   {
1953     // Set the alignment.
1954     mImpl->mLayoutEngine.SetHorizontalAlignment( alignment );
1955
1956     // Set the flag to redo the alignment operation.
1957     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | ALIGN );
1958
1959     mImpl->RequestRelayout();
1960   }
1961 }
1962
1963 LayoutEngine::HorizontalAlignment Controller::GetHorizontalAlignment() const
1964 {
1965   return mImpl->mLayoutEngine.GetHorizontalAlignment();
1966 }
1967
1968 void Controller::SetVerticalAlignment( LayoutEngine::VerticalAlignment alignment )
1969 {
1970   if( alignment != mImpl->mLayoutEngine.GetVerticalAlignment() )
1971   {
1972     // Set the alignment.
1973     mImpl->mLayoutEngine.SetVerticalAlignment( alignment );
1974
1975     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | ALIGN );
1976
1977     mImpl->RequestRelayout();
1978   }
1979 }
1980
1981 LayoutEngine::VerticalAlignment Controller::GetVerticalAlignment() const
1982 {
1983   return mImpl->mLayoutEngine.GetVerticalAlignment();
1984 }
1985
1986 void Controller::CalculateVerticalOffset( const Size& controlSize )
1987 {
1988   Size layoutSize = mImpl->mVisualModel->GetLayoutSize();
1989
1990   if( fabsf( layoutSize.height ) < Math::MACHINE_EPSILON_1000 )
1991   {
1992     // Get the line height of the default font.
1993     layoutSize.height = mImpl->GetDefaultFontLineHeight();
1994   }
1995
1996   switch( mImpl->mLayoutEngine.GetVerticalAlignment() )
1997   {
1998     case LayoutEngine::VERTICAL_ALIGN_TOP:
1999     {
2000       mImpl->mScrollPosition.y = 0.f;
2001       break;
2002     }
2003     case LayoutEngine::VERTICAL_ALIGN_CENTER:
2004     {
2005       mImpl->mScrollPosition.y = floorf( 0.5f * ( controlSize.height - layoutSize.height ) ); // try to avoid pixel alignment.
2006       break;
2007     }
2008     case LayoutEngine::VERTICAL_ALIGN_BOTTOM:
2009     {
2010       mImpl->mScrollPosition.y = controlSize.height - layoutSize.height;
2011       break;
2012     }
2013   }
2014 }
2015
2016 LayoutEngine& Controller::GetLayoutEngine()
2017 {
2018   return mImpl->mLayoutEngine;
2019 }
2020
2021 View& Controller::GetView()
2022 {
2023   return mImpl->mView;
2024 }
2025
2026 void Controller::KeyboardFocusGainEvent()
2027 {
2028   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusGainEvent" );
2029
2030   if( NULL != mImpl->mEventData )
2031   {
2032     if( ( EventData::INACTIVE == mImpl->mEventData->mState ) ||
2033         ( EventData::INTERRUPTED == mImpl->mEventData->mState ) )
2034     {
2035       mImpl->ChangeState( EventData::EDITING );
2036       mImpl->mEventData->mUpdateCursorPosition = true; //If editing started without tap event, cursor update must be triggered.
2037     }
2038     mImpl->NotifyImfMultiLineStatus();
2039     if( mImpl->IsShowingPlaceholderText() )
2040     {
2041       // Show alternative placeholder-text when editing
2042       ShowPlaceholderText();
2043     }
2044
2045     mImpl->RequestRelayout();
2046   }
2047 }
2048
2049 void Controller::KeyboardFocusLostEvent()
2050 {
2051   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusLostEvent" );
2052
2053   if( NULL != mImpl->mEventData )
2054   {
2055     if( EventData::INTERRUPTED != mImpl->mEventData->mState )
2056     {
2057       mImpl->ChangeState( EventData::INACTIVE );
2058
2059       if( !mImpl->IsShowingRealText() )
2060       {
2061         // Revert to regular placeholder-text when not editing
2062         ShowPlaceholderText();
2063       }
2064     }
2065   }
2066   mImpl->RequestRelayout();
2067 }
2068
2069 bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
2070 {
2071   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyEvent" );
2072
2073   bool textChanged( false );
2074
2075   if( ( NULL != mImpl->mEventData ) &&
2076       ( keyEvent.state == KeyEvent::Down ) )
2077   {
2078     int keyCode = keyEvent.keyCode;
2079     const std::string& keyString = keyEvent.keyPressed;
2080
2081     // Pre-process to separate modifying events from non-modifying input events.
2082     if( Dali::DALI_KEY_ESCAPE == keyCode )
2083     {
2084       // Escape key is a special case which causes focus loss
2085       KeyboardFocusLostEvent();
2086     }
2087     else if( ( Dali::DALI_KEY_CURSOR_LEFT  == keyCode ) ||
2088              ( Dali::DALI_KEY_CURSOR_RIGHT == keyCode ) ||
2089              ( Dali::DALI_KEY_CURSOR_UP    == keyCode ) ||
2090              ( Dali::DALI_KEY_CURSOR_DOWN  == keyCode ) )
2091     {
2092       Event event( Event::CURSOR_KEY_EVENT );
2093       event.p1.mInt = keyCode;
2094       mImpl->mEventData->mEventQueue.push_back( event );
2095     }
2096     else if( Dali::DALI_KEY_BACKSPACE == keyCode )
2097     {
2098       textChanged = BackspaceKeyEvent();
2099     }
2100     else if( IsKey( keyEvent,  Dali::DALI_KEY_POWER ) )
2101     {
2102       mImpl->ChangeState( EventData::INTERRUPTED ); // State is not INACTIVE as expect to return to edit mode.
2103       // Avoids calling the InsertText() method which can delete selected text
2104     }
2105     else if( IsKey( keyEvent, Dali::DALI_KEY_MENU ) ||
2106              IsKey( keyEvent, Dali::DALI_KEY_HOME ) )
2107     {
2108       mImpl->ChangeState( EventData::INACTIVE );
2109       // Menu/Home key behaviour does not allow edit mode to resume like Power key
2110       // Avoids calling the InsertText() method which can delete selected text
2111     }
2112     else if( Dali::DALI_KEY_SHIFT_LEFT == keyCode )
2113     {
2114       // DALI_KEY_SHIFT_LEFT is the key code for the Left Shift. It's sent (by the imf?) when the predictive text is enabled
2115       // and a character is typed after the type of a upper case latin character.
2116
2117       // Do nothing.
2118     }
2119     else
2120     {
2121       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p keyString %s\n", this, keyString.c_str() );
2122
2123       // IMF manager is no longer handling key-events
2124       mImpl->ClearPreEditFlag();
2125
2126       InsertText( keyString, COMMIT );
2127       textChanged = true;
2128     }
2129
2130     if ( ( mImpl->mEventData->mState != EventData::INTERRUPTED ) &&
2131          ( mImpl->mEventData->mState != EventData::INACTIVE ) &&
2132          ( Dali::DALI_KEY_SHIFT_LEFT != keyCode ) )
2133     {
2134       // Should not change the state if the key is the shift send by the imf manager.
2135       // Otherwise, when the state is SELECTING the text controller can't send the right
2136       // surrounding info to the imf.
2137       mImpl->ChangeState( EventData::EDITING );
2138     }
2139
2140     mImpl->RequestRelayout();
2141   }
2142
2143   if( textChanged )
2144   {
2145     // Do this last since it provides callbacks into application code
2146     mImpl->mControlInterface.TextChanged();
2147   }
2148
2149   return true;
2150 }
2151
2152 void Controller::InsertText( const std::string& text, Controller::InsertType type )
2153 {
2154   bool removedPrevious( false );
2155   bool maxLengthReached( false );
2156
2157   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected InsertText" )
2158
2159   if( NULL == mImpl->mEventData )
2160   {
2161     return;
2162   }
2163
2164   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::InsertText %p %s (%s) mPrimaryCursorPosition %d mPreEditFlag %d mPreEditStartPosition %d mPreEditLength %d\n",
2165                  this, text.c_str(), (COMMIT == type ? "COMMIT" : "PRE_EDIT"),
2166                  mImpl->mEventData->mPrimaryCursorPosition, mImpl->mEventData->mPreEditFlag, mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
2167
2168   // TODO: At the moment the underline runs are only for pre-edit.
2169   mImpl->mVisualModel->mUnderlineRuns.Clear();
2170
2171   // Keep the current number of characters.
2172   const Length currentNumberOfCharacters = mImpl->IsShowingRealText() ? mImpl->mLogicalModel->mText.Count() : 0u;
2173
2174   // Remove the previous IMF pre-edit.
2175   if( mImpl->mEventData->mPreEditFlag && ( 0u != mImpl->mEventData->mPreEditLength ) )
2176   {
2177     removedPrevious = RemoveText( -static_cast<int>( mImpl->mEventData->mPrimaryCursorPosition - mImpl->mEventData->mPreEditStartPosition ),
2178                                   mImpl->mEventData->mPreEditLength,
2179                                   DONT_UPDATE_INPUT_STYLE );
2180
2181     mImpl->mEventData->mPrimaryCursorPosition = mImpl->mEventData->mPreEditStartPosition;
2182     mImpl->mEventData->mPreEditLength = 0u;
2183   }
2184   else
2185   {
2186     // Remove the previous Selection.
2187     removedPrevious = RemoveSelectedText();
2188   }
2189
2190   Vector<Character> utf32Characters;
2191   Length characterCount = 0u;
2192
2193   if( !text.empty() )
2194   {
2195     //  Convert text into UTF-32
2196     utf32Characters.Resize( text.size() );
2197
2198     // This is a bit horrible but std::string returns a (signed) char*
2199     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
2200
2201     // Transform a text array encoded in utf8 into an array encoded in utf32.
2202     // It returns the actual number of characters.
2203     characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
2204     utf32Characters.Resize( characterCount );
2205
2206     DALI_ASSERT_DEBUG( text.size() >= utf32Characters.Count() && "Invalid UTF32 conversion length" );
2207     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "UTF8 size %d, UTF32 size %d\n", text.size(), utf32Characters.Count() );
2208   }
2209
2210   if( 0u != utf32Characters.Count() ) // Check if Utf8ToUtf32 conversion succeeded
2211   {
2212     // The placeholder text is no longer needed
2213     if( mImpl->IsShowingPlaceholderText() )
2214     {
2215       ResetText();
2216     }
2217
2218     mImpl->ChangeState( EventData::EDITING );
2219
2220     // Handle the IMF (predicitive text) state changes
2221     if( COMMIT == type )
2222     {
2223       // IMF manager is no longer handling key-events
2224       mImpl->ClearPreEditFlag();
2225     }
2226     else // PRE_EDIT
2227     {
2228       if( !mImpl->mEventData->mPreEditFlag )
2229       {
2230         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Entered PreEdit state\n" );
2231
2232         // Record the start of the pre-edit text
2233         mImpl->mEventData->mPreEditStartPosition = mImpl->mEventData->mPrimaryCursorPosition;
2234       }
2235
2236       mImpl->mEventData->mPreEditLength = utf32Characters.Count();
2237       mImpl->mEventData->mPreEditFlag = true;
2238
2239       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "mPreEditStartPosition %d mPreEditLength %d\n", mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
2240     }
2241
2242     const Length numberOfCharactersInModel = mImpl->mLogicalModel->mText.Count();
2243
2244     // Restrict new text to fit within Maximum characters setting.
2245     Length maxSizeOfNewText = std::min( ( mImpl->mMaximumNumberOfCharacters - numberOfCharactersInModel ), characterCount );
2246     maxLengthReached = ( characterCount > maxSizeOfNewText );
2247
2248     // The cursor position.
2249     CharacterIndex& cursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
2250
2251     // Update the text's style.
2252
2253     // Updates the text style runs by adding characters.
2254     mImpl->mLogicalModel->UpdateTextStyleRuns( cursorIndex, maxSizeOfNewText );
2255
2256     // Get the character index from the cursor index.
2257     const CharacterIndex styleIndex = ( cursorIndex > 0u ) ? cursorIndex - 1u : 0u;
2258
2259     // Retrieve the text's style for the given index.
2260     InputStyle style;
2261     mImpl->RetrieveDefaultInputStyle( style );
2262     mImpl->mLogicalModel->RetrieveStyle( styleIndex, style );
2263
2264     // Whether to add a new text color run.
2265     const bool addColorRun = ( style.textColor != mImpl->mEventData->mInputStyle.textColor );
2266
2267     // Whether to add a new font run.
2268     const bool addFontNameRun = style.familyName != mImpl->mEventData->mInputStyle.familyName;
2269     const bool addFontWeightRun = style.weight != mImpl->mEventData->mInputStyle.weight;
2270     const bool addFontWidthRun = style.width != mImpl->mEventData->mInputStyle.width;
2271     const bool addFontSlantRun = style.slant != mImpl->mEventData->mInputStyle.slant;
2272     const bool addFontSizeRun = style.size != mImpl->mEventData->mInputStyle.size;
2273
2274     // Add style runs.
2275     if( addColorRun )
2276     {
2277       const VectorBase::SizeType numberOfRuns = mImpl->mLogicalModel->mColorRuns.Count();
2278       mImpl->mLogicalModel->mColorRuns.Resize( numberOfRuns + 1u );
2279
2280       ColorRun& colorRun = *( mImpl->mLogicalModel->mColorRuns.Begin() + numberOfRuns );
2281       colorRun.color = mImpl->mEventData->mInputStyle.textColor;
2282       colorRun.characterRun.characterIndex = cursorIndex;
2283       colorRun.characterRun.numberOfCharacters = maxSizeOfNewText;
2284     }
2285
2286     if( addFontNameRun   ||
2287         addFontWeightRun ||
2288         addFontWidthRun  ||
2289         addFontSlantRun  ||
2290         addFontSizeRun )
2291     {
2292       const VectorBase::SizeType numberOfRuns = mImpl->mLogicalModel->mFontDescriptionRuns.Count();
2293       mImpl->mLogicalModel->mFontDescriptionRuns.Resize( numberOfRuns + 1u );
2294
2295       FontDescriptionRun& fontDescriptionRun = *( mImpl->mLogicalModel->mFontDescriptionRuns.Begin() + numberOfRuns );
2296
2297       if( addFontNameRun )
2298       {
2299         fontDescriptionRun.familyLength = mImpl->mEventData->mInputStyle.familyName.size();
2300         fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
2301         memcpy( fontDescriptionRun.familyName, mImpl->mEventData->mInputStyle.familyName.c_str(), fontDescriptionRun.familyLength );
2302         fontDescriptionRun.familyDefined = true;
2303
2304         // The memory allocated for the font family name is freed when the font description is removed from the logical model.
2305       }
2306
2307       if( addFontWeightRun )
2308       {
2309         fontDescriptionRun.weight = mImpl->mEventData->mInputStyle.weight;
2310         fontDescriptionRun.weightDefined = true;
2311       }
2312
2313       if( addFontWidthRun )
2314       {
2315         fontDescriptionRun.width = mImpl->mEventData->mInputStyle.width;
2316         fontDescriptionRun.widthDefined = true;
2317       }
2318
2319       if( addFontSlantRun )
2320       {
2321         fontDescriptionRun.slant = mImpl->mEventData->mInputStyle.slant;
2322         fontDescriptionRun.slantDefined = true;
2323       }
2324
2325       if( addFontSizeRun )
2326       {
2327         fontDescriptionRun.size = static_cast<PointSize26Dot6>( mImpl->mEventData->mInputStyle.size * 64.f );
2328         fontDescriptionRun.sizeDefined = true;
2329       }
2330
2331       fontDescriptionRun.characterRun.characterIndex = cursorIndex;
2332       fontDescriptionRun.characterRun.numberOfCharacters = maxSizeOfNewText;
2333     }
2334
2335     // Insert at current cursor position.
2336     Vector<Character>& modifyText = mImpl->mLogicalModel->mText;
2337
2338     if( cursorIndex < numberOfCharactersInModel )
2339     {
2340       modifyText.Insert( modifyText.Begin() + cursorIndex, utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
2341     }
2342     else
2343     {
2344       modifyText.Insert( modifyText.End(), utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
2345     }
2346
2347     // Mark the first paragraph to be updated.
2348     mImpl->mTextUpdateInfo.mCharacterIndex = std::min( cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex );
2349     mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd += maxSizeOfNewText;
2350
2351     // Update the cursor index.
2352     cursorIndex += maxSizeOfNewText;
2353
2354     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Inserted %d characters, new size %d new cursor %d\n", maxSizeOfNewText, mImpl->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition );
2355   }
2356
2357   const Length numberOfCharacters = mImpl->IsShowingRealText() ? mImpl->mLogicalModel->mText.Count() : 0u;
2358
2359   if( ( 0u == mImpl->mLogicalModel->mText.Count() ) &&
2360       mImpl->IsPlaceholderAvailable() )
2361   {
2362     // Show place-holder if empty after removing the pre-edit text
2363     ShowPlaceholderText();
2364     mImpl->mEventData->mUpdateCursorPosition = true;
2365     mImpl->ClearPreEditFlag();
2366   }
2367   else if( removedPrevious ||
2368            ( 0 != utf32Characters.Count() ) )
2369   {
2370     // Queue an inserted event
2371     mImpl->QueueModifyEvent( ModifyEvent::TEXT_INSERTED );
2372
2373     mImpl->mEventData->mUpdateCursorPosition = true;
2374     if( numberOfCharacters < currentNumberOfCharacters )
2375     {
2376       mImpl->mEventData->mScrollAfterDelete = true;
2377     }
2378     else
2379     {
2380       mImpl->mEventData->mScrollAfterUpdatePosition = true;
2381     }
2382   }
2383
2384   if( maxLengthReached )
2385   {
2386     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "MaxLengthReached (%d)\n", mImpl->mLogicalModel->mText.Count() );
2387
2388     mImpl->ResetImfManager();
2389
2390     // Do this last since it provides callbacks into application code
2391     mImpl->mControlInterface.MaxLengthReached();
2392   }
2393 }
2394
2395 bool Controller::RemoveSelectedText()
2396 {
2397   bool textRemoved( false );
2398
2399   if( EventData::SELECTING == mImpl->mEventData->mState )
2400   {
2401     std::string removedString;
2402     mImpl->RetrieveSelection( removedString, true );
2403
2404     if( !removedString.empty() )
2405     {
2406       textRemoved = true;
2407       mImpl->ChangeState( EventData::EDITING );
2408     }
2409   }
2410
2411   return textRemoved;
2412 }
2413
2414 void Controller::TapEvent( unsigned int tapCount, float x, float y )
2415 {
2416   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected TapEvent" );
2417
2418   if( NULL != mImpl->mEventData )
2419   {
2420     DALI_LOG_INFO( gLogFilter, Debug::Concise, "TapEvent state:%d \n", mImpl->mEventData->mState );
2421
2422     if( 1u == tapCount )
2423     {
2424       // This is to avoid unnecessary relayouts when tapping an empty text-field
2425       bool relayoutNeeded( false );
2426
2427       if( ( EventData::EDITING_WITH_POPUP == mImpl->mEventData->mState ) ||
2428           ( EventData::EDITING_WITH_PASTE_POPUP == mImpl->mEventData->mState ) )
2429       {
2430         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );  // If Popup shown hide it here so can be shown again if required.
2431       }
2432
2433       if( mImpl->IsShowingRealText() && ( EventData::INACTIVE != mImpl->mEventData->mState ) )
2434       {
2435         // Already in an active state so show a popup
2436         if( !mImpl->IsClipboardEmpty() )
2437         {
2438           // Shows Paste popup but could show full popup with Selection options. ( EDITING_WITH_POPUP )
2439           mImpl->ChangeState( EventData::EDITING_WITH_PASTE_POPUP );
2440         }
2441         else
2442         {
2443           // Show cursor and grabhandle on first tap, this matches the behaviour of tapping when already editing
2444           mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );
2445         }
2446         relayoutNeeded = true;
2447       }
2448       else
2449       {
2450         if( mImpl->IsShowingPlaceholderText() && !mImpl->IsFocusedPlaceholderAvailable() )
2451         {
2452           // Hide placeholder text
2453           ResetText();
2454         }
2455
2456         if( EventData::INACTIVE == mImpl->mEventData->mState )
2457         {
2458           mImpl->ChangeState( EventData::EDITING );
2459         }
2460         else if( !mImpl->IsClipboardEmpty() )
2461         {
2462           mImpl->ChangeState( EventData::EDITING_WITH_POPUP );
2463         }
2464         relayoutNeeded = true;
2465       }
2466
2467       // Handles & cursors must be repositioned after Relayout() i.e. after the Model has been updated
2468       if( relayoutNeeded )
2469       {
2470         Event event( Event::TAP_EVENT );
2471         event.p1.mUint = tapCount;
2472         event.p2.mFloat = x;
2473         event.p3.mFloat = y;
2474         mImpl->mEventData->mEventQueue.push_back( event );
2475
2476         mImpl->RequestRelayout();
2477       }
2478     }
2479     else if( 2u == tapCount )
2480     {
2481       if( mImpl->mEventData->mSelectionEnabled &&
2482           mImpl->IsShowingRealText() )
2483       {
2484         SelectEvent( x, y, false );
2485       }
2486     }
2487   }
2488
2489   // Reset keyboard as tap event has occurred.
2490   mImpl->ResetImfManager();
2491 }
2492
2493 void Controller::PanEvent( Gesture::State state, const Vector2& displacement )
2494 {
2495   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected PanEvent" );
2496
2497   if( NULL != mImpl->mEventData )
2498   {
2499     Event event( Event::PAN_EVENT );
2500     event.p1.mInt = state;
2501     event.p2.mFloat = displacement.x;
2502     event.p3.mFloat = displacement.y;
2503     mImpl->mEventData->mEventQueue.push_back( event );
2504
2505     mImpl->RequestRelayout();
2506   }
2507 }
2508
2509 void Controller::LongPressEvent( Gesture::State state, float x, float y  )
2510 {
2511   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected LongPressEvent" );
2512
2513   if( ( state == Gesture::Started ) &&
2514       ( NULL != mImpl->mEventData ) )
2515   {
2516     if( !mImpl->IsShowingRealText() )
2517     {
2518       Event event( Event::LONG_PRESS_EVENT );
2519       event.p1.mInt = state;
2520       mImpl->mEventData->mEventQueue.push_back( event );
2521       mImpl->RequestRelayout();
2522     }
2523     else
2524     {
2525       // The 1st long-press on inactive text-field is treated as tap
2526       if( EventData::INACTIVE == mImpl->mEventData->mState )
2527       {
2528         mImpl->ChangeState( EventData::EDITING );
2529
2530         Event event( Event::TAP_EVENT );
2531         event.p1.mUint = 1;
2532         event.p2.mFloat = x;
2533         event.p3.mFloat = y;
2534         mImpl->mEventData->mEventQueue.push_back( event );
2535
2536         mImpl->RequestRelayout();
2537       }
2538       else
2539       {
2540         // Reset the imf manger to commit the pre-edit before selecting the text.
2541         mImpl->ResetImfManager();
2542
2543         SelectEvent( x, y, false );
2544       }
2545     }
2546   }
2547 }
2548
2549 void Controller::SelectEvent( float x, float y, bool selectAll )
2550 {
2551   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SelectEvent\n" );
2552
2553   if( NULL != mImpl->mEventData )
2554   {
2555     if( selectAll )
2556     {
2557       Event event( Event::SELECT_ALL );
2558       mImpl->mEventData->mEventQueue.push_back( event );
2559     }
2560     else
2561     {
2562       Event event( Event::SELECT );
2563       event.p2.mFloat = x;
2564       event.p3.mFloat = y;
2565       mImpl->mEventData->mEventQueue.push_back( event );
2566     }
2567
2568     mImpl->RequestRelayout();
2569   }
2570 }
2571
2572 void Controller::GetTargetSize( Vector2& targetSize )
2573 {
2574   targetSize = mImpl->mVisualModel->mControlSize;
2575 }
2576
2577 void Controller::AddDecoration( Actor& actor, bool needsClipping )
2578 {
2579   mImpl->mControlInterface.AddDecoration( actor, needsClipping );
2580 }
2581
2582 void Controller::DecorationEvent( HandleType handleType, HandleState state, float x, float y )
2583 {
2584   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected DecorationEvent" );
2585
2586   if( NULL != mImpl->mEventData )
2587   {
2588     switch( handleType )
2589     {
2590       case GRAB_HANDLE:
2591       {
2592         Event event( Event::GRAB_HANDLE_EVENT );
2593         event.p1.mUint  = state;
2594         event.p2.mFloat = x;
2595         event.p3.mFloat = y;
2596
2597         mImpl->mEventData->mEventQueue.push_back( event );
2598         break;
2599       }
2600       case LEFT_SELECTION_HANDLE:
2601       {
2602         Event event( Event::LEFT_SELECTION_HANDLE_EVENT );
2603         event.p1.mUint  = state;
2604         event.p2.mFloat = x;
2605         event.p3.mFloat = y;
2606
2607         mImpl->mEventData->mEventQueue.push_back( event );
2608         break;
2609       }
2610       case RIGHT_SELECTION_HANDLE:
2611       {
2612         Event event( Event::RIGHT_SELECTION_HANDLE_EVENT );
2613         event.p1.mUint  = state;
2614         event.p2.mFloat = x;
2615         event.p3.mFloat = y;
2616
2617         mImpl->mEventData->mEventQueue.push_back( event );
2618         break;
2619       }
2620       case LEFT_SELECTION_HANDLE_MARKER:
2621       case RIGHT_SELECTION_HANDLE_MARKER:
2622       {
2623         // Markers do not move the handles.
2624         break;
2625       }
2626       case HANDLE_TYPE_COUNT:
2627       {
2628         DALI_ASSERT_DEBUG( !"Controller::HandleEvent. Unexpected handle type" );
2629       }
2630     }
2631
2632     mImpl->RequestRelayout();
2633   }
2634 }
2635
2636 void Controller::PasteText( const std::string& stringToPaste )
2637 {
2638   InsertText( stringToPaste, Text::Controller::COMMIT );
2639   mImpl->ChangeState( EventData::EDITING );
2640   mImpl->RequestRelayout();
2641
2642   // Do this last since it provides callbacks into application code
2643   mImpl->mControlInterface.TextChanged();
2644 }
2645
2646 void Controller::PasteClipboardItemEvent()
2647 {
2648   // Retrieve the clipboard contents first
2649   ClipboardEventNotifier notifier( ClipboardEventNotifier::Get() );
2650   std::string stringToPaste( notifier.GetContent() );
2651
2652   // Commit the current pre-edit text; the contents of the clipboard should be appended
2653   mImpl->ResetImfManager();
2654
2655   // Temporary disable hiding clipboard
2656   mImpl->SetClipboardHideEnable( false );
2657
2658   // Paste
2659   PasteText( stringToPaste );
2660
2661   mImpl->SetClipboardHideEnable( true );
2662 }
2663
2664 void Controller::TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::Buttons button )
2665 {
2666   if( NULL == mImpl->mEventData )
2667   {
2668     return;
2669   }
2670
2671   switch( button )
2672   {
2673     case Toolkit::TextSelectionPopup::CUT:
2674     {
2675       mImpl->SendSelectionToClipboard( true ); // Synchronous call to modify text
2676       mImpl->mOperationsPending = ALL_OPERATIONS;
2677
2678       if( ( 0u != mImpl->mLogicalModel->mText.Count() ) ||
2679           !mImpl->IsPlaceholderAvailable() )
2680       {
2681         mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
2682       }
2683       else
2684       {
2685         ShowPlaceholderText();
2686       }
2687
2688       mImpl->mEventData->mUpdateCursorPosition = true;
2689       mImpl->mEventData->mScrollAfterDelete = true;
2690
2691       mImpl->RequestRelayout();
2692       mImpl->mControlInterface.TextChanged();
2693       break;
2694     }
2695     case Toolkit::TextSelectionPopup::COPY:
2696     {
2697       mImpl->SendSelectionToClipboard( false ); // Text not modified
2698
2699       mImpl->mEventData->mUpdateCursorPosition = true;
2700
2701       mImpl->RequestRelayout(); // Cursor, Handles, Selection Highlight, Popup
2702       break;
2703     }
2704     case Toolkit::TextSelectionPopup::PASTE:
2705     {
2706       std::string stringToPaste("");
2707       mImpl->GetTextFromClipboard( 0, stringToPaste ); // Paste latest item from system clipboard
2708       PasteText( stringToPaste );
2709       break;
2710     }
2711     case Toolkit::TextSelectionPopup::SELECT:
2712     {
2713       const Vector2& currentCursorPosition = mImpl->mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
2714
2715       if( mImpl->mEventData->mSelectionEnabled )
2716       {
2717         // Creates a SELECT event.
2718         SelectEvent( currentCursorPosition.x, currentCursorPosition.y, false );
2719       }
2720       break;
2721     }
2722     case Toolkit::TextSelectionPopup::SELECT_ALL:
2723     {
2724       // Creates a SELECT_ALL event
2725       SelectEvent( 0.f, 0.f, true );
2726       break;
2727     }
2728     case Toolkit::TextSelectionPopup::CLIPBOARD:
2729     {
2730       mImpl->ShowClipboard();
2731       break;
2732     }
2733     case Toolkit::TextSelectionPopup::NONE:
2734     {
2735       // Nothing to do.
2736       break;
2737     }
2738   }
2739 }
2740
2741 ImfManager::ImfCallbackData Controller::OnImfEvent( ImfManager& imfManager, const ImfManager::ImfEventData& imfEvent )
2742 {
2743   // Whether the text needs to be relaid-out.
2744   bool requestRelayout = false;
2745
2746   // Whether to retrieve the text and cursor position to be sent to the IMF manager.
2747   bool retrieveText = false;
2748   bool retrieveCursor = false;
2749
2750   switch( imfEvent.eventName )
2751   {
2752     case ImfManager::COMMIT:
2753     {
2754       InsertText( imfEvent.predictiveString, Text::Controller::COMMIT );
2755       requestRelayout = true;
2756       retrieveCursor = true;
2757       break;
2758     }
2759     case ImfManager::PREEDIT:
2760     {
2761       InsertText( imfEvent.predictiveString, Text::Controller::PRE_EDIT );
2762       requestRelayout = true;
2763       retrieveCursor = true;
2764       break;
2765     }
2766     case ImfManager::DELETESURROUNDING:
2767     {
2768       const bool textDeleted = RemoveText( imfEvent.cursorOffset,
2769                                            imfEvent.numberOfChars,
2770                                            DONT_UPDATE_INPUT_STYLE );
2771
2772       if( textDeleted )
2773       {
2774         if( ( 0u != mImpl->mLogicalModel->mText.Count() ) ||
2775             !mImpl->IsPlaceholderAvailable() )
2776         {
2777           mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
2778         }
2779         else
2780         {
2781           ShowPlaceholderText();
2782         }
2783         mImpl->mEventData->mUpdateCursorPosition = true;
2784         mImpl->mEventData->mScrollAfterDelete = true;
2785
2786         requestRelayout = true;
2787       }
2788       break;
2789     }
2790     case ImfManager::GETSURROUNDING:
2791     {
2792       retrieveText = true;
2793       retrieveCursor = true;
2794       break;
2795     }
2796     case ImfManager::VOID:
2797     {
2798       // do nothing
2799       break;
2800     }
2801   } // end switch
2802
2803   if( requestRelayout )
2804   {
2805     mImpl->mOperationsPending = ALL_OPERATIONS;
2806     mImpl->RequestRelayout();
2807   }
2808
2809   std::string text;
2810   CharacterIndex cursorPosition = 0u;
2811   Length numberOfWhiteSpaces = 0u;
2812
2813   if( retrieveCursor )
2814   {
2815     numberOfWhiteSpaces = mImpl->GetNumberOfWhiteSpaces( 0u );
2816
2817     cursorPosition = mImpl->GetLogicalCursorPosition();
2818
2819     if( cursorPosition < numberOfWhiteSpaces )
2820     {
2821       cursorPosition = 0u;
2822     }
2823     else
2824     {
2825       cursorPosition -= numberOfWhiteSpaces;
2826     }
2827   }
2828
2829   if( retrieveText )
2830   {
2831     mImpl->GetText( numberOfWhiteSpaces, text );
2832   }
2833
2834   ImfManager::ImfCallbackData callbackData( ( retrieveText || retrieveCursor ), cursorPosition, text, false );
2835
2836   if( requestRelayout )
2837   {
2838     // Do this last since it provides callbacks into application code
2839     mImpl->mControlInterface.TextChanged();
2840   }
2841
2842   return callbackData;
2843 }
2844
2845 Controller::~Controller()
2846 {
2847   delete mImpl;
2848 }
2849
2850 bool Controller::BackspaceKeyEvent()
2851 {
2852   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p DALI_KEY_BACKSPACE\n", this );
2853
2854   bool removed = false;
2855
2856   if( NULL == mImpl->mEventData )
2857   {
2858     return removed;
2859   }
2860
2861   // IMF manager is no longer handling key-events
2862   mImpl->ClearPreEditFlag();
2863
2864   if( EventData::SELECTING == mImpl->mEventData->mState )
2865   {
2866     removed = RemoveSelectedText();
2867   }
2868   else if( mImpl->mEventData->mPrimaryCursorPosition > 0 )
2869   {
2870     // Remove the character before the current cursor position
2871     removed = RemoveText( -1,
2872                           1,
2873                           UPDATE_INPUT_STYLE );
2874   }
2875
2876   if( removed )
2877   {
2878     if( ( 0u != mImpl->mLogicalModel->mText.Count() ) ||
2879         !mImpl->IsPlaceholderAvailable() )
2880     {
2881       mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
2882     }
2883     else
2884     {
2885       ShowPlaceholderText();
2886     }
2887     mImpl->mEventData->mUpdateCursorPosition = true;
2888     mImpl->mEventData->mScrollAfterDelete = true;
2889   }
2890
2891   return removed;
2892 }
2893
2894 void Controller::ShowPlaceholderText()
2895 {
2896   if( mImpl->IsPlaceholderAvailable() )
2897   {
2898     DALI_ASSERT_DEBUG( mImpl->mEventData && "No placeholder text available" );
2899
2900     if( NULL == mImpl->mEventData )
2901     {
2902       return;
2903     }
2904
2905     mImpl->mEventData->mIsShowingPlaceholderText = true;
2906
2907     // Disable handles when showing place-holder text
2908     mImpl->mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
2909     mImpl->mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2910     mImpl->mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2911
2912     const char* text( NULL );
2913     size_t size( 0 );
2914
2915     // TODO - Switch placeholder text styles when changing state
2916     if( ( EventData::INACTIVE != mImpl->mEventData->mState ) &&
2917         ( 0u != mImpl->mEventData->mPlaceholderTextActive.c_str() ) )
2918     {
2919       text = mImpl->mEventData->mPlaceholderTextActive.c_str();
2920       size = mImpl->mEventData->mPlaceholderTextActive.size();
2921     }
2922     else
2923     {
2924       text = mImpl->mEventData->mPlaceholderTextInactive.c_str();
2925       size = mImpl->mEventData->mPlaceholderTextInactive.size();
2926     }
2927
2928     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
2929     mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
2930
2931     // Reset model for showing placeholder.
2932     mImpl->mLogicalModel->mText.Clear();
2933     mImpl->mVisualModel->SetTextColor( mImpl->mEventData->mPlaceholderTextColor );
2934
2935     // Convert text into UTF-32
2936     Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
2937     utf32Characters.Resize( size );
2938
2939     // This is a bit horrible but std::string returns a (signed) char*
2940     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text );
2941
2942     // Transform a text array encoded in utf8 into an array encoded in utf32.
2943     // It returns the actual number of characters.
2944     const Length characterCount = Utf8ToUtf32( utf8, size, utf32Characters.Begin() );
2945     utf32Characters.Resize( characterCount );
2946
2947     // The characters to be added.
2948     mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = characterCount;
2949
2950     // Reset the cursor position
2951     mImpl->mEventData->mPrimaryCursorPosition = 0;
2952
2953     // The natural size needs to be re-calculated.
2954     mImpl->mRecalculateNaturalSize = true;
2955
2956     // Apply modifications to the model
2957     mImpl->mOperationsPending = ALL_OPERATIONS;
2958
2959     // Update the rest of the model during size negotiation
2960     mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
2961   }
2962 }
2963
2964 void Controller::ClearFontData()
2965 {
2966   if( mImpl->mFontDefaults )
2967   {
2968     mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
2969   }
2970
2971   // Set flags to update the model.
2972   mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
2973   mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
2974   mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mLogicalModel->mText.Count();
2975
2976   mImpl->mTextUpdateInfo.mClearAll = true;
2977   mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
2978   mImpl->mRecalculateNaturalSize = true;
2979
2980   mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
2981                                                            VALIDATE_FONTS            |
2982                                                            SHAPE_TEXT                |
2983                                                            GET_GLYPH_METRICS         |
2984                                                            LAYOUT                    |
2985                                                            UPDATE_LAYOUT_SIZE        |
2986                                                            REORDER                   |
2987                                                            ALIGN );
2988 }
2989
2990 void Controller::ClearStyleData()
2991 {
2992   mImpl->mLogicalModel->mColorRuns.Clear();
2993   mImpl->mLogicalModel->ClearFontDescriptionRuns();
2994 }
2995
2996 Controller::Controller( ControlInterface& controlInterface )
2997 : mImpl( NULL )
2998 {
2999   mImpl = new Controller::Impl( controlInterface );
3000 }
3001
3002 } // namespace Text
3003
3004 } // namespace Toolkit
3005
3006 } // namespace Dali