[Tizen] Delete callback memory when rasterize callback not processed
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-controller-impl.cpp
1 /*
2  * Copyright (c) 2020 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-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/public-api/rendering/renderer.h>
23 #include <dali/integration-api/debug.h>
24 #include <limits>
25
26 // INTERNAL INCLUDES
27 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
28 #include <dali-toolkit/internal/text/bidirectional-support.h>
29 #include <dali-toolkit/internal/text/character-set-conversion.h>
30 #include <dali-toolkit/internal/text/color-segmentation.h>
31 #include <dali-toolkit/internal/text/cursor-helper-functions.h>
32 #include <dali-toolkit/internal/text/multi-language-support.h>
33 #include <dali-toolkit/internal/text/segmentation.h>
34 #include <dali-toolkit/internal/text/shaper.h>
35 #include <dali-toolkit/internal/text/text-control-interface.h>
36 #include <dali-toolkit/internal/text/text-controller-impl-event-handler.h>
37 #include <dali-toolkit/internal/text/text-editable-control-interface.h>
38 #include <dali-toolkit/internal/text/text-enumerations-impl.h>
39 #include <dali-toolkit/internal/text/text-run-container.h>
40
41 using namespace Dali;
42
43 namespace
44 {
45
46 /**
47  * @brief Struct used to calculate the selection box.
48  */
49 struct SelectionBoxInfo
50 {
51   float lineOffset;
52   float lineHeight;
53   float minX;
54   float maxX;
55 };
56
57 #if defined(DEBUG_ENABLED)
58 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
59 #endif
60
61 const float MAX_FLOAT = std::numeric_limits<float>::max();
62 const float MIN_FLOAT = std::numeric_limits<float>::min();
63 const Dali::Toolkit::Text::CharacterDirection LTR = false; ///< Left To Right direction
64
65 #define MAKE_SHADER(A)#A
66
67 const char* VERTEX_SHADER_BACKGROUND = MAKE_SHADER(
68 attribute mediump vec2    aPosition;
69 attribute mediump vec4    aColor;
70 varying   mediump vec4    vColor;
71 uniform   highp mat4      uMvpMatrix;
72
73 void main()
74 {
75   mediump vec4 position = vec4( aPosition, 0.0, 1.0 );
76   gl_Position = uMvpMatrix * position;
77   vColor = aColor;
78 }
79 );
80
81 const char* FRAGMENT_SHADER_BACKGROUND = MAKE_SHADER(
82 varying mediump vec4      vColor;
83 uniform lowp    vec4      uColor;
84
85 void main()
86 {
87   gl_FragColor = vColor * uColor;
88 }
89 );
90
91 struct BackgroundVertex
92 {
93   Vector2 mPosition;        ///< Vertex posiiton
94   Vector4 mColor;           ///< Vertex color
95 };
96
97 struct BackgroundMesh
98 {
99   Vector< BackgroundVertex > mVertices;    ///< container of vertices
100   Vector< unsigned short > mIndices;       ///< container of indices
101 };
102
103 // The relative luminance of a color is defined as (L = 0.2126 * R + 0.7152 * G + 0.0722 * B)
104 // based on W3C Recommendations (https://www.w3.org/TR/WCAG20/)
105 const float         BRIGHTNESS_THRESHOLD = 0.179f;
106 const float         CONSTANT_R           = 0.2126f;
107 const float         CONSTANT_G           = 0.7152f;
108 const float         CONSTANT_B           = 0.0722f;
109 const Dali::Vector4 BLACK(0.f, 0.f, 0.f, 1.f);
110 const Dali::Vector4 WHITE(1.f, 1.f, 1.f, 1.f);
111 const Dali::Vector4 LIGHT_BLUE(0.75f, 0.96f, 1.f, 1.f);
112 const Dali::Vector4 BACKGROUND_SUB4(0.58f, 0.87f, 0.96f, 1.f);
113 const Dali::Vector4 BACKGROUND_SUB5(0.83f, 0.94f, 0.98f, 1.f);
114 const Dali::Vector4 BACKGROUND_SUB6(1.f, 0.5f, 0.5f, 1.f);
115 const Dali::Vector4 BACKGROUND_SUB7(1.f, 0.8f, 0.8f, 1.f);
116
117 } // namespace
118
119 namespace Dali
120 {
121
122 namespace Toolkit
123 {
124
125 namespace Text
126 {
127
128 EventData::EventData( DecoratorPtr decorator, InputMethodContext& inputMethodContext )
129 : mDecorator( decorator ),
130   mInputMethodContext( inputMethodContext ),
131   mPlaceholderFont( NULL ),
132   mPlaceholderTextActive(),
133   mPlaceholderTextInactive(),
134   mPlaceholderTextColor( 0.8f, 0.8f, 0.8f, 0.8f ), // This color has been published in the Public API (placeholder-properties.h).
135   mEventQueue(),
136   mInputStyleChangedQueue(),
137   mPreviousState( INACTIVE ),
138   mState( INACTIVE ),
139   mPrimaryCursorPosition( 0u ),
140   mLeftSelectionPosition( 0u ),
141   mRightSelectionPosition( 0u ),
142   mPreEditStartPosition( 0u ),
143   mPreEditLength( 0u ),
144   mPreEditTextLength ( 0u ),
145   mCursorHookPositionX( 0.f ),
146   mDoubleTapAction( Controller::NoTextTap::NO_ACTION ),
147   mLongPressAction( Controller::NoTextTap::SHOW_SELECTION_POPUP ),
148   mIsShowingPlaceholderText( false ),
149   mPreEditFlag( false ),
150   mPreEditToCommitFlag ( false ),
151   mDecoratorUpdated( false ),
152   mCursorBlinkEnabled( true ),
153   mGrabHandleEnabled( true ),
154   mGrabHandlePopupEnabled( true ),
155   mSelectionEnabled( true ),
156   mUpdateCursorHookPosition( false ),
157   mUpdateCursorPosition( false ),
158   mUpdateGrabHandlePosition( false ),
159   mUpdateLeftSelectionPosition( false ),
160   mUpdateRightSelectionPosition( false ),
161   mIsLeftHandleSelected( false ),
162   mIsRightHandleSelected( false ),
163   mUpdateHighlightBox( false ),
164   mScrollAfterUpdatePosition( false ),
165   mScrollAfterDelete( false ),
166   mAllTextSelected( false ),
167   mUpdateInputStyle( false ),
168   mPasswordInput( false ),
169   mCheckScrollAmount( false ),
170   mIsPlaceholderPixelSize( false ),
171   mIsPlaceholderElideEnabled( false ),
172   mPlaceholderEllipsisFlag( false ),
173   mShiftSelectionFlag( true ),
174   mUpdateAlignment( false ),
175   mEditingEnabled( true )
176 {
177 }
178
179 EventData::~EventData()
180 {}
181
182 bool Controller::Impl::ProcessInputEvents()
183 {
184   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::ProcessInputEvents\n" );
185   if( NULL == mEventData )
186   {
187     // Nothing to do if there is no text input.
188     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::ProcessInputEvents no event data\n" );
189     return false;
190   }
191
192   if( mEventData->mDecorator )
193   {
194     for( std::vector<Event>::iterator iter = mEventData->mEventQueue.begin();
195          iter != mEventData->mEventQueue.end();
196          ++iter )
197     {
198       switch( iter->type )
199       {
200         case Event::CURSOR_KEY_EVENT:
201         {
202           OnCursorKeyEvent( *iter );
203           break;
204         }
205         case Event::TAP_EVENT:
206         {
207           OnTapEvent( *iter );
208           break;
209         }
210         case Event::LONG_PRESS_EVENT:
211         {
212           OnLongPressEvent( *iter );
213           break;
214         }
215         case Event::PAN_EVENT:
216         {
217           OnPanEvent( *iter );
218           break;
219         }
220         case Event::GRAB_HANDLE_EVENT:
221         case Event::LEFT_SELECTION_HANDLE_EVENT:
222         case Event::RIGHT_SELECTION_HANDLE_EVENT: // Fall through
223         {
224           OnHandleEvent( *iter );
225           break;
226         }
227         case Event::SELECT:
228         {
229           OnSelectEvent( *iter );
230           break;
231         }
232         case Event::SELECT_ALL:
233         {
234           OnSelectAllEvent();
235           break;
236         }
237         case Event::SELECT_NONE:
238         {
239           OnSelectNoneEvent();
240           break;
241         }
242       }
243     }
244   }
245
246   if( mEventData->mUpdateCursorPosition ||
247       mEventData->mUpdateHighlightBox )
248   {
249     NotifyInputMethodContext();
250   }
251
252   // The cursor must also be repositioned after inserts into the model
253   if( mEventData->mUpdateCursorPosition )
254   {
255     // Updates the cursor position and scrolls the text to make it visible.
256     CursorInfo cursorInfo;
257     // Calculate the cursor position from the new cursor index.
258     GetCursorPosition( mEventData->mPrimaryCursorPosition,
259                        cursorInfo );
260
261     if( mEventData->mUpdateCursorHookPosition )
262     {
263       // Update the cursor hook position. Used to move the cursor with the keys 'up' and 'down'.
264       mEventData->mCursorHookPositionX = cursorInfo.primaryPosition.x;
265       mEventData->mUpdateCursorHookPosition = false;
266     }
267
268     // Scroll first the text after delete ...
269     if( mEventData->mScrollAfterDelete )
270     {
271       ScrollTextToMatchCursor( cursorInfo );
272     }
273
274     // ... then, text can be scrolled to make the cursor visible.
275     if( mEventData->mScrollAfterUpdatePosition )
276     {
277       const Vector2 currentCursorPosition( cursorInfo.primaryPosition.x, cursorInfo.lineOffset );
278       ScrollToMakePositionVisible( currentCursorPosition, cursorInfo.lineHeight );
279     }
280     mEventData->mScrollAfterUpdatePosition = false;
281     mEventData->mScrollAfterDelete = false;
282
283     UpdateCursorPosition( cursorInfo );
284
285     mEventData->mDecoratorUpdated = true;
286     mEventData->mUpdateCursorPosition = false;
287     mEventData->mUpdateGrabHandlePosition = false;
288   }
289   else
290   {
291     CursorInfo leftHandleInfo;
292     CursorInfo rightHandleInfo;
293
294     if( mEventData->mUpdateHighlightBox )
295     {
296       GetCursorPosition( mEventData->mLeftSelectionPosition,
297                          leftHandleInfo );
298
299       GetCursorPosition( mEventData->mRightSelectionPosition,
300                          rightHandleInfo );
301
302       if( mEventData->mScrollAfterUpdatePosition && ( mEventData->mIsLeftHandleSelected ? mEventData->mUpdateLeftSelectionPosition : mEventData->mUpdateRightSelectionPosition ) )
303       {
304         if( mEventData->mIsLeftHandleSelected && mEventData->mIsRightHandleSelected )
305         {
306           CursorInfo& infoLeft = leftHandleInfo;
307
308           const Vector2 currentCursorPositionLeft( infoLeft.primaryPosition.x, infoLeft.lineOffset );
309           ScrollToMakePositionVisible( currentCursorPositionLeft, infoLeft.lineHeight );
310
311           CursorInfo& infoRight = rightHandleInfo;
312
313           const Vector2 currentCursorPositionRight( infoRight.primaryPosition.x, infoRight.lineOffset );
314           ScrollToMakePositionVisible( currentCursorPositionRight, infoRight.lineHeight );
315         }
316         else
317         {
318           CursorInfo& info = mEventData->mIsLeftHandleSelected ? leftHandleInfo : rightHandleInfo;
319
320           const Vector2 currentCursorPosition( info.primaryPosition.x, info.lineOffset );
321           ScrollToMakePositionVisible( currentCursorPosition, info.lineHeight );
322         }
323       }
324     }
325
326     if( mEventData->mUpdateLeftSelectionPosition )
327     {
328       UpdateSelectionHandle( LEFT_SELECTION_HANDLE,
329                              leftHandleInfo );
330
331       SetPopupButtons();
332       mEventData->mDecoratorUpdated = true;
333       mEventData->mUpdateLeftSelectionPosition = false;
334     }
335
336     if( mEventData->mUpdateRightSelectionPosition )
337     {
338       UpdateSelectionHandle( RIGHT_SELECTION_HANDLE,
339                              rightHandleInfo );
340
341       SetPopupButtons();
342       mEventData->mDecoratorUpdated = true;
343       mEventData->mUpdateRightSelectionPosition = false;
344     }
345
346     if( mEventData->mUpdateHighlightBox )
347     {
348       RepositionSelectionHandles();
349
350       mEventData->mUpdateLeftSelectionPosition = false;
351       mEventData->mUpdateRightSelectionPosition = false;
352       mEventData->mUpdateHighlightBox = false;
353       mEventData->mIsLeftHandleSelected = false;
354       mEventData->mIsRightHandleSelected = false;
355     }
356
357     mEventData->mScrollAfterUpdatePosition = false;
358   }
359
360   if( mEventData->mUpdateInputStyle )
361   {
362     // Keep a copy of the current input style.
363     InputStyle currentInputStyle;
364     currentInputStyle.Copy( mEventData->mInputStyle );
365
366     // Set the default style first.
367     RetrieveDefaultInputStyle( mEventData->mInputStyle );
368
369     // Get the character index from the cursor index.
370     const CharacterIndex styleIndex = ( mEventData->mPrimaryCursorPosition > 0u ) ? mEventData->mPrimaryCursorPosition - 1u : 0u;
371
372     // Retrieve the style from the style runs stored in the logical model.
373     mModel->mLogicalModel->RetrieveStyle( styleIndex, mEventData->mInputStyle );
374
375     // Compare if the input style has changed.
376     const bool hasInputStyleChanged = !currentInputStyle.Equal( mEventData->mInputStyle );
377
378     if( hasInputStyleChanged )
379     {
380       const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask( mEventData->mInputStyle );
381       // Queue the input style changed signal.
382       mEventData->mInputStyleChangedQueue.PushBack( styleChangedMask );
383     }
384
385     mEventData->mUpdateInputStyle = false;
386   }
387
388   mEventData->mEventQueue.clear();
389
390   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::ProcessInputEvents\n" );
391
392   const bool decoratorUpdated = mEventData->mDecoratorUpdated;
393   mEventData->mDecoratorUpdated = false;
394
395   return decoratorUpdated;
396 }
397
398 void Controller::Impl::NotifyInputMethodContext()
399 {
400   if( mEventData && mEventData->mInputMethodContext )
401   {
402     CharacterIndex cursorPosition = GetLogicalCursorPosition();
403
404     const Length numberOfWhiteSpaces = GetNumberOfWhiteSpaces( 0u );
405
406     // Update the cursor position by removing the initial white spaces.
407     if( cursorPosition < numberOfWhiteSpaces )
408     {
409       cursorPosition = 0u;
410     }
411     else
412     {
413       cursorPosition -= numberOfWhiteSpaces;
414     }
415
416     mEventData->mInputMethodContext.SetCursorPosition( cursorPosition );
417     mEventData->mInputMethodContext.NotifyCursorPosition();
418   }
419 }
420
421 void Controller::Impl::NotifyInputMethodContextMultiLineStatus()
422 {
423   if ( mEventData && mEventData->mInputMethodContext )
424   {
425     Text::Layout::Engine::Type layout = mLayoutEngine.GetLayout();
426     mEventData->mInputMethodContext.NotifyTextInputMultiLine( layout == Text::Layout::Engine::MULTI_LINE_BOX );
427   }
428 }
429
430 CharacterIndex Controller::Impl::GetLogicalCursorPosition() const
431 {
432   CharacterIndex cursorPosition = 0u;
433
434   if( mEventData )
435   {
436     if( ( EventData::SELECTING == mEventData->mState ) ||
437         ( EventData::SELECTION_HANDLE_PANNING == mEventData->mState ) )
438     {
439       cursorPosition = std::min( mEventData->mRightSelectionPosition, mEventData->mLeftSelectionPosition );
440     }
441     else
442     {
443       cursorPosition = mEventData->mPrimaryCursorPosition;
444     }
445   }
446
447   return cursorPosition;
448 }
449
450 Length Controller::Impl::GetNumberOfWhiteSpaces( CharacterIndex index ) const
451 {
452   Length numberOfWhiteSpaces = 0u;
453
454   // Get the buffer to the text.
455   Character* utf32CharacterBuffer = mModel->mLogicalModel->mText.Begin();
456
457   const Length totalNumberOfCharacters = mModel->mLogicalModel->mText.Count();
458   for( ; index < totalNumberOfCharacters; ++index, ++numberOfWhiteSpaces )
459   {
460     if( !TextAbstraction::IsWhiteSpace( *( utf32CharacterBuffer + index ) ) )
461     {
462       break;
463     }
464   }
465
466   return numberOfWhiteSpaces;
467 }
468
469 void Controller::Impl::GetText( CharacterIndex index, std::string& text ) const
470 {
471   // Get the total number of characters.
472   Length numberOfCharacters = mModel->mLogicalModel->mText.Count();
473
474   // Retrieve the text.
475   if( 0u != numberOfCharacters )
476   {
477     Utf32ToUtf8( mModel->mLogicalModel->mText.Begin() + index, numberOfCharacters - index, text );
478   }
479 }
480
481 void Controller::Impl::CalculateTextUpdateIndices( Length& numberOfCharacters )
482 {
483   mTextUpdateInfo.mParagraphCharacterIndex = 0u;
484   mTextUpdateInfo.mStartGlyphIndex = 0u;
485   mTextUpdateInfo.mStartLineIndex = 0u;
486   numberOfCharacters = 0u;
487
488   const Length numberOfParagraphs = mModel->mLogicalModel->mParagraphInfo.Count();
489   if( 0u == numberOfParagraphs )
490   {
491     mTextUpdateInfo.mParagraphCharacterIndex = 0u;
492     numberOfCharacters = 0u;
493
494     mTextUpdateInfo.mRequestedNumberOfCharacters = mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
495
496     // Nothing else to do if there are no paragraphs.
497     return;
498   }
499
500   // Find the paragraphs to be updated.
501   Vector<ParagraphRunIndex> paragraphsToBeUpdated;
502   if( mTextUpdateInfo.mCharacterIndex >= mTextUpdateInfo.mPreviousNumberOfCharacters )
503   {
504     // Text is being added at the end of the current text.
505     if( mTextUpdateInfo.mIsLastCharacterNewParagraph )
506     {
507       // Text is being added in a new paragraph after the last character of the text.
508       mTextUpdateInfo.mParagraphCharacterIndex = mTextUpdateInfo.mPreviousNumberOfCharacters;
509       numberOfCharacters = 0u;
510       mTextUpdateInfo.mRequestedNumberOfCharacters = mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
511
512       mTextUpdateInfo.mStartGlyphIndex = mModel->mVisualModel->mGlyphs.Count();
513       mTextUpdateInfo.mStartLineIndex = mModel->mVisualModel->mLines.Count() - 1u;
514
515       // Nothing else to do;
516       return;
517     }
518
519     paragraphsToBeUpdated.PushBack( numberOfParagraphs - 1u );
520   }
521   else
522   {
523     Length numberOfCharactersToUpdate = 0u;
524     if( mTextUpdateInfo.mFullRelayoutNeeded )
525     {
526       numberOfCharactersToUpdate = mTextUpdateInfo.mPreviousNumberOfCharacters;
527     }
528     else
529     {
530       numberOfCharactersToUpdate = ( mTextUpdateInfo.mNumberOfCharactersToRemove > 0u ) ? mTextUpdateInfo.mNumberOfCharactersToRemove : 1u;
531     }
532     mModel->mLogicalModel->FindParagraphs( mTextUpdateInfo.mCharacterIndex,
533                                            numberOfCharactersToUpdate,
534                                            paragraphsToBeUpdated );
535   }
536
537   if( 0u != paragraphsToBeUpdated.Count() )
538   {
539     const ParagraphRunIndex firstParagraphIndex = *( paragraphsToBeUpdated.Begin() );
540     const ParagraphRun& firstParagraph = *( mModel->mLogicalModel->mParagraphInfo.Begin() + firstParagraphIndex );
541     mTextUpdateInfo.mParagraphCharacterIndex = firstParagraph.characterRun.characterIndex;
542
543     ParagraphRunIndex lastParagraphIndex = *( paragraphsToBeUpdated.End() - 1u );
544     const ParagraphRun& lastParagraph = *( mModel->mLogicalModel->mParagraphInfo.Begin() + lastParagraphIndex );
545
546     if( ( mTextUpdateInfo.mNumberOfCharactersToRemove > 0u ) &&                                            // Some character are removed.
547         ( lastParagraphIndex < numberOfParagraphs - 1u ) &&                                                // There is a next paragraph.
548         ( ( lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters ) == // The last removed character is the new paragraph character.
549           ( mTextUpdateInfo.mCharacterIndex + mTextUpdateInfo.mNumberOfCharactersToRemove ) ) )
550     {
551       // The new paragraph character of the last updated paragraph has been removed so is going to be merged with the next one.
552       const ParagraphRun& lastParagraph = *( mModel->mLogicalModel->mParagraphInfo.Begin() + lastParagraphIndex + 1u );
553
554       numberOfCharacters = lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters - mTextUpdateInfo.mParagraphCharacterIndex;
555     }
556     else
557     {
558       numberOfCharacters = lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters - mTextUpdateInfo.mParagraphCharacterIndex;
559     }
560   }
561
562   mTextUpdateInfo.mRequestedNumberOfCharacters = numberOfCharacters + mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
563   mTextUpdateInfo.mStartGlyphIndex = *( mModel->mVisualModel->mCharactersToGlyph.Begin() + mTextUpdateInfo.mParagraphCharacterIndex );
564 }
565
566 void Controller::Impl::ClearFullModelData( OperationsMask operations )
567 {
568   if( NO_OPERATION != ( GET_LINE_BREAKS & operations ) )
569   {
570     mModel->mLogicalModel->mLineBreakInfo.Clear();
571     mModel->mLogicalModel->mParagraphInfo.Clear();
572   }
573
574   if( NO_OPERATION != ( GET_SCRIPTS & operations ) )
575   {
576     mModel->mLogicalModel->mScriptRuns.Clear();
577   }
578
579   if( NO_OPERATION != ( VALIDATE_FONTS & operations ) )
580   {
581     mModel->mLogicalModel->mFontRuns.Clear();
582   }
583
584   if( 0u != mModel->mLogicalModel->mBidirectionalParagraphInfo.Count() )
585   {
586     if( NO_OPERATION != ( BIDI_INFO & operations ) )
587     {
588       mModel->mLogicalModel->mBidirectionalParagraphInfo.Clear();
589       mModel->mLogicalModel->mCharacterDirections.Clear();
590     }
591
592     if( NO_OPERATION != ( REORDER & operations ) )
593     {
594       // Free the allocated memory used to store the conversion table in the bidirectional line info run.
595       for( Vector<BidirectionalLineInfoRun>::Iterator it = mModel->mLogicalModel->mBidirectionalLineInfo.Begin(),
596              endIt = mModel->mLogicalModel->mBidirectionalLineInfo.End();
597            it != endIt;
598            ++it )
599       {
600         BidirectionalLineInfoRun& bidiLineInfo = *it;
601
602         free( bidiLineInfo.visualToLogicalMap );
603         bidiLineInfo.visualToLogicalMap = NULL;
604       }
605       mModel->mLogicalModel->mBidirectionalLineInfo.Clear();
606     }
607   }
608
609   if( NO_OPERATION != ( SHAPE_TEXT & operations ) )
610   {
611     mModel->mVisualModel->mGlyphs.Clear();
612     mModel->mVisualModel->mGlyphsToCharacters.Clear();
613     mModel->mVisualModel->mCharactersToGlyph.Clear();
614     mModel->mVisualModel->mCharactersPerGlyph.Clear();
615     mModel->mVisualModel->mGlyphsPerCharacter.Clear();
616     mModel->mVisualModel->mGlyphPositions.Clear();
617   }
618
619   if( NO_OPERATION != ( LAYOUT & operations ) )
620   {
621     mModel->mVisualModel->mLines.Clear();
622   }
623
624   if( NO_OPERATION != ( COLOR & operations ) )
625   {
626     mModel->mVisualModel->mColorIndices.Clear();
627     mModel->mVisualModel->mBackgroundColorIndices.Clear();
628   }
629 }
630
631 void Controller::Impl::ClearCharacterModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations )
632 {
633   const CharacterIndex endIndexPlusOne = endIndex + 1u;
634
635   if( NO_OPERATION != ( GET_LINE_BREAKS & operations ) )
636   {
637     // Clear the line break info.
638     LineBreakInfo* lineBreakInfoBuffer = mModel->mLogicalModel->mLineBreakInfo.Begin();
639
640     mModel->mLogicalModel->mLineBreakInfo.Erase( lineBreakInfoBuffer + startIndex,
641                                                  lineBreakInfoBuffer + endIndexPlusOne );
642
643     // Clear the paragraphs.
644     ClearCharacterRuns( startIndex,
645                         endIndex,
646                         mModel->mLogicalModel->mParagraphInfo );
647   }
648
649   if( NO_OPERATION != ( GET_SCRIPTS & operations ) )
650   {
651     // Clear the scripts.
652     ClearCharacterRuns( startIndex,
653                         endIndex,
654                         mModel->mLogicalModel->mScriptRuns );
655   }
656
657   if( NO_OPERATION != ( VALIDATE_FONTS & operations ) )
658   {
659     // Clear the fonts.
660     ClearCharacterRuns( startIndex,
661                         endIndex,
662                         mModel->mLogicalModel->mFontRuns );
663   }
664
665   if( 0u != mModel->mLogicalModel->mBidirectionalParagraphInfo.Count() )
666   {
667     if( NO_OPERATION != ( BIDI_INFO & operations ) )
668     {
669       // Clear the bidirectional paragraph info.
670       ClearCharacterRuns( startIndex,
671                           endIndex,
672                           mModel->mLogicalModel->mBidirectionalParagraphInfo );
673
674       // Clear the character's directions.
675       CharacterDirection* characterDirectionsBuffer = mModel->mLogicalModel->mCharacterDirections.Begin();
676
677       mModel->mLogicalModel->mCharacterDirections.Erase( characterDirectionsBuffer + startIndex,
678                                                          characterDirectionsBuffer + endIndexPlusOne );
679     }
680
681     if( NO_OPERATION != ( REORDER & operations ) )
682     {
683       uint32_t startRemoveIndex = mModel->mLogicalModel->mBidirectionalLineInfo.Count();
684       uint32_t endRemoveIndex = startRemoveIndex;
685       ClearCharacterRuns( startIndex,
686                           endIndex,
687                           mModel->mLogicalModel->mBidirectionalLineInfo,
688                           startRemoveIndex,
689                           endRemoveIndex );
690
691       BidirectionalLineInfoRun* bidirectionalLineInfoBuffer = mModel->mLogicalModel->mBidirectionalLineInfo.Begin();
692
693       // Free the allocated memory used to store the conversion table in the bidirectional line info run.
694       for( Vector<BidirectionalLineInfoRun>::Iterator it = bidirectionalLineInfoBuffer + startRemoveIndex,
695              endIt = bidirectionalLineInfoBuffer + endRemoveIndex;
696            it != endIt;
697            ++it )
698       {
699         BidirectionalLineInfoRun& bidiLineInfo = *it;
700
701         free( bidiLineInfo.visualToLogicalMap );
702         bidiLineInfo.visualToLogicalMap = NULL;
703       }
704
705       mModel->mLogicalModel->mBidirectionalLineInfo.Erase( bidirectionalLineInfoBuffer + startRemoveIndex,
706                                                            bidirectionalLineInfoBuffer + endRemoveIndex );
707     }
708   }
709 }
710
711 void Controller::Impl::ClearGlyphModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations )
712 {
713   const CharacterIndex endIndexPlusOne = endIndex + 1u;
714   const Length numberOfCharactersRemoved = endIndexPlusOne - startIndex;
715
716   // Convert the character index to glyph index before deleting the character to glyph and the glyphs per character buffers.
717   GlyphIndex* charactersToGlyphBuffer = mModel->mVisualModel->mCharactersToGlyph.Begin();
718   Length* glyphsPerCharacterBuffer = mModel->mVisualModel->mGlyphsPerCharacter.Begin();
719
720   const GlyphIndex endGlyphIndexPlusOne = *( charactersToGlyphBuffer + endIndex ) + *( glyphsPerCharacterBuffer + endIndex );
721   const Length numberOfGlyphsRemoved = endGlyphIndexPlusOne - mTextUpdateInfo.mStartGlyphIndex;
722
723   if( NO_OPERATION != ( SHAPE_TEXT & operations ) )
724   {
725     // Update the character to glyph indices.
726     for( Vector<GlyphIndex>::Iterator it =  charactersToGlyphBuffer + endIndexPlusOne,
727            endIt =  charactersToGlyphBuffer + mModel->mVisualModel->mCharactersToGlyph.Count();
728          it != endIt;
729          ++it )
730     {
731       CharacterIndex& index = *it;
732       index -= numberOfGlyphsRemoved;
733     }
734
735     // Clear the character to glyph conversion table.
736     mModel->mVisualModel->mCharactersToGlyph.Erase( charactersToGlyphBuffer + startIndex,
737                                                     charactersToGlyphBuffer + endIndexPlusOne );
738
739     // Clear the glyphs per character table.
740     mModel->mVisualModel->mGlyphsPerCharacter.Erase( glyphsPerCharacterBuffer + startIndex,
741                                                      glyphsPerCharacterBuffer + endIndexPlusOne );
742
743     // Clear the glyphs buffer.
744     GlyphInfo* glyphsBuffer = mModel->mVisualModel->mGlyphs.Begin();
745     mModel->mVisualModel->mGlyphs.Erase( glyphsBuffer + mTextUpdateInfo.mStartGlyphIndex,
746                                          glyphsBuffer + endGlyphIndexPlusOne );
747
748     CharacterIndex* glyphsToCharactersBuffer = mModel->mVisualModel->mGlyphsToCharacters.Begin();
749
750     // Update the glyph to character indices.
751     for( Vector<CharacterIndex>::Iterator it = glyphsToCharactersBuffer + endGlyphIndexPlusOne,
752            endIt = glyphsToCharactersBuffer + mModel->mVisualModel->mGlyphsToCharacters.Count();
753          it != endIt;
754          ++it )
755     {
756       CharacterIndex& index = *it;
757       index -= numberOfCharactersRemoved;
758     }
759
760     // Clear the glyphs to characters buffer.
761     mModel->mVisualModel->mGlyphsToCharacters.Erase( glyphsToCharactersBuffer + mTextUpdateInfo.mStartGlyphIndex,
762                                                      glyphsToCharactersBuffer  + endGlyphIndexPlusOne );
763
764     // Clear the characters per glyph buffer.
765     Length* charactersPerGlyphBuffer = mModel->mVisualModel->mCharactersPerGlyph.Begin();
766     mModel->mVisualModel->mCharactersPerGlyph.Erase( charactersPerGlyphBuffer + mTextUpdateInfo.mStartGlyphIndex,
767                                                      charactersPerGlyphBuffer + endGlyphIndexPlusOne );
768
769     // Clear the positions buffer.
770     Vector2* positionsBuffer = mModel->mVisualModel->mGlyphPositions.Begin();
771     mModel->mVisualModel->mGlyphPositions.Erase( positionsBuffer + mTextUpdateInfo.mStartGlyphIndex,
772                                                  positionsBuffer + endGlyphIndexPlusOne );
773   }
774
775   if( NO_OPERATION != ( LAYOUT & operations ) )
776   {
777     // Clear the lines.
778     uint32_t startRemoveIndex = mModel->mVisualModel->mLines.Count();
779     uint32_t endRemoveIndex = startRemoveIndex;
780     ClearCharacterRuns( startIndex,
781                         endIndex,
782                         mModel->mVisualModel->mLines,
783                         startRemoveIndex,
784                         endRemoveIndex );
785
786     // Will update the glyph runs.
787     startRemoveIndex = mModel->mVisualModel->mLines.Count();
788     endRemoveIndex = startRemoveIndex;
789     ClearGlyphRuns( mTextUpdateInfo.mStartGlyphIndex,
790                     endGlyphIndexPlusOne - 1u,
791                     mModel->mVisualModel->mLines,
792                     startRemoveIndex,
793                     endRemoveIndex );
794
795     // Set the line index from where to insert the new laid-out lines.
796     mTextUpdateInfo.mStartLineIndex = startRemoveIndex;
797
798     LineRun* linesBuffer = mModel->mVisualModel->mLines.Begin();
799     mModel->mVisualModel->mLines.Erase( linesBuffer + startRemoveIndex,
800                                         linesBuffer + endRemoveIndex );
801   }
802
803   if( NO_OPERATION != ( COLOR & operations ) )
804   {
805     if( 0u != mModel->mVisualModel->mColorIndices.Count() )
806     {
807       ColorIndex* colorIndexBuffer = mModel->mVisualModel->mColorIndices.Begin();
808       mModel->mVisualModel->mColorIndices.Erase( colorIndexBuffer + mTextUpdateInfo.mStartGlyphIndex,
809                                                  colorIndexBuffer + endGlyphIndexPlusOne );
810     }
811
812     if( 0u != mModel->mVisualModel->mBackgroundColorIndices.Count() )
813     {
814       ColorIndex* backgroundColorIndexBuffer = mModel->mVisualModel->mBackgroundColorIndices.Begin();
815       mModel->mVisualModel->mBackgroundColorIndices.Erase( backgroundColorIndexBuffer + mTextUpdateInfo.mStartGlyphIndex,
816                                                            backgroundColorIndexBuffer + endGlyphIndexPlusOne );
817     }
818   }
819 }
820
821 void Controller::Impl::ClearModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations )
822 {
823   if( mTextUpdateInfo.mClearAll ||
824       ( ( 0u == startIndex ) &&
825         ( mTextUpdateInfo.mPreviousNumberOfCharacters == endIndex + 1u ) ) )
826   {
827     ClearFullModelData( operations );
828   }
829   else
830   {
831     // Clear the model data related with characters.
832     ClearCharacterModelData( startIndex, endIndex, operations );
833
834     // Clear the model data related with glyphs.
835     ClearGlyphModelData( startIndex, endIndex, operations );
836   }
837
838   // The estimated number of lines. Used to avoid reallocations when layouting.
839   mTextUpdateInfo.mEstimatedNumberOfLines = std::max( mModel->mVisualModel->mLines.Count(), mModel->mLogicalModel->mParagraphInfo.Count() );
840
841   mModel->mVisualModel->ClearCaches();
842 }
843
844 bool Controller::Impl::UpdateModel( OperationsMask operationsRequired )
845 {
846   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::UpdateModel\n" );
847
848   // Calculate the operations to be done.
849   const OperationsMask operations = static_cast<OperationsMask>( mOperationsPending & operationsRequired );
850
851   if( NO_OPERATION == operations )
852   {
853     // Nothing to do if no operations are pending and required.
854     return false;
855   }
856
857   Vector<Character>& srcCharacters = mModel->mLogicalModel->mText;
858   Vector<Character> displayCharacters;
859   bool useHiddenText = false;
860   if ( mHiddenInput && mEventData != NULL && !mEventData->mIsShowingPlaceholderText)
861   {
862     mHiddenInput->Substitute( srcCharacters,displayCharacters );
863     useHiddenText = true;
864   }
865
866   Vector<Character>& utf32Characters = useHiddenText ? displayCharacters : srcCharacters;
867   const Length numberOfCharacters = utf32Characters.Count();
868
869   // Index to the first character of the first paragraph to be updated.
870   CharacterIndex startIndex = 0u;
871   // Number of characters of the paragraphs to be removed.
872   Length paragraphCharacters = 0u;
873
874   CalculateTextUpdateIndices( paragraphCharacters );
875
876   // Check whether the indices for updating the text is valid
877   if ( numberOfCharacters > 0u &&
878        ( mTextUpdateInfo.mParagraphCharacterIndex > numberOfCharacters ||
879          mTextUpdateInfo.mRequestedNumberOfCharacters > numberOfCharacters ) )
880   {
881     std::string currentText;
882     Utf32ToUtf8( mModel->mLogicalModel->mText.Begin(), numberOfCharacters, currentText );
883
884     DALI_LOG_ERROR( "Controller::Impl::UpdateModel: mTextUpdateInfo has invalid indices\n" );
885     DALI_LOG_ERROR( "Number of characters: %d, current text is: %s\n", numberOfCharacters, currentText.c_str() );
886
887     // Dump mTextUpdateInfo
888     DALI_LOG_ERROR( "Dump mTextUpdateInfo:\n" );
889     DALI_LOG_ERROR( "     mTextUpdateInfo.mCharacterIndex = %u\n", mTextUpdateInfo.mCharacterIndex );
890     DALI_LOG_ERROR( "     mTextUpdateInfo.mNumberOfCharactersToRemove = %u\n", mTextUpdateInfo.mNumberOfCharactersToRemove );
891     DALI_LOG_ERROR( "     mTextUpdateInfo.mNumberOfCharactersToAdd = %u\n", mTextUpdateInfo.mNumberOfCharactersToAdd );
892     DALI_LOG_ERROR( "     mTextUpdateInfo.mPreviousNumberOfCharacters = %u\n", mTextUpdateInfo.mPreviousNumberOfCharacters );
893     DALI_LOG_ERROR( "     mTextUpdateInfo.mParagraphCharacterIndex = %u\n", mTextUpdateInfo.mParagraphCharacterIndex );
894     DALI_LOG_ERROR( "     mTextUpdateInfo.mRequestedNumberOfCharacters = %u\n", mTextUpdateInfo.mRequestedNumberOfCharacters );
895     DALI_LOG_ERROR( "     mTextUpdateInfo.mStartGlyphIndex = %u\n", mTextUpdateInfo.mStartGlyphIndex );
896     DALI_LOG_ERROR( "     mTextUpdateInfo.mStartLineIndex = %u\n", mTextUpdateInfo.mStartLineIndex );
897     DALI_LOG_ERROR( "     mTextUpdateInfo.mEstimatedNumberOfLines = %u\n", mTextUpdateInfo.mEstimatedNumberOfLines );
898     DALI_LOG_ERROR( "     mTextUpdateInfo.mClearAll = %d\n", mTextUpdateInfo.mClearAll );
899     DALI_LOG_ERROR( "     mTextUpdateInfo.mFullRelayoutNeeded = %d\n", mTextUpdateInfo.mFullRelayoutNeeded );
900     DALI_LOG_ERROR( "     mTextUpdateInfo.mIsLastCharacterNewParagraph = %d\n", mTextUpdateInfo.mIsLastCharacterNewParagraph );
901
902     return false;
903   }
904
905   startIndex = mTextUpdateInfo.mParagraphCharacterIndex;
906
907   if( mTextUpdateInfo.mClearAll ||
908       ( 0u != paragraphCharacters ) )
909   {
910     ClearModelData( startIndex, startIndex + ( ( paragraphCharacters > 0u ) ? paragraphCharacters - 1u : 0u ), operations );
911   }
912
913   mTextUpdateInfo.mClearAll = false;
914
915   // Whether the model is updated.
916   bool updated = false;
917
918   Vector<LineBreakInfo>& lineBreakInfo = mModel->mLogicalModel->mLineBreakInfo;
919   const Length requestedNumberOfCharacters = mTextUpdateInfo.mRequestedNumberOfCharacters;
920
921   if( NO_OPERATION != ( GET_LINE_BREAKS & operations ) )
922   {
923     // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
924     // calculate the bidirectional info for each 'paragraph'.
925     // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
926     // is not shaped together).
927     lineBreakInfo.Resize( numberOfCharacters, TextAbstraction::LINE_NO_BREAK );
928
929     SetLineBreakInfo( utf32Characters,
930                       startIndex,
931                       requestedNumberOfCharacters,
932                       lineBreakInfo );
933
934     // Create the paragraph info.
935     mModel->mLogicalModel->CreateParagraphInfo( startIndex,
936                                                 requestedNumberOfCharacters );
937     updated = true;
938   }
939
940   const bool getScripts = NO_OPERATION != ( GET_SCRIPTS & operations );
941   const bool validateFonts = NO_OPERATION != ( VALIDATE_FONTS & operations );
942
943   Vector<ScriptRun>& scripts = mModel->mLogicalModel->mScriptRuns;
944   Vector<FontRun>& validFonts = mModel->mLogicalModel->mFontRuns;
945
946   if( getScripts || validateFonts )
947   {
948     // Validates the fonts assigned by the application or assigns default ones.
949     // It makes sure all the characters are going to be rendered by the correct font.
950     MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
951
952     if( getScripts )
953     {
954       // Retrieves the scripts used in the text.
955       multilanguageSupport.SetScripts( utf32Characters,
956                                        startIndex,
957                                        requestedNumberOfCharacters,
958                                        scripts );
959     }
960
961     if( validateFonts )
962     {
963       // Validate the fonts set through the mark-up string.
964       Vector<FontDescriptionRun>& fontDescriptionRuns = mModel->mLogicalModel->mFontDescriptionRuns;
965
966       // Get the default font's description.
967       TextAbstraction::FontDescription defaultFontDescription;
968       TextAbstraction::PointSize26Dot6 defaultPointSize = TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
969
970       if( IsShowingPlaceholderText() && mEventData && ( NULL != mEventData->mPlaceholderFont ) )
971       {
972         // If the placeholder font is set specifically, only placeholder font is changed.
973         defaultFontDescription = mEventData->mPlaceholderFont->mFontDescription;
974         if( mEventData->mPlaceholderFont->sizeDefined )
975         {
976           defaultPointSize = mEventData->mPlaceholderFont->mDefaultPointSize * 64u;
977         }
978       }
979       else if( NULL != mFontDefaults )
980       {
981         // Set the normal font and the placeholder font.
982         defaultFontDescription = mFontDefaults->mFontDescription;
983
984         if( mTextFitEnabled )
985         {
986           defaultPointSize = mFontDefaults->mFitPointSize * 64u;
987         }
988         else
989         {
990           defaultPointSize = mFontDefaults->mDefaultPointSize * 64u;
991         }
992       }
993
994       // Validates the fonts. If there is a character with no assigned font it sets a default one.
995       // After this call, fonts are validated.
996       multilanguageSupport.ValidateFonts( utf32Characters,
997                                           scripts,
998                                           fontDescriptionRuns,
999                                           defaultFontDescription,
1000                                           defaultPointSize,
1001                                           startIndex,
1002                                           requestedNumberOfCharacters,
1003                                           validFonts );
1004     }
1005     updated = true;
1006   }
1007
1008   Vector<Character> mirroredUtf32Characters;
1009   bool textMirrored = false;
1010   const Length numberOfParagraphs = mModel->mLogicalModel->mParagraphInfo.Count();
1011   if( NO_OPERATION != ( BIDI_INFO & operations ) )
1012   {
1013     Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mModel->mLogicalModel->mBidirectionalParagraphInfo;
1014     bidirectionalInfo.Reserve( numberOfParagraphs );
1015
1016     // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
1017     SetBidirectionalInfo( utf32Characters,
1018                           scripts,
1019                           lineBreakInfo,
1020                           startIndex,
1021                           requestedNumberOfCharacters,
1022                           bidirectionalInfo,
1023                           mModel->mMatchSystemLanguageDirection,
1024                           mLayoutDirection );
1025
1026     if( 0u != bidirectionalInfo.Count() )
1027     {
1028       // Only set the character directions if there is right to left characters.
1029       Vector<CharacterDirection>& directions = mModel->mLogicalModel->mCharacterDirections;
1030       GetCharactersDirection( bidirectionalInfo,
1031                               numberOfCharacters,
1032                               startIndex,
1033                               requestedNumberOfCharacters,
1034                               directions );
1035
1036       // This paragraph has right to left text. Some characters may need to be mirrored.
1037       // TODO: consider if the mirrored string can be stored as well.
1038
1039       textMirrored = GetMirroredText( utf32Characters,
1040                                       directions,
1041                                       bidirectionalInfo,
1042                                       startIndex,
1043                                       requestedNumberOfCharacters,
1044                                       mirroredUtf32Characters );
1045     }
1046     else
1047     {
1048       // There is no right to left characters. Clear the directions vector.
1049       mModel->mLogicalModel->mCharacterDirections.Clear();
1050     }
1051     updated = true;
1052   }
1053
1054   Vector<GlyphInfo>& glyphs = mModel->mVisualModel->mGlyphs;
1055   Vector<CharacterIndex>& glyphsToCharactersMap = mModel->mVisualModel->mGlyphsToCharacters;
1056   Vector<Length>& charactersPerGlyph = mModel->mVisualModel->mCharactersPerGlyph;
1057   Vector<GlyphIndex> newParagraphGlyphs;
1058   newParagraphGlyphs.Reserve( numberOfParagraphs );
1059
1060   const Length currentNumberOfGlyphs = glyphs.Count();
1061   if( NO_OPERATION != ( SHAPE_TEXT & operations ) )
1062   {
1063     const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
1064     // Shapes the text.
1065     ShapeText( textToShape,
1066                lineBreakInfo,
1067                scripts,
1068                validFonts,
1069                startIndex,
1070                mTextUpdateInfo.mStartGlyphIndex,
1071                requestedNumberOfCharacters,
1072                glyphs,
1073                glyphsToCharactersMap,
1074                charactersPerGlyph,
1075                newParagraphGlyphs );
1076
1077     // Create the 'number of glyphs' per character and the glyph to character conversion tables.
1078     mModel->mVisualModel->CreateGlyphsPerCharacterTable( startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters );
1079     mModel->mVisualModel->CreateCharacterToGlyphTable( startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters );
1080     updated = true;
1081   }
1082
1083   const Length numberOfGlyphs = glyphs.Count() - currentNumberOfGlyphs;
1084
1085   if( NO_OPERATION != ( GET_GLYPH_METRICS & operations ) )
1086   {
1087     GlyphInfo* glyphsBuffer = glyphs.Begin();
1088     mMetrics->GetGlyphMetrics( glyphsBuffer + mTextUpdateInfo.mStartGlyphIndex, numberOfGlyphs );
1089
1090     // Update the width and advance of all new paragraph characters.
1091     for( Vector<GlyphIndex>::ConstIterator it = newParagraphGlyphs.Begin(), endIt = newParagraphGlyphs.End(); it != endIt; ++it )
1092     {
1093       const GlyphIndex index = *it;
1094       GlyphInfo& glyph = *( glyphsBuffer + index );
1095
1096       glyph.xBearing = 0.f;
1097       glyph.width = 0.f;
1098       glyph.advance = 0.f;
1099     }
1100     updated = true;
1101   }
1102
1103   if( ( NULL != mEventData ) &&
1104       mEventData->mPreEditFlag &&
1105       ( 0u != mModel->mVisualModel->mCharactersToGlyph.Count() ) )
1106   {
1107     Dali::InputMethodContext::PreEditAttributeDataContainer attrs;
1108     mEventData->mInputMethodContext.GetPreeditStyle( attrs );
1109     Dali::InputMethodContext::PreeditStyle type = Dali::InputMethodContext::PreeditStyle::NONE;
1110
1111     // Check the type of preedit and run it.
1112     for( Dali::InputMethodContext::PreEditAttributeDataContainer::Iterator it = attrs.Begin(), endIt = attrs.End(); it != endIt; it++ )
1113     {
1114       Dali::InputMethodContext::PreeditAttributeData attrData = *it;
1115       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::UpdateModel PreeditStyle type : %d  start %d end %d \n", attrData.preeditType, attrData.startIndex, attrData.endIndex  );
1116       type = attrData.preeditType;
1117
1118       // Check the number of commit characters for the start position.
1119       unsigned int numberOfCommit = mEventData->mPrimaryCursorPosition - mEventData->mPreEditLength;
1120       Length numberOfIndices = attrData.endIndex - attrData.startIndex;
1121
1122       switch( type )
1123       {
1124         case Dali::InputMethodContext::PreeditStyle::UNDERLINE:
1125         {
1126           // Add the underline for the pre-edit text.
1127           GlyphRun underlineRun;
1128           underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
1129           underlineRun.numberOfGlyphs = numberOfIndices;
1130           mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
1131           break;
1132         }
1133         case Dali::InputMethodContext::PreeditStyle::REVERSE:
1134         {
1135           Vector4 textColor = mModel->mVisualModel->GetTextColor();
1136           ColorRun backgroundColorRun;
1137           backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
1138           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
1139           backgroundColorRun.color                           = textColor;
1140           mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
1141
1142           Vector4 backgroundColor = mModel->mVisualModel->GetBackgroundColor();
1143           if(backgroundColor.a == 0) // There is no text background color.
1144           {
1145             // Try use the control's background color.
1146             if(nullptr != mEditableControlInterface)
1147             {
1148               mEditableControlInterface->GetControlBackgroundColor(backgroundColor);
1149               if(backgroundColor.a == 0) // There is no control background color.
1150               {
1151                 // Determines black or white color according to text color.
1152                 // Based on W3C Recommendations (https://www.w3.org/TR/WCAG20/)
1153                 float L         = CONSTANT_R * textColor.r + CONSTANT_G * textColor.g + CONSTANT_B * textColor.b;
1154                 backgroundColor = L > BRIGHTNESS_THRESHOLD ? BLACK : WHITE;
1155               }
1156             }
1157           }
1158
1159           Vector<ColorRun> colorRuns;
1160           colorRuns.Resize(1u);
1161           ColorRun& colorRun                       = *(colorRuns.Begin());
1162           colorRun.color                           = backgroundColor;
1163           colorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
1164           colorRun.characterRun.numberOfCharacters = numberOfIndices;
1165
1166           mModel->mLogicalModel->mColorRuns.PushBack( colorRun );
1167           break;
1168         }
1169         case Dali::InputMethodContext::PreeditStyle::HIGHLIGHT:
1170         {
1171           ColorRun backgroundColorRun;
1172           backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
1173           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
1174           backgroundColorRun.color = LIGHT_BLUE;
1175           mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
1176           break;
1177         }
1178         case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_1:
1179         {
1180           // CUSTOM_PLATFORM_STYLE_1 should be drawn with background and underline together.
1181           ColorRun backgroundColorRun;
1182           backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
1183           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
1184           backgroundColorRun.color = BACKGROUND_SUB4;
1185           mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
1186
1187           GlyphRun underlineRun;
1188           underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
1189           underlineRun.numberOfGlyphs = numberOfIndices;
1190           mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
1191           break;
1192         }
1193         case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_2:
1194         {
1195           // CUSTOM_PLATFORM_STYLE_2 should be drawn with background and underline together.
1196           ColorRun backgroundColorRun;
1197           backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
1198           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
1199           backgroundColorRun.color = BACKGROUND_SUB5;
1200           mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
1201
1202           GlyphRun underlineRun;
1203           underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
1204           underlineRun.numberOfGlyphs = numberOfIndices;
1205           mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
1206           break;
1207         }
1208         case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_3:
1209         {
1210           // CUSTOM_PLATFORM_STYLE_3 should be drawn with background and underline together.
1211           ColorRun backgroundColorRun;
1212           backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
1213           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
1214           backgroundColorRun.color = BACKGROUND_SUB6;
1215           mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
1216
1217           GlyphRun underlineRun;
1218           underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
1219           underlineRun.numberOfGlyphs = numberOfIndices;
1220           mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
1221           break;
1222         }
1223         case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_4:
1224         {
1225           // CUSTOM_PLATFORM_STYLE_4 should be drawn with background and underline together.
1226           ColorRun backgroundColorRun;
1227           backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
1228           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
1229           backgroundColorRun.color = BACKGROUND_SUB7;
1230           mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
1231
1232           GlyphRun underlineRun;
1233           underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
1234           underlineRun.numberOfGlyphs = numberOfIndices;
1235           mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
1236           break;
1237         }
1238         case Dali::InputMethodContext::PreeditStyle::NONE:
1239         default:
1240         {
1241           break;
1242         }
1243       }
1244     }
1245     attrs.Clear();
1246     updated = true;
1247   }
1248
1249   if( NO_OPERATION != ( COLOR & operations ) )
1250   {
1251     // Set the color runs in glyphs.
1252     SetColorSegmentationInfo( mModel->mLogicalModel->mColorRuns,
1253                               mModel->mVisualModel->mCharactersToGlyph,
1254                               mModel->mVisualModel->mGlyphsPerCharacter,
1255                               startIndex,
1256                               mTextUpdateInfo.mStartGlyphIndex,
1257                               requestedNumberOfCharacters,
1258                               mModel->mVisualModel->mColors,
1259                               mModel->mVisualModel->mColorIndices );
1260
1261     // Set the background color runs in glyphs.
1262     SetColorSegmentationInfo( mModel->mLogicalModel->mBackgroundColorRuns,
1263                               mModel->mVisualModel->mCharactersToGlyph,
1264                               mModel->mVisualModel->mGlyphsPerCharacter,
1265                               startIndex,
1266                               mTextUpdateInfo.mStartGlyphIndex,
1267                               requestedNumberOfCharacters,
1268                               mModel->mVisualModel->mBackgroundColors,
1269                               mModel->mVisualModel->mBackgroundColorIndices );
1270
1271     updated = true;
1272   }
1273
1274
1275   // The estimated number of lines. Used to avoid reallocations when layouting.
1276   mTextUpdateInfo.mEstimatedNumberOfLines = std::max( mModel->mVisualModel->mLines.Count(), mModel->mLogicalModel->mParagraphInfo.Count() );
1277
1278   // Set the previous number of characters for the next time the text is updated.
1279   mTextUpdateInfo.mPreviousNumberOfCharacters = numberOfCharacters;
1280
1281   return updated;
1282 }
1283
1284 void Controller::Impl::RetrieveDefaultInputStyle( InputStyle& inputStyle )
1285 {
1286   // Sets the default text's color.
1287   inputStyle.textColor = mTextColor;
1288   inputStyle.isDefaultColor = true;
1289
1290   inputStyle.familyName.clear();
1291   inputStyle.weight = TextAbstraction::FontWeight::NORMAL;
1292   inputStyle.width = TextAbstraction::FontWidth::NORMAL;
1293   inputStyle.slant = TextAbstraction::FontSlant::NORMAL;
1294   inputStyle.size = 0.f;
1295
1296   inputStyle.lineSpacing = 0.f;
1297
1298   inputStyle.underlineProperties.clear();
1299   inputStyle.shadowProperties.clear();
1300   inputStyle.embossProperties.clear();
1301   inputStyle.outlineProperties.clear();
1302
1303   inputStyle.isFamilyDefined = false;
1304   inputStyle.isWeightDefined = false;
1305   inputStyle.isWidthDefined = false;
1306   inputStyle.isSlantDefined = false;
1307   inputStyle.isSizeDefined = false;
1308
1309   inputStyle.isLineSpacingDefined = false;
1310
1311   inputStyle.isUnderlineDefined = false;
1312   inputStyle.isShadowDefined = false;
1313   inputStyle.isEmbossDefined = false;
1314   inputStyle.isOutlineDefined = false;
1315
1316   // Sets the default font's family name, weight, width, slant and size.
1317   if( mFontDefaults )
1318   {
1319     if( mFontDefaults->familyDefined )
1320     {
1321       inputStyle.familyName = mFontDefaults->mFontDescription.family;
1322       inputStyle.isFamilyDefined = true;
1323     }
1324
1325     if( mFontDefaults->weightDefined )
1326     {
1327       inputStyle.weight = mFontDefaults->mFontDescription.weight;
1328       inputStyle.isWeightDefined = true;
1329     }
1330
1331     if( mFontDefaults->widthDefined )
1332     {
1333       inputStyle.width = mFontDefaults->mFontDescription.width;
1334       inputStyle.isWidthDefined = true;
1335     }
1336
1337     if( mFontDefaults->slantDefined )
1338     {
1339       inputStyle.slant = mFontDefaults->mFontDescription.slant;
1340       inputStyle.isSlantDefined = true;
1341     }
1342
1343     if( mFontDefaults->sizeDefined )
1344     {
1345       inputStyle.size = mFontDefaults->mDefaultPointSize;
1346       inputStyle.isSizeDefined = true;
1347     }
1348   }
1349 }
1350
1351 float Controller::Impl::GetDefaultFontLineHeight()
1352 {
1353   FontId defaultFontId = 0u;
1354   if( NULL == mFontDefaults )
1355   {
1356     TextAbstraction::FontDescription fontDescription;
1357     defaultFontId = mFontClient.GetFontId( fontDescription );
1358   }
1359   else
1360   {
1361     defaultFontId = mFontDefaults->GetFontId( mFontClient );
1362   }
1363
1364   Text::FontMetrics fontMetrics;
1365   mMetrics->GetFontMetrics( defaultFontId, fontMetrics );
1366
1367   return( fontMetrics.ascender - fontMetrics.descender );
1368 }
1369
1370 void Controller::Impl::OnCursorKeyEvent( const Event& event )
1371 {
1372   ControllerImplEventHandler::OnCursorKeyEvent(*this, event);
1373 }
1374
1375 void Controller::Impl::OnTapEvent( const Event& event )
1376 {
1377   ControllerImplEventHandler::OnTapEvent(*this, event);
1378 }
1379
1380 void Controller::Impl::OnPanEvent( const Event& event )
1381 {
1382   ControllerImplEventHandler::OnPanEvent(*this, event);
1383 }
1384
1385 void Controller::Impl::OnLongPressEvent( const Event& event )
1386 {
1387   ControllerImplEventHandler::OnLongPressEvent(*this, event);
1388 }
1389
1390 void Controller::Impl::OnHandleEvent( const Event& event )
1391 {
1392   ControllerImplEventHandler::OnHandleEvent(*this, event);
1393 }
1394
1395 void Controller::Impl::OnSelectEvent( const Event& event )
1396 {
1397   ControllerImplEventHandler::OnSelectEvent(*this, event);
1398 }
1399
1400 void Controller::Impl::OnSelectAllEvent()
1401 {
1402   ControllerImplEventHandler::OnSelectAllEvent(*this);
1403 }
1404
1405 void Controller::Impl::OnSelectNoneEvent()
1406 {
1407   ControllerImplEventHandler::OnSelectNoneEvent(*this);
1408 }
1409
1410 void Controller::Impl::SetTextSelectionRange(const uint32_t *pStart, const uint32_t *pEnd)
1411 {
1412   if( nullptr == mEventData )
1413   {
1414     // Nothing to do if there is no text.
1415     return;
1416   }
1417
1418   if( mEventData->mSelectionEnabled && (pStart || pEnd))
1419   {
1420     uint32_t length = static_cast<uint32_t>(mModel->mLogicalModel->mText.Count());
1421
1422     if (pStart)
1423     {
1424       mEventData->mLeftSelectionPosition = std::min(*pStart, length);
1425     }
1426     if (pEnd)
1427     {
1428       mEventData->mRightSelectionPosition = std::min(*pEnd, length);
1429     }
1430
1431     if (mEventData->mLeftSelectionPosition == mEventData->mRightSelectionPosition)
1432     {
1433       ChangeState( EventData::EDITING );
1434       mEventData->mPrimaryCursorPosition = mEventData->mLeftSelectionPosition = mEventData->mRightSelectionPosition;
1435       mEventData->mUpdateCursorPosition = true;
1436     }
1437     else
1438     {
1439       ChangeState( EventData::SELECTING );
1440       mEventData->mUpdateHighlightBox = true;
1441       mEventData->mUpdateLeftSelectionPosition = true;
1442       mEventData->mUpdateRightSelectionPosition = true;
1443     }
1444   }
1445 }
1446
1447 Uint32Pair Controller::Impl::GetTextSelectionRange() const
1448 {
1449   Uint32Pair range;
1450
1451   if( mEventData )
1452   {
1453     range.first = mEventData->mLeftSelectionPosition;
1454     range.second = mEventData->mRightSelectionPosition;
1455   }
1456
1457   return range;
1458 }
1459
1460 bool Controller::Impl::IsEditable() const
1461 {
1462   return mEventData && mEventData->mEditingEnabled;
1463 }
1464
1465 void Controller::Impl::SetEditable( bool editable )
1466 {
1467   if( mEventData)
1468   {
1469     mEventData->mEditingEnabled = editable;
1470   }
1471 }
1472
1473 void Controller::Impl::RetrieveSelection( std::string& selectedText, bool deleteAfterRetrieval )
1474 {
1475   if( mEventData->mLeftSelectionPosition == mEventData->mRightSelectionPosition )
1476   {
1477     // Nothing to select if handles are in the same place.
1478     selectedText.clear();
1479     return;
1480   }
1481
1482   const bool handlesCrossed = mEventData->mLeftSelectionPosition > mEventData->mRightSelectionPosition;
1483
1484   //Get start and end position of selection
1485   const CharacterIndex startOfSelectedText = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
1486   const Length lengthOfSelectedText = ( handlesCrossed ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition ) - startOfSelectedText;
1487
1488   Vector<Character>& utf32Characters = mModel->mLogicalModel->mText;
1489   const Length numberOfCharacters = utf32Characters.Count();
1490
1491   // Validate the start and end selection points
1492   if( ( startOfSelectedText + lengthOfSelectedText ) <= numberOfCharacters )
1493   {
1494     //Get text as a UTF8 string
1495     Utf32ToUtf8( &utf32Characters[startOfSelectedText], lengthOfSelectedText, selectedText );
1496
1497     if( deleteAfterRetrieval ) // Only delete text if copied successfully
1498     {
1499       // Keep a copy of the current input style.
1500       InputStyle currentInputStyle;
1501       currentInputStyle.Copy( mEventData->mInputStyle );
1502
1503       // Set as input style the style of the first deleted character.
1504       mModel->mLogicalModel->RetrieveStyle( startOfSelectedText, mEventData->mInputStyle );
1505
1506       // Compare if the input style has changed.
1507       const bool hasInputStyleChanged = !currentInputStyle.Equal( mEventData->mInputStyle );
1508
1509       if( hasInputStyleChanged )
1510       {
1511         const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask( mEventData->mInputStyle );
1512         // Queue the input style changed signal.
1513         mEventData->mInputStyleChangedQueue.PushBack( styleChangedMask );
1514       }
1515
1516       mModel->mLogicalModel->UpdateTextStyleRuns( startOfSelectedText, -static_cast<int>( lengthOfSelectedText ) );
1517
1518       // Mark the paragraphs to be updated.
1519       if( Layout::Engine::SINGLE_LINE_BOX == mLayoutEngine.GetLayout() )
1520       {
1521         mTextUpdateInfo.mCharacterIndex = 0;
1522         mTextUpdateInfo.mNumberOfCharactersToRemove = mTextUpdateInfo.mPreviousNumberOfCharacters;
1523         mTextUpdateInfo.mNumberOfCharactersToAdd = mTextUpdateInfo.mPreviousNumberOfCharacters - lengthOfSelectedText;
1524         mTextUpdateInfo.mClearAll = true;
1525       }
1526       else
1527       {
1528         mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1529         mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1530       }
1531
1532       // Delete text between handles
1533       Vector<Character>::Iterator first = utf32Characters.Begin() + startOfSelectedText;
1534       Vector<Character>::Iterator last  = first + lengthOfSelectedText;
1535       utf32Characters.Erase( first, last );
1536
1537       // Will show the cursor at the first character of the selection.
1538       mEventData->mPrimaryCursorPosition = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
1539     }
1540     else
1541     {
1542       // Will show the cursor at the last character of the selection.
1543       mEventData->mPrimaryCursorPosition = handlesCrossed ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition;
1544     }
1545
1546     mEventData->mDecoratorUpdated = true;
1547   }
1548 }
1549
1550 void Controller::Impl::ShowClipboard()
1551 {
1552   if( mClipboard )
1553   {
1554     mClipboard.ShowClipboard();
1555   }
1556 }
1557
1558 void Controller::Impl::HideClipboard()
1559 {
1560   if( mClipboard && mClipboardHideEnabled )
1561   {
1562     mClipboard.HideClipboard();
1563   }
1564 }
1565
1566 void Controller::Impl::SetClipboardHideEnable(bool enable)
1567 {
1568   mClipboardHideEnabled = enable;
1569 }
1570
1571 bool Controller::Impl::CopyStringToClipboard( std::string& source )
1572 {
1573   //Send string to clipboard
1574   return ( mClipboard && mClipboard.SetItem( source ) );
1575 }
1576
1577 void Controller::Impl::SendSelectionToClipboard( bool deleteAfterSending )
1578 {
1579   std::string selectedText;
1580   RetrieveSelection( selectedText, deleteAfterSending );
1581   CopyStringToClipboard( selectedText );
1582   ChangeState( EventData::EDITING );
1583 }
1584
1585 void Controller::Impl::RequestGetTextFromClipboard()
1586 {
1587   if ( mClipboard )
1588   {
1589     mClipboard.RequestItem();
1590   }
1591 }
1592
1593 void Controller::Impl::RepositionSelectionHandles()
1594 {
1595   CharacterIndex selectionStart = mEventData->mLeftSelectionPosition;
1596   CharacterIndex selectionEnd = mEventData->mRightSelectionPosition;
1597
1598   if( selectionStart == selectionEnd )
1599   {
1600     // Nothing to select if handles are in the same place.
1601     // So, deactive Highlight box.
1602     mEventData->mDecorator->SetHighlightActive( false );
1603     return;
1604   }
1605
1606   mEventData->mDecorator->ClearHighlights();
1607
1608   const GlyphIndex* const charactersToGlyphBuffer = mModel->mVisualModel->mCharactersToGlyph.Begin();
1609   const Length* const glyphsPerCharacterBuffer = mModel->mVisualModel->mGlyphsPerCharacter.Begin();
1610   const GlyphInfo* const glyphsBuffer = mModel->mVisualModel->mGlyphs.Begin();
1611   const Vector2* const positionsBuffer = mModel->mVisualModel->mGlyphPositions.Begin();
1612   const Length* const charactersPerGlyphBuffer = mModel->mVisualModel->mCharactersPerGlyph.Begin();
1613   const CharacterIndex* const glyphToCharacterBuffer = mModel->mVisualModel->mGlyphsToCharacters.Begin();
1614   const CharacterDirection* const modelCharacterDirectionsBuffer = ( 0u != mModel->mLogicalModel->mCharacterDirections.Count() ) ? mModel->mLogicalModel->mCharacterDirections.Begin() : NULL;
1615
1616   const bool isLastCharacter = selectionEnd >= mModel->mLogicalModel->mText.Count();
1617   const CharacterDirection startDirection = ( ( NULL == modelCharacterDirectionsBuffer ) ? false : *( modelCharacterDirectionsBuffer + selectionStart ) );
1618   const CharacterDirection endDirection = ( ( NULL == modelCharacterDirectionsBuffer ) ? false : *( modelCharacterDirectionsBuffer + ( selectionEnd - ( isLastCharacter ? 1u : 0u ) ) ) );
1619
1620   // Swap the indices if the start is greater than the end.
1621   const bool indicesSwapped = selectionStart > selectionEnd;
1622
1623   // Tell the decorator to flip the selection handles if needed.
1624   mEventData->mDecorator->SetSelectionHandleFlipState( indicesSwapped, startDirection, endDirection );
1625
1626   if( indicesSwapped )
1627   {
1628     std::swap( selectionStart, selectionEnd );
1629   }
1630
1631   // Get the indices to the first and last selected glyphs.
1632   const CharacterIndex selectionEndMinusOne = selectionEnd - 1u;
1633   const GlyphIndex glyphStart = *( charactersToGlyphBuffer + selectionStart );
1634   const Length numberOfGlyphs = *( glyphsPerCharacterBuffer + selectionEndMinusOne );
1635   const GlyphIndex glyphEnd = *( charactersToGlyphBuffer + selectionEndMinusOne ) + ( ( numberOfGlyphs > 0 ) ? numberOfGlyphs - 1u : 0u );
1636
1637   // Get the lines where the glyphs are laid-out.
1638   const LineRun* lineRun = mModel->mVisualModel->mLines.Begin();
1639
1640   LineIndex lineIndex = 0u;
1641   Length numberOfLines = 0u;
1642   mModel->mVisualModel->GetNumberOfLines( glyphStart,
1643                                           1u + glyphEnd - glyphStart,
1644                                           lineIndex,
1645                                           numberOfLines );
1646   const LineIndex firstLineIndex = lineIndex;
1647
1648   // Create the structure to store some selection box info.
1649   Vector<SelectionBoxInfo> selectionBoxLinesInfo;
1650   selectionBoxLinesInfo.Resize( numberOfLines );
1651
1652   SelectionBoxInfo* selectionBoxInfo = selectionBoxLinesInfo.Begin();
1653   selectionBoxInfo->minX = MAX_FLOAT;
1654   selectionBoxInfo->maxX = MIN_FLOAT;
1655
1656   // Keep the min and max 'x' position to calculate the size and position of the highlighed text.
1657   float minHighlightX = std::numeric_limits<float>::max();
1658   float maxHighlightX = std::numeric_limits<float>::min();
1659   Size highLightSize;
1660   Vector2 highLightPosition; // The highlight position in decorator's coords.
1661
1662   // Retrieve the first line and get the line's vertical offset, the line's height and the index to the last glyph.
1663
1664   // The line's vertical offset of all the lines before the line where the first glyph is laid-out.
1665   selectionBoxInfo->lineOffset = CalculateLineOffset( mModel->mVisualModel->mLines,
1666                                                       firstLineIndex );
1667
1668   // Transform to decorator's (control) coords.
1669   selectionBoxInfo->lineOffset += mModel->mScrollPosition.y;
1670
1671   lineRun += firstLineIndex;
1672
1673   // The line height is the addition of the line ascender and the line descender.
1674   // However, the line descender has a negative value, hence the subtraction.
1675   selectionBoxInfo->lineHeight = lineRun->ascender - lineRun->descender;
1676
1677   GlyphIndex lastGlyphOfLine = lineRun->glyphRun.glyphIndex + lineRun->glyphRun.numberOfGlyphs - 1u;
1678
1679   // Check if the first glyph is a ligature that must be broken like Latin ff, fi, or Arabic ï»», etc which needs special code.
1680   const Length numberOfCharactersStart = *( charactersPerGlyphBuffer + glyphStart );
1681   bool splitStartGlyph = ( numberOfCharactersStart > 1u ) && HasLigatureMustBreak( mModel->mLogicalModel->GetScript( selectionStart ) );
1682
1683   // Check if the last glyph is a ligature that must be broken like Latin ff, fi, or Arabic ï»», etc which needs special code.
1684   const Length numberOfCharactersEnd = *( charactersPerGlyphBuffer + glyphEnd );
1685   bool splitEndGlyph = ( glyphStart != glyphEnd ) && ( numberOfCharactersEnd > 1u ) && HasLigatureMustBreak( mModel->mLogicalModel->GetScript( selectionEndMinusOne ) );
1686
1687   // The number of quads of the selection box.
1688   const unsigned int numberOfQuads = 1u + ( glyphEnd - glyphStart ) + ( ( numberOfLines > 1u ) ? 2u * numberOfLines : 0u );
1689   mEventData->mDecorator->ResizeHighlightQuads( numberOfQuads );
1690
1691   // Count the actual number of quads.
1692   unsigned int actualNumberOfQuads = 0u;
1693   Vector4 quad;
1694
1695   // Traverse the glyphs.
1696   for( GlyphIndex index = glyphStart; index <= glyphEnd; ++index )
1697   {
1698     const GlyphInfo& glyph = *( glyphsBuffer + index );
1699     const Vector2& position = *( positionsBuffer + index );
1700
1701     if( splitStartGlyph )
1702     {
1703       // If the first glyph is a ligature that must be broken it may be needed to add only part of the glyph to the highlight box.
1704
1705       const float glyphAdvance = glyph.advance / static_cast<float>( numberOfCharactersStart );
1706       const CharacterIndex interGlyphIndex = selectionStart - *( glyphToCharacterBuffer + glyphStart );
1707       // Get the direction of the character.
1708       CharacterDirection isCurrentRightToLeft = false;
1709       if( NULL != modelCharacterDirectionsBuffer ) // If modelCharacterDirectionsBuffer is NULL, it means the whole text is left to right.
1710       {
1711         isCurrentRightToLeft = *( modelCharacterDirectionsBuffer + selectionStart );
1712       }
1713
1714       // The end point could be in the middle of the ligature.
1715       // Calculate the number of characters selected.
1716       const Length numberOfCharacters = ( glyphStart == glyphEnd ) ? ( selectionEnd - selectionStart ) : ( numberOfCharactersStart - interGlyphIndex );
1717
1718       quad.x = lineRun->alignmentOffset + position.x - glyph.xBearing + mModel->mScrollPosition.x + glyphAdvance * static_cast<float>( isCurrentRightToLeft ? ( numberOfCharactersStart - interGlyphIndex - numberOfCharacters ) : interGlyphIndex );
1719       quad.y = selectionBoxInfo->lineOffset;
1720       quad.z = quad.x + static_cast<float>( numberOfCharacters ) * glyphAdvance;
1721       quad.w = selectionBoxInfo->lineOffset + selectionBoxInfo->lineHeight;
1722
1723       // Store the min and max 'x' for each line.
1724       selectionBoxInfo->minX = std::min( selectionBoxInfo->minX, quad.x );
1725       selectionBoxInfo->maxX = std::max( selectionBoxInfo->maxX, quad.z );
1726
1727       mEventData->mDecorator->AddHighlight( actualNumberOfQuads, quad );
1728       ++actualNumberOfQuads;
1729
1730       splitStartGlyph = false;
1731       continue;
1732     }
1733
1734     if( splitEndGlyph && ( index == glyphEnd ) )
1735     {
1736       // Equally, if the last glyph is a ligature that must be broken it may be needed to add only part of the glyph to the highlight box.
1737
1738       const float glyphAdvance = glyph.advance / static_cast<float>( numberOfCharactersEnd );
1739       const CharacterIndex interGlyphIndex = selectionEnd - *( glyphToCharacterBuffer + glyphEnd );
1740       // Get the direction of the character.
1741       CharacterDirection isCurrentRightToLeft = false;
1742       if( NULL != modelCharacterDirectionsBuffer ) // If modelCharacterDirectionsBuffer is NULL, it means the whole text is left to right.
1743       {
1744         isCurrentRightToLeft = *( modelCharacterDirectionsBuffer + selectionEnd );
1745       }
1746
1747       const Length numberOfCharacters = numberOfCharactersEnd - interGlyphIndex;
1748
1749       quad.x = lineRun->alignmentOffset + position.x - glyph.xBearing + mModel->mScrollPosition.x + ( isCurrentRightToLeft ? ( glyphAdvance * static_cast<float>( numberOfCharacters ) ) : 0.f );
1750       quad.y = selectionBoxInfo->lineOffset;
1751       quad.z = quad.x + static_cast<float>( interGlyphIndex ) * glyphAdvance;
1752       quad.w = quad.y + selectionBoxInfo->lineHeight;
1753
1754       // Store the min and max 'x' for each line.
1755       selectionBoxInfo->minX = std::min( selectionBoxInfo->minX, quad.x );
1756       selectionBoxInfo->maxX = std::max( selectionBoxInfo->maxX, quad.z );
1757
1758       mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
1759                                             quad );
1760       ++actualNumberOfQuads;
1761
1762       splitEndGlyph = false;
1763       continue;
1764     }
1765
1766     quad.x = lineRun->alignmentOffset + position.x - glyph.xBearing + mModel->mScrollPosition.x;
1767     quad.y = selectionBoxInfo->lineOffset;
1768     quad.z = quad.x + glyph.advance;
1769     quad.w = quad.y + selectionBoxInfo->lineHeight;
1770
1771     // Store the min and max 'x' for each line.
1772     selectionBoxInfo->minX = std::min( selectionBoxInfo->minX, quad.x );
1773     selectionBoxInfo->maxX = std::max( selectionBoxInfo->maxX, quad.z );
1774
1775     mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
1776                                           quad );
1777     ++actualNumberOfQuads;
1778
1779     // Whether to retrieve the next line.
1780     if( index == lastGlyphOfLine )
1781     {
1782       ++lineIndex;
1783       if( lineIndex < firstLineIndex + numberOfLines )
1784       {
1785         // Retrieve the next line.
1786         ++lineRun;
1787
1788         // Get the last glyph of the new line.
1789         lastGlyphOfLine = lineRun->glyphRun.glyphIndex + lineRun->glyphRun.numberOfGlyphs - 1u;
1790
1791         // Keep the offset and height of the current selection box.
1792         const float currentLineOffset = selectionBoxInfo->lineOffset;
1793         const float currentLineHeight = selectionBoxInfo->lineHeight;
1794
1795         // Get the selection box info for the next line.
1796         ++selectionBoxInfo;
1797
1798         selectionBoxInfo->minX = MAX_FLOAT;
1799         selectionBoxInfo->maxX = MIN_FLOAT;
1800
1801         // Update the line's vertical offset.
1802         selectionBoxInfo->lineOffset = currentLineOffset + currentLineHeight;
1803
1804         // The line height is the addition of the line ascender and the line descender.
1805         // However, the line descender has a negative value, hence the subtraction.
1806         selectionBoxInfo->lineHeight = lineRun->ascender - lineRun->descender;
1807       }
1808     }
1809   }
1810
1811   // Traverses all the lines and updates the min and max 'x' positions and the total height.
1812   // The final width is calculated after 'boxifying' the selection.
1813   for( Vector<SelectionBoxInfo>::ConstIterator it = selectionBoxLinesInfo.Begin(),
1814          endIt = selectionBoxLinesInfo.End();
1815        it != endIt;
1816        ++it )
1817   {
1818     const SelectionBoxInfo& info = *it;
1819
1820     // Update the size of the highlighted text.
1821     highLightSize.height += info.lineHeight;
1822     minHighlightX = std::min( minHighlightX, info.minX );
1823     maxHighlightX = std::max( maxHighlightX, info.maxX );
1824   }
1825
1826   // Add extra geometry to 'boxify' the selection.
1827
1828   if( 1u < numberOfLines )
1829   {
1830     // Boxify the first line.
1831     lineRun = mModel->mVisualModel->mLines.Begin() + firstLineIndex;
1832     const SelectionBoxInfo& firstSelectionBoxLineInfo = *( selectionBoxLinesInfo.Begin() );
1833
1834     bool boxifyBegin = ( LTR != lineRun->direction ) && ( LTR != startDirection );
1835     bool boxifyEnd = ( LTR == lineRun->direction ) && ( LTR == startDirection );
1836
1837     if( boxifyBegin )
1838     {
1839       quad.x = 0.f;
1840       quad.y = firstSelectionBoxLineInfo.lineOffset;
1841       quad.z = firstSelectionBoxLineInfo.minX;
1842       quad.w = firstSelectionBoxLineInfo.lineOffset + firstSelectionBoxLineInfo.lineHeight;
1843
1844       // Boxify at the beginning of the line.
1845       mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
1846                                             quad );
1847       ++actualNumberOfQuads;
1848
1849       // Update the size of the highlighted text.
1850       minHighlightX = 0.f;
1851     }
1852
1853     if( boxifyEnd )
1854     {
1855       quad.x = firstSelectionBoxLineInfo.maxX;
1856       quad.y = firstSelectionBoxLineInfo.lineOffset;
1857       quad.z = mModel->mVisualModel->mControlSize.width;
1858       quad.w = firstSelectionBoxLineInfo.lineOffset + firstSelectionBoxLineInfo.lineHeight;
1859
1860       // Boxify at the end of the line.
1861       mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
1862                                             quad );
1863       ++actualNumberOfQuads;
1864
1865       // Update the size of the highlighted text.
1866       maxHighlightX = mModel->mVisualModel->mControlSize.width;
1867     }
1868
1869     // Boxify the central lines.
1870     if( 2u < numberOfLines )
1871     {
1872       for( Vector<SelectionBoxInfo>::ConstIterator it = selectionBoxLinesInfo.Begin() + 1u,
1873              endIt = selectionBoxLinesInfo.End() - 1u;
1874            it != endIt;
1875            ++it )
1876       {
1877         const SelectionBoxInfo& info = *it;
1878
1879         quad.x = 0.f;
1880         quad.y = info.lineOffset;
1881         quad.z = info.minX;
1882         quad.w = info.lineOffset + info.lineHeight;
1883
1884         mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
1885                                               quad );
1886         ++actualNumberOfQuads;
1887
1888         quad.x = info.maxX;
1889         quad.y = info.lineOffset;
1890         quad.z = mModel->mVisualModel->mControlSize.width;
1891         quad.w = info.lineOffset + info.lineHeight;
1892
1893         mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
1894                                               quad );
1895         ++actualNumberOfQuads;
1896       }
1897
1898       // Update the size of the highlighted text.
1899       minHighlightX = 0.f;
1900       maxHighlightX = mModel->mVisualModel->mControlSize.width;
1901     }
1902
1903     // Boxify the last line.
1904     lineRun = mModel->mVisualModel->mLines.Begin() + firstLineIndex + numberOfLines - 1u;
1905     const SelectionBoxInfo& lastSelectionBoxLineInfo = *( selectionBoxLinesInfo.End() - 1u );
1906
1907     boxifyBegin = ( LTR == lineRun->direction ) && ( LTR == endDirection );
1908     boxifyEnd = ( LTR != lineRun->direction ) && ( LTR != endDirection );
1909
1910     if( boxifyBegin )
1911     {
1912       quad.x = 0.f;
1913       quad.y = lastSelectionBoxLineInfo.lineOffset;
1914       quad.z = lastSelectionBoxLineInfo.minX;
1915       quad.w = lastSelectionBoxLineInfo.lineOffset + lastSelectionBoxLineInfo.lineHeight;
1916
1917       // Boxify at the beginning of the line.
1918       mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
1919                                             quad );
1920       ++actualNumberOfQuads;
1921
1922       // Update the size of the highlighted text.
1923       minHighlightX = 0.f;
1924     }
1925
1926     if( boxifyEnd )
1927     {
1928       quad.x = lastSelectionBoxLineInfo.maxX;
1929       quad.y = lastSelectionBoxLineInfo.lineOffset;
1930       quad.z = mModel->mVisualModel->mControlSize.width;
1931       quad.w = lastSelectionBoxLineInfo.lineOffset + lastSelectionBoxLineInfo.lineHeight;
1932
1933       // Boxify at the end of the line.
1934       mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
1935                                             quad );
1936       ++actualNumberOfQuads;
1937
1938       // Update the size of the highlighted text.
1939       maxHighlightX = mModel->mVisualModel->mControlSize.width;
1940     }
1941   }
1942
1943   // Set the actual number of quads.
1944   mEventData->mDecorator->ResizeHighlightQuads( actualNumberOfQuads );
1945
1946   // Sets the highlight's size and position. In decorator's coords.
1947   // The highlight's height has been calculated above (before 'boxifying' the highlight).
1948   highLightSize.width = maxHighlightX - minHighlightX;
1949
1950   highLightPosition.x = minHighlightX;
1951   const SelectionBoxInfo& firstSelectionBoxLineInfo = *( selectionBoxLinesInfo.Begin() );
1952   highLightPosition.y = firstSelectionBoxLineInfo.lineOffset;
1953
1954   mEventData->mDecorator->SetHighLightBox( highLightPosition, highLightSize, static_cast<float>( mModel->GetOutlineWidth() ) );
1955
1956   if( !mEventData->mDecorator->IsSmoothHandlePanEnabled() )
1957   {
1958     CursorInfo primaryCursorInfo;
1959     GetCursorPosition( mEventData->mLeftSelectionPosition,
1960                        primaryCursorInfo );
1961
1962     const Vector2 primaryPosition = primaryCursorInfo.primaryPosition + mModel->mScrollPosition;
1963
1964     mEventData->mDecorator->SetPosition( LEFT_SELECTION_HANDLE,
1965                                          primaryPosition.x,
1966                                          primaryCursorInfo.lineOffset + mModel->mScrollPosition.y,
1967                                          primaryCursorInfo.lineHeight );
1968
1969     CursorInfo secondaryCursorInfo;
1970     GetCursorPosition( mEventData->mRightSelectionPosition,
1971                        secondaryCursorInfo );
1972
1973     const Vector2 secondaryPosition = secondaryCursorInfo.primaryPosition + mModel->mScrollPosition;
1974
1975     mEventData->mDecorator->SetPosition( RIGHT_SELECTION_HANDLE,
1976                                          secondaryPosition.x,
1977                                          secondaryCursorInfo.lineOffset + mModel->mScrollPosition.y,
1978                                          secondaryCursorInfo.lineHeight );
1979   }
1980
1981   // Set the flag to update the decorator.
1982   mEventData->mDecoratorUpdated = true;
1983 }
1984
1985 void Controller::Impl::RepositionSelectionHandles( float visualX, float visualY, Controller::NoTextTap::Action action )
1986 {
1987   if( NULL == mEventData )
1988   {
1989     // Nothing to do if there is no text input.
1990     return;
1991   }
1992
1993   if( IsShowingPlaceholderText() )
1994   {
1995     // Nothing to do if there is the place-holder text.
1996     return;
1997   }
1998
1999   const Length numberOfGlyphs = mModel->mVisualModel->mGlyphs.Count();
2000   const Length numberOfLines  = mModel->mVisualModel->mLines.Count();
2001   if( ( 0 == numberOfGlyphs ) ||
2002       ( 0 == numberOfLines ) )
2003   {
2004     // Nothing to do if there is no text.
2005     return;
2006   }
2007
2008   // Find which word was selected
2009   CharacterIndex selectionStart( 0 );
2010   CharacterIndex selectionEnd( 0 );
2011   CharacterIndex noTextHitIndex( 0 );
2012   const bool characterHit = FindSelectionIndices( mModel->mVisualModel,
2013                                                   mModel->mLogicalModel,
2014                                                   mMetrics,
2015                                                   visualX,
2016                                                   visualY,
2017                                                   selectionStart,
2018                                                   selectionEnd,
2019                                                   noTextHitIndex );
2020   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "%p selectionStart %d selectionEnd %d\n", this, selectionStart, selectionEnd );
2021
2022   if( characterHit || ( Controller::NoTextTap::HIGHLIGHT == action ) )
2023   {
2024     ChangeState( EventData::SELECTING );
2025
2026     mEventData->mLeftSelectionPosition = selectionStart;
2027     mEventData->mRightSelectionPosition = selectionEnd;
2028
2029     mEventData->mUpdateLeftSelectionPosition = true;
2030     mEventData->mUpdateRightSelectionPosition = true;
2031     mEventData->mUpdateHighlightBox = true;
2032
2033     // It may happen an InputMethodContext commit event arrives before the selection event
2034     // if the InputMethodContext is in pre-edit state. The commit event will set the
2035     // mEventData->mUpdateCursorPosition flag to true. If it's not set back
2036     // to false, the highlight box won't be updated.
2037     mEventData->mUpdateCursorPosition = false;
2038
2039     mEventData->mScrollAfterUpdatePosition = ( mEventData->mLeftSelectionPosition != mEventData->mRightSelectionPosition );
2040
2041     // Cursor to be positioned at end of selection so if selection interrupted and edit mode restarted the cursor will be at end of selection
2042     mEventData->mPrimaryCursorPosition = std::max( mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition );
2043   }
2044   else if( Controller::NoTextTap::SHOW_SELECTION_POPUP == action )
2045   {
2046     // Nothing to select. i.e. a white space, out of bounds
2047     ChangeState( EventData::EDITING_WITH_POPUP );
2048
2049     mEventData->mPrimaryCursorPosition = noTextHitIndex;
2050
2051     mEventData->mUpdateCursorPosition = true;
2052     mEventData->mUpdateGrabHandlePosition = true;
2053     mEventData->mScrollAfterUpdatePosition = true;
2054     mEventData->mUpdateInputStyle = true;
2055   }
2056   else if( Controller::NoTextTap::NO_ACTION == action )
2057   {
2058     // Nothing to select. i.e. a white space, out of bounds
2059     mEventData->mPrimaryCursorPosition = noTextHitIndex;
2060
2061     mEventData->mUpdateCursorPosition = true;
2062     mEventData->mUpdateGrabHandlePosition = true;
2063     mEventData->mScrollAfterUpdatePosition = true;
2064     mEventData->mUpdateInputStyle = true;
2065   }
2066 }
2067
2068 void Controller::Impl::SetPopupButtons()
2069 {
2070   /**
2071    *  Sets the Popup buttons to be shown depending on State.
2072    *
2073    *  If SELECTING :  CUT & COPY + ( PASTE & CLIPBOARD if content available to paste )
2074    *
2075    *  If EDITING_WITH_POPUP : SELECT & SELECT_ALL
2076    */
2077
2078   bool isEditable = IsEditable();
2079   TextSelectionPopup::Buttons buttonsToShow = TextSelectionPopup::NONE;
2080
2081   if( EventData::SELECTING == mEventData->mState )
2082   {
2083     buttonsToShow = TextSelectionPopup::Buttons( TextSelectionPopup::COPY );
2084     if(isEditable)
2085     {
2086       buttonsToShow = TextSelectionPopup::Buttons( buttonsToShow | TextSelectionPopup::CUT );
2087     }
2088
2089     if( !IsClipboardEmpty() )
2090     {
2091       if(isEditable)
2092       {
2093         buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
2094       }
2095       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
2096     }
2097
2098     if( !mEventData->mAllTextSelected )
2099     {
2100       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::SELECT_ALL ) );
2101     }
2102   }
2103   else if( EventData::EDITING_WITH_POPUP == mEventData->mState )
2104   {
2105     if( mModel->mLogicalModel->mText.Count() && !IsShowingPlaceholderText() )
2106     {
2107       buttonsToShow = TextSelectionPopup::Buttons( TextSelectionPopup::SELECT | TextSelectionPopup::SELECT_ALL );
2108     }
2109
2110     if( !IsClipboardEmpty() )
2111     {
2112       if(isEditable)
2113       {
2114         buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
2115       }
2116       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
2117     }
2118   }
2119   else if( EventData::EDITING_WITH_PASTE_POPUP == mEventData->mState )
2120   {
2121     if ( !IsClipboardEmpty() )
2122     {
2123       if(isEditable)
2124       {
2125         buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
2126       }
2127       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
2128     }
2129   }
2130
2131   mEventData->mDecorator->SetEnabledPopupButtons( buttonsToShow );
2132 }
2133
2134 void Controller::Impl::ChangeState( EventData::State newState )
2135 {
2136   if( NULL == mEventData )
2137   {
2138     // Nothing to do if there is no text input.
2139     return;
2140   }
2141
2142   DALI_LOG_INFO( gLogFilter, Debug::General, "ChangeState state:%d  newstate:%d\n", mEventData->mState, newState );
2143
2144   if( mEventData->mState != newState )
2145   {
2146     mEventData->mPreviousState = mEventData->mState;
2147     mEventData->mState = newState;
2148
2149     switch( mEventData->mState )
2150     {
2151       case EventData::INACTIVE:
2152       {
2153         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
2154         mEventData->mDecorator->StopCursorBlink();
2155         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
2156         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2157         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2158         mEventData->mDecorator->SetHighlightActive( false );
2159         mEventData->mDecorator->SetPopupActive( false );
2160         mEventData->mDecoratorUpdated = true;
2161         break;
2162       }
2163       case EventData::INTERRUPTED:
2164       {
2165         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
2166         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2167         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2168         mEventData->mDecorator->SetHighlightActive( false );
2169         mEventData->mDecorator->SetPopupActive( false );
2170         mEventData->mDecoratorUpdated = true;
2171         break;
2172       }
2173       case EventData::SELECTING:
2174       {
2175         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
2176         mEventData->mDecorator->StopCursorBlink();
2177         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
2178         if ( mEventData->mGrabHandleEnabled )
2179         {
2180           mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, true );
2181           mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, true );
2182         }
2183         mEventData->mDecorator->SetHighlightActive( true );
2184         if( mEventData->mGrabHandlePopupEnabled )
2185         {
2186           SetPopupButtons();
2187           mEventData->mDecorator->SetPopupActive( true );
2188         }
2189         mEventData->mDecoratorUpdated = true;
2190         break;
2191       }
2192       case EventData::EDITING:
2193       {
2194         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
2195         if( mEventData->mCursorBlinkEnabled )
2196         {
2197           mEventData->mDecorator->StartCursorBlink();
2198         }
2199         // Grab handle is not shown until a tap is received whilst EDITING
2200         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
2201         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2202         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2203         mEventData->mDecorator->SetHighlightActive( false );
2204         if( mEventData->mGrabHandlePopupEnabled )
2205         {
2206           mEventData->mDecorator->SetPopupActive( false );
2207         }
2208         mEventData->mDecoratorUpdated = true;
2209         break;
2210       }
2211       case EventData::EDITING_WITH_POPUP:
2212       {
2213         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "EDITING_WITH_POPUP \n", newState );
2214
2215         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
2216         if( mEventData->mCursorBlinkEnabled )
2217         {
2218           mEventData->mDecorator->StartCursorBlink();
2219         }
2220         if( mEventData->mSelectionEnabled )
2221         {
2222           mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2223           mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2224           mEventData->mDecorator->SetHighlightActive( false );
2225         }
2226         else if ( mEventData->mGrabHandleEnabled )
2227         {
2228           mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
2229         }
2230         if( mEventData->mGrabHandlePopupEnabled )
2231         {
2232           SetPopupButtons();
2233           mEventData->mDecorator->SetPopupActive( true );
2234         }
2235         mEventData->mDecoratorUpdated = true;
2236         break;
2237       }
2238       case EventData::EDITING_WITH_GRAB_HANDLE:
2239       {
2240         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "EDITING_WITH_GRAB_HANDLE \n", newState );
2241
2242         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
2243         if( mEventData->mCursorBlinkEnabled )
2244         {
2245           mEventData->mDecorator->StartCursorBlink();
2246         }
2247         // Grab handle is not shown until a tap is received whilst EDITING
2248         if ( mEventData->mGrabHandleEnabled )
2249         {
2250           mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
2251         }
2252         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2253         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2254         mEventData->mDecorator->SetHighlightActive( false );
2255         if( mEventData->mGrabHandlePopupEnabled )
2256         {
2257           mEventData->mDecorator->SetPopupActive( false );
2258         }
2259         mEventData->mDecoratorUpdated = true;
2260         break;
2261       }
2262       case EventData::SELECTION_HANDLE_PANNING:
2263       {
2264         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
2265         mEventData->mDecorator->StopCursorBlink();
2266         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
2267         if ( mEventData->mGrabHandleEnabled )
2268         {
2269           mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, true );
2270           mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, true );
2271         }
2272         mEventData->mDecorator->SetHighlightActive( true );
2273         if( mEventData->mGrabHandlePopupEnabled )
2274         {
2275           mEventData->mDecorator->SetPopupActive( false );
2276         }
2277         mEventData->mDecoratorUpdated = true;
2278         break;
2279       }
2280       case EventData::GRAB_HANDLE_PANNING:
2281       {
2282         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "GRAB_HANDLE_PANNING \n", newState );
2283
2284         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
2285         if( mEventData->mCursorBlinkEnabled )
2286         {
2287           mEventData->mDecorator->StartCursorBlink();
2288         }
2289         if ( mEventData->mGrabHandleEnabled )
2290         {
2291           mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
2292         }
2293         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2294         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2295         mEventData->mDecorator->SetHighlightActive( false );
2296         if( mEventData->mGrabHandlePopupEnabled )
2297         {
2298           mEventData->mDecorator->SetPopupActive( false );
2299         }
2300         mEventData->mDecoratorUpdated = true;
2301         break;
2302       }
2303       case EventData::EDITING_WITH_PASTE_POPUP:
2304       {
2305         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "EDITING_WITH_PASTE_POPUP \n", newState );
2306
2307         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
2308         if( mEventData->mCursorBlinkEnabled )
2309         {
2310           mEventData->mDecorator->StartCursorBlink();
2311         }
2312
2313         if ( mEventData->mGrabHandleEnabled )
2314         {
2315           mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
2316         }
2317         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2318         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2319         mEventData->mDecorator->SetHighlightActive( false );
2320
2321         if( mEventData->mGrabHandlePopupEnabled )
2322         {
2323           SetPopupButtons();
2324           mEventData->mDecorator->SetPopupActive( true );
2325         }
2326         mEventData->mDecoratorUpdated = true;
2327         break;
2328       }
2329       case EventData::TEXT_PANNING:
2330       {
2331         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
2332         mEventData->mDecorator->StopCursorBlink();
2333         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
2334         if( mEventData->mDecorator->IsHandleActive( LEFT_SELECTION_HANDLE ) ||
2335             mEventData->mDecorator->IsHandleActive( RIGHT_SELECTION_HANDLE ) )
2336         {
2337           mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2338           mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2339           mEventData->mDecorator->SetHighlightActive( true );
2340         }
2341
2342         if( mEventData->mGrabHandlePopupEnabled )
2343         {
2344           mEventData->mDecorator->SetPopupActive( false );
2345         }
2346
2347         mEventData->mDecoratorUpdated = true;
2348         break;
2349       }
2350     }
2351   }
2352 }
2353
2354 void Controller::Impl::GetCursorPosition( CharacterIndex logical,
2355                                           CursorInfo& cursorInfo )
2356 {
2357   if( !IsShowingRealText() )
2358   {
2359     // Do not want to use the place-holder text to set the cursor position.
2360
2361     // Use the line's height of the font's family set to set the cursor's size.
2362     // If there is no font's family set, use the default font.
2363     // Use the current alignment to place the cursor at the beginning, center or end of the box.
2364
2365     cursorInfo.lineOffset = 0.f;
2366     cursorInfo.lineHeight = GetDefaultFontLineHeight();
2367     cursorInfo.primaryCursorHeight = cursorInfo.lineHeight;
2368
2369     bool isRTL = false;
2370     if( mModel->mMatchSystemLanguageDirection )
2371     {
2372       isRTL = mLayoutDirection == LayoutDirection::RIGHT_TO_LEFT;
2373     }
2374
2375     switch( mModel->mHorizontalAlignment )
2376     {
2377       case Text::HorizontalAlignment::BEGIN :
2378       {
2379         if( isRTL )
2380         {
2381           cursorInfo.primaryPosition.x = mModel->mVisualModel->mControlSize.width - mEventData->mDecorator->GetCursorWidth();
2382         }
2383         else
2384         {
2385           cursorInfo.primaryPosition.x = 0.f;
2386         }
2387         break;
2388       }
2389       case Text::HorizontalAlignment::CENTER:
2390       {
2391         cursorInfo.primaryPosition.x = floorf( 0.5f * mModel->mVisualModel->mControlSize.width );
2392         break;
2393       }
2394       case Text::HorizontalAlignment::END:
2395       {
2396         if( isRTL )
2397         {
2398           cursorInfo.primaryPosition.x = 0.f;
2399         }
2400         else
2401         {
2402           cursorInfo.primaryPosition.x = mModel->mVisualModel->mControlSize.width - mEventData->mDecorator->GetCursorWidth();
2403         }
2404         break;
2405       }
2406     }
2407
2408     // Nothing else to do.
2409     return;
2410   }
2411
2412   const bool isMultiLine = ( Layout::Engine::MULTI_LINE_BOX == mLayoutEngine.GetLayout() );
2413   GetCursorPositionParameters parameters;
2414   parameters.visualModel = mModel->mVisualModel;
2415   parameters.logicalModel = mModel->mLogicalModel;
2416   parameters.metrics = mMetrics;
2417   parameters.logical = logical;
2418   parameters.isMultiline = isMultiLine;
2419
2420   Text::GetCursorPosition( parameters,
2421                            cursorInfo );
2422
2423   // Adds Outline offset.
2424   const float outlineWidth = static_cast<float>( mModel->GetOutlineWidth() );
2425   cursorInfo.primaryPosition.x += outlineWidth;
2426   cursorInfo.primaryPosition.y += outlineWidth;
2427   cursorInfo.secondaryPosition.x += outlineWidth;
2428   cursorInfo.secondaryPosition.y += outlineWidth;
2429
2430   if( isMultiLine )
2431   {
2432     // If the text is editable and multi-line, the cursor position after a white space shouldn't exceed the boundaries of the text control.
2433
2434     // Note the white spaces laid-out at the end of the line might exceed the boundaries of the control.
2435     // The reason is a wrapped line must not start with a white space so they are laid-out at the end of the line.
2436
2437     if( 0.f > cursorInfo.primaryPosition.x )
2438     {
2439       cursorInfo.primaryPosition.x = 0.f;
2440     }
2441
2442     const float edgeWidth = mModel->mVisualModel->mControlSize.width - static_cast<float>( mEventData->mDecorator->GetCursorWidth() );
2443     if( cursorInfo.primaryPosition.x > edgeWidth )
2444     {
2445       cursorInfo.primaryPosition.x = edgeWidth;
2446     }
2447   }
2448 }
2449
2450 CharacterIndex Controller::Impl::CalculateNewCursorIndex( CharacterIndex index ) const
2451 {
2452   if( NULL == mEventData )
2453   {
2454     // Nothing to do if there is no text input.
2455     return 0u;
2456   }
2457
2458   CharacterIndex cursorIndex = mEventData->mPrimaryCursorPosition;
2459
2460   const GlyphIndex* const charactersToGlyphBuffer = mModel->mVisualModel->mCharactersToGlyph.Begin();
2461   const Length* const charactersPerGlyphBuffer = mModel->mVisualModel->mCharactersPerGlyph.Begin();
2462
2463   GlyphIndex glyphIndex = *( charactersToGlyphBuffer + index );
2464   Length numberOfCharacters = *( charactersPerGlyphBuffer + glyphIndex );
2465
2466   if( numberOfCharacters > 1u )
2467   {
2468     const Script script = mModel->mLogicalModel->GetScript( index );
2469     if( HasLigatureMustBreak( script ) )
2470     {
2471       // Prevents to jump the whole Latin ligatures like fi, ff, or Arabic ï»», ...
2472       numberOfCharacters = 1u;
2473     }
2474   }
2475   else
2476   {
2477     while( 0u == numberOfCharacters )
2478     {
2479       ++glyphIndex;
2480       numberOfCharacters = *( charactersPerGlyphBuffer + glyphIndex );
2481     }
2482   }
2483
2484   if( index < mEventData->mPrimaryCursorPosition )
2485   {
2486     cursorIndex -= numberOfCharacters;
2487   }
2488   else
2489   {
2490     cursorIndex += numberOfCharacters;
2491   }
2492
2493   // Will update the cursor hook position.
2494   mEventData->mUpdateCursorHookPosition = true;
2495
2496   return cursorIndex;
2497 }
2498
2499 void Controller::Impl::UpdateCursorPosition( const CursorInfo& cursorInfo )
2500 {
2501   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::UpdateCursorPosition %p\n", this );
2502   if( NULL == mEventData )
2503   {
2504     // Nothing to do if there is no text input.
2505     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::UpdateCursorPosition no event data\n" );
2506     return;
2507   }
2508
2509   const Vector2 cursorPosition = cursorInfo.primaryPosition + mModel->mScrollPosition;
2510
2511   mEventData->mDecorator->SetGlyphOffset( PRIMARY_CURSOR, cursorInfo.glyphOffset );
2512
2513   // Sets the cursor position.
2514   mEventData->mDecorator->SetPosition( PRIMARY_CURSOR,
2515                                        cursorPosition.x,
2516                                        cursorPosition.y,
2517                                        cursorInfo.primaryCursorHeight,
2518                                        cursorInfo.lineHeight );
2519   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Primary cursor position: %f,%f\n", cursorPosition.x, cursorPosition.y );
2520
2521   if( mEventData->mUpdateGrabHandlePosition )
2522   {
2523     // Sets the grab handle position.
2524     mEventData->mDecorator->SetPosition( GRAB_HANDLE,
2525                                          cursorPosition.x,
2526                                          cursorInfo.lineOffset + mModel->mScrollPosition.y,
2527                                          cursorInfo.lineHeight );
2528   }
2529
2530   if( cursorInfo.isSecondaryCursor )
2531   {
2532     mEventData->mDecorator->SetPosition( SECONDARY_CURSOR,
2533                                          cursorInfo.secondaryPosition.x + mModel->mScrollPosition.x,
2534                                          cursorInfo.secondaryPosition.y + mModel->mScrollPosition.y,
2535                                          cursorInfo.secondaryCursorHeight,
2536                                          cursorInfo.lineHeight );
2537     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Secondary cursor position: %f,%f\n", cursorInfo.secondaryPosition.x + mModel->mScrollPosition.x, cursorInfo.secondaryPosition.y + mModel->mScrollPosition.y );
2538   }
2539
2540   // Set which cursors are active according the state.
2541   if( EventData::IsEditingState( mEventData->mState ) || ( EventData::GRAB_HANDLE_PANNING == mEventData->mState ) )
2542   {
2543     if( cursorInfo.isSecondaryCursor )
2544     {
2545       mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_BOTH );
2546     }
2547     else
2548     {
2549       mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
2550     }
2551   }
2552   else
2553   {
2554     mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
2555   }
2556
2557   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::UpdateCursorPosition\n" );
2558 }
2559
2560 void Controller::Impl::UpdateSelectionHandle( HandleType handleType,
2561                                               const CursorInfo& cursorInfo )
2562 {
2563   if( ( LEFT_SELECTION_HANDLE != handleType ) &&
2564       ( RIGHT_SELECTION_HANDLE != handleType ) )
2565   {
2566     return;
2567   }
2568
2569   const Vector2 cursorPosition = cursorInfo.primaryPosition + mModel->mScrollPosition;
2570
2571   // Sets the handle's position.
2572   mEventData->mDecorator->SetPosition( handleType,
2573                                        cursorPosition.x,
2574                                        cursorInfo.lineOffset + mModel->mScrollPosition.y,
2575                                        cursorInfo.lineHeight );
2576
2577   // If selection handle at start of the text and other at end of the text then all text is selected.
2578   const CharacterIndex startOfSelection = std::min( mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition );
2579   const CharacterIndex endOfSelection = std::max ( mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition );
2580   mEventData->mAllTextSelected = ( startOfSelection == 0 ) && ( endOfSelection == mModel->mLogicalModel->mText.Count() );
2581 }
2582
2583 void Controller::Impl::ClampHorizontalScroll( const Vector2& layoutSize )
2584 {
2585   // Clamp between -space & -alignment offset.
2586
2587   if( layoutSize.width > mModel->mVisualModel->mControlSize.width )
2588   {
2589     const float space = ( layoutSize.width - mModel->mVisualModel->mControlSize.width ) + mModel->mAlignmentOffset;
2590     mModel->mScrollPosition.x = ( mModel->mScrollPosition.x < -space ) ? -space : mModel->mScrollPosition.x;
2591     mModel->mScrollPosition.x = ( mModel->mScrollPosition.x > -mModel->mAlignmentOffset ) ? -mModel->mAlignmentOffset : mModel->mScrollPosition.x;
2592
2593     mEventData->mDecoratorUpdated = true;
2594   }
2595   else
2596   {
2597     mModel->mScrollPosition.x = 0.f;
2598   }
2599 }
2600
2601 void Controller::Impl::ClampVerticalScroll( const Vector2& layoutSize )
2602 {
2603   if( Layout::Engine::SINGLE_LINE_BOX == mLayoutEngine.GetLayout() )
2604   {
2605     // Nothing to do if the text is single line.
2606     return;
2607   }
2608
2609   // Clamp between -space & 0.
2610   if( layoutSize.height > mModel->mVisualModel->mControlSize.height )
2611   {
2612     const float space = ( layoutSize.height - mModel->mVisualModel->mControlSize.height );
2613     mModel->mScrollPosition.y = ( mModel->mScrollPosition.y < -space ) ? -space : mModel->mScrollPosition.y;
2614     mModel->mScrollPosition.y = ( mModel->mScrollPosition.y > 0.f ) ? 0.f : mModel->mScrollPosition.y;
2615
2616     mEventData->mDecoratorUpdated = true;
2617   }
2618   else
2619   {
2620     mModel->mScrollPosition.y = 0.f;
2621   }
2622 }
2623
2624 void Controller::Impl::ScrollToMakePositionVisible( const Vector2& position, float lineHeight )
2625 {
2626   const float cursorWidth = mEventData->mDecorator ? static_cast<float>( mEventData->mDecorator->GetCursorWidth() ) : 0.f;
2627
2628   // position is in actor's coords.
2629   const float positionEndX = position.x + cursorWidth;
2630   const float positionEndY = position.y + lineHeight;
2631
2632   // Transform the position to decorator coords.
2633   const float decoratorPositionBeginX = position.x + mModel->mScrollPosition.x;
2634   const float decoratorPositionEndX = positionEndX + mModel->mScrollPosition.x;
2635
2636   const float decoratorPositionBeginY = position.y + mModel->mScrollPosition.y;
2637   const float decoratorPositionEndY = positionEndY + mModel->mScrollPosition.y;
2638
2639   if( decoratorPositionBeginX < 0.f )
2640   {
2641     mModel->mScrollPosition.x = -position.x;
2642   }
2643   else if( decoratorPositionEndX > mModel->mVisualModel->mControlSize.width )
2644   {
2645     mModel->mScrollPosition.x = mModel->mVisualModel->mControlSize.width - positionEndX;
2646   }
2647
2648   if( Layout::Engine::MULTI_LINE_BOX == mLayoutEngine.GetLayout() )
2649   {
2650     if( decoratorPositionBeginY < 0.f )
2651     {
2652       mModel->mScrollPosition.y = -position.y;
2653     }
2654     else if( decoratorPositionEndY > mModel->mVisualModel->mControlSize.height )
2655     {
2656       mModel->mScrollPosition.y = mModel->mVisualModel->mControlSize.height - positionEndY;
2657     }
2658   }
2659 }
2660
2661 void Controller::Impl::ScrollTextToMatchCursor( const CursorInfo& cursorInfo )
2662 {
2663   // Get the current cursor position in decorator coords.
2664   const Vector2& currentCursorPosition = mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
2665
2666   const LineIndex lineIndex = mModel->mVisualModel->GetLineOfCharacter( mEventData->mPrimaryCursorPosition  );
2667
2668
2669
2670   // Calculate the offset to match the cursor position before the character was deleted.
2671   mModel->mScrollPosition.x = currentCursorPosition.x - cursorInfo.primaryPosition.x;
2672
2673   //If text control has more than two lines and current line index is not last, calculate scrollpositionY
2674   if( mModel->mVisualModel->mLines.Count() > 1u && lineIndex != mModel->mVisualModel->mLines.Count() -1u )
2675   {
2676     const float currentCursorGlyphOffset = mEventData->mDecorator->GetGlyphOffset( PRIMARY_CURSOR );
2677     mModel->mScrollPosition.y = currentCursorPosition.y - cursorInfo.lineOffset - currentCursorGlyphOffset;
2678   }
2679
2680
2681   ClampHorizontalScroll( mModel->mVisualModel->GetLayoutSize() );
2682   ClampVerticalScroll( mModel->mVisualModel->GetLayoutSize() );
2683
2684   // Makes the new cursor position visible if needed.
2685   ScrollToMakePositionVisible( cursorInfo.primaryPosition, cursorInfo.lineHeight );
2686 }
2687
2688 void Controller::Impl::RequestRelayout()
2689 {
2690   if( NULL != mControlInterface )
2691   {
2692     mControlInterface->RequestTextRelayout();
2693   }
2694 }
2695
2696 Actor Controller::Impl::CreateBackgroundActor()
2697 {
2698   // NOTE: Currently we only support background color for one line left-to-right text,
2699   //       so the following calculation is based on one line left-to-right text only!
2700
2701   Actor actor;
2702
2703   Length numberOfGlyphs = mView.GetNumberOfGlyphs();
2704   if( numberOfGlyphs > 0u )
2705   {
2706     Vector<GlyphInfo> glyphs;
2707     glyphs.Resize( numberOfGlyphs );
2708
2709     Vector<Vector2> positions;
2710     positions.Resize( numberOfGlyphs );
2711
2712     // Get the line where the glyphs are laid-out.
2713     const LineRun* lineRun = mModel->mVisualModel->mLines.Begin();
2714     float alignmentOffset = lineRun->alignmentOffset;
2715     numberOfGlyphs = mView.GetGlyphs( glyphs.Begin(),
2716                                       positions.Begin(),
2717                                       alignmentOffset,
2718                                       0u,
2719                                       numberOfGlyphs );
2720
2721     glyphs.Resize( numberOfGlyphs );
2722     positions.Resize( numberOfGlyphs );
2723
2724     const GlyphInfo* const glyphsBuffer = glyphs.Begin();
2725     const Vector2* const positionsBuffer = positions.Begin();
2726
2727     BackgroundMesh mesh;
2728     mesh.mVertices.Reserve( 4u * glyphs.Size() );
2729     mesh.mIndices.Reserve( 6u * glyphs.Size() );
2730
2731     const Vector2 textSize = mView.GetLayoutSize();
2732
2733     const float offsetX = alignmentOffset + textSize.width * 0.5f;
2734     const float offsetY = textSize.height * 0.5f;
2735
2736     const Vector4* const backgroundColorsBuffer = mView.GetBackgroundColors();
2737     const ColorIndex* const backgroundColorIndicesBuffer = mView.GetBackgroundColorIndices();
2738     const Vector4& defaultBackgroundColor = mModel->mVisualModel->IsBackgroundEnabled() ? mModel->mVisualModel->GetBackgroundColor() : Color::TRANSPARENT;
2739
2740     Vector4 quad;
2741     uint32_t numberOfQuads = 0u;
2742     Length    yLineOffset   = 0;
2743     Length    prevLineIndex = 0;
2744     LineIndex lineIndex;
2745     Length    numberOfLines;
2746
2747     for( uint32_t i = 0, glyphSize = glyphs.Size(); i < glyphSize; ++i )
2748     {
2749       const GlyphInfo& glyph = *( glyphsBuffer + i );
2750
2751       // Get the background color of the character.
2752       // The color index zero is reserved for the default background color (i.e. Color::TRANSPARENT)
2753       const ColorIndex backgroundColorIndex = ( nullptr == backgroundColorsBuffer ) ? 0u : *( backgroundColorIndicesBuffer + i );
2754       const Vector4& backgroundColor = ( 0u == backgroundColorIndex ) ? defaultBackgroundColor : *( backgroundColorsBuffer + backgroundColorIndex - 1u );
2755
2756       mModel->mVisualModel->GetNumberOfLines(i, 1, lineIndex, numberOfLines);
2757       Length lineHeight = lineRun[lineIndex].ascender + -(lineRun[lineIndex].descender) + lineRun[lineIndex].lineSpacing;
2758
2759       if(lineIndex != prevLineIndex)
2760       {
2761         yLineOffset += lineHeight;
2762       }
2763
2764       // Only create quads for glyphs with a background color
2765       if(backgroundColor != Color::TRANSPARENT)
2766       {
2767         const Vector2 position = *(positionsBuffer + i);
2768
2769         if(i == 0u && glyphSize == 1u) // Only one glyph in the whole text
2770         {
2771           quad.x = position.x;
2772           quad.y = yLineOffset;
2773           quad.z = quad.x + std::max(glyph.advance, glyph.xBearing + glyph.width);
2774           quad.w = lineHeight;
2775         }
2776         else if((lineIndex != prevLineIndex) || (i == 0u)) // The first glyph in the line
2777         {
2778           quad.x = position.x;
2779           quad.y = yLineOffset;
2780           quad.z = quad.x - glyph.xBearing + glyph.advance;
2781           quad.w = quad.y + lineHeight;
2782         }
2783         else if(i == glyphSize - 1u) // The last glyph in the whole text
2784         {
2785           quad.x = position.x - glyph.xBearing;
2786           quad.y = yLineOffset;
2787           quad.z = quad.x + std::max(glyph.advance, glyph.xBearing + glyph.width);
2788           quad.w = quad.y + lineHeight;
2789         }
2790         else // The glyph in the middle of the text
2791         {
2792           quad.x = position.x - glyph.xBearing;
2793           quad.y = yLineOffset;
2794           quad.z = quad.x + glyph.advance;
2795           quad.w = quad.y + lineHeight;
2796         }
2797
2798         BackgroundVertex vertex;
2799
2800         // Top left
2801         vertex.mPosition.x = quad.x - offsetX;
2802         vertex.mPosition.y = quad.y - offsetY;
2803         vertex.mColor = backgroundColor;
2804         mesh.mVertices.PushBack(vertex);
2805
2806         // Top right
2807         vertex.mPosition.x = quad.z - offsetX;
2808         vertex.mPosition.y = quad.y - offsetY;
2809         vertex.mColor = backgroundColor;
2810         mesh.mVertices.PushBack(vertex);
2811
2812         // Bottom left
2813         vertex.mPosition.x = quad.x - offsetX;
2814         vertex.mPosition.y = quad.w - offsetY;
2815         vertex.mColor = backgroundColor;
2816         mesh.mVertices.PushBack(vertex);
2817
2818         // Bottom right
2819         vertex.mPosition.x = quad.z - offsetX;
2820         vertex.mPosition.y = quad.w - offsetY;
2821         vertex.mColor = backgroundColor;
2822         mesh.mVertices.PushBack(vertex);
2823
2824         // Six indices in counter clockwise winding
2825         mesh.mIndices.PushBack(1u + 4 * numberOfQuads);
2826         mesh.mIndices.PushBack(0u + 4 * numberOfQuads);
2827         mesh.mIndices.PushBack(2u + 4 * numberOfQuads);
2828         mesh.mIndices.PushBack(2u + 4 * numberOfQuads);
2829         mesh.mIndices.PushBack(3u + 4 * numberOfQuads);
2830         mesh.mIndices.PushBack(1u + 4 * numberOfQuads);
2831
2832         numberOfQuads++;
2833       }
2834
2835       if(lineIndex != prevLineIndex)
2836       {
2837         prevLineIndex = lineIndex;
2838       }
2839     }
2840
2841     // Only create the background actor if there are glyphs with background color
2842     if ( mesh.mVertices.Count() > 0u )
2843     {
2844       Property::Map quadVertexFormat;
2845       quadVertexFormat[ "aPosition" ] = Property::VECTOR2;
2846       quadVertexFormat[ "aColor" ] = Property::VECTOR4;
2847
2848       VertexBuffer quadVertices = VertexBuffer::New( quadVertexFormat );
2849       quadVertices.SetData( &mesh.mVertices[ 0 ], mesh.mVertices.Size() );
2850
2851       Geometry quadGeometry = Geometry::New();
2852       quadGeometry.AddVertexBuffer( quadVertices );
2853       quadGeometry.SetIndexBuffer( &mesh.mIndices[ 0 ], mesh.mIndices.Size() );
2854
2855       if( !mShaderBackground )
2856       {
2857         mShaderBackground = Shader::New( VERTEX_SHADER_BACKGROUND, FRAGMENT_SHADER_BACKGROUND );
2858       }
2859
2860       Dali::Renderer renderer = Dali::Renderer::New( quadGeometry, mShaderBackground );
2861       renderer.SetProperty( Dali::Renderer::Property::BLEND_MODE, BlendMode::ON );
2862       renderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, DepthIndex::CONTENT );
2863
2864       actor = Actor::New();
2865       actor.SetProperty( Dali::Actor::Property::NAME, "TextBackgroundColorActor" );
2866       actor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT );
2867       actor.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT );
2868       actor.SetProperty( Actor::Property::SIZE, textSize );
2869       actor.SetProperty( Actor::Property::COLOR_MODE, USE_OWN_MULTIPLY_PARENT_COLOR );
2870       actor.AddRenderer( renderer );
2871     }
2872   }
2873
2874   return actor;
2875 }
2876
2877 } // namespace Text
2878
2879 } // namespace Toolkit
2880
2881 } // namespace Dali