Skeleton Decorator API
[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( 0, &firstGlyph, 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( i, &glyph, 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       // FIXME Single font assumption
119       Text::FontMetrics fontMetrics;
120       GlyphInfo firstGlyph;
121       visualModel.GetGlyphs( 0, &firstGlyph, 1 );
122       mFontClient.GetFontMetrics( firstGlyph.fontId, fontMetrics );
123
124       float penX( 0 );
125       float penY( fontMetrics.ascender ); // Move to baseline
126
127       unsigned int i=0;
128       while( i < glyphCount )
129       {
130         // Skip initial whitespace
131         for( ; i<glyphCount; ++i )
132         {
133           GlyphInfo glyph;
134           visualModel.GetGlyphs( i, &glyph, 1 );
135
136           if( glyph.width  > 0 &&
137               glyph.height > 0 )
138           {
139             break;
140           }
141           else
142           {
143             glyphPositions.push_back( Vector2( penX + glyph.xBearing,
144                                                penY - glyph.yBearing ) );
145           }
146         }
147
148         // Find last glyph for the next line
149         unsigned int endIndex = i;
150         float endPenX = penX;
151         unsigned int j=i;
152         for( ; j<glyphCount; ++j )
153         {
154           GlyphInfo glyph;
155           visualModel.GetGlyphs( j, &glyph, 1 );
156
157           endPenX += glyph.advance;
158
159           if( glyph.width  <= 0 ||
160               glyph.height <= 0 )
161           {
162             // Potential line end found
163             endIndex = j;
164           }
165           else if( endPenX > boundingBox.width )
166           {
167             break;
168           }
169         }
170
171         // If end of text or no whitespace found
172         if( glyphCount == j ||
173             endIndex == i )
174         {
175           endIndex = j;
176         }
177
178         for( ; i<endIndex; ++i )
179         {
180           GlyphInfo glyph;
181           visualModel.GetGlyphs( i, &glyph, 1 );
182
183           glyphPositions.push_back( Vector2( penX + glyph.xBearing,
184                                              penY - glyph.yBearing ) );
185
186           penX += glyph.advance;
187         }
188
189         // Go to next line
190         penX = 0;
191         penY += fontMetrics.height;
192       }
193
194       visualModel.SetGlyphPositions( &glyphPositions[0], glyphCount );
195     }
196   }
197
198   unsigned int mLayout;
199
200   TextAbstraction::FontClient mFontClient;
201 };
202
203 LayoutEngine::LayoutEngine()
204 : mImpl( NULL )
205 {
206   mImpl = new LayoutEngine::Impl();
207 }
208
209 LayoutEngine::~LayoutEngine()
210 {
211   delete mImpl;
212 }
213
214 void LayoutEngine::SetLayout( Layout layout )
215 {
216   mImpl->mLayout = layout;
217 }
218
219 void LayoutEngine::UpdateVisualModel( const Vector2& boundingBox,
220                                       const Vector<GlyphInfo>& glyphs,
221                                       const Vector<CharacterIndex>& characterIndices,
222                                       const Vector<Length>& charactersPerGlyph,
223                                       VisualModel& visualModel )
224 {
225   mImpl->UpdateVisualModel( boundingBox,
226                             glyphs,
227                             characterIndices,
228                             charactersPerGlyph,
229                             visualModel );
230 }
231
232 } // namespace Text
233
234 } // namespace Toolkit
235
236 } // namespace Dali