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