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