Fixes for multi-language.
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / public-api / 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/public-api/text/text-controller.h>
20
21 // INTERNAL INCLUDES
22 #include <dali-toolkit/public-api/text/character-set-conversion.h>
23 #include <dali-toolkit/public-api/text/layouts/layout-engine.h>
24 #include <dali-toolkit/public-api/text/logical-model.h>
25 #include <dali-toolkit/public-api/text/multi-language-support.h>
26 #include <dali-toolkit/public-api/text/script-run.h>
27 #include <dali-toolkit/public-api/text/segmentation.h>
28 #include <dali-toolkit/public-api/text/shaper.h>
29 #include <dali-toolkit/public-api/text/text-view.h>
30 #include <dali-toolkit/public-api/text/visual-model.h>
31
32 // EXTERNAL INCLUDES
33 #include <dali/public-api/text-abstraction/font-client.h>
34 #include <limits>
35
36 namespace Dali
37 {
38
39 namespace Toolkit
40 {
41
42 namespace Text
43 {
44
45 struct Controller::Impl
46 {
47   Impl()
48   : mNewText(),
49     mOperations( NO_OPERATION ),
50     mControlSize()
51   {
52     mLogicalModel = LogicalModel::New();
53     mVisualModel  = VisualModel::New();
54
55     mView.SetVisualModel( mVisualModel );
56
57     mFontClient = TextAbstraction::FontClient::Get();
58   }
59
60   std::string mNewText;
61
62   LogicalModelPtr mLogicalModel;
63   VisualModelPtr  mVisualModel;
64
65   View mView;
66
67   LayoutEngine mLayoutEngine;
68
69   TextAbstraction::FontClient mFontClient;
70
71   OperationsMask mOperations;
72
73   Size mControlSize;
74 };
75
76 ControllerPtr Controller::New()
77 {
78   return ControllerPtr( new Controller() );
79 }
80
81 void Controller::SetText( const std::string& text )
82 {
83   // Keep until size negotiation
84   mImpl->mNewText = text;
85   mImpl->mOperations = ALL_OPERATIONS;
86 }
87
88 bool Controller::Relayout( const Vector2& size )
89 {
90   if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
91   {
92     // Not worth to relayout if width or height is equal to zero.
93     return false;
94   }
95
96   bool viewUpdated = false;
97
98   if( size != mImpl->mControlSize )
99   {
100     viewUpdated = DoRelayout( size, mImpl->mOperations );
101
102     // Do not re-do any operation until something changes.
103     mImpl->mOperations = NO_OPERATION;
104
105     mImpl->mControlSize = size;
106   }
107
108   return viewUpdated;
109 }
110
111 bool Controller::DoRelayout( const Vector2& size, OperationsMask operations )
112 {
113   bool viewUpdated( false );
114
115   Vector<Character> utf32Characters;
116   Length characterCount = 0u;
117   if( CONVERT_TO_UTF32 & operations )
118   {
119     std::string& text = mImpl->mNewText;
120
121     //  Convert text into UTF-32
122     utf32Characters.Resize( text.size() );
123
124     // This is a bit horrible but std::string returns a (signed) char*
125     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
126
127     // Transform a text array encoded in utf8 into an array encoded in utf32.
128     // It returns the actual number of characters.
129     characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
130     utf32Characters.Resize( characterCount );
131
132     // Sets the text into the model.
133     mImpl->mLogicalModel->SetText( utf32Characters.Begin(), characterCount );
134
135     // Discard temporary text
136     text.clear();
137   }
138
139   Vector<LineBreakInfo> lineBreakInfo;
140   if( GET_LINE_BREAKS & operations )
141   {
142     // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
143     // calculate the bidirectional info for each 'paragraph'.
144     // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
145     // is not shaped together).
146     lineBreakInfo.Resize( characterCount, TextAbstraction::LINE_NO_BREAK );
147
148     SetLineBreakInfo( utf32Characters,
149                       lineBreakInfo );
150
151     mImpl->mLogicalModel->SetLineBreakInfo( lineBreakInfo.Begin(), characterCount );
152   }
153
154   const bool getScripts = GET_SCRIPTS & operations;
155   const bool validateFonts = VALIDATE_FONTS & operations;
156
157   Vector<ScriptRun> scripts;
158   Vector<FontRun> fonts;
159   if( getScripts || validateFonts )
160   {
161     // Validates the fonts assigned by the application or assigns default ones.
162     // It makes sure all the characters are going to be rendered by the correct font.
163     MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
164
165     if( getScripts )
166     {
167       // Retrieves the scripts used in the text.
168       multilanguageSupport.SetScripts( utf32Characters,
169                                        lineBreakInfo,
170                                        scripts );
171
172       // Sets the scripts into the model.
173       mImpl->mLogicalModel->SetScripts( scripts.Begin(), scripts.Count() );
174     }
175
176     if( validateFonts )
177     {
178       // Validates the fonts. If there is a character with no assigned font it sets a default one.
179       // After this call, fonts are validated.
180       multilanguageSupport.ValidateFonts( utf32Characters,
181                                           scripts,
182                                           fonts );
183
184       // Sets the fonts into the model.
185       mImpl->mLogicalModel->SetFonts( fonts.Begin(), fonts.Count() );
186     }
187   }
188
189   Vector<GlyphInfo> glyphs;
190   Vector<CharacterIndex> characterIndices;
191   Vector<Length> charactersPerGlyph;
192   if( SHAPE_TEXT & operations )
193   {
194     // Shapes the text.
195     ShapeText( utf32Characters,
196                lineBreakInfo,
197                scripts,
198                fonts,
199                glyphs,
200                characterIndices,
201                charactersPerGlyph );
202   }
203
204   if( GET_GLYPH_METRICS & operations )
205   {
206     TextAbstraction::FontClient::Get().GetGlyphMetrics( glyphs.Begin(), glyphs.Count() );
207   }
208
209   if( LAYOUT & operations )
210   {
211     if( 0u == glyphs.Count() )
212     {
213       const Length numberOfGlyphs = mImpl->mVisualModel->GetNumberOfGlyphs();
214
215       glyphs.Resize( numberOfGlyphs );
216       characterIndices.Resize( numberOfGlyphs );
217       charactersPerGlyph.Resize( numberOfGlyphs );
218
219       mImpl->mVisualModel->GetGlyphs( glyphs.Begin(),
220                                       0u,
221                                       numberOfGlyphs );
222
223       mImpl->mVisualModel->GetGlyphToCharacterMap( characterIndices.Begin(),
224                                                    0u,
225                                                    numberOfGlyphs );
226
227       mImpl->mVisualModel->GetCharactersPerGlyphMap( charactersPerGlyph.Begin(),
228                                                      0u,
229                                                      numberOfGlyphs );
230     }
231
232     // Update the visual model
233     mImpl->mLayoutEngine.UpdateVisualModel( size,
234                                             glyphs,
235                                             characterIndices,
236                                             charactersPerGlyph,
237                                             *mImpl->mVisualModel );
238
239     viewUpdated = true;
240   }
241
242   return viewUpdated;
243 }
244
245 Vector3 Controller::GetNaturalSize()
246 {
247   // Operations that can be done only once until the text changes.
248   const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32 |
249                                                                          GET_SCRIPTS      |
250                                                                          VALIDATE_FONTS   |
251                                                                          GET_LINE_BREAKS  |
252                                                                          GET_WORD_BREAKS  |
253                                                                          SHAPE_TEXT       |
254                                                                          GET_GLYPH_METRICS );
255
256   // Operations that need to be done if the size or the text changes.
257   const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
258                                                                       REORDER );
259
260   const float maxFloat = std::numeric_limits<float>::max();
261   DoRelayout( Vector2( maxFloat, maxFloat ),
262               static_cast<OperationsMask>( onlyOnceOperations |
263                                            sizeOperations ) );
264
265   // Do not do again the only once operations.
266   mImpl->mOperations = static_cast<OperationsMask>( mImpl->mOperations & ~onlyOnceOperations );
267
268   // Do the size related operations again.
269   mImpl->mOperations = static_cast<OperationsMask>( mImpl->mOperations | sizeOperations );
270
271   return Vector3( mImpl->mVisualModel->GetNaturalSize() );
272 }
273
274 float Controller::GetHeightForWidth( float width )
275 {
276   // Operations that can be done only once until the text changes.
277   const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32 |
278                                                                          GET_SCRIPTS      |
279                                                                          VALIDATE_FONTS   |
280                                                                          GET_LINE_BREAKS  |
281                                                                          GET_WORD_BREAKS  |
282                                                                          SHAPE_TEXT       |
283                                                                          GET_GLYPH_METRICS );
284
285   // Operations that need to be done if the size or the text changes.
286   const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
287                                                                       REORDER );
288
289   DoRelayout( Size( width, 0.f ),
290               static_cast<OperationsMask>( onlyOnceOperations |
291                                            sizeOperations ) );
292
293   // Do not do again the only once operations.
294   mImpl->mOperations = static_cast<OperationsMask>( mImpl->mOperations & ~onlyOnceOperations );
295
296   // Do the size related operations again.
297   mImpl->mOperations = static_cast<OperationsMask>( mImpl->mOperations | sizeOperations );
298
299   return mImpl->mVisualModel->GetActualSize().height;
300 }
301
302 View& Controller::GetView()
303 {
304   return mImpl->mView;
305 }
306
307 LayoutEngine& Controller::GetLayoutEngine()
308 {
309   return mImpl->mLayoutEngine;
310 }
311
312 Controller::~Controller()
313 {
314   delete mImpl;
315 }
316
317 Controller::Controller()
318 : mImpl( NULL )
319 {
320   mImpl = new Controller::Impl();
321 }
322
323 } // namespace Text
324
325 } // namespace Toolkit
326
327 } // namespace Dali