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