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