2 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali-toolkit/internal/text/text-controller.h>
24 #include <dali/public-api/adaptor-framework/key.h>
25 #include <dali/public-api/text-abstraction/font-client.h>
28 #include <dali-toolkit/internal/text/bidirectional-support.h>
29 #include <dali-toolkit/internal/text/character-set-conversion.h>
30 #include <dali-toolkit/internal/text/layouts/layout-engine.h>
31 #include <dali-toolkit/internal/text/layouts/layout-parameters.h>
32 #include <dali-toolkit/internal/text/logical-model.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-view.h>
38 #include <dali-toolkit/internal/text/visual-model.h>
44 const float MAX_FLOAT = std::numeric_limits<float>::max();
45 const std::string EMPTY_STRING;
57 struct Controller::TextInput
59 // Used to queue input events until DoRelayout()
62 KEYBOARD_FOCUS_GAIN_EVENT,
63 KEYBOARD_FOCUS_LOST_EVENT,
79 Event( EventType eventType )
99 TextInput( LogicalModelPtr logicalModel,
100 VisualModelPtr visualModel,
101 DecoratorPtr decorator )
102 : mLogicalModel( logicalModel ),
103 mVisualModel( visualModel ),
104 mDecorator( decorator ),
110 * @brief Helper to move the cursor, grab handle etc.
112 bool ProcessInputEvents()
114 mDecoratorUpdated = false;
118 for( vector<TextInput::Event>::iterator iter = mEventQueue.begin(); iter != mEventQueue.end(); ++iter )
122 case KEYBOARD_FOCUS_GAIN_EVENT:
124 OnKeyboardFocus( true );
127 case KEYBOARD_FOCUS_LOST_EVENT:
129 OnKeyboardFocus( false );
142 case GRAB_HANDLE_EVENT:
144 OnGrabHandleEvent( *iter );
153 return mDecoratorUpdated;
156 void OnKeyboardFocus( bool hasFocus )
160 void OnKeyEvent( const Event& event )
162 int keyCode = event.p1.mInt;
164 // Handle state changes
165 if( Dali::DALI_KEY_ESCAPE == keyCode )
167 ChangeState( INACTIVE ); // Escape key ends edit mode
169 else if ( event.p2.mString )
171 // Some text may be selected, hiding keyboard causes an empty keystring to be sent, we don't want to delete highlight in this case
172 ChangeState( EDITING );
175 // Handle the actual key event
176 if( Dali::DALI_KEY_BACKSPACE == keyCode )
178 HandleBackspaceKey();
180 else if( Dali::DALI_KEY_CURSOR_LEFT == keyCode ||
181 Dali::DALI_KEY_CURSOR_RIGHT == keyCode ||
182 Dali::DALI_KEY_CURSOR_UP == keyCode ||
183 Dali::DALI_KEY_CURSOR_DOWN == keyCode )
185 HandleCursorKey( keyCode );
187 else if ( event.p2.mString )
189 HandleKeyString( event.p2.mString );
191 delete [] event.p2.mString;
195 void HandleBackspaceKey()
200 void HandleCursorKey( int keyCode )
205 void HandleKeyString( const char* keyString )
210 void OnTapEvent( const Event& event )
212 unsigned int tapCount = event.p1.mUint;
216 ChangeState( EDITING );
218 float xPosition = event.p2.mFloat;
219 float yPosition = event.p3.mFloat;
221 GetClosestCursorPosition( xPosition, yPosition, height );
222 mDecorator->SetPosition( PRIMARY_CURSOR, xPosition, yPosition, height );
224 mDecoratorUpdated = true;
226 else if( 2u == tapCount )
228 ChangeState( SELECTING );
232 void OnGrabHandleEvent( const Event& event )
234 unsigned int state = event.p1.mUint;
236 if( GRAB_HANDLE_PRESSED == state )
238 float xPosition = event.p2.mFloat;
239 float yPosition = event.p3.mFloat;
242 GetClosestCursorPosition( xPosition, yPosition, height );
244 mDecorator->SetPosition( PRIMARY_CURSOR, xPosition, yPosition, height );
245 mDecorator->HidePopup();
246 mDecoratorUpdated = true;
248 else if ( GRAB_HANDLE_RELEASED == state )
250 mDecorator->ShowPopup();
255 void ChangeState( State newState )
257 if( mState != newState )
261 if( INACTIVE == mState )
263 mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
264 mDecorator->StopCursorBlink();
265 mDecorator->SetGrabHandleActive( false );
266 mDecorator->SetSelectionActive( false );
267 mDecorator->HidePopup();
268 mDecoratorUpdated = true;
270 else if ( SELECTING == mState )
272 mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
273 mDecorator->StopCursorBlink();
274 mDecorator->SetGrabHandleActive( false );
275 mDecorator->SetSelectionActive( true );
276 mDecoratorUpdated = true;
278 else if( EDITING == mState )
280 mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
281 mDecorator->StartCursorBlink();
282 mDecorator->SetGrabHandleActive( true );
283 mDecorator->SetSelectionActive( false );
284 mDecoratorUpdated = true;
289 void GetClosestCursorPosition( float& x, float& y, float& height )
291 // TODO - Look at LineRuns first
293 Text::Length numberOfGlyphs = mVisualModel->GetNumberOfGlyphs();
294 if( 0 == numberOfGlyphs )
299 Vector<GlyphInfo> glyphs;
300 glyphs.Resize( numberOfGlyphs );
301 mVisualModel->GetGlyphs( glyphs.Begin(), 0, numberOfGlyphs );
302 const GlyphInfo* const glyphsBuffer = glyphs.Begin();
304 Vector<Vector2> positions;
305 positions.Resize( numberOfGlyphs );
306 mVisualModel->GetGlyphPositions( positions.Begin(), 0, numberOfGlyphs );
307 const Vector2* const positionsBuffer = positions.Begin();
309 unsigned int closestGlyph = 0;
310 float closestDistance = MAX_FLOAT;
312 for( unsigned int i = 0, numberOfGLyphs = glyphs.Count(); i < numberOfGLyphs; ++i )
314 const GlyphInfo& glyphInfo = *( glyphsBuffer + i );
315 const Vector2& position = *( positionsBuffer + i );
316 float glyphX = position.x + glyphInfo.width*0.5f;
317 float glyphY = position.y + glyphInfo.height*0.5f;
319 float distanceToGlyph = fabsf( glyphX - x ) + fabsf( glyphY - y );
321 if( distanceToGlyph < closestDistance )
323 closestDistance = distanceToGlyph;
328 // TODO - Consider RTL languages
329 x = positions[closestGlyph].x + glyphs[closestGlyph].width;
333 TextAbstraction::FontClient::Get().GetFontMetrics( glyphs[closestGlyph].fontId, metrics );
334 height = metrics.height; // TODO - Fix for multi-line
337 LogicalModelPtr mLogicalModel;
338 VisualModelPtr mVisualModel;
339 DecoratorPtr mDecorator;
341 std::string mPlaceholderText;
344 * This is used to delay handling events until after the model has been updated.
345 * The number of updates to the model is minimized to improve performance.
347 vector<Event> mEventQueue; ///< The queue of touch events etc.
351 bool mDecoratorUpdated;
354 struct Controller::FontDefaults
357 : mDefaultPointSize(0.0f),
362 FontId GetFontId( TextAbstraction::FontClient& fontClient )
366 Dali::TextAbstraction::PointSize26Dot6 pointSize = mDefaultPointSize*64;
367 mFontId = fontClient.GetFontId( mDefaultFontFamily, mDefaultFontStyle, pointSize );
373 std::string mDefaultFontFamily;
374 std::string mDefaultFontStyle;
375 float mDefaultPointSize;
379 struct Controller::Impl
381 Impl( ControlInterface& controlInterface )
382 : mControlInterface( controlInterface ),
385 mFontDefaults( NULL ),
392 mOperationsPending( NO_OPERATION ),
393 mRecalculateNaturalSize( true )
395 mLogicalModel = LogicalModel::New();
396 mVisualModel = VisualModel::New();
398 mFontClient = TextAbstraction::FontClient::Get();
400 mView.SetVisualModel( mVisualModel );
408 ControlInterface& mControlInterface; ///< Reference to the text controller.
409 LogicalModelPtr mLogicalModel; ///< Pointer to the logical model.
410 VisualModelPtr mVisualModel; ///< Pointer to the visual model.
411 FontDefaults* mFontDefaults; ///< Avoid allocating this when the user does not specify a font.
412 Controller::TextInput* mTextInput; ///< Avoid allocating everything for text input until EnableTextInput().
413 TextAbstraction::FontClient mFontClient; ///< Handle to the font client.
414 View mView; ///< The view interface to the rendering back-end.
415 LayoutEngine mLayoutEngine; ///< The layout engine.
416 std::string mNewText; ///< Temporary stores the text set until the next relayout.
417 Size mControlSize; ///< The size of the control.
418 OperationsMask mOperationsPending; ///< Operations pending to be done to layout the text.
419 bool mRecalculateNaturalSize:1; ///< Whether the natural size needs to be recalculated.
422 ControllerPtr Controller::New( ControlInterface& controlInterface )
424 return ControllerPtr( new Controller( controlInterface ) );
427 void Controller::SetText( const std::string& text )
429 // Keep until size negotiation
430 mImpl->mNewText = text;
432 // All operations need to be done. (convert to utf32, get break info, ..., layout, ...)
433 mImpl->mOperationsPending = ALL_OPERATIONS;
435 // The natural size needs to be re-calculated.
436 mImpl->mRecalculateNaturalSize = true;
439 mImpl->mLogicalModel->SetText( NULL, 0u );
440 mImpl->mLogicalModel->SetScripts( NULL, 0u );
441 mImpl->mLogicalModel->SetFonts( NULL, 0u );
442 mImpl->mLogicalModel->SetLineBreakInfo( NULL, 0u );
443 mImpl->mLogicalModel->SetWordBreakInfo( NULL, 0u );
444 mImpl->mLogicalModel->SetBidirectionalInfo( NULL, 0u );
445 mImpl->mLogicalModel->SetVisualToLogicalMap( NULL, 0u );
446 mImpl->mVisualModel->SetGlyphs( NULL, NULL, NULL, 0u );
447 mImpl->mVisualModel->SetGlyphPositions( NULL, 0u );
448 mImpl->mVisualModel->SetLines( NULL, 0u );
450 if( mImpl->mTextInput )
452 // Cancel previously queued events
453 mImpl->mTextInput->mEventQueue.clear();
455 // TODO - Hide selection decorations
459 void Controller::GetText( std::string& text ) const
461 if( !mImpl->mNewText.empty() )
463 text = mImpl->mNewText;
467 // TODO - Convert from UTF-32
471 void Controller::SetPlaceholderText( const std::string& text )
473 if( !mImpl->mTextInput )
475 mImpl->mTextInput->mPlaceholderText = text;
479 void Controller::GetPlaceholderText( std::string& text ) const
481 if( !mImpl->mTextInput )
483 text = mImpl->mTextInput->mPlaceholderText;
487 void Controller::SetDefaultFontFamily( const std::string& defaultFontFamily )
489 if( !mImpl->mFontDefaults )
491 mImpl->mFontDefaults = new Controller::FontDefaults();
494 mImpl->mFontDefaults->mDefaultFontFamily = defaultFontFamily;
495 mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
496 mImpl->mOperationsPending = ALL_OPERATIONS;
497 mImpl->mRecalculateNaturalSize = true;
500 const std::string& Controller::GetDefaultFontFamily() const
502 if( mImpl->mFontDefaults )
504 return mImpl->mFontDefaults->mDefaultFontFamily;
510 void Controller::SetDefaultFontStyle( const std::string& defaultFontStyle )
512 if( !mImpl->mFontDefaults )
514 mImpl->mFontDefaults = new Controller::FontDefaults();
517 mImpl->mFontDefaults->mDefaultFontStyle = defaultFontStyle;
518 mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
519 mImpl->mOperationsPending = ALL_OPERATIONS;
520 mImpl->mRecalculateNaturalSize = true;
523 const std::string& Controller::GetDefaultFontStyle() const
525 if( mImpl->mFontDefaults )
527 return mImpl->mFontDefaults->mDefaultFontStyle;
533 void Controller::SetDefaultPointSize( float pointSize )
535 if( !mImpl->mFontDefaults )
537 mImpl->mFontDefaults = new Controller::FontDefaults();
540 mImpl->mFontDefaults->mDefaultPointSize = pointSize;
541 mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
542 mImpl->mOperationsPending = ALL_OPERATIONS;
543 mImpl->mRecalculateNaturalSize = true;
546 float Controller::GetDefaultPointSize() const
548 if( mImpl->mFontDefaults )
550 return mImpl->mFontDefaults->mDefaultPointSize;
556 void Controller::GetDefaultFonts( Vector<FontRun>& fonts, Length numberOfCharacters )
558 if( mImpl->mFontDefaults )
561 fontRun.characterRun.characterIndex = 0;
562 fontRun.characterRun.numberOfCharacters = numberOfCharacters;
563 fontRun.fontId = mImpl->mFontDefaults->GetFontId( mImpl->mFontClient );
564 fontRun.isDefault = true;
566 fonts.PushBack( fontRun );
570 void Controller::EnableTextInput( DecoratorPtr decorator )
572 if( !mImpl->mTextInput )
574 mImpl->mTextInput = new TextInput( mImpl->mLogicalModel, mImpl->mVisualModel, decorator );
578 bool Controller::Relayout( const Vector2& size )
580 if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
582 // Not worth to relayout if width or height is equal to zero.
586 if( size != mImpl->mControlSize )
588 // Operations that need to be done if the size changes.
589 mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
596 mImpl->mControlSize = size;
600 bool updated = DoRelayout( mImpl->mControlSize,
601 mImpl->mOperationsPending,
604 // Do not re-do any operation until something changes.
605 mImpl->mOperationsPending = NO_OPERATION;
607 if( mImpl->mTextInput )
609 // Move the cursor, grab handle etc.
610 updated = mImpl->mTextInput->ProcessInputEvents() || updated;
616 bool Controller::DoRelayout( const Vector2& size,
617 OperationsMask operationsRequired,
620 bool viewUpdated( false );
622 // Calculate the operations to be done.
623 const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
625 Vector<Character> utf32Characters;
626 Length characterCount = 0u;
627 if( CONVERT_TO_UTF32 & operations )
629 std::string& text = mImpl->mNewText;
631 // Convert text into UTF-32
632 utf32Characters.Resize( text.size() );
634 // This is a bit horrible but std::string returns a (signed) char*
635 const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
637 // Transform a text array encoded in utf8 into an array encoded in utf32.
638 // It returns the actual number of characters.
639 characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
640 utf32Characters.Resize( characterCount );
642 // Sets the text into the model.
643 mImpl->mLogicalModel->SetText( utf32Characters.Begin(), characterCount );
645 // Discard temporary text
649 const Length numberOfCharacters = mImpl->mLogicalModel->GetNumberOfCharacters();
651 Vector<LineBreakInfo> lineBreakInfo;
652 if( GET_LINE_BREAKS & operations )
654 // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
655 // calculate the bidirectional info for each 'paragraph'.
656 // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
657 // is not shaped together).
658 lineBreakInfo.Resize( characterCount, TextAbstraction::LINE_NO_BREAK );
660 SetLineBreakInfo( utf32Characters,
663 mImpl->mLogicalModel->SetLineBreakInfo( lineBreakInfo.Begin(), characterCount );
666 Vector<WordBreakInfo> wordBreakInfo;
667 if( GET_WORD_BREAKS & operations )
669 // Retrieves the word break info. The word break info is used to layout the text (where to wrap the text in lines).
670 wordBreakInfo.Resize( characterCount, TextAbstraction::WORD_NO_BREAK );
672 SetWordBreakInfo( utf32Characters,
675 mImpl->mLogicalModel->SetWordBreakInfo( wordBreakInfo.Begin(), characterCount );
678 const bool getScripts = GET_SCRIPTS & operations;
679 const bool validateFonts = VALIDATE_FONTS & operations;
681 Vector<ScriptRun> scripts;
682 Vector<FontRun> validFonts;
684 if( getScripts || validateFonts )
686 // Validates the fonts assigned by the application or assigns default ones.
687 // It makes sure all the characters are going to be rendered by the correct font.
688 MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
692 // Retrieves the scripts used in the text.
693 multilanguageSupport.SetScripts( utf32Characters,
697 // Sets the scripts into the model.
698 mImpl->mLogicalModel->SetScripts( scripts.Begin(), scripts.Count() );
703 // Copy the requested font defaults received via the property system.
704 // These may not be valid i.e. may not contain glyphs for the necessary scripts.
705 GetDefaultFonts( validFonts, numberOfCharacters );
707 // Validates the fonts. If there is a character with no assigned font it sets a default one.
708 // After this call, fonts are validated.
709 multilanguageSupport.ValidateFonts( utf32Characters,
713 // Sets the fonts into the model.
714 mImpl->mLogicalModel->SetFonts( validFonts.Begin(), validFonts.Count() );
718 Vector<BidirectionalParagraphInfoRun> bidirectionalInfo;
719 if( BIDI_INFO & operations )
721 // Some vectors with data needed to get the paragraph's bidirectional info may be void
722 // after the first time the text has been laid out.
723 // Fill the vectors again.
725 if( 0u == utf32Characters.Count() )
727 utf32Characters.Resize( numberOfCharacters );
729 mImpl->mLogicalModel->GetText( utf32Characters.Begin(),
731 numberOfCharacters );
734 if( 0u == lineBreakInfo.Count() )
736 lineBreakInfo.Resize( numberOfCharacters );
738 mImpl->mLogicalModel->GetLineBreakInfo( lineBreakInfo.Begin(),
740 numberOfCharacters );
743 if( 0u == scripts.Count() )
745 scripts.Resize( mImpl->mLogicalModel->GetNumberOfScriptRuns( 0u,
746 numberOfCharacters ) );
747 mImpl->mLogicalModel->GetScriptRuns( scripts.Begin(),
749 numberOfCharacters );
752 // Count the number of LINE_NO_BREAK to reserve some space for the vector of paragraph's
753 // bidirectional info.
755 Length numberOfParagraphs = 0u;
757 const TextAbstraction::LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
758 for( Length index = 0u; index < characterCount; ++index )
760 if( TextAbstraction::LINE_NO_BREAK == *( lineBreakInfoBuffer + index ) )
762 ++numberOfParagraphs;
766 bidirectionalInfo.Reserve( numberOfParagraphs );
768 // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
769 SetBidirectionalInfo( utf32Characters,
774 mImpl->mLogicalModel->SetBidirectionalInfo( bidirectionalInfo.Begin(),
775 bidirectionalInfo.Count() );
778 Vector<GlyphInfo> glyphs;
779 Vector<CharacterIndex> glyphsToCharactersMap;
780 Vector<Length> charactersPerGlyph;
781 if( SHAPE_TEXT & operations )
783 if( 0u == validFonts.Count() )
785 validFonts.Resize( mImpl->mLogicalModel->GetNumberOfFontRuns( 0u,
786 numberOfCharacters ) );
787 mImpl->mLogicalModel->GetFontRuns( validFonts.Begin(),
789 numberOfCharacters );
793 ShapeText( utf32Characters,
798 glyphsToCharactersMap,
799 charactersPerGlyph );
802 if( GET_GLYPH_METRICS & operations )
804 mImpl->mFontClient.GetGlyphMetrics( glyphs.Begin(), glyphs.Count() );
807 Length numberOfGlyphs = glyphs.Count();
808 if( 0u != numberOfGlyphs )
810 // Sets the glyphs into the model.
811 mImpl->mVisualModel->SetGlyphs( glyphs.Begin(),
812 glyphsToCharactersMap.Begin(),
813 charactersPerGlyph.Begin(),
817 if( LAYOUT & operations )
819 // Some vectors with data needed to layout and reorder may be void
820 // after the first time the text has been laid out.
821 // Fill the vectors again.
823 const Length numberOfCharacters = mImpl->mLogicalModel->GetNumberOfCharacters();
824 numberOfGlyphs = mImpl->mVisualModel->GetNumberOfGlyphs();
826 if( 0u == lineBreakInfo.Count() )
828 lineBreakInfo.Resize( numberOfCharacters );
829 mImpl->mLogicalModel->GetLineBreakInfo( lineBreakInfo.Begin(),
831 numberOfCharacters );
834 if( 0u == wordBreakInfo.Count() )
836 wordBreakInfo.Resize( numberOfCharacters );
837 mImpl->mLogicalModel->GetWordBreakInfo( wordBreakInfo.Begin(),
839 numberOfCharacters );
842 if( 0u == glyphs.Count() )
844 glyphs.Resize( numberOfGlyphs );
845 mImpl->mVisualModel->GetGlyphs( glyphs.Begin(),
850 if( 0u == glyphsToCharactersMap.Count() )
852 glyphsToCharactersMap.Resize( numberOfGlyphs );
853 mImpl->mVisualModel->GetGlyphToCharacterMap( glyphsToCharactersMap.Begin(),
858 if( 0u == charactersPerGlyph.Count() )
860 charactersPerGlyph.Resize( numberOfGlyphs );
861 mImpl->mVisualModel->GetCharactersPerGlyphMap( charactersPerGlyph.Begin(),
866 // Set the layout parameters.
867 LayoutParameters layoutParameters( size,
868 lineBreakInfo.Begin(),
869 wordBreakInfo.Begin(),
872 glyphsToCharactersMap.Begin(),
873 charactersPerGlyph.Begin() );
875 // Reserve space to set the positions of the glyphs.
876 Vector<Vector2> glyphPositions;
877 glyphPositions.Resize( numberOfGlyphs );
879 // The laid-out lines.
880 // It's not possible to know in how many lines the text is going to be laid-out,
881 // but it can be resized at least with the number of 'paragraphs' to avoid
882 // some re-allocations.
883 Vector<LineRun> lines;
884 lines.Reserve( mImpl->mLogicalModel->GetNumberOfBidirectionalInfoRuns( 0u, numberOfCharacters ) );
886 // Update the visual model.
887 viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
895 if( REORDER & operations )
897 const Length numberOfBidiParagraphs = mImpl->mLogicalModel->GetNumberOfBidirectionalInfoRuns( 0u, numberOfCharacters );
899 if( 0u == bidirectionalInfo.Count() )
901 bidirectionalInfo.Resize( numberOfBidiParagraphs );
902 mImpl->mLogicalModel->GetBidirectionalInfo( bidirectionalInfo.Begin(),
904 numberOfCharacters );
907 // Check first if there are paragraphs with bidirectional info.
908 if( 0u != bidirectionalInfo.Count() )
911 const Length numberOfLines = mImpl->mVisualModel->GetNumberOfLines();
913 // Reorder the lines.
914 Vector<BidirectionalLineInfoRun> lineBidirectionalInfoRuns;
915 lineBidirectionalInfoRuns.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
916 ReorderLines( bidirectionalInfo,
918 lineBidirectionalInfoRuns );
920 // Set the bidirectional info into the model.
921 const Length numberOfBidirectionalInfoRuns = lineBidirectionalInfoRuns.Count();
922 mImpl->mLogicalModel->SetVisualToLogicalMap( lineBidirectionalInfoRuns.Begin(),
923 numberOfBidirectionalInfoRuns );
925 // Set the bidirectional info per line into the layout parameters.
926 layoutParameters.lineBidirectionalInfoRunsBuffer = lineBidirectionalInfoRuns.Begin();
927 layoutParameters.numberOfBidirectionalInfoRuns = numberOfBidirectionalInfoRuns;
929 // Get the character to glyph conversion table and set into the layout.
930 Vector<GlyphIndex> characterToGlyphMap;
931 characterToGlyphMap.Resize( numberOfCharacters );
933 layoutParameters.charactersToGlyphsBuffer = characterToGlyphMap.Begin();
934 mImpl->mVisualModel->GetCharacterToGlyphMap( layoutParameters.charactersToGlyphsBuffer,
936 numberOfCharacters );
938 // Get the glyphs per character table and set into the layout.
939 Vector<Length> glyphsPerCharacter;
940 glyphsPerCharacter.Resize( numberOfCharacters );
942 layoutParameters.glyphsPerCharacterBuffer = glyphsPerCharacter.Begin();
943 mImpl->mVisualModel->GetGlyphsPerCharacterMap( layoutParameters.glyphsPerCharacterBuffer,
945 numberOfCharacters );
947 // Re-layout the text. Reorder those lines with right to left characters.
948 mImpl->mLayoutEngine.ReLayoutRightToLeftLines( layoutParameters,
951 // Free the allocated memory used to store the conversion table in the bidirectional line info run.
952 for( Vector<BidirectionalLineInfoRun>::Iterator it = lineBidirectionalInfoRuns.Begin(),
953 endIt = lineBidirectionalInfoRuns.End();
957 BidirectionalLineInfoRun& bidiLineInfo = *it;
959 free( bidiLineInfo.visualToLogicalMap );
964 // Sets the positions into the model.
965 if( UPDATE_POSITIONS & operations )
967 mImpl->mVisualModel->SetGlyphPositions( glyphPositions.Begin(),
971 // Sets the lines into the model.
972 if( UPDATE_LINES & operations )
974 mImpl->mVisualModel->SetLines( lines.Begin(),
978 // Sets the actual size.
979 if( UPDATE_ACTUAL_SIZE & operations )
981 mImpl->mVisualModel->SetActualSize( layoutSize );
987 layoutSize = mImpl->mVisualModel->GetActualSize();
993 Vector3 Controller::GetNaturalSize()
997 if( mImpl->mRecalculateNaturalSize )
999 // Operations that can be done only once until the text changes.
1000 const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32 |
1006 GET_GLYPH_METRICS );
1008 // Operations that need to be done if the size changes.
1009 const OperationsMask sizeOperations = static_cast<OperationsMask>( LAYOUT |
1012 DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
1013 static_cast<OperationsMask>( onlyOnceOperations |
1015 naturalSize.GetVectorXY() );
1017 // Do not do again the only once operations.
1018 mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
1020 // Do the size related operations again.
1021 mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
1023 // Stores the natural size to avoid recalculate it again
1024 // unless the text/style changes.
1025 mImpl->mVisualModel->SetNaturalSize( naturalSize.GetVectorXY() );
1027 mImpl->mRecalculateNaturalSize = false;
1031 naturalSize = mImpl->mVisualModel->GetNaturalSize();
1037 float Controller::GetHeightForWidth( float width )
1040 if( width != mImpl->mControlSize.width )
1042 // Operations that can be done only once until the text changes.
1043 const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32 |
1049 GET_GLYPH_METRICS );
1051 // Operations that need to be done if the size changes.
1052 const OperationsMask sizeOperations = static_cast<OperationsMask>( LAYOUT |
1055 DoRelayout( Size( width, MAX_FLOAT ),
1056 static_cast<OperationsMask>( onlyOnceOperations |
1060 // Do not do again the only once operations.
1061 mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
1063 // Do the size related operations again.
1064 mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
1068 layoutSize = mImpl->mVisualModel->GetActualSize();
1071 return layoutSize.height;
1074 View& Controller::GetView()
1076 return mImpl->mView;
1079 LayoutEngine& Controller::GetLayoutEngine()
1081 return mImpl->mLayoutEngine;
1084 void Controller::RequestRelayout()
1086 mImpl->mControlInterface.RequestTextRelayout();
1089 void Controller::KeyboardFocusGainEvent()
1091 DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyboardFocusGainEvent" );
1093 if( mImpl->mTextInput )
1095 TextInput::Event event( TextInput::KEYBOARD_FOCUS_GAIN_EVENT );
1096 mImpl->mTextInput->mEventQueue.push_back( event );
1102 void Controller::KeyboardFocusLostEvent()
1104 DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyboardFocusLostEvent" );
1106 if( mImpl->mTextInput )
1108 TextInput::Event event( TextInput::KEYBOARD_FOCUS_LOST_EVENT );
1109 mImpl->mTextInput->mEventQueue.push_back( event );
1115 bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
1117 DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyEvent" );
1119 if( mImpl->mTextInput )
1121 TextInput::Event event( TextInput::KEY_EVENT );
1122 event.p1.mInt = keyEvent.keyCode;
1123 event.p2.mString = NULL;
1125 const std::string& keyString = keyEvent.keyPressed;
1126 if ( !keyString.empty() )
1128 event.p2.mString = new char[keyString.size() + 1];
1129 std::copy(keyString.begin(), keyString.end(), event.p2.mString);
1130 event.p2.mString[keyString.size()] = '\0';
1133 mImpl->mTextInput->mEventQueue.push_back( event );
1141 void Controller::TapEvent( unsigned int tapCount, float x, float y )
1143 DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected TapEvent" );
1145 if( mImpl->mTextInput )
1147 TextInput::Event event( TextInput::TAP_EVENT );
1148 event.p1.mUint = tapCount;
1149 event.p2.mFloat = x;
1150 event.p3.mFloat = y;
1151 mImpl->mTextInput->mEventQueue.push_back( event );
1157 void Controller::GrabHandleEvent( GrabHandleState state, float x, float y )
1159 DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected GrabHandleEvent" );
1161 if( mImpl->mTextInput )
1163 TextInput::Event event( TextInput::GRAB_HANDLE_EVENT );
1164 event.p1.mUint = state;
1165 event.p2.mFloat = x;
1166 event.p3.mFloat = y;
1167 mImpl->mTextInput->mEventQueue.push_back( event );
1173 Controller::~Controller()
1178 Controller::Controller( ControlInterface& controlInterface )
1181 mImpl = new Controller::Impl( controlInterface );
1186 } // namespace Toolkit