Revert "License conversion from Flora to Apache 2.0"
[platform/core/uifw/dali-core.git] / dali / internal / event / text / generator / text-vertex-generator.cpp
1 //
2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
3 //
4 // Licensed under the Flora License, Version 1.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://floralicense.org/license/
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 // FILE HEADER
18 #include "text-vertex-generator.h"
19
20 // INTERNAL INCLUDES
21 #include <dali/public-api/common/constants.h>
22 #include <dali/internal/event/text/glyph-status/glyph-status.h>
23 #include <dali/internal/event/text/special-characters.h>
24
25 // EXTERNAL INCLUDES
26 #include <cmath>  // for std::sin
27
28 namespace Dali
29 {
30
31 namespace Internal
32 {
33
34 namespace // unnamed namespace
35 {
36
37 typedef std::vector<TextVertex2D> VertexBuffer;
38
39 void RepositionData( VertexBuffer& buffer, Vector2 offset )
40 {
41   /*
42    *
43    * As 0,0 is the middle of the actor, text will be displayed like this
44    *
45    *  |-------------------------------|
46    *  |            Actor              |
47    *  |                               |
48    *  |                               |
49    *  |          (0,0)|----------     | (x)
50    *  |               | Hello World   |
51    *  |               |               |
52    *  |               |               |
53    *  |-------------------------------|
54    *                 (y)
55    *
56    *  Below it is repositioned to the centre of the actor
57    *  |-------------------------------|
58    *  |            Actor              |
59    *  |                               |
60    *  |                               |
61    *  |          Hello World------    | (x)
62    *  |               |               |
63    *  |               |               |
64    *  |               |               |
65    *  |-------------------------------|
66    */
67
68   // move the vertices so 0,0 is the centre of the text string.
69   offset.x/=2.0f;
70   offset.y/=2.0f;
71
72   for (std::size_t i=0, size = buffer.size() ; i< size; ++i)
73   {
74       buffer[i].mX -= offset.x;
75       buffer[i].mY -= offset.y;
76   }
77 }
78
79 void AddVertex( VertexBuffer& vertexBuffer,
80                 const float xPos,
81                 const float yPos,
82                 const float charWidth,
83                 const float charHeight,
84                 const UvRect& uv,
85                 const Vector2& uvShadow )
86 {
87   /*
88    * Create 4 vertices
89    * 1 --- 2
90    * |    /|
91    * |  A  |
92    * | /   |
93    * 0 --- 3
94    *
95    * 2 triangles with clock wise winding: 0->1->2 and 0->2->3
96    */
97
98   TextVertex2D v;
99
100   // set U1,V1 for all vertices
101   v.mU1 = uvShadow.x;
102   v.mV1 = uvShadow.y;
103
104   // bottom left, 0
105   v.mX = xPos;
106   v.mY = yPos;
107   v.mU = uv.u0;
108   v.mV = uv.v0;
109   vertexBuffer.push_back(v);
110
111   // top left, 1
112   v.mX = xPos;
113   v.mY = yPos + charHeight;
114   v.mU = uv.u0;
115   v.mV = uv.v2;
116   vertexBuffer.push_back(v);
117
118   // top right, 2
119   v.mX = xPos + charWidth;
120   v.mY = yPos + charHeight;
121   v.mU = uv.u2;
122   v.mV = uv.v2;
123   vertexBuffer.push_back(v);
124
125   // bottom right, 3
126   v.mX = xPos + charWidth;
127   v.mY = yPos;
128   v.mU = uv.u2;
129   v.mV = uv.v0;
130   vertexBuffer.push_back(v);
131 }
132
133 /**
134  * Adjust the vertex data for italics.
135  * Skews the vertices by a value
136  */
137 void AdjustForItalics( VertexBuffer&  vertexBuffer,
138                        const float italicsTopDisplacement,
139                        const float italicsBottomDisplacement)
140 {
141
142   std::size_t index = vertexBuffer.size()-4;
143   TextVertex2D &v1 = vertexBuffer.at( index );
144   v1.mX+= italicsBottomDisplacement;
145
146
147   // top left
148   index++;
149   TextVertex2D &v2 = vertexBuffer.at( index );
150   v2.mX+= italicsTopDisplacement;
151
152
153   // top right
154   index++;
155   TextVertex2D &v3 = vertexBuffer.at( index );
156   v3.mX+= italicsTopDisplacement;
157
158   // bottom right
159   index++;
160   TextVertex2D &v4 = vertexBuffer.at( index );
161   v4.mX+= italicsBottomDisplacement;
162 }
163
164 void AddUnderline( VertexBuffer& vertexBuffer,
165                    const float totalWidth,
166                    const float thickness,
167                    const float yPosition,
168                    const UvRect& uv )
169 {
170   /*
171    *  Add an underline to a string of text.
172    *
173    *
174    *  A thin vertical slice of the underline character is stretched to the
175    *  length of the string.
176    *
177    *  If we stretch the entire underline character (not a thin slice) then
178    *  the rounded edges will be stretched as well, giving inconsistent results.
179    *
180    *   Underline glyph                     Only use a thin slice for texturing
181    *
182    *  |-------------------|           (u0,v2)|--------|X|---------|(u2,v2)
183    *  |                   |                  |        |X|         |
184    *  |   /-----------\   |                  |   /----|X|-----\   |
185    *  |  |  underline  |  |                  |  |     |X|     |   |
186    *  |   \___________/   |                  |   \____|X|_____/   |
187    *  |                   |                  |        |X|         |
188    *  |                   |                  |        |X|         |
189    *  |-------------------|                  |--------|X|---------|
190    *
191    *                                      (u0,v0)    halfU       (u2,v0)
192    *
193    *  In calculation below
194    *  HalfU = half way between u0 and u2. This gives a thin slice.
195    *  So we use the texture-coordinates from  (halfU, v0) -> (halfU, v2).
196    *
197    *  End result is: A solid edge on the left / right side of the underline:
198    *                 A smooth (anti-aliased) edge on the top / bottom of the underline
199    */
200
201   TextVertex2D v;
202
203   // set U1,V1 for all vertices
204   v.mU1 = 1.0f;
205   v.mV1 = 1.0f;
206
207   float halfU = (uv.u0 + uv.u2)/2.0f;
208
209   /*
210    * Create 4 vertices
211    * 1 --- 2
212    * |    /|
213    * |  A  |
214    * | /   |
215    * 0 --- 3
216    */
217
218   // 0
219   v.mX = 0.0f;
220   v.mY = yPosition;
221   v.mU = halfU;
222   v.mV = uv.v2;
223   vertexBuffer.push_back(v);
224
225   // 1
226   v.mX = 0.0f;
227   v.mY = yPosition + thickness;
228   v.mU = halfU;
229   v.mV = uv.v0;
230   vertexBuffer.push_back(v);
231
232   // 2
233   v.mX = totalWidth;
234   v.mY = yPosition + thickness;
235   v.mU = halfU;
236   v.mV = uv.v0;
237   vertexBuffer.push_back(v);
238
239   // 3
240   v.mX = totalWidth;
241   v.mY = yPosition;
242   v.mU = halfU;
243   v.mV = uv.v2;
244   vertexBuffer.push_back(v);
245 }
246
247 void GetAdjustedSize(float &charWidth,
248                      float &charHeight,
249                      float &left,
250                      float &top,
251                      float padAdjustX,
252                      float padAdjustY,
253                      float scalar,
254                      const GlyphMetric& glyph)
255 {
256   charWidth  = (glyph.GetWidth()  + padAdjustX * 2.0f) * scalar;
257   charHeight = (glyph.GetHeight() + padAdjustY * 2.0f) * scalar;
258   left = (glyph.GetLeft() - padAdjustX) * scalar;
259   top  = (glyph.GetTop()  + padAdjustY) * scalar;
260 }
261
262 #ifdef DEBUG_VERTS
263
264 void DebugVertexBuffer( VertexBuffer& buffer )
265 {
266   for (std::size_t i = 0, size = buffer.size(); i< size ; ++i)
267   {
268     TextVertex2D &v = buffer.at( i );
269     printf("%d: xyuv =, %f , %f, %f, %f  \n", (unsigned int) i, v.mX,v.mY, v.mU, v.mV);
270   }
271 }
272 #endif
273
274 } // unnamed namespace
275
276 TextVertexBuffer* TextVertexGenerator::Generate(const TextArray& text,
277                            const TextFormat& format,
278                            const FontMetricsInterface& metrics,
279                            const AtlasUvInterface& uvInterface,
280                            const FontId fontId)
281
282 {
283   TextVertexBuffer* textVertexBuffer = new TextVertexBuffer;
284   VertexBuffer &vertexBuffer(textVertexBuffer->mVertices);
285
286   const GlyphMetric* glyph( NULL );
287   float xPos( 0.0f );
288   float yPos( 0.0f );
289   float underlineWidth( 0.0f );
290   float totalWidth( 0.0f );
291   float charWidth( 0.0f );
292   float charHeight( 0.0f );
293   float left(0.0f);
294   float top(0.0f);
295
296   float scalar = metrics.GetUnitsToPixels( format.GetPointSize() );
297
298   // Italics displacement
299   // the text is rendered upside down
300   const float sinAngle = format.IsItalic() ? std::sin( format.GetItalicsAngle() ) : 0.0f;
301
302   // get the line height and ascender from the font
303   const float lineHeight( metrics.GetLineHeight() * scalar );
304   const float ascender( metrics.GetAscender() * scalar );
305   const float padAdjustX( metrics.GetPadAdjustX() );
306   const float padAdjustY( metrics.GetPadAdjustY() );
307   const float tileWidth( metrics.GetMaxWidth() * scalar );
308   const float tileHeight( metrics.GetMaxHeight() * scalar );
309   unsigned int textSize = text.size();
310
311   for (unsigned int i = 0; i < textSize; ++i)
312   {
313     // buffer is always filled starting from the first vector position. However text characters are visited from left to right or from right to left.
314     uint32_t charIndex = text[ ( format.IsLeftToRight() ? i : ( textSize - 1 - i ) ) ];
315
316     glyph = metrics.GetGlyph( charIndex );
317
318     if (charIndex >= SpecialCharacters::FIRST_VISIBLE_CHAR && glyph )
319     {
320       // get char size and offset adjusted for padding in the atlas
321       GetAdjustedSize(charWidth, charHeight, left, top, padAdjustX, padAdjustY, scalar, *glyph );
322
323       yPos = (ascender - top);
324       xPos += left;
325
326       // a combination of character index and font id is used to uniquely identify the character
327       unsigned int encodedChar = GlyphStatus::GetEncodedValue( charIndex, fontId );
328       UvRect uv = uvInterface.GetUvCoordinates( encodedChar );
329
330       const Vector2 uvShadow( tileWidth / charWidth, tileHeight / charHeight );
331
332       AddVertex( vertexBuffer, xPos, yPos, charWidth, charHeight, uv, uvShadow );
333
334       if( format.IsItalic() )
335       {
336         float italicsTopDisplacement = ( top - charHeight ) * sinAngle;
337         float italicsBottomDisplacement = top * sinAngle;
338         AdjustForItalics( vertexBuffer, italicsTopDisplacement, italicsBottomDisplacement);
339       }
340
341       xPos -= left;
342     }
343
344     if( glyph )
345     {
346       underlineWidth = std::max( underlineWidth, xPos + glyph->GetXAdvance() * scalar );
347       xPos += glyph->GetXAdvance() * scalar;
348       totalWidth = std::max(totalWidth, xPos);
349     }
350   } // for
351
352   if( format.IsUnderLined() )
353   {
354     unsigned int encodedChar = GlyphStatus::GetEncodedValue( SpecialCharacters::UNDERLINE_CHARACTER, fontId );
355     UvRect uv( uvInterface.GetUvCoordinates( encodedChar ));
356
357     glyph = metrics.GetGlyph( SpecialCharacters::UNDERLINE_CHARACTER );
358
359     if( glyph )
360     {
361       // Adjust uv coordinates for scaling within atlas tile
362       GetAdjustedSize(charWidth, charHeight, left, top, padAdjustX, padAdjustY, scalar, *glyph );
363
364       // Get underline thickness and position.
365       // These values could be retrieved from the text-format, set to the text-actor through text-style,
366       // or retrieved directly from the font metrics.
367       float thickness = 0.f;
368       float position = 0.f;
369
370       if( fabs( format.GetUnderlineThickness() ) > Math::MACHINE_EPSILON_0 )
371       {
372         // Thickness and position retrieved from the format, which are passed to the
373         // text-actor through the text-style, it adds the vertical pad adjust used to fit some effects like glow or shadow..
374         thickness = -format.GetUnderlineThickness();
375         position = format.GetUnderlinePosition();
376       }
377       else
378       {
379         // Thickness and position retrieved from the font metrics.
380         // It adds the vertical pad adjust ( padAdjustY ) used to fit some effects like glow or shadow.
381         thickness = -( metrics.GetUnderlineThickness() + 2.f * padAdjustY ) * scalar;
382         position = ascender - ( metrics.GetUnderlinePosition() - padAdjustY ) * scalar;
383       }
384       AddUnderline( vertexBuffer, underlineWidth, thickness, position, uv );
385     }
386   }
387
388   textVertexBuffer->mVertexMax = Vector2(totalWidth,lineHeight);
389
390   RepositionData( vertexBuffer, textVertexBuffer->mVertexMax );
391
392 #ifdef DEBUG_VERTS
393   DebugVertexBuffer( vertexBuffer );
394 #endif
395
396   return textVertexBuffer;
397 }
398
399 } // namespace Internal
400
401 } // namespace Dali