2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include "text-vertex-generator.h"
22 #include <dali/public-api/common/constants.h>
23 #include <dali/internal/event/text/glyph-status/glyph-status.h>
24 #include <dali/internal/event/text/special-characters.h>
27 #include <cmath> // for std::sin
35 namespace // unnamed namespace
38 typedef std::vector<TextVertex2D> VertexBuffer;
40 void RepositionData( VertexBuffer& buffer, Vector2 offset )
44 * As 0,0 is the middle of the actor, text will be displayed like this
46 * |-------------------------------|
50 * | (0,0)|---------- | (x)
54 * |-------------------------------|
57 * Below it is repositioned to the centre of the actor
58 * |-------------------------------|
62 * | Hello World------ | (x)
66 * |-------------------------------|
69 // move the vertices so 0,0 is the centre of the text string.
73 for (std::size_t i=0, size = buffer.size() ; i< size; ++i)
75 buffer[i].mX -= offset.x;
76 buffer[i].mY -= offset.y;
80 void AddVertex( VertexBuffer& vertexBuffer,
83 const float charWidth,
84 const float charHeight,
86 const Vector2& uvShadow )
96 * 2 triangles with clock wise winding: 0->1->2 and 0->2->3
101 // set U1,V1 for all vertices
110 vertexBuffer.push_back(v);
114 v.mY = yPos + charHeight;
117 vertexBuffer.push_back(v);
120 v.mX = xPos + charWidth;
121 v.mY = yPos + charHeight;
124 vertexBuffer.push_back(v);
127 v.mX = xPos + charWidth;
131 vertexBuffer.push_back(v);
135 * Adjust the vertex data for italics.
136 * Skews the vertices by a value
138 void AdjustForItalics( VertexBuffer& vertexBuffer,
139 const float italicsTopDisplacement,
140 const float italicsBottomDisplacement)
143 std::size_t index = vertexBuffer.size()-4;
144 TextVertex2D &v1 = vertexBuffer.at( index );
145 v1.mX+= italicsBottomDisplacement;
150 TextVertex2D &v2 = vertexBuffer.at( index );
151 v2.mX+= italicsTopDisplacement;
156 TextVertex2D &v3 = vertexBuffer.at( index );
157 v3.mX+= italicsTopDisplacement;
161 TextVertex2D &v4 = vertexBuffer.at( index );
162 v4.mX+= italicsBottomDisplacement;
165 void AddUnderline( VertexBuffer& vertexBuffer,
166 const float totalWidth,
167 const float thickness,
168 const float yPosition,
172 * Add an underline to a string of text.
175 * A thin vertical slice of the underline character is stretched to the
176 * length of the string.
178 * If we stretch the entire underline character (not a thin slice) then
179 * the rounded edges will be stretched as well, giving inconsistent results.
181 * Underline glyph Only use a thin slice for texturing
183 * |-------------------| (u0,v2)|--------|X|---------|(u2,v2)
185 * | /-----------\ | | /----|X|-----\ |
186 * | | underline | | | | |X| | |
187 * | \___________/ | | \____|X|_____/ |
190 * |-------------------| |--------|X|---------|
192 * (u0,v0) halfU (u2,v0)
194 * In calculation below
195 * HalfU = half way between u0 and u2. This gives a thin slice.
196 * So we use the texture-coordinates from (halfU, v0) -> (halfU, v2).
198 * End result is: A solid edge on the left / right side of the underline:
199 * A smooth (anti-aliased) edge on the top / bottom of the underline
204 // set U1,V1 for all vertices
208 float halfU = (uv.u0 + uv.u2)/2.0f;
224 vertexBuffer.push_back(v);
228 v.mY = yPosition + thickness;
231 vertexBuffer.push_back(v);
235 v.mY = yPosition + thickness;
238 vertexBuffer.push_back(v);
245 vertexBuffer.push_back(v);
248 void GetAdjustedSize(float &charWidth,
255 const GlyphMetric& glyph)
257 charWidth = (glyph.GetWidth() + padAdjustX * 2.0f) * scalar;
258 charHeight = (glyph.GetHeight() + padAdjustY * 2.0f) * scalar;
259 left = (glyph.GetLeft() - padAdjustX) * scalar;
260 top = (glyph.GetTop() + padAdjustY) * scalar;
265 void DebugVertexBuffer( VertexBuffer& buffer )
267 for (std::size_t i = 0, size = buffer.size(); i< size ; ++i)
269 TextVertex2D &v = buffer.at( i );
270 printf("%d: xyuv =, %f , %f, %f, %f \n", (unsigned int) i, v.mX,v.mY, v.mU, v.mV);
275 } // unnamed namespace
277 TextVertexBuffer* TextVertexGenerator::Generate(const TextArray& text,
278 const TextFormat& format,
279 const FontMetricsInterface& metrics,
280 const AtlasUvInterface& uvInterface,
284 TextVertexBuffer* textVertexBuffer = new TextVertexBuffer;
285 VertexBuffer &vertexBuffer(textVertexBuffer->mVertices);
287 const GlyphMetric* glyph( NULL );
290 float underlineWidth( 0.0f );
291 float totalWidth( 0.0f );
292 float charWidth( 0.0f );
293 float charHeight( 0.0f );
297 float scalar = metrics.GetUnitsToPixels( format.GetPointSize() );
299 // Italics displacement
300 // the text is rendered upside down
301 const float sinAngle = format.IsItalic() ? std::sin( format.GetItalicsAngle() ) : 0.0f;
303 // get the line height and ascender from the font
304 const float lineHeight( metrics.GetLineHeight() * scalar );
305 const float ascender( metrics.GetAscender() * scalar );
306 const float padAdjustX( metrics.GetPadAdjustX() );
307 const float padAdjustY( metrics.GetPadAdjustY() );
308 const float tileWidth( metrics.GetMaxWidth() * scalar );
309 const float tileHeight( metrics.GetMaxHeight() * scalar );
310 unsigned int textSize = text.size();
312 for (unsigned int i = 0; i < textSize; ++i)
314 // buffer is always filled starting from the first vector position. However text characters are visited from left to right or from right to left.
315 uint32_t charIndex = text[ ( format.IsLeftToRight() ? i : ( textSize - 1 - i ) ) ];
317 glyph = metrics.GetGlyph( charIndex );
319 if (charIndex >= SpecialCharacters::FIRST_VISIBLE_CHAR && glyph )
321 // get char size and offset adjusted for padding in the atlas
322 GetAdjustedSize(charWidth, charHeight, left, top, padAdjustX, padAdjustY, scalar, *glyph );
324 yPos = (ascender - top);
327 // a combination of character index and font id is used to uniquely identify the character
328 unsigned int encodedChar = GlyphStatus::GetEncodedValue( charIndex, fontId );
329 UvRect uv = uvInterface.GetUvCoordinates( encodedChar );
331 const Vector2 uvShadow( tileWidth / charWidth, tileHeight / charHeight );
333 AddVertex( vertexBuffer, xPos, yPos, charWidth, charHeight, uv, uvShadow );
335 if( format.IsItalic() )
337 float italicsTopDisplacement = ( top - charHeight ) * sinAngle;
338 float italicsBottomDisplacement = top * sinAngle;
339 AdjustForItalics( vertexBuffer, italicsTopDisplacement, italicsBottomDisplacement);
347 underlineWidth = std::max( underlineWidth, xPos + glyph->GetXAdvance() * scalar );
348 xPos += glyph->GetXAdvance() * scalar;
349 totalWidth = std::max(totalWidth, xPos);
353 if( format.IsUnderLined() )
355 unsigned int encodedChar = GlyphStatus::GetEncodedValue( SpecialCharacters::UNDERLINE_CHARACTER, fontId );
356 UvRect uv( uvInterface.GetUvCoordinates( encodedChar ));
358 glyph = metrics.GetGlyph( SpecialCharacters::UNDERLINE_CHARACTER );
362 // Adjust uv coordinates for scaling within atlas tile
363 GetAdjustedSize(charWidth, charHeight, left, top, padAdjustX, padAdjustY, scalar, *glyph );
365 // Get underline thickness and position.
366 // These values could be retrieved from the text-format, set to the text-actor through text-style,
367 // or retrieved directly from the font metrics.
368 float thickness = 0.f;
369 float position = 0.f;
371 if( fabs( format.GetUnderlineThickness() ) > Math::MACHINE_EPSILON_0 )
373 // Thickness and position retrieved from the format, which are passed to the
374 // text-actor through the text-style, it adds the vertical pad adjust used to fit some effects like glow or shadow..
375 thickness = -format.GetUnderlineThickness();
376 position = format.GetUnderlinePosition();
380 // Thickness and position retrieved from the font metrics.
381 // It adds the vertical pad adjust ( padAdjustY ) used to fit some effects like glow or shadow.
382 thickness = -( metrics.GetUnderlineThickness() + 2.f * padAdjustY ) * scalar;
383 position = ascender - ( metrics.GetUnderlinePosition() - padAdjustY ) * scalar;
385 AddUnderline( vertexBuffer, underlineWidth, thickness, position, uv );
389 textVertexBuffer->mVertexMax = Vector2(totalWidth,lineHeight);
391 RepositionData( vertexBuffer, textVertexBuffer->mVertexMax );
394 DebugVertexBuffer( vertexBuffer );
397 return textVertexBuffer;
400 } // namespace Internal