cfdd9d43d7892007fbc846db0d66e2a3533cc3ed
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / public-api / text / layouts / layout-engine.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/layouts/layout-engine.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/public-api/math/vector2.h>
23 #include <dali/public-api/text-abstraction/font-client.h>
24
25 // INTERNAL INCLUDES
26 #include <dali-toolkit/public-api/text/logical-model.h>
27 #include <dali-toolkit/public-api/text/visual-model.h>
28
29 namespace Dali
30 {
31
32 namespace Toolkit
33 {
34
35 namespace Text
36 {
37
38 struct LayoutEngine::Impl
39 {
40   Impl()
41   : mLayout( LayoutEngine::SINGLE_LINE_BOX )
42   {
43     mFontClient = TextAbstraction::FontClient::Get();
44   }
45
46   void UpdateVisualModel( const Vector2& boundingBox,
47                           const Vector<GlyphInfo>& glyphs,
48                           const Vector<CharacterIndex>& characterIndices,
49                           const Vector<Length>& charactersPerGlyph,
50                           VisualModel& visualModel )
51   {
52     // TODO Switch between different layouts
53
54     visualModel.SetGlyphs( &glyphs[0],
55                            &characterIndices[0],
56                            &charactersPerGlyph[0],
57                            glyphs.Count() );
58
59     UpdateGlyphPositions( boundingBox, visualModel );
60   }
61
62   void UpdateGlyphPositions( const Vector2& boundingBox, VisualModel& visualModel )
63   {
64     if( LayoutEngine::SINGLE_LINE_BOX == mLayout )
65     {
66       SingleLineLayout( boundingBox, visualModel );
67     }
68     else
69     {
70       MultiLineLayout( boundingBox, visualModel );
71     }
72   }
73
74   // TODO - Rewrite this to handle bidi
75   void SingleLineLayout( const Vector2& boundingBox, VisualModel& visualModel )
76   {
77     Length glyphCount = visualModel.GetNumberOfGlyphs();
78
79     std::vector<Vector2> glyphPositions;
80     glyphPositions.reserve( glyphCount );
81
82     if( glyphCount > 0 )
83     {
84       // FIXME Single font assumption
85       Text::FontMetrics fontMetrics;
86       GlyphInfo firstGlyph;
87       visualModel.GetGlyphs( &firstGlyph, 0, 1 );
88       mFontClient.GetFontMetrics( firstGlyph.fontId, fontMetrics );
89
90       float penX( 0 );
91       float penY( fontMetrics.ascender ); // Move to baseline
92
93       for( unsigned int i=0; i<glyphCount; ++i )
94       {
95         GlyphInfo glyph;
96         visualModel.GetGlyphs( &glyph, i, 1 );
97
98         glyphPositions.push_back( Vector2( penX + glyph.xBearing,
99                                            penY - glyph.yBearing ) );
100
101         penX += glyph.advance;
102       }
103
104       visualModel.SetGlyphPositions( &glyphPositions[0], glyphCount );
105     }
106   }
107
108   // TODO - Rewrite this to handle bidi
109   void MultiLineLayout( const Vector2& boundingBox, VisualModel& visualModel )
110   {
111     Length glyphCount = visualModel.GetNumberOfGlyphs();
112
113     std::vector<Vector2> glyphPositions;
114     glyphPositions.reserve( glyphCount );
115
116     if( glyphCount > 0 )
117     {
118       Size actualSize;
119
120       // FIXME Single font assumption
121       Text::FontMetrics fontMetrics;
122       GlyphInfo firstGlyph;
123       visualModel.GetGlyphs( &firstGlyph, 0, 1 );
124       mFontClient.GetFontMetrics( firstGlyph.fontId, fontMetrics );
125
126       float penX( 0 );
127       float penY( fontMetrics.ascender ); // Move to baseline
128
129       unsigned int i=0;
130       while( i < glyphCount )
131       {
132         // Skip initial whitespace
133         for( ; i<glyphCount; ++i )
134         {
135           GlyphInfo glyph;
136           visualModel.GetGlyphs( &glyph, i, 1 );
137
138           if( glyph.width  > 0 &&
139               glyph.height > 0 )
140           {
141             break;
142           }
143           else
144           {
145             glyphPositions.push_back( Vector2( penX + glyph.xBearing,
146                                                penY - glyph.yBearing ) );
147           }
148         }
149
150         // Find last glyph for the next line
151         unsigned int endIndex = i;
152         float endPenX = penX;
153         unsigned int j=i;
154         for( ; j<glyphCount; ++j )
155         {
156           GlyphInfo glyph;
157           visualModel.GetGlyphs( &glyph, j, 1 );
158
159           endPenX += glyph.advance;
160
161           if( glyph.width  <= 0 ||
162               glyph.height <= 0 )
163           {
164             // Potential line end found
165             endIndex = j;
166           }
167           else if( endPenX > boundingBox.width )
168           {
169             actualSize.width = ( actualSize.width < endPenX - glyph.advance ) ? endPenX - glyph.advance : actualSize.width;
170             break;
171           }
172         }
173
174         // If end of text or no whitespace found
175         if( glyphCount == j ||
176             endIndex == i )
177         {
178           endIndex = j;
179         }
180
181         for( ; i<endIndex; ++i )
182         {
183           GlyphInfo glyph;
184           visualModel.GetGlyphs( &glyph, i, 1 );
185
186           glyphPositions.push_back( Vector2( penX + glyph.xBearing,
187                                              penY - glyph.yBearing ) );
188
189           penX += glyph.advance;
190         }
191
192         // Go to next line
193         penX = 0;
194         penY += fontMetrics.height;
195
196         actualSize.height += fontMetrics.height;
197       }
198
199       visualModel.SetGlyphPositions( &glyphPositions[0], glyphCount );
200
201       visualModel.SetActualSize( actualSize );
202     }
203   }
204
205   unsigned int mLayout;
206
207   TextAbstraction::FontClient mFontClient;
208 };
209
210 LayoutEngine::LayoutEngine()
211 : mImpl( NULL )
212 {
213   mImpl = new LayoutEngine::Impl();
214 }
215
216 LayoutEngine::~LayoutEngine()
217 {
218   delete mImpl;
219 }
220
221 void LayoutEngine::SetLayout( Layout layout )
222 {
223   mImpl->mLayout = layout;
224 }
225
226 void LayoutEngine::UpdateVisualModel( const Vector2& boundingBox,
227                                       const Vector<GlyphInfo>& glyphs,
228                                       const Vector<CharacterIndex>& characterIndices,
229                                       const Vector<Length>& charactersPerGlyph,
230                                       VisualModel& visualModel )
231 {
232   mImpl->UpdateVisualModel( boundingBox,
233                             glyphs,
234                             characterIndices,
235                             charactersPerGlyph,
236                             visualModel );
237 }
238
239 } // namespace Text
240
241 } // namespace Toolkit
242
243 } // namespace Dali