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