Merge branch 'new_text' into tizen
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-controller.cpp
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-toolkit/internal/text/text-controller.h>
20
21 // EXTERNAL INCLUDES
22 #include <limits>
23 #include <vector>
24 #include <dali/public-api/adaptor-framework/key.h>
25 #include <dali/public-api/text-abstraction/font-client.h>
26
27 // INTERNAL INCLUDES
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/layouts/layout-engine.h>
31 #include <dali-toolkit/internal/text/layouts/layout-parameters.h>
32 #include <dali-toolkit/internal/text/logical-model-impl.h>
33 #include <dali-toolkit/internal/text/multi-language-support.h>
34 #include <dali-toolkit/internal/text/script-run.h>
35 #include <dali-toolkit/internal/text/segmentation.h>
36 #include <dali-toolkit/internal/text/shaper.h>
37 #include <dali-toolkit/internal/text/text-io.h>
38 #include <dali-toolkit/internal/text/text-view.h>
39 #include <dali-toolkit/internal/text/visual-model-impl.h>
40
41 using std::vector;
42
43 namespace
44 {
45
46 const float MAX_FLOAT = std::numeric_limits<float>::max();
47
48 enum ModifyType
49 {
50   REPLACE_TEXT, ///< Replace the entire text
51   INSERT_TEXT,  ///< Insert characters at the current cursor position
52   DELETE_TEXT   ///< Delete a character at the current cursor position
53 };
54
55 struct ModifyEvent
56 {
57   ModifyType type;
58   std::string text;
59 };
60
61 const std::string EMPTY_STRING("");
62
63 } // namespace
64
65 namespace Dali
66 {
67
68 namespace Toolkit
69 {
70
71 namespace Text
72 {
73
74 struct Controller::FontDefaults
75 {
76   FontDefaults()
77   : mDefaultPointSize(0.0f),
78     mFontId(0u)
79   {
80   }
81
82   FontId GetFontId( TextAbstraction::FontClient& fontClient )
83   {
84     if( !mFontId )
85     {
86       Dali::TextAbstraction::PointSize26Dot6 pointSize = mDefaultPointSize*64;
87       mFontId = fontClient.GetFontId( mDefaultFontFamily, mDefaultFontStyle, pointSize );
88     }
89
90     return mFontId;
91   }
92
93   std::string mDefaultFontFamily;
94   std::string mDefaultFontStyle;
95   float mDefaultPointSize;
96   FontId mFontId;
97 };
98
99 struct Controller::TextInput
100 {
101   // Used to queue input events until DoRelayout()
102   enum EventType
103   {
104     KEYBOARD_FOCUS_GAIN_EVENT,
105     KEYBOARD_FOCUS_LOST_EVENT,
106     CURSOR_KEY_EVENT,
107     TAP_EVENT,
108     PAN_EVENT,
109     GRAB_HANDLE_EVENT
110   };
111
112   union Param
113   {
114     int mInt;
115     unsigned int mUint;
116     float mFloat;
117   };
118
119   struct Event
120   {
121     Event( EventType eventType )
122     : type( eventType )
123     {
124       p1.mInt = 0;
125       p2.mInt = 0;
126     }
127
128     EventType type;
129     Param p1;
130     Param p2;
131     Param p3;
132   };
133
134   struct CursorInfo
135   {
136     CursorInfo()
137     : primaryPosition(),
138       secondaryPosition(),
139       lineHeight( 0.f ),
140       primaryCursorHeight( 0.f ),
141       secondaryCursorHeight( 0.f ),
142       isSecondaryCursor( false )
143     {}
144
145     ~CursorInfo()
146     {}
147
148     Vector2 primaryPosition;       ///< The primary cursor's position.
149     Vector2 secondaryPosition;     ///< The secondary cursor's position.
150     float   lineHeight;            ///< The height of the line where the cursor is placed.
151     float   primaryCursorHeight;   ///< The primary cursor's height.
152     float   secondaryCursorHeight; ///< The secondary cursor's height.
153     bool    isSecondaryCursor;     ///< Whether the secondary cursor is valid.
154   };
155
156   /**
157    * @brief Some characters can be shaped in more than one glyph.
158    * This struct is used to retrieve metrics from these group of glyphs.
159    */
160   struct GlyphMetrics
161   {
162     GlyphMetrics()
163     : fontHeight( 0.f ),
164       advance( 0.f ),
165       ascender( 0.f ),
166       xBearing( 0.f )
167     {}
168
169     ~GlyphMetrics()
170     {}
171
172     float fontHeight; ///< The font's height of that glyphs.
173     float advance;    ///< The sum of all the advances of all the glyphs.
174     float ascender;   ///< The font's ascender.
175     float xBearing;   ///< The x bearing of the first glyph.
176   };
177
178   enum State
179   {
180     INACTIVE,
181     SELECTING,
182     EDITING,
183     EDITING_WITH_POPUP
184   };
185
186   TextInput( LogicalModelPtr logicalModel,
187              VisualModelPtr visualModel,
188              DecoratorPtr decorator,
189              FontDefaults* fontDefaults,
190              TextAbstraction::FontClient& fontClient )
191   : mLogicalModel( logicalModel ),
192     mVisualModel( visualModel ),
193     mDecorator( decorator ),
194     mFontDefaults( fontDefaults ),
195     mFontClient( fontClient ),
196     mState( INACTIVE ),
197     mPrimaryCursorPosition( 0u ),
198     mSecondaryCursorPosition( 0u ),
199     mDecoratorUpdated( false ),
200     mCursorBlinkEnabled( true ),
201     mGrabHandleEnabled( true ),
202     mGrabHandlePopupEnabled( true ),
203     mSelectionEnabled( true ),
204     mHorizontalScrollingEnabled( true ),
205     mVerticalScrollingEnabled( false ),
206     mUpdateCursorPosition( false )
207   {}
208
209   /**
210    * @brief Helper to move the cursor, grab handle etc.
211    */
212   bool ProcessInputEvents( const Vector2& controlSize,
213                            const Vector2& alignmentOffset )
214   {
215     mDecoratorUpdated = false;
216
217     if( mDecorator )
218     {
219       for( vector<TextInput::Event>::iterator iter = mEventQueue.begin(); iter != mEventQueue.end(); ++iter )
220       {
221         switch( iter->type )
222         {
223           case KEYBOARD_FOCUS_GAIN_EVENT:
224           {
225             OnKeyboardFocus( true );
226             break;
227           }
228           case KEYBOARD_FOCUS_LOST_EVENT:
229           {
230             OnKeyboardFocus( false );
231             break;
232           }
233           case CURSOR_KEY_EVENT:
234           {
235             OnCursorKeyEvent( *iter );
236             break;
237           }
238           case TAP_EVENT:
239           {
240             OnTapEvent( *iter, alignmentOffset );
241             break;
242           }
243           case PAN_EVENT:
244           {
245             OnPanEvent( *iter, controlSize, alignmentOffset );
246             break;
247           }
248           case GRAB_HANDLE_EVENT:
249           {
250             OnGrabHandleEvent( *iter );
251             break;
252           }
253         }
254       }
255     }
256
257     // The cursor must also be repositioned after inserts into the model
258     if( mUpdateCursorPosition )
259     {
260       UpdateCursorPosition();
261       mUpdateCursorPosition = false;
262     }
263
264     mEventQueue.clear();
265
266     return mDecoratorUpdated;
267   }
268
269   void OnKeyboardFocus( bool hasFocus )
270   {
271     if( !hasFocus )
272     {
273       ChangeState( INACTIVE );
274     }
275     else
276     {
277       ChangeState( EDITING );
278     }
279   }
280
281   void OnCursorKeyEvent( const Event& event )
282   {
283     int keyCode = event.p1.mInt;
284
285     if( Dali::DALI_KEY_CURSOR_LEFT == keyCode )
286     {
287       if( mPrimaryCursorPosition > 0u )
288       {
289         mPrimaryCursorPosition = CalculateNewCursorIndex( mPrimaryCursorPosition - 1u );
290       }
291     }
292     else if( Dali::DALI_KEY_CURSOR_RIGHT == keyCode )
293     {
294       if( mLogicalModel->GetNumberOfCharacters() > mPrimaryCursorPosition )
295       {
296         mPrimaryCursorPosition = CalculateNewCursorIndex( mPrimaryCursorPosition );
297       }
298     }
299     else if( Dali::DALI_KEY_CURSOR_UP == keyCode )
300     {
301       // TODO
302     }
303     else if(   Dali::DALI_KEY_CURSOR_DOWN == keyCode )
304     {
305       // TODO
306     }
307
308     UpdateCursorPosition();
309   }
310
311   void HandleCursorKey( int keyCode )
312   {
313     // TODO
314   }
315
316   void OnTapEvent( const Event& event,
317                    const Vector2& alignmentOffset  )
318   {
319     unsigned int tapCount = event.p1.mUint;
320
321     if( 1u == tapCount )
322     {
323       ChangeState( EDITING );
324
325       float xPosition = event.p2.mFloat - alignmentOffset.x;
326       float yPosition = event.p3.mFloat - alignmentOffset.y;
327
328       mPrimaryCursorPosition = GetClosestCursorIndex( xPosition,
329                                                       yPosition );
330
331       UpdateCursorPosition();
332     }
333     else if( mSelectionEnabled &&
334              2u == tapCount )
335     {
336       ChangeState( SELECTING );
337
338       RepositionSelectionHandles( event.p2.mFloat, event.p3.mFloat );
339     }
340  }
341
342   void OnPanEvent( const Event& event,
343                    const Vector2& controlSize,
344                    const Vector2& alignmentOffset )
345   {
346     int state = event.p1.mInt;
347
348     if( Gesture::Started    == state ||
349         Gesture::Continuing == state )
350     {
351       const Vector2& actualSize = mVisualModel->GetActualSize();
352
353       if( mHorizontalScrollingEnabled )
354       {
355         const float displacementX = event.p2.mFloat;
356         mScrollPosition.x += displacementX;
357
358         // Clamp between -space & 0 (and the text alignment).
359         const float contentWidth = actualSize.width;
360         if( contentWidth > controlSize.width )
361         {
362           const float space = ( contentWidth - controlSize.width ) + alignmentOffset.x;
363           mScrollPosition.x = ( mScrollPosition.x < -space ) ? -space : mScrollPosition.x;
364           mScrollPosition.x = ( mScrollPosition.x > -alignmentOffset.x ) ? -alignmentOffset.x : mScrollPosition.x;
365
366           mDecoratorUpdated = true;
367         }
368         else
369         {
370           mScrollPosition.x = 0.f;
371         }
372       }
373
374       if( mVerticalScrollingEnabled )
375       {
376         const float displacementY = event.p3.mFloat;
377         mScrollPosition.y += displacementY;
378
379         // Clamp between -space & 0 (and the text alignment).
380         if( actualSize.height > controlSize.height )
381         {
382           const float space = ( actualSize.height - controlSize.height ) + alignmentOffset.y;
383           mScrollPosition.y = ( mScrollPosition.y < -space ) ? -space : mScrollPosition.y;
384           mScrollPosition.y = ( mScrollPosition.y > -alignmentOffset.y ) ? -alignmentOffset.y : mScrollPosition.y;
385
386           mDecoratorUpdated = true;
387         }
388         else
389         {
390           mScrollPosition.y = 0.f;
391         }
392       }
393     }
394   }
395
396   void OnGrabHandleEvent( const Event& event )
397   {
398     unsigned int state = event.p1.mUint;
399
400     if( GRAB_HANDLE_PRESSED == state )
401     {
402       float xPosition = event.p2.mFloat + mScrollPosition.x;
403       float yPosition = event.p3.mFloat + mScrollPosition.y;
404
405       mPrimaryCursorPosition = GetClosestCursorIndex( xPosition,
406                                                       yPosition );
407
408       UpdateCursorPosition();
409
410       //mDecorator->HidePopup();
411       ChangeState ( EDITING );
412     }
413     else if ( mGrabHandlePopupEnabled &&
414               GRAB_HANDLE_RELEASED == state )
415     {
416       //mDecorator->ShowPopup();
417       ChangeState ( EDITING_WITH_POPUP );
418       mDecoratorUpdated = true;
419     }
420   }
421
422   void RepositionSelectionHandles( float visualX, float visualY )
423   {
424     // TODO - Find which word was selected
425
426     const Vector<GlyphInfo>& glyphs = mVisualModel->mGlyphs;
427     const Vector<Vector2>::SizeType glyphCount = glyphs.Count();
428
429     const Vector<Vector2>& positions = mVisualModel->mGlyphPositions;
430     const Vector<Vector2>::SizeType positionCount = positions.Count();
431
432     // Guard against glyphs which did not fit inside the layout
433     const Vector<Vector2>::SizeType count = (positionCount < glyphCount) ? positionCount : glyphCount;
434
435     if( count )
436     {
437       float primaryX   = positions[0].x;
438       float secondaryX = positions[count-1].x + glyphs[count-1].width;
439
440       // TODO - multi-line selection
441       const Vector<LineRun>& lines = mVisualModel->mLines;
442       float height = lines.Count() ? lines[0].ascender + -lines[0].descender : 0.0f;
443
444       mDecorator->SetPosition( PRIMARY_SELECTION_HANDLE,   primaryX,   0.0f, height );
445       mDecorator->SetPosition( SECONDARY_SELECTION_HANDLE, secondaryX, 0.0f, height );
446
447       mDecorator->ClearHighlights();
448       mDecorator->AddHighlight( primaryX, 0.0f, secondaryX, height );
449     }
450   }
451
452   void ChangeState( State newState )
453   {
454     if( mState != newState )
455     {
456       mState = newState;
457
458       if( INACTIVE == mState )
459       {
460         mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
461         mDecorator->StopCursorBlink();
462         mDecorator->SetGrabHandleActive( false );
463         mDecorator->SetSelectionActive( false );
464         mDecorator->SetPopupActive( false );
465         mDecoratorUpdated = true;
466       }
467       else if ( SELECTING == mState )
468       {
469         mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
470         mDecorator->StopCursorBlink();
471         mDecorator->SetGrabHandleActive( false );
472         mDecorator->SetSelectionActive( true );
473         mDecoratorUpdated = true;
474       }
475       else if( EDITING == mState )
476       {
477         mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
478         if( mCursorBlinkEnabled )
479         {
480           mDecorator->StartCursorBlink();
481         }
482         if( mGrabHandleEnabled )
483         {
484           mDecorator->SetGrabHandleActive( true );
485         }
486         if( mGrabHandlePopupEnabled )
487         {
488           mDecorator->SetPopupActive( false );
489         }
490         mDecorator->SetSelectionActive( false );
491         mDecoratorUpdated = true;
492       }
493       else if( EDITING_WITH_POPUP == mState )
494       {
495         mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
496         if( mCursorBlinkEnabled )
497         {
498           mDecorator->StartCursorBlink();
499         }
500         if( mGrabHandleEnabled )
501         {
502           mDecorator->SetGrabHandleActive( true );
503         }
504         if( mGrabHandlePopupEnabled )
505         {
506           mDecorator->SetPopupActive( true );
507         }
508         mDecorator->SetSelectionActive( false );
509         mDecoratorUpdated = true;
510       }
511     }
512   }
513
514   LineIndex GetClosestLine( float y ) const
515   {
516     float totalHeight = 0.f;
517     LineIndex lineIndex = 0u;
518
519     const Vector<LineRun>& lines = mVisualModel->mLines;
520     for( LineIndex endLine = lines.Count();
521          lineIndex < endLine;
522          ++lineIndex )
523     {
524       const LineRun& lineRun = lines[lineIndex];
525       totalHeight += lineRun.ascender + -lineRun.descender;
526       if( y < totalHeight )
527       {
528         return lineIndex;
529       }
530     }
531
532     return lineIndex-1;
533   }
534
535   /**
536    * @brief Retrieves the cursor's logical position for a given touch point x,y
537    *
538    * @param[in] visualX The touch point x.
539    * @param[in] visualY The touch point y.
540    *
541    * @return The logical cursor position (in characters). 0 is just before the first character, a value equal to the number of characters is just after the last character.
542    */
543   CharacterIndex GetClosestCursorIndex( float visualX,
544                                         float visualY ) const
545   {
546     CharacterIndex logicalIndex = 0u;
547
548     const Length numberOfGlyphs = mVisualModel->mGlyphs.Count();
549     const Length numberOfLines  = mVisualModel->mLines.Count();
550     if( 0 == numberOfGlyphs ||
551         0 == numberOfLines )
552     {
553       return logicalIndex;
554     }
555
556     // Transform to visual model coords
557     visualX -= mScrollPosition.x;
558     visualY -= mScrollPosition.y;
559
560     // Find which line is closest
561     const LineIndex lineIndex = GetClosestLine( visualY );
562     const LineRun& line = mVisualModel->mLines[lineIndex];
563
564     // Get the positions of the glyphs.
565     const Vector<Vector2>& positions = mVisualModel->mGlyphPositions;
566     const Vector2* const positionsBuffer = positions.Begin();
567
568     // Get the visual to logical conversion tables.
569     const CharacterIndex* const visualToLogicalBuffer = ( 0u != mLogicalModel->mVisualToLogicalMap.Count() ) ? mLogicalModel->mVisualToLogicalMap.Begin() : NULL;
570     const CharacterIndex* const visualToLogicalCursorBuffer = mLogicalModel->mVisualToLogicalCursorMap.Begin();
571
572     // Get the character to glyph conversion table.
573     const GlyphIndex* const charactersToGlyphBuffer = mVisualModel->mCharactersToGlyph.Begin();
574
575     // Get the glyphs per character table.
576     const Length* const glyphsPerCharacterBuffer = mVisualModel->mGlyphsPerCharacter.Begin();
577
578     // If the vector is void, there is no right to left characters.
579     const bool hasRightToLeftCharacters = NULL != visualToLogicalBuffer;
580
581     const CharacterIndex startCharacter = line.characterRun.characterIndex;
582     const CharacterIndex endCharacter   = line.characterRun.characterIndex + line.characterRun.numberOfCharacters;
583     DALI_ASSERT_DEBUG( endCharacter <= mLogicalModel->mText.Count() && "Invalid line info" );
584
585     // Whether there is a hit on a glyph.
586     bool matched = false;
587
588     // Traverses glyphs in visual order. To do that use the visual to logical conversion table.
589     CharacterIndex visualIndex = startCharacter;
590     for( ; !matched && ( visualIndex < endCharacter ); ++visualIndex )
591     {
592       // The character in logical order.
593       const CharacterIndex characterLogicalOrderIndex = hasRightToLeftCharacters ? *( visualToLogicalBuffer + visualIndex ) : visualIndex;
594
595       // The first glyph for that character in logical order.
596       const GlyphIndex glyphLogicalOrderIndex = *( charactersToGlyphBuffer + characterLogicalOrderIndex );
597
598       // The number of glyphs for that character
599       const Length numberOfGlyphs = *( glyphsPerCharacterBuffer + characterLogicalOrderIndex );
600
601       // Get the metrics for the group of glyphs.
602       GlyphMetrics glyphMetrics;
603       GetGlyphsMetrics( glyphLogicalOrderIndex,
604                         numberOfGlyphs,
605                         glyphMetrics );
606
607       const Vector2& position = *( positionsBuffer + glyphLogicalOrderIndex );
608
609       const float glyphX = -glyphMetrics.xBearing + position.x + 0.5f * glyphMetrics.advance;
610
611       if( visualX < glyphX )
612       {
613         matched = true;
614         break;
615       }
616     }
617
618     // Return the logical position of the cursor in characters.
619
620     if( !matched )
621     {
622       visualIndex = endCharacter;
623     }
624
625     return hasRightToLeftCharacters ? *( visualToLogicalCursorBuffer + visualIndex ) : visualIndex;
626   }
627
628   /**
629    * @brief Calculates the cursor's position for a given character index in the logical order.
630    *
631    * It retrieves as well the line's height and the cursor's height and
632    * if there is a valid alternative cursor, its position and height.
633    *
634    * @param[in] logical The logical cursor position (in characters). 0 is just before the first character, a value equal to the number of characters is just after the last character.
635    * @param[out] cursorInfo The line's height, the cursor's height, the cursor's position and whether there is an alternative cursor.
636    */
637   void GetCursorPosition( CharacterIndex logical,
638                           CursorInfo& cursorInfo ) const
639   {
640     // TODO: Check for multiline with \n, etc...
641
642     // Check if the logical position is the first or the last one of the text.
643     const bool isFirstPosition = 0u == logical;
644     const bool isLastPosition = mLogicalModel->GetNumberOfCharacters() == logical;
645
646     if( isFirstPosition && isLastPosition )
647     {
648       // There is zero characters. Get the default font.
649
650       FontId defaultFontId = 0u;
651       if( NULL == mFontDefaults )
652       {
653         defaultFontId = mFontClient.GetFontId( EMPTY_STRING,
654                                                EMPTY_STRING );
655       }
656       else
657       {
658         defaultFontId = mFontDefaults->GetFontId( mFontClient );
659       }
660
661       Text::FontMetrics fontMetrics;
662       mFontClient.GetFontMetrics( defaultFontId, fontMetrics );
663
664       cursorInfo.lineHeight = fontMetrics.ascender - fontMetrics.descender;
665       cursorInfo.primaryCursorHeight = cursorInfo.lineHeight;
666
667       cursorInfo.primaryPosition.x = 0.f;
668       cursorInfo.primaryPosition.y = 0.f;
669
670       // Nothing else to do.
671       return;
672     }
673
674     // Get the previous logical index.
675     const CharacterIndex previousLogical = isFirstPosition ? 0u : logical - 1u;
676
677     // Decrease the logical index if it's the last one.
678     if( isLastPosition )
679     {
680       --logical;
681     }
682
683     // Get the direction of the character and the previous one.
684     const CharacterDirection* const modelCharacterDirectionsBuffer = ( 0u != mLogicalModel->mCharacterDirections.Count() ) ? mLogicalModel->mCharacterDirections.Begin() : NULL;
685
686     CharacterDirection isCurrentRightToLeft = false;
687     CharacterDirection isPreviousRightToLeft = false;
688     if( NULL != modelCharacterDirectionsBuffer ) // If modelCharacterDirectionsBuffer is NULL, it means the whole text is left to right.
689     {
690       isCurrentRightToLeft = *( modelCharacterDirectionsBuffer + logical );
691       isPreviousRightToLeft = *( modelCharacterDirectionsBuffer + previousLogical );
692     }
693
694     // Get the line where the character is laid-out.
695     const LineRun* modelLines = mVisualModel->mLines.Begin();
696
697     const LineIndex lineIndex = mVisualModel->GetLineOfCharacter( logical );
698     const LineRun& line = *( modelLines + lineIndex );
699
700     // Get the paragraph's direction.
701     const CharacterDirection isRightToLeftParagraph = line.direction;
702
703     // Check whether there is an alternative position:
704
705     cursorInfo.isSecondaryCursor = ( isCurrentRightToLeft != isPreviousRightToLeft ) ||
706                                    ( isLastPosition && ( isRightToLeftParagraph != isCurrentRightToLeft ) );
707
708     // Set the line height.
709     cursorInfo.lineHeight = line.ascender + -line.descender;
710
711     // Convert the cursor position into the glyph position.
712     CharacterIndex characterIndex = logical;
713     if( cursorInfo.isSecondaryCursor &&
714         ( isRightToLeftParagraph != isCurrentRightToLeft ) )
715     {
716       characterIndex = previousLogical;
717     }
718
719     const GlyphIndex currentGlyphIndex = *( mVisualModel->mCharactersToGlyph.Begin() + characterIndex );
720     const Length numberOfGlyphs = *( mVisualModel->mGlyphsPerCharacter.Begin() + characterIndex );
721     const Length numberOfCharacters = *( mVisualModel->mCharactersPerGlyph.Begin() +currentGlyphIndex );
722
723     // Get the metrics for the group of glyphs.
724     GlyphMetrics glyphMetrics;
725     GetGlyphsMetrics( currentGlyphIndex,
726                       numberOfGlyphs,
727                       glyphMetrics );
728
729     float interGlyphAdvance = 0.f;
730     if( !isLastPosition &&
731         ( numberOfCharacters > 1u ) )
732     {
733       const CharacterIndex firstIndex = *( mVisualModel->mGlyphsToCharacters.Begin() + currentGlyphIndex );
734       interGlyphAdvance = static_cast<float>( characterIndex - firstIndex ) * glyphMetrics.advance / static_cast<float>( numberOfCharacters );
735     }
736
737     // Get the glyph position and x bearing.
738     const Vector2& currentPosition = *( mVisualModel->mGlyphPositions.Begin() + currentGlyphIndex );
739
740     // Set the cursor's height.
741     cursorInfo.primaryCursorHeight = glyphMetrics.fontHeight;
742
743     // Set the position.
744     cursorInfo.primaryPosition.x = -glyphMetrics.xBearing + currentPosition.x + ( isCurrentRightToLeft ? glyphMetrics.advance : interGlyphAdvance );
745     cursorInfo.primaryPosition.y = line.ascender - glyphMetrics.ascender;
746
747     if( isLastPosition )
748     {
749       // The position of the cursor after the last character needs special
750       // care depending on its direction and the direction of the paragraph.
751
752       if( cursorInfo.isSecondaryCursor )
753       {
754         // Need to find the first character after the last character with the paragraph's direction.
755         // i.e l0 l1 l2 r0 r1 should find r0.
756
757         // TODO: check for more than one line!
758         characterIndex = isRightToLeftParagraph ? line.characterRun.characterIndex : line.characterRun.characterIndex + line.characterRun.numberOfCharacters - 1u;
759         characterIndex = mLogicalModel->GetLogicalCharacterIndex( characterIndex );
760
761         const GlyphIndex glyphIndex = *( mVisualModel->mCharactersToGlyph.Begin() + characterIndex );
762         const Length numberOfGlyphs = *( mVisualModel->mGlyphsPerCharacter.Begin() + characterIndex );
763
764         const Vector2& position = *( mVisualModel->mGlyphPositions.Begin() + glyphIndex );
765
766         // Get the metrics for the group of glyphs.
767         GlyphMetrics glyphMetrics;
768         GetGlyphsMetrics( glyphIndex,
769                           numberOfGlyphs,
770                           glyphMetrics );
771
772         cursorInfo.primaryPosition.x = -glyphMetrics.xBearing + position.x + ( isRightToLeftParagraph ? 0.f : glyphMetrics.advance );
773
774         cursorInfo.primaryPosition.y = line.ascender - glyphMetrics.ascender;
775       }
776       else
777       {
778         if( !isCurrentRightToLeft )
779         {
780           cursorInfo.primaryPosition.x += glyphMetrics.advance;
781         }
782         else
783         {
784           cursorInfo.primaryPosition.x -= glyphMetrics.advance;
785         }
786       }
787     }
788
789     // Set the alternative cursor position.
790     if( cursorInfo.isSecondaryCursor )
791     {
792       // Convert the cursor position into the glyph position.
793       const CharacterIndex previousCharacterIndex = ( ( isRightToLeftParagraph != isCurrentRightToLeft ) ? logical : previousLogical );
794       const GlyphIndex previousGlyphIndex = *( mVisualModel->mCharactersToGlyph.Begin() + previousCharacterIndex );
795       const Length numberOfGlyphs = *( mVisualModel->mGlyphsPerCharacter.Begin() + previousCharacterIndex );
796
797       // Get the glyph position.
798       const Vector2& previousPosition = *( mVisualModel->mGlyphPositions.Begin() + previousGlyphIndex );
799
800       // Get the metrics for the group of glyphs.
801       GlyphMetrics glyphMetrics;
802       GetGlyphsMetrics( previousGlyphIndex,
803                         numberOfGlyphs,
804                         glyphMetrics );
805
806       // Set the cursor position and height.
807       cursorInfo.secondaryPosition.x = -glyphMetrics.xBearing + previousPosition.x + ( ( ( isLastPosition && !isCurrentRightToLeft ) ||
808                                                                                          ( !isLastPosition && isCurrentRightToLeft )    ) ? glyphMetrics.advance : 0.f );
809
810       cursorInfo.secondaryCursorHeight = 0.5f * glyphMetrics.fontHeight;
811
812       cursorInfo.secondaryPosition.y = cursorInfo.lineHeight - cursorInfo.secondaryCursorHeight - line.descender - ( glyphMetrics.fontHeight - glyphMetrics.ascender );
813
814       // Update the primary cursor height as well.
815       cursorInfo.primaryCursorHeight *= 0.5f;
816     }
817   }
818
819   /**
820    * @brief Get some glyph's metrics of a group of glyphs formed as a result of shaping one character.
821    *
822    * @param[in] glyphIndex The index to the first glyph.
823    * @param[in] numberOfGlyphs The number of glyphs.
824    * @param[out] glyphMetrics Some glyph metrics (font height, advance, ascender and x bearing).
825    */
826   void GetGlyphsMetrics( GlyphIndex glyphIndex,
827                          Length numberOfGlyphs,
828                          GlyphMetrics& glyphMetrics ) const
829   {
830     const GlyphInfo* glyphsBuffer = mVisualModel->mGlyphs.Begin();
831
832     const GlyphInfo& firstGlyph = *( glyphsBuffer + glyphIndex );
833
834     Text::FontMetrics fontMetrics;
835     mFontClient.GetFontMetrics( firstGlyph.fontId, fontMetrics );
836
837     glyphMetrics.fontHeight = fontMetrics.height;
838     glyphMetrics.advance = firstGlyph.advance;
839     glyphMetrics.ascender = fontMetrics.ascender;
840     glyphMetrics.xBearing = firstGlyph.xBearing;
841
842     for( unsigned int i = 1u; i < numberOfGlyphs; ++i )
843     {
844       const GlyphInfo& glyphInfo = *( glyphsBuffer + glyphIndex + i );
845
846       glyphMetrics.advance += glyphInfo.advance;
847     }
848   }
849
850   /**
851    * @brief Calculates the new cursor index.
852    *
853    * It takes into account that in some scripts multiple characters can form a glyph and all of them
854    * need to be jumped with one key event.
855    *
856    * @param[in] index The initial new index.
857    *
858    * @return The new cursor index.
859    */
860   CharacterIndex CalculateNewCursorIndex( CharacterIndex index ) const
861   {
862     CharacterIndex cursorIndex = mPrimaryCursorPosition;
863
864     const Script script = mLogicalModel->GetScript( index );
865     const GlyphIndex* charactersToGlyphBuffer = mVisualModel->mCharactersToGlyph.Begin();
866     const Length* charactersPerGlyphBuffer = mVisualModel->mCharactersPerGlyph.Begin();
867
868     Length numberOfCharacters = 0u;
869     if( TextAbstraction::LATIN == script )
870     {
871       // Prevents to jump the whole Latin ligatures like fi, ff, ...
872       numberOfCharacters = 1u;
873     }
874     else
875     {
876       GlyphIndex glyphIndex = *( charactersToGlyphBuffer + index );
877       numberOfCharacters = *( charactersPerGlyphBuffer + glyphIndex );
878
879       while( 0u == numberOfCharacters )
880       {
881         numberOfCharacters = *( charactersPerGlyphBuffer + glyphIndex );
882         ++glyphIndex;
883       }
884     }
885
886     if( index < mPrimaryCursorPosition )
887     {
888       cursorIndex -= numberOfCharacters;
889     }
890     else
891     {
892       cursorIndex += numberOfCharacters;
893     }
894
895     return cursorIndex;
896   }
897
898   void UpdateCursorPosition()
899   {
900     CursorInfo cursorInfo;
901
902     GetCursorPosition( mPrimaryCursorPosition,
903                        cursorInfo );
904
905     mDecorator->SetPosition( PRIMARY_CURSOR,
906                              cursorInfo.primaryPosition.x,
907                              cursorInfo.primaryPosition.y,
908                              cursorInfo.primaryCursorHeight,
909                              cursorInfo.lineHeight );
910
911     if( cursorInfo.isSecondaryCursor )
912     {
913       mDecorator->SetActiveCursor( ACTIVE_CURSOR_BOTH );
914       mDecorator->SetPosition( SECONDARY_CURSOR,
915                                cursorInfo.secondaryPosition.x,
916                                cursorInfo.secondaryPosition.y,
917                                cursorInfo.secondaryCursorHeight,
918                                cursorInfo.lineHeight );
919     }
920     else
921     {
922       mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
923     }
924
925     mUpdateCursorPosition = false;
926     mDecoratorUpdated = true;
927   }
928
929   LogicalModelPtr              mLogicalModel;
930   VisualModelPtr               mVisualModel;
931   DecoratorPtr                 mDecorator;
932   FontDefaults*                mFontDefaults;
933   TextAbstraction::FontClient& mFontClient;
934   std::string                  mPlaceholderText;
935
936   /**
937    * This is used to delay handling events until after the model has been updated.
938    * The number of updates to the model is minimized to improve performance.
939    */
940   vector<Event> mEventQueue; ///< The queue of touch events etc.
941
942   State mState; ///< Selection mode, edit mode etc.
943
944   CharacterIndex mPrimaryCursorPosition;   ///< Index into logical model for primary cursor
945   CharacterIndex mSecondaryCursorPosition; ///< Index into logical model for secondary cursor
946
947   /**
948    * 0,0 means that the top-left corner of the layout matches the top-left corner of the UI control.
949    * Typically this will have a negative value with scrolling occurs.
950    */
951   Vector2 mScrollPosition; ///< The text is offset by this position when scrolling.
952
953   bool mDecoratorUpdated           : 1; ///< True if the decorator was updated during event processing
954   bool mCursorBlinkEnabled         : 1; ///< True if cursor should blink when active
955   bool mGrabHandleEnabled          : 1; ///< True if grab handle is enabled
956   bool mGrabHandlePopupEnabled     : 1; ///< True if the grab handle popu-up should be shown
957   bool mSelectionEnabled           : 1; ///< True if selection handles, highlight etc. are enabled
958   bool mHorizontalScrollingEnabled : 1; ///< True if horizontal scrolling is enabled
959   bool mVerticalScrollingEnabled   : 1; ///< True if vertical scrolling is enabled
960   bool mUpdateCursorPosition       : 1; ///< True if the visual position of the cursor must be recalculated
961 };
962
963 struct Controller::Impl
964 {
965   Impl( ControlInterface& controlInterface )
966   : mControlInterface( controlInterface ),
967     mLogicalModel(),
968     mVisualModel(),
969     mFontDefaults( NULL ),
970     mTextInput( NULL ),
971     mFontClient(),
972     mView(),
973     mLayoutEngine(),
974     mModifyEvents(),
975     mControlSize(),
976     mAlignmentOffset(),
977     mOperationsPending( NO_OPERATION ),
978     mRecalculateNaturalSize( true )
979   {
980     mLogicalModel = LogicalModel::New();
981     mVisualModel  = VisualModel::New();
982
983     mFontClient = TextAbstraction::FontClient::Get();
984
985     mView.SetVisualModel( mVisualModel );
986
987     // Set the text properties to default
988     mVisualModel->SetTextColor( Color::WHITE );
989     mVisualModel->SetShadowOffset( Vector2::ZERO );
990     mVisualModel->SetShadowColor( Vector4::ZERO );
991     mVisualModel->SetUnderlineEnabled( false );
992   }
993
994   ~Impl()
995   {
996     delete mTextInput;
997   }
998
999   ControlInterface& mControlInterface;     ///< Reference to the text controller.
1000   LogicalModelPtr mLogicalModel;           ///< Pointer to the logical model.
1001   VisualModelPtr  mVisualModel;            ///< Pointer to the visual model.
1002   FontDefaults* mFontDefaults;             ///< Avoid allocating this when the user does not specify a font.
1003   Controller::TextInput* mTextInput;       ///< Avoid allocating everything for text input until EnableTextInput().
1004   TextAbstraction::FontClient mFontClient; ///< Handle to the font client.
1005   View mView;                              ///< The view interface to the rendering back-end.
1006   LayoutEngine mLayoutEngine;              ///< The layout engine.
1007   std::vector<ModifyEvent> mModifyEvents;  ///< Temporary stores the text set until the next relayout.
1008   Size mControlSize;                       ///< The size of the control.
1009   Vector2 mAlignmentOffset;                ///< Vertical and horizontal offset of the whole text inside the control due to alignment.
1010   OperationsMask mOperationsPending;       ///< Operations pending to be done to layout the text.
1011   bool mRecalculateNaturalSize:1;          ///< Whether the natural size needs to be recalculated.
1012 };
1013
1014 ControllerPtr Controller::New( ControlInterface& controlInterface )
1015 {
1016   return ControllerPtr( new Controller( controlInterface ) );
1017 }
1018
1019 void Controller::SetText( const std::string& text )
1020 {
1021   // Cancel previously queued inserts etc.
1022   mImpl->mModifyEvents.clear();
1023
1024   // Keep until size negotiation
1025   ModifyEvent event;
1026   event.type = REPLACE_TEXT;
1027   event.text = text;
1028   mImpl->mModifyEvents.push_back( event );
1029
1030   if( mImpl->mTextInput )
1031   {
1032     // Cancel previously queued events
1033     mImpl->mTextInput->mEventQueue.clear();
1034
1035     // TODO - Hide selection decorations
1036   }
1037 }
1038
1039 void Controller::GetText( std::string& text ) const
1040 {
1041   if( !mImpl->mModifyEvents.empty() &&
1042        REPLACE_TEXT == mImpl->mModifyEvents[0].type )
1043   {
1044     text = mImpl->mModifyEvents[0].text;
1045   }
1046   else
1047   {
1048     // TODO - Convert from UTF-32
1049   }
1050 }
1051
1052 void Controller::SetPlaceholderText( const std::string& text )
1053 {
1054   if( !mImpl->mTextInput )
1055   {
1056     mImpl->mTextInput->mPlaceholderText = text;
1057   }
1058 }
1059
1060 void Controller::GetPlaceholderText( std::string& text ) const
1061 {
1062   if( !mImpl->mTextInput )
1063   {
1064     text = mImpl->mTextInput->mPlaceholderText;
1065   }
1066 }
1067
1068 void Controller::SetDefaultFontFamily( const std::string& defaultFontFamily )
1069 {
1070   if( !mImpl->mFontDefaults )
1071   {
1072     mImpl->mFontDefaults = new Controller::FontDefaults();
1073   }
1074
1075   mImpl->mFontDefaults->mDefaultFontFamily = defaultFontFamily;
1076   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
1077   mImpl->mOperationsPending = ALL_OPERATIONS;
1078   mImpl->mRecalculateNaturalSize = true;
1079
1080   // Clear the font-specific data
1081   mImpl->mLogicalModel->mFontRuns.Clear();
1082   mImpl->mVisualModel->mGlyphs.Clear();
1083   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
1084   mImpl->mVisualModel->mCharactersToGlyph.Clear();
1085   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
1086   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
1087   mImpl->mVisualModel->mGlyphPositions.Clear();
1088   mImpl->mVisualModel->mLines.Clear();
1089   mImpl->mVisualModel->ClearCaches();
1090
1091   RequestRelayout();
1092 }
1093
1094 const std::string& Controller::GetDefaultFontFamily() const
1095 {
1096   if( mImpl->mFontDefaults )
1097   {
1098     return mImpl->mFontDefaults->mDefaultFontFamily;
1099   }
1100
1101   return EMPTY_STRING;
1102 }
1103
1104 void Controller::SetDefaultFontStyle( const std::string& defaultFontStyle )
1105 {
1106   if( !mImpl->mFontDefaults )
1107   {
1108     mImpl->mFontDefaults = new Controller::FontDefaults();
1109   }
1110
1111   mImpl->mFontDefaults->mDefaultFontStyle = defaultFontStyle;
1112   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
1113   mImpl->mOperationsPending = ALL_OPERATIONS;
1114   mImpl->mRecalculateNaturalSize = true;
1115
1116   // Clear the font-specific data
1117   mImpl->mLogicalModel->mFontRuns.Clear();
1118   mImpl->mVisualModel->mGlyphs.Clear();
1119   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
1120   mImpl->mVisualModel->mCharactersToGlyph.Clear();
1121   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
1122   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
1123   mImpl->mVisualModel->mGlyphPositions.Clear();
1124   mImpl->mVisualModel->mLines.Clear();
1125   mImpl->mVisualModel->ClearCaches();
1126
1127   RequestRelayout();
1128 }
1129
1130 const std::string& Controller::GetDefaultFontStyle() const
1131 {
1132   if( mImpl->mFontDefaults )
1133   {
1134     return mImpl->mFontDefaults->mDefaultFontStyle;
1135   }
1136
1137   return EMPTY_STRING;
1138 }
1139
1140 void Controller::SetDefaultPointSize( float pointSize )
1141 {
1142   if( !mImpl->mFontDefaults )
1143   {
1144     mImpl->mFontDefaults = new Controller::FontDefaults();
1145   }
1146
1147   mImpl->mFontDefaults->mDefaultPointSize = pointSize;
1148   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
1149   mImpl->mOperationsPending = ALL_OPERATIONS;
1150   mImpl->mRecalculateNaturalSize = true;
1151
1152   // Clear the font-specific data
1153   mImpl->mLogicalModel->mFontRuns.Clear();
1154   mImpl->mVisualModel->mGlyphs.Clear();
1155   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
1156   mImpl->mVisualModel->mCharactersToGlyph.Clear();
1157   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
1158   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
1159   mImpl->mVisualModel->mGlyphPositions.Clear();
1160   mImpl->mVisualModel->mLines.Clear();
1161   mImpl->mVisualModel->ClearCaches();
1162
1163   RequestRelayout();
1164 }
1165
1166 float Controller::GetDefaultPointSize() const
1167 {
1168   if( mImpl->mFontDefaults )
1169   {
1170     return mImpl->mFontDefaults->mDefaultPointSize;
1171   }
1172
1173   return 0.0f;
1174 }
1175
1176 void Controller::GetDefaultFonts( Vector<FontRun>& fonts, Length numberOfCharacters ) const
1177 {
1178   if( mImpl->mFontDefaults )
1179   {
1180     FontRun fontRun;
1181     fontRun.characterRun.characterIndex = 0;
1182     fontRun.characterRun.numberOfCharacters = numberOfCharacters;
1183     fontRun.fontId = mImpl->mFontDefaults->GetFontId( mImpl->mFontClient );
1184     fontRun.isDefault = true;
1185
1186     fonts.PushBack( fontRun );
1187   }
1188 }
1189
1190 const Vector4& Controller::GetTextColor() const
1191 {
1192   return mImpl->mVisualModel->GetTextColor();
1193 }
1194
1195 const Vector2& Controller::GetShadowOffset() const
1196 {
1197   return mImpl->mVisualModel->GetShadowOffset();
1198 }
1199
1200 const Vector4& Controller::GetShadowColor() const
1201 {
1202   return mImpl->mVisualModel->GetShadowColor();
1203 }
1204
1205 const Vector4& Controller::GetUnderlineColor() const
1206 {
1207   return mImpl->mVisualModel->GetUnderlineColor();
1208 }
1209
1210 bool Controller::IsUnderlineEnabled() const
1211 {
1212   return mImpl->mVisualModel->IsUnderlineEnabled();
1213 }
1214
1215 void Controller::SetTextColor( const Vector4& textColor )
1216 {
1217   mImpl->mVisualModel->SetTextColor( textColor );
1218 }
1219
1220 void Controller::SetShadowOffset( const Vector2& shadowOffset )
1221 {
1222   mImpl->mVisualModel->SetShadowOffset( shadowOffset );
1223 }
1224
1225 void Controller::SetShadowColor( const Vector4& shadowColor )
1226 {
1227   mImpl->mVisualModel->SetShadowColor( shadowColor );
1228 }
1229
1230 void Controller::SetUnderlineColor( const Vector4& color )
1231 {
1232   mImpl->mVisualModel->SetUnderlineColor( color );
1233 }
1234
1235 void Controller::SetUnderlineEnabled( bool enabled )
1236 {
1237   mImpl->mVisualModel->SetUnderlineEnabled( enabled );
1238 }
1239
1240 void Controller::EnableTextInput( DecoratorPtr decorator )
1241 {
1242   if( !mImpl->mTextInput )
1243   {
1244     mImpl->mTextInput = new TextInput( mImpl->mLogicalModel,
1245                                        mImpl->mVisualModel,
1246                                        decorator,
1247                                        mImpl->mFontDefaults,
1248                                        mImpl->mFontClient );
1249   }
1250 }
1251
1252 void Controller::SetEnableCursorBlink( bool enable )
1253 {
1254   DALI_ASSERT_DEBUG( NULL != mImpl->mTextInput && "TextInput disabled" );
1255
1256   if( mImpl->mTextInput )
1257   {
1258     mImpl->mTextInput->mCursorBlinkEnabled = enable;
1259
1260     if( !enable &&
1261         mImpl->mTextInput->mDecorator )
1262     {
1263       mImpl->mTextInput->mDecorator->StopCursorBlink();
1264     }
1265   }
1266 }
1267
1268 bool Controller::GetEnableCursorBlink() const
1269 {
1270   if( mImpl->mTextInput )
1271   {
1272     return mImpl->mTextInput->mCursorBlinkEnabled;
1273   }
1274
1275   return false;
1276 }
1277
1278 const Vector2& Controller::GetScrollPosition() const
1279 {
1280   if( mImpl->mTextInput )
1281   {
1282     return mImpl->mTextInput->mScrollPosition;
1283   }
1284
1285   return Vector2::ZERO;
1286 }
1287
1288 const Vector2& Controller::GetAlignmentOffset() const
1289 {
1290   return mImpl->mAlignmentOffset;
1291 }
1292
1293 Vector3 Controller::GetNaturalSize()
1294 {
1295   Vector3 naturalSize;
1296
1297   // Make sure the model is up-to-date before layouting
1298   ProcessModifyEvents();
1299
1300   if( mImpl->mRecalculateNaturalSize )
1301   {
1302     // Operations that can be done only once until the text changes.
1303     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
1304                                                                            GET_SCRIPTS       |
1305                                                                            VALIDATE_FONTS    |
1306                                                                            GET_LINE_BREAKS   |
1307                                                                            GET_WORD_BREAKS   |
1308                                                                            BIDI_INFO         |
1309                                                                            SHAPE_TEXT        |
1310                                                                            GET_GLYPH_METRICS );
1311     // Make sure the model is up-to-date before layouting
1312     UpdateModel( onlyOnceOperations );
1313
1314     // Operations that need to be done if the size changes.
1315     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
1316                                                                         ALIGN  |
1317                                                                         REORDER );
1318
1319     DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
1320                 static_cast<OperationsMask>( onlyOnceOperations |
1321                                              sizeOperations ),
1322                 naturalSize.GetVectorXY() );
1323
1324     // Do not do again the only once operations.
1325     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
1326
1327     // Do the size related operations again.
1328     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
1329
1330     // Stores the natural size to avoid recalculate it again
1331     // unless the text/style changes.
1332     mImpl->mVisualModel->SetNaturalSize( naturalSize.GetVectorXY() );
1333
1334     mImpl->mRecalculateNaturalSize = false;
1335   }
1336   else
1337   {
1338     naturalSize = mImpl->mVisualModel->GetNaturalSize();
1339   }
1340
1341   return naturalSize;
1342 }
1343
1344 float Controller::GetHeightForWidth( float width )
1345 {
1346   // Make sure the model is up-to-date before layouting
1347   ProcessModifyEvents();
1348
1349   Size layoutSize;
1350   if( width != mImpl->mControlSize.width )
1351   {
1352     // Operations that can be done only once until the text changes.
1353     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
1354                                                                            GET_SCRIPTS       |
1355                                                                            VALIDATE_FONTS    |
1356                                                                            GET_LINE_BREAKS   |
1357                                                                            GET_WORD_BREAKS   |
1358                                                                            BIDI_INFO         |
1359                                                                            SHAPE_TEXT        |
1360                                                                            GET_GLYPH_METRICS );
1361     // Make sure the model is up-to-date before layouting
1362     UpdateModel( onlyOnceOperations );
1363
1364     // Operations that need to be done if the size changes.
1365     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
1366                                                                         ALIGN  |
1367                                                                         REORDER );
1368
1369     DoRelayout( Size( width, MAX_FLOAT ),
1370                 static_cast<OperationsMask>( onlyOnceOperations |
1371                                              sizeOperations ),
1372                 layoutSize );
1373
1374     // Do not do again the only once operations.
1375     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
1376
1377     // Do the size related operations again.
1378     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
1379   }
1380   else
1381   {
1382     layoutSize = mImpl->mVisualModel->GetActualSize();
1383   }
1384
1385   return layoutSize.height;
1386 }
1387
1388 bool Controller::Relayout( const Size& size )
1389 {
1390   if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
1391   {
1392     bool glyphsRemoved( false );
1393     if( 0u != mImpl->mVisualModel->GetNumberOfGlyphPositions() )
1394     {
1395       mImpl->mVisualModel->SetGlyphPositions( NULL, 0u );
1396       glyphsRemoved = true;
1397     }
1398
1399     // Not worth to relayout if width or height is equal to zero.
1400     return glyphsRemoved;
1401   }
1402
1403   if( size != mImpl->mControlSize )
1404   {
1405     // Operations that need to be done if the size changes.
1406     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1407                                                              LAYOUT                    |
1408                                                              ALIGN                     |
1409                                                              UPDATE_ACTUAL_SIZE        |
1410                                                              REORDER );
1411
1412     mImpl->mControlSize = size;
1413   }
1414
1415   // Make sure the model is up-to-date before layouting
1416   ProcessModifyEvents();
1417   UpdateModel( mImpl->mOperationsPending );
1418
1419   Size layoutSize;
1420   bool updated = DoRelayout( mImpl->mControlSize,
1421                              mImpl->mOperationsPending,
1422                              layoutSize );
1423
1424   // Do not re-do any operation until something changes.
1425   mImpl->mOperationsPending = NO_OPERATION;
1426
1427   // After doing the text layout, the alignment offset to place the actor in the desired position can be calculated.
1428   CalculateTextAlignment( size );
1429
1430   if( mImpl->mTextInput )
1431   {
1432     // Move the cursor, grab handle etc.
1433     updated = mImpl->mTextInput->ProcessInputEvents( mImpl->mControlSize, mImpl->mAlignmentOffset ) || updated;
1434   }
1435
1436   return updated;
1437 }
1438
1439 void Controller::ProcessModifyEvents()
1440 {
1441   std::vector<ModifyEvent>& events = mImpl->mModifyEvents;
1442
1443   for( unsigned int i=0; i<events.size(); ++i )
1444   {
1445     if( REPLACE_TEXT == events[0].type )
1446     {
1447       // A (single) replace event should come first, otherwise we wasted time processing NOOP events
1448       DALI_ASSERT_DEBUG( 0 == i && "Unexpected REPLACE event" );
1449
1450       ReplaceTextEvent( events[0].text );
1451     }
1452     else if( INSERT_TEXT == events[0].type )
1453     {
1454       InsertTextEvent( events[0].text );
1455     }
1456     else if( DELETE_TEXT == events[0].type )
1457     {
1458       DeleteTextEvent();
1459     }
1460   }
1461
1462   // Discard temporary text
1463   events.clear();
1464 }
1465
1466 void Controller::ReplaceTextEvent( const std::string& text )
1467 {
1468   // Reset buffers.
1469   mImpl->mLogicalModel->mText.Clear();
1470   mImpl->mLogicalModel->mScriptRuns.Clear();
1471   mImpl->mLogicalModel->mFontRuns.Clear();
1472   mImpl->mLogicalModel->mLineBreakInfo.Clear();
1473   mImpl->mLogicalModel->mWordBreakInfo.Clear();
1474   mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
1475   mImpl->mLogicalModel->mCharacterDirections.Clear();
1476   mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
1477   mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
1478   mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
1479   mImpl->mVisualModel->mGlyphs.Clear();
1480   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
1481   mImpl->mVisualModel->mCharactersToGlyph.Clear();
1482   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
1483   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
1484   mImpl->mVisualModel->mGlyphPositions.Clear();
1485   mImpl->mVisualModel->mLines.Clear();
1486   mImpl->mVisualModel->ClearCaches();
1487
1488   //  Convert text into UTF-32
1489   Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
1490   utf32Characters.Resize( text.size() );
1491
1492   // This is a bit horrible but std::string returns a (signed) char*
1493   const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
1494
1495   // Transform a text array encoded in utf8 into an array encoded in utf32.
1496   // It returns the actual number of characters.
1497   Length characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
1498   utf32Characters.Resize( characterCount );
1499
1500   // Reset the cursor position
1501   if( mImpl->mTextInput )
1502   {
1503     mImpl->mTextInput->mPrimaryCursorPosition = characterCount;
1504     // TODO - handle secondary cursor
1505   }
1506
1507   // The natural size needs to be re-calculated.
1508   mImpl->mRecalculateNaturalSize = true;
1509
1510   // Apply modifications to the model
1511   mImpl->mOperationsPending = ALL_OPERATIONS;
1512   UpdateModel( ALL_OPERATIONS );
1513   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
1514                                                            ALIGN              |
1515                                                            UPDATE_ACTUAL_SIZE |
1516                                                            REORDER );
1517 }
1518
1519 void Controller::InsertTextEvent( const std::string& text )
1520 {
1521   DALI_ASSERT_DEBUG( NULL != mImpl->mTextInput && "Unexpected InsertTextEvent" );
1522
1523   // TODO - Optimize this
1524   mImpl->mLogicalModel->mScriptRuns.Clear();
1525   mImpl->mLogicalModel->mFontRuns.Clear();
1526   mImpl->mLogicalModel->mLineBreakInfo.Clear();
1527   mImpl->mLogicalModel->mWordBreakInfo.Clear();
1528   mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
1529   mImpl->mLogicalModel->mCharacterDirections.Clear();
1530   mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
1531   mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
1532   mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
1533   mImpl->mVisualModel->mGlyphs.Clear();
1534   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
1535   mImpl->mVisualModel->mCharactersToGlyph.Clear();
1536   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
1537   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
1538   mImpl->mVisualModel->mGlyphPositions.Clear();
1539   mImpl->mVisualModel->mLines.Clear();
1540   mImpl->mVisualModel->ClearCaches();
1541
1542   //  Convert text into UTF-32
1543   Vector<Character> utf32Characters;
1544   utf32Characters.Resize( text.size() );
1545
1546   // This is a bit horrible but std::string returns a (signed) char*
1547   const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
1548
1549   // Transform a text array encoded in utf8 into an array encoded in utf32.
1550   // It returns the actual number of characters.
1551   Length characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
1552   utf32Characters.Resize( characterCount );
1553
1554   // Insert at current cursor position
1555   Vector<Character>& modifyText = mImpl->mLogicalModel->mText;
1556   CharacterIndex& cursorIndex = mImpl->mTextInput->mPrimaryCursorPosition;
1557
1558   if( cursorIndex < modifyText.Count() )
1559   {
1560     modifyText.Insert( modifyText.Begin() + cursorIndex, utf32Characters.Begin(), utf32Characters.End() );
1561   }
1562   else
1563   {
1564     modifyText.Insert( modifyText.End(), utf32Characters.Begin(), utf32Characters.End() );
1565   }
1566
1567   // Advance the cursor position
1568   ++cursorIndex;
1569
1570   // The natural size needs to be re-calculated.
1571   mImpl->mRecalculateNaturalSize = true;
1572
1573   // Apply modifications to the model; TODO - Optimize this
1574   mImpl->mOperationsPending = ALL_OPERATIONS;
1575   UpdateModel( ALL_OPERATIONS );
1576   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
1577                                                            ALIGN              |
1578                                                            UPDATE_ACTUAL_SIZE |
1579                                                            REORDER );
1580
1581   // Queue a cursor reposition event; this must wait until after DoRelayout()
1582   mImpl->mTextInput->mUpdateCursorPosition = true;
1583 }
1584
1585 void Controller::DeleteTextEvent()
1586 {
1587   DALI_ASSERT_DEBUG( NULL != mImpl->mTextInput && "Unexpected InsertTextEvent" );
1588
1589   // TODO - Optimize this
1590   mImpl->mLogicalModel->mScriptRuns.Clear();
1591   mImpl->mLogicalModel->mFontRuns.Clear();
1592   mImpl->mLogicalModel->mLineBreakInfo.Clear();
1593   mImpl->mLogicalModel->mWordBreakInfo.Clear();
1594   mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
1595   mImpl->mLogicalModel->mCharacterDirections.Clear();
1596   mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
1597   mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
1598   mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
1599   mImpl->mVisualModel->mGlyphs.Clear();
1600   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
1601   mImpl->mVisualModel->mCharactersToGlyph.Clear();
1602   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
1603   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
1604   mImpl->mVisualModel->mGlyphPositions.Clear();
1605   mImpl->mVisualModel->mLines.Clear();
1606   mImpl->mVisualModel->ClearCaches();
1607
1608   // Delte at current cursor position
1609   Vector<Character>& modifyText = mImpl->mLogicalModel->mText;
1610   CharacterIndex& cursorIndex = mImpl->mTextInput->mPrimaryCursorPosition;
1611
1612   if( cursorIndex > 0 &&
1613       cursorIndex-1 < modifyText.Count() )
1614   {
1615     modifyText.Remove( modifyText.Begin() + cursorIndex - 1 );
1616
1617     // Cursor position retreat
1618     --cursorIndex;
1619   }
1620
1621   // The natural size needs to be re-calculated.
1622   mImpl->mRecalculateNaturalSize = true;
1623
1624   // Apply modifications to the model; TODO - Optimize this
1625   mImpl->mOperationsPending = ALL_OPERATIONS;
1626   UpdateModel( ALL_OPERATIONS );
1627   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
1628                                                            ALIGN              |
1629                                                            UPDATE_ACTUAL_SIZE |
1630                                                            REORDER );
1631
1632   // Queue a cursor reposition event; this must wait until after DoRelayout()
1633   mImpl->mTextInput->mUpdateCursorPosition = true;
1634 }
1635
1636 void Controller::UpdateModel( OperationsMask operationsRequired )
1637 {
1638   // Calculate the operations to be done.
1639   const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
1640
1641   Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
1642
1643   const Length numberOfCharacters = mImpl->mLogicalModel->GetNumberOfCharacters();
1644
1645   Vector<LineBreakInfo>& lineBreakInfo = mImpl->mLogicalModel->mLineBreakInfo;
1646   if( GET_LINE_BREAKS & operations )
1647   {
1648     // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
1649     // calculate the bidirectional info for each 'paragraph'.
1650     // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
1651     // is not shaped together).
1652     lineBreakInfo.Resize( numberOfCharacters, TextAbstraction::LINE_NO_BREAK );
1653
1654     SetLineBreakInfo( utf32Characters,
1655                       lineBreakInfo );
1656   }
1657
1658   Vector<WordBreakInfo>& wordBreakInfo = mImpl->mLogicalModel->mWordBreakInfo;
1659   if( GET_WORD_BREAKS & operations )
1660   {
1661     // Retrieves the word break info. The word break info is used to layout the text (where to wrap the text in lines).
1662     wordBreakInfo.Resize( numberOfCharacters, TextAbstraction::WORD_NO_BREAK );
1663
1664     SetWordBreakInfo( utf32Characters,
1665                       wordBreakInfo );
1666   }
1667
1668   const bool getScripts = GET_SCRIPTS & operations;
1669   const bool validateFonts = VALIDATE_FONTS & operations;
1670
1671   Vector<ScriptRun>& scripts = mImpl->mLogicalModel->mScriptRuns;
1672   Vector<FontRun>& validFonts = mImpl->mLogicalModel->mFontRuns;
1673
1674   if( getScripts || validateFonts )
1675   {
1676     // Validates the fonts assigned by the application or assigns default ones.
1677     // It makes sure all the characters are going to be rendered by the correct font.
1678     MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
1679
1680     if( getScripts )
1681     {
1682       // Retrieves the scripts used in the text.
1683       multilanguageSupport.SetScripts( utf32Characters,
1684                                        lineBreakInfo,
1685                                        scripts );
1686     }
1687
1688     if( validateFonts )
1689     {
1690       if( 0u == validFonts.Count() )
1691       {
1692         // Copy the requested font defaults received via the property system.
1693         // These may not be valid i.e. may not contain glyphs for the necessary scripts.
1694         GetDefaultFonts( validFonts, numberOfCharacters );
1695       }
1696
1697       // Validates the fonts. If there is a character with no assigned font it sets a default one.
1698       // After this call, fonts are validated.
1699       multilanguageSupport.ValidateFonts( utf32Characters,
1700                                           scripts,
1701                                           validFonts );
1702     }
1703   }
1704
1705   Vector<Character> mirroredUtf32Characters;
1706   bool textMirrored = false;
1707   if( BIDI_INFO & operations )
1708   {
1709     // Count the number of LINE_NO_BREAK to reserve some space for the vector of paragraph's
1710     // bidirectional info.
1711
1712     Length numberOfParagraphs = 0u;
1713
1714     const TextAbstraction::LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
1715     for( Length index = 0u; index < numberOfCharacters; ++index )
1716     {
1717       if( TextAbstraction::LINE_NO_BREAK == *( lineBreakInfoBuffer + index ) )
1718       {
1719         ++numberOfParagraphs;
1720       }
1721     }
1722
1723     Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mImpl->mLogicalModel->mBidirectionalParagraphInfo;
1724     bidirectionalInfo.Reserve( numberOfParagraphs );
1725
1726     // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
1727     SetBidirectionalInfo( utf32Characters,
1728                           scripts,
1729                           lineBreakInfo,
1730                           bidirectionalInfo );
1731
1732     if( 0u != bidirectionalInfo.Count() )
1733     {
1734       // This paragraph has right to left text. Some characters may need to be mirrored.
1735       // TODO: consider if the mirrored string can be stored as well.
1736
1737       textMirrored = GetMirroredText( utf32Characters, mirroredUtf32Characters );
1738
1739       // Only set the character directions if there is right to left characters.
1740       Vector<CharacterDirection>& directions = mImpl->mLogicalModel->mCharacterDirections;
1741       directions.Resize( numberOfCharacters );
1742
1743       GetCharactersDirection( bidirectionalInfo,
1744                               directions );
1745     }
1746     else
1747     {
1748       // There is no right to left characters. Clear the directions vector.
1749       mImpl->mLogicalModel->mCharacterDirections.Clear();
1750     }
1751
1752    }
1753
1754   Vector<GlyphInfo>& glyphs = mImpl->mVisualModel->mGlyphs;
1755   Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mVisualModel->mGlyphsToCharacters;
1756   Vector<Length>& charactersPerGlyph = mImpl->mVisualModel->mCharactersPerGlyph;
1757   if( SHAPE_TEXT & operations )
1758   {
1759     const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
1760     // Shapes the text.
1761     ShapeText( textToShape,
1762                lineBreakInfo,
1763                scripts,
1764                validFonts,
1765                glyphs,
1766                glyphsToCharactersMap,
1767                charactersPerGlyph );
1768
1769     // Create the 'number of glyphs' per character and the glyph to character conversion tables.
1770     mImpl->mVisualModel->CreateGlyphsPerCharacterTable( numberOfCharacters );
1771     mImpl->mVisualModel->CreateCharacterToGlyphTable( numberOfCharacters );
1772   }
1773
1774   const Length numberOfGlyphs = glyphs.Count();
1775
1776   if( GET_GLYPH_METRICS & operations )
1777   {
1778     mImpl->mFontClient.GetGlyphMetrics( glyphs.Begin(), numberOfGlyphs );
1779   }
1780 }
1781
1782 bool Controller::DoRelayout( const Size& size,
1783                              OperationsMask operationsRequired,
1784                              Size& layoutSize )
1785 {
1786   bool viewUpdated( false );
1787
1788   // Calculate the operations to be done.
1789   const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
1790
1791   if( LAYOUT & operations )
1792   {
1793     // Some vectors with data needed to layout and reorder may be void
1794     // after the first time the text has been laid out.
1795     // Fill the vectors again.
1796
1797     Length numberOfGlyphs = mImpl->mVisualModel->GetNumberOfGlyphs();
1798
1799     if( 0u == numberOfGlyphs )
1800     {
1801       // Nothing else to do if there is no glyphs.
1802       return true;
1803     }
1804
1805     Vector<LineBreakInfo>& lineBreakInfo = mImpl->mLogicalModel->mLineBreakInfo;
1806     Vector<WordBreakInfo>& wordBreakInfo = mImpl->mLogicalModel->mWordBreakInfo;
1807     Vector<GlyphInfo>& glyphs = mImpl->mVisualModel->mGlyphs;
1808     Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mVisualModel->mGlyphsToCharacters;
1809     Vector<Length>& charactersPerGlyph = mImpl->mVisualModel->mCharactersPerGlyph;
1810
1811     // Set the layout parameters.
1812     LayoutParameters layoutParameters( size,
1813                                        mImpl->mLogicalModel->mText.Begin(),
1814                                        lineBreakInfo.Begin(),
1815                                        wordBreakInfo.Begin(),
1816                                        numberOfGlyphs,
1817                                        glyphs.Begin(),
1818                                        glyphsToCharactersMap.Begin(),
1819                                        charactersPerGlyph.Begin() );
1820
1821     // The laid-out lines.
1822     // It's not possible to know in how many lines the text is going to be laid-out,
1823     // but it can be resized at least with the number of 'paragraphs' to avoid
1824     // some re-allocations.
1825     Vector<LineRun>& lines = mImpl->mVisualModel->mLines;
1826
1827     // Delete any previous laid out lines before setting the new ones.
1828     lines.Clear();
1829
1830     // The capacity of the bidirectional paragraph info is the number of paragraphs.
1831     lines.Reserve( mImpl->mLogicalModel->mBidirectionalParagraphInfo.Capacity() );
1832
1833     // Resize the vector of positions to have the same size than the vector of glyphs.
1834     Vector<Vector2>& glyphPositions = mImpl->mVisualModel->mGlyphPositions;
1835     glyphPositions.Resize( numberOfGlyphs );
1836
1837     // Update the visual model.
1838     viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
1839                                                    glyphPositions,
1840                                                    lines,
1841                                                    layoutSize );
1842
1843     if( viewUpdated )
1844     {
1845       // Reorder the lines
1846       if( REORDER & operations )
1847       {
1848         Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mImpl->mLogicalModel->mBidirectionalParagraphInfo;
1849
1850         // Check first if there are paragraphs with bidirectional info.
1851         if( 0u != bidirectionalInfo.Count() )
1852         {
1853           // Get the lines
1854           const Length numberOfLines = mImpl->mVisualModel->GetNumberOfLines();
1855
1856           // Reorder the lines.
1857           Vector<BidirectionalLineInfoRun> lineBidirectionalInfoRuns;
1858           lineBidirectionalInfoRuns.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
1859           ReorderLines( bidirectionalInfo,
1860                         lines,
1861                         lineBidirectionalInfoRuns );
1862
1863           // Set the bidirectional info into the model.
1864           const Length numberOfBidirectionalInfoRuns = lineBidirectionalInfoRuns.Count();
1865           mImpl->mLogicalModel->SetVisualToLogicalMap( lineBidirectionalInfoRuns.Begin(),
1866                                                        numberOfBidirectionalInfoRuns );
1867
1868           // Set the bidirectional info per line into the layout parameters.
1869           layoutParameters.lineBidirectionalInfoRunsBuffer = lineBidirectionalInfoRuns.Begin();
1870           layoutParameters.numberOfBidirectionalInfoRuns = numberOfBidirectionalInfoRuns;
1871
1872           // Get the character to glyph conversion table and set into the layout.
1873           layoutParameters.charactersToGlyphsBuffer = mImpl->mVisualModel->mCharactersToGlyph.Begin();
1874
1875           // Get the glyphs per character table and set into the layout.
1876           layoutParameters.glyphsPerCharacterBuffer = mImpl->mVisualModel->mGlyphsPerCharacter.Begin();
1877
1878           // Re-layout the text. Reorder those lines with right to left characters.
1879           mImpl->mLayoutEngine.ReLayoutRightToLeftLines( layoutParameters,
1880                                                          glyphPositions );
1881
1882           // Free the allocated memory used to store the conversion table in the bidirectional line info run.
1883           for( Vector<BidirectionalLineInfoRun>::Iterator it = lineBidirectionalInfoRuns.Begin(),
1884                  endIt = lineBidirectionalInfoRuns.End();
1885                it != endIt;
1886                ++it )
1887           {
1888             BidirectionalLineInfoRun& bidiLineInfo = *it;
1889
1890             free( bidiLineInfo.visualToLogicalMap );
1891           }
1892         }
1893       } // REORDER
1894
1895       if( ALIGN & operations )
1896       {
1897         mImpl->mLayoutEngine.Align( layoutParameters,
1898                                     layoutSize,
1899                                     lines,
1900                                     glyphPositions );
1901       }
1902
1903       // Sets the actual size.
1904       if( UPDATE_ACTUAL_SIZE & operations )
1905       {
1906         mImpl->mVisualModel->SetActualSize( layoutSize );
1907       }
1908     } // view updated
1909   }
1910   else
1911   {
1912     layoutSize = mImpl->mVisualModel->GetActualSize();
1913   }
1914
1915   return viewUpdated;
1916 }
1917
1918 void Controller::CalculateTextAlignment( const Size& size )
1919 {
1920   // Get the direction of the first character.
1921   const CharacterDirection firstParagraphDirection = mImpl->mLogicalModel->GetCharacterDirection( 0u );
1922
1923   const Size& actualSize = mImpl->mVisualModel->GetActualSize();
1924
1925   // If the first paragraph is right to left swap ALIGN_BEGIN and ALIGN_END;
1926   LayoutEngine::HorizontalAlignment horizontalAlignment = mImpl->mLayoutEngine.GetHorizontalAlignment();
1927   if( firstParagraphDirection &&
1928       ( LayoutEngine::HORIZONTAL_ALIGN_CENTER != horizontalAlignment ) )
1929   {
1930     if( LayoutEngine::HORIZONTAL_ALIGN_BEGIN == horizontalAlignment )
1931     {
1932       horizontalAlignment = LayoutEngine::HORIZONTAL_ALIGN_END;
1933     }
1934     else
1935     {
1936       horizontalAlignment = LayoutEngine::HORIZONTAL_ALIGN_BEGIN;
1937     }
1938   }
1939
1940   switch( horizontalAlignment )
1941   {
1942     case LayoutEngine::HORIZONTAL_ALIGN_BEGIN:
1943     {
1944       mImpl->mAlignmentOffset.x = 0.f;
1945       break;
1946     }
1947     case LayoutEngine::HORIZONTAL_ALIGN_CENTER:
1948     {
1949       const int intOffset = static_cast<int>( 0.5f * ( size.width - actualSize.width ) ); // try to avoid pixel alignment.
1950       mImpl->mAlignmentOffset.x = static_cast<float>( intOffset );
1951       break;
1952     }
1953     case LayoutEngine::HORIZONTAL_ALIGN_END:
1954     {
1955       mImpl->mAlignmentOffset.x = size.width - actualSize.width;
1956       break;
1957     }
1958   }
1959
1960   const LayoutEngine::VerticalAlignment verticalAlignment = mImpl->mLayoutEngine.GetVerticalAlignment();
1961   switch( verticalAlignment )
1962   {
1963     case LayoutEngine::VERTICAL_ALIGN_TOP:
1964     {
1965       mImpl->mAlignmentOffset.y = 0.f;
1966       break;
1967     }
1968     case LayoutEngine::VERTICAL_ALIGN_CENTER:
1969     {
1970       const int intOffset = static_cast<int>( 0.5f * ( size.height - actualSize.height ) ); // try to avoid pixel alignment.
1971       mImpl->mAlignmentOffset.y = static_cast<float>( intOffset );
1972       break;
1973     }
1974     case LayoutEngine::VERTICAL_ALIGN_BOTTOM:
1975     {
1976       mImpl->mAlignmentOffset.y = size.height - actualSize.height;
1977       break;
1978     }
1979   }
1980 }
1981
1982 View& Controller::GetView()
1983 {
1984   return mImpl->mView;
1985 }
1986
1987 LayoutEngine& Controller::GetLayoutEngine()
1988 {
1989   return mImpl->mLayoutEngine;
1990 }
1991
1992 void Controller::RequestRelayout()
1993 {
1994   mImpl->mControlInterface.RequestTextRelayout();
1995 }
1996
1997 void Controller::KeyboardFocusGainEvent()
1998 {
1999   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyboardFocusGainEvent" );
2000
2001   if( mImpl->mTextInput )
2002   {
2003     TextInput::Event event( TextInput::KEYBOARD_FOCUS_GAIN_EVENT );
2004     mImpl->mTextInput->mEventQueue.push_back( event );
2005
2006     RequestRelayout();
2007   }
2008 }
2009
2010 void Controller::KeyboardFocusLostEvent()
2011 {
2012   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyboardFocusLostEvent" );
2013
2014   if( mImpl->mTextInput )
2015   {
2016     TextInput::Event event( TextInput::KEYBOARD_FOCUS_LOST_EVENT );
2017     mImpl->mTextInput->mEventQueue.push_back( event );
2018
2019     RequestRelayout();
2020   }
2021 }
2022
2023 bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
2024 {
2025   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyEvent" );
2026
2027   if( mImpl->mTextInput &&
2028       keyEvent.state == KeyEvent::Down )
2029   {
2030     int keyCode = keyEvent.keyCode;
2031     const std::string& keyString = keyEvent.keyPressed;
2032
2033     // Pre-process to separate modifying events from non-modifying input events.
2034     if( Dali::DALI_KEY_ESCAPE == keyCode )
2035     {
2036       // Escape key is a special case which causes focus loss
2037       KeyboardFocusLostEvent();
2038     }
2039     else if( Dali::DALI_KEY_CURSOR_LEFT  == keyCode ||
2040              Dali::DALI_KEY_CURSOR_RIGHT == keyCode ||
2041              Dali::DALI_KEY_CURSOR_UP    == keyCode ||
2042              Dali::DALI_KEY_CURSOR_DOWN  == keyCode )
2043     {
2044       TextInput::Event event( TextInput::CURSOR_KEY_EVENT );
2045       event.p1.mInt = keyCode;
2046       mImpl->mTextInput->mEventQueue.push_back( event );
2047     }
2048     else if( Dali::DALI_KEY_BACKSPACE == keyCode )
2049     {
2050       // Queue a delete event
2051       ModifyEvent event;
2052       event.type = DELETE_TEXT;
2053       mImpl->mModifyEvents.push_back( event );
2054     }
2055     else if( !keyString.empty() )
2056     {
2057       // Queue an insert event
2058       ModifyEvent event;
2059       event.type = INSERT_TEXT;
2060       event.text = keyString;
2061       mImpl->mModifyEvents.push_back( event );
2062     }
2063
2064     mImpl->mTextInput->ChangeState( TextInput::EDITING ); // todo Confirm this is the best place to change the state of
2065
2066     RequestRelayout();
2067   }
2068
2069   return false;
2070 }
2071
2072 void Controller::TapEvent( unsigned int tapCount, float x, float y )
2073 {
2074   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected TapEvent" );
2075
2076   if( mImpl->mTextInput )
2077   {
2078     TextInput::Event event( TextInput::TAP_EVENT );
2079     event.p1.mUint = tapCount;
2080     event.p2.mFloat = x;
2081     event.p3.mFloat = y;
2082     mImpl->mTextInput->mEventQueue.push_back( event );
2083
2084     RequestRelayout();
2085   }
2086 }
2087
2088 void Controller::PanEvent( Gesture::State state, const Vector2& displacement )
2089 {
2090   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected PanEvent" );
2091
2092   if( mImpl->mTextInput )
2093   {
2094     TextInput::Event event( TextInput::PAN_EVENT );
2095     event.p1.mInt = state;
2096     event.p2.mFloat = displacement.x;
2097     event.p3.mFloat = displacement.y;
2098     mImpl->mTextInput->mEventQueue.push_back( event );
2099
2100     RequestRelayout();
2101   }
2102 }
2103
2104 void Controller::GrabHandleEvent( GrabHandleState state, float x, float y )
2105 {
2106   DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected GrabHandleEvent" );
2107
2108   if( mImpl->mTextInput )
2109   {
2110     TextInput::Event event( TextInput::GRAB_HANDLE_EVENT );
2111     event.p1.mUint  = state;
2112     event.p2.mFloat = x;
2113     event.p3.mFloat = y;
2114     mImpl->mTextInput->mEventQueue.push_back( event );
2115
2116     RequestRelayout();
2117   }
2118 }
2119
2120 Controller::~Controller()
2121 {
2122   delete mImpl;
2123 }
2124
2125 Controller::Controller( ControlInterface& controlInterface )
2126 : mImpl( NULL )
2127 {
2128   mImpl = new Controller::Impl( controlInterface );
2129 }
2130
2131 } // namespace Text
2132
2133 } // namespace Toolkit
2134
2135 } // namespace Dali