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