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>
25 #include <dali/integration-api/debug.h>
28 #include <cmath> // for std::sin
36 namespace // unnamed namespace
39 #if defined(DEBUG_ENABLED)
40 Debug::Filter* gTextVertsLogFilter = Debug::Filter::New( Debug::Concise, false, "LOG_TEXT_VERTEX_FILTER" );
43 typedef std::vector<TextVertex2D> VertexBuffer;
45 void RepositionData( TextVertexBuffer& buffer )
49 * As 0,0 is the middle of the actor, text will be displayed like this
51 * |-------------------------------|
55 * | (0,0)|---------- | (x)
59 * |-------------------------------|
62 * Below it is repositioned to the centre of the actor
63 * |-------------------------------|
67 * | Hello World------ | (x)
71 * |-------------------------------|
74 // move the vertices so 0,0 is the centre of the text string.
75 float minX=1e8f, maxX=-1e8f;
76 float minY=1e8f, maxY=-1e8f;
77 std::vector<TextVertex2D>& vertices = buffer.mVertices;
79 for (std::size_t i=0, size = vertices.size() ; i < size; ++i)
81 TextVertex2D& vertex = vertices[i];
82 minX = std::min(minX, vertex.mX);
83 maxX = std::max(maxX, vertex.mX);
85 minY = std::min(minY, vertex.mY);
86 maxY = std::max(maxY, vertex.mY);
90 offset.x = ( maxX + minX ) * 0.5f;
91 offset.y = ( maxY + minY ) * 0.5f;
93 for (std::size_t i=0, size = vertices.size() ; i< size; ++i)
95 TextVertex2D& vertex = vertices[i];
96 vertex.mX -= offset.x;
97 vertex.mY -= offset.y;
100 buffer.mGeometryExtent.width = maxX - minX;
101 buffer.mGeometryExtent.height = maxY - minY;
104 void AddVertex( VertexBuffer& vertexBuffer,
107 const float charWidth,
108 const float charHeight,
110 const Vector2& uvShadow )
120 * 2 triangles with clock wise winding: 0->1->2 and 0->2->3
125 // set U1,V1 for all vertices
134 vertexBuffer.push_back(v);
138 v.mY = yPos + charHeight;
141 vertexBuffer.push_back(v);
144 v.mX = xPos + charWidth;
145 v.mY = yPos + charHeight;
148 vertexBuffer.push_back(v);
151 v.mX = xPos + charWidth;
155 vertexBuffer.push_back(v);
159 * Adjust the vertex data for italics.
160 * Skews the vertices by a value
162 void AdjustForItalics( VertexBuffer& vertexBuffer,
163 const float italicsTopDisplacement,
164 const float italicsBottomDisplacement)
167 std::size_t index = vertexBuffer.size()-4;
168 TextVertex2D &v1 = vertexBuffer.at( index );
169 v1.mX+= italicsBottomDisplacement;
174 TextVertex2D &v2 = vertexBuffer.at( index );
175 v2.mX+= italicsTopDisplacement;
180 TextVertex2D &v3 = vertexBuffer.at( index );
181 v3.mX+= italicsTopDisplacement;
185 TextVertex2D &v4 = vertexBuffer.at( index );
186 v4.mX+= italicsBottomDisplacement;
189 void AddUnderline( VertexBuffer& vertexBuffer,
190 const float totalWidth,
191 const float thickness,
192 const float yPosition,
196 * Add an underline to a string of text.
199 * A thin vertical slice of the underline character is stretched to the
200 * length of the string.
202 * If we stretch the entire underline character (not a thin slice) then
203 * the rounded edges will be stretched as well, giving inconsistent results.
205 * Underline glyph Only use a thin slice for texturing
207 * |-------------------| (u0,v2)|--------|X|---------|(u2,v2)
209 * | /-----------\ | | /----|X|-----\ |
210 * | | underline | | | | |X| | |
211 * | \___________/ | | \____|X|_____/ |
214 * |-------------------| |--------|X|---------|
216 * (u0,v0) halfU (u2,v0)
218 * In calculation below
219 * HalfU = half way between u0 and u2. This gives a thin slice.
220 * So we use the texture-coordinates from (halfU, v0) -> (halfU, v2).
222 * End result is: A solid edge on the left / right side of the underline:
223 * A smooth (anti-aliased) edge on the top / bottom of the underline
228 // set U1,V1 for all vertices
232 float halfU = (uv.u0 + uv.u2)/2.0f;
248 vertexBuffer.push_back(v);
252 v.mY = yPosition + thickness;
255 vertexBuffer.push_back(v);
259 v.mY = yPosition + thickness;
262 vertexBuffer.push_back(v);
269 vertexBuffer.push_back(v);
272 void GetAdjustedSize(float &charWidth,
279 const GlyphMetric& glyph)
281 charWidth = (glyph.GetWidth() + padAdjustX * 2.0f) * scalar;
282 charHeight = (glyph.GetHeight() + padAdjustY * 2.0f) * scalar;
283 left = (glyph.GetLeft() - padAdjustX) * scalar;
284 top = (glyph.GetTop() + padAdjustY) * scalar;
289 void DebugVertexBuffer( VertexBuffer& buffer )
291 for (std::size_t i = 0, size = buffer.size(); i< size ; ++i)
293 TextVertex2D &v = buffer.at( i );
294 printf("%d: xyuv =, %f , %f, %f, %f \n", (unsigned int) i, v.mX,v.mY, v.mU, v.mV);
299 } // unnamed namespace
301 TextVertexBuffer* TextVertexGenerator::Generate( const TextArray& text,
302 const TextFormat& format,
303 const FontMetricsInterface& metrics,
304 const AtlasUvInterface& uvInterface,
308 TextVertexBuffer* textVertexBuffer = new TextVertexBuffer;
309 VertexBuffer &vertexBuffer(textVertexBuffer->mVertices);
311 const GlyphMetric* glyph( NULL );
314 float underlineWidth( 0.0f );
315 float totalWidth( 0.0f );
316 float charWidth( 0.0f );
317 float charHeight( 0.0f );
321 float scalar = metrics.GetUnitsToPixels( format.GetPointSize() );
323 // Italics displacement
324 // the text is rendered upside down
325 const float sinAngle = format.IsItalic() ? std::sin( format.GetItalicsAngle() ) : 0.0f;
327 // get the line height and ascender from the font
328 const float lineHeight( metrics.GetLineHeight() * scalar );
329 const float ascender( metrics.GetAscender() * scalar );
330 const float padAdjustX( metrics.GetPadAdjustX() );
331 const float padAdjustY( metrics.GetPadAdjustY() );
332 const float tileWidth( metrics.GetMaxWidth() * scalar );
333 const float tileHeight( metrics.GetMaxHeight() * scalar );
335 for( TextArray::const_iterator it = text.begin(), endIt = text.end(); it != endIt; ++it )
337 const uint32_t charIndex = *it;
339 glyph = metrics.GetGlyph( charIndex );
341 if (charIndex >= SpecialCharacters::FIRST_VISIBLE_CHAR && glyph )
343 // get char size and offset adjusted for padding in the atlas
344 GetAdjustedSize(charWidth, charHeight, left, top, padAdjustX, padAdjustY, scalar, *glyph );
346 yPos = (ascender - top);
349 // a combination of character index and font id is used to uniquely identify the character
350 unsigned int encodedChar = GlyphStatus::GetEncodedValue( charIndex, fontId );
351 UvRect uv = uvInterface.GetUvCoordinates( encodedChar );
353 const Vector2 uvShadow( tileWidth / charWidth, tileHeight / charHeight );
355 AddVertex( vertexBuffer, xPos, yPos, charWidth, charHeight, uv, uvShadow );
357 if( format.IsItalic() )
359 float italicsTopDisplacement = ( top - charHeight ) * sinAngle;
360 float italicsBottomDisplacement = top * sinAngle;
361 AdjustForItalics( vertexBuffer, italicsTopDisplacement, italicsBottomDisplacement);
369 underlineWidth = std::max( underlineWidth, xPos + glyph->GetXAdvance() * scalar );
370 xPos += glyph->GetXAdvance() * scalar;
371 totalWidth = std::max(totalWidth, xPos);
375 if( format.IsUnderLined() )
377 unsigned int encodedChar = GlyphStatus::GetEncodedValue( SpecialCharacters::UNDERLINE_CHARACTER, fontId );
378 UvRect uv( uvInterface.GetUvCoordinates( encodedChar ));
380 glyph = metrics.GetGlyph( SpecialCharacters::UNDERLINE_CHARACTER );
384 // Adjust uv coordinates for scaling within atlas tile
385 GetAdjustedSize(charWidth, charHeight, left, top, padAdjustX, padAdjustY, scalar, *glyph );
387 // Get underline thickness and position.
388 // These values could be retrieved from the text-format, set to the text-actor through text-style,
389 // or retrieved directly from the font metrics.
390 float thickness = 0.f;
391 float position = 0.f;
393 if( fabs( format.GetUnderlineThickness() ) > Math::MACHINE_EPSILON_0 )
395 // Thickness and position retrieved from the format, which are passed to the
396 // text-actor through the text-style, it adds the vertical pad adjust used to fit some effects like glow or shadow..
397 thickness = -format.GetUnderlineThickness();
398 position = format.GetUnderlinePosition();
402 // Thickness and position retrieved from the font metrics.
403 // It adds the vertical pad adjust ( padAdjustY ) used to fit some effects like glow or shadow.
404 thickness = -( metrics.GetUnderlineThickness() + 2.f * padAdjustY ) * scalar;
405 position = ascender - ( metrics.GetUnderlinePosition() - padAdjustY ) * scalar;
407 AddUnderline( vertexBuffer, underlineWidth, thickness, position, uv );
411 textVertexBuffer->mVertexMax = Vector2( totalWidth, lineHeight );
412 RepositionData( *textVertexBuffer );
415 DebugVertexBuffer( vertexBuffer );
418 DALI_LOG_INFO(gTextVertsLogFilter, Debug::General, "TextVertexBuffer for %c%c%c...: Calculated Extents:(%5.2f, %5.2f)\n Geometry Extents:(%5.2f, %5.2f )\n",
419 text.size()>0?(char)text[0]:' ', text.size()>1?(char)text[1]:' ', text.size()>2?(char)text[2]:' ',
420 textVertexBuffer->mVertexMax.x,textVertexBuffer->mVertexMax.y,
421 textVertexBuffer->mGeometryExtent.width,textVertexBuffer->mGeometryExtent.height);
423 return textVertexBuffer;
426 } // namespace Internal