Merged with Tizen Branch ( builds )
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / rendering / basic / text-basic-renderer.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/internal/text/rendering/basic/text-basic-renderer.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/public-api/text-abstraction/font-client.h>
23 #include <dali/public-api/actors/image-actor.h>
24 #include <dali/public-api/images/atlas.h>
25 #include <dali-toolkit/internal/text/rendering/shaders/text-basic-shader.h>
26 #include <dali-toolkit/internal/text/rendering/shaders/text-bgra-shader.h>
27
28
29 using namespace Dali;
30 using namespace Dali::Toolkit;
31 using namespace Dali::Toolkit::Text;
32
33 namespace
34 {
35
36 const std::size_t PADDING = 2; //< To avoid GL filtering artefacts
37
38 struct TextureCoordinates
39 {
40   TextureCoordinates()
41   : topLeft( 0.0f, 0.0f ),
42     topRight( 1.0f, 0.0f ),
43     bottomLeft( 0.0f, 1.0f ),
44     bottomRight( 1.0f, 1.0f )
45   {
46   }
47
48   Vector2 topLeft;
49   Vector2 topRight;
50   Vector2 bottomLeft;
51   Vector2 bottomRight;
52 };
53
54 struct AtlasGlyph
55 {
56   AtlasGlyph()
57   : fontId( 0 ),
58     index( 0 ),
59     xOffset( 0 ),
60     width( 0 ),
61     height( 0 )
62   {
63   }
64
65   AtlasGlyph( FontId id,
66               GlyphIndex glyphIndex,
67               std::size_t offset,
68               std::size_t widthPixels,
69               std::size_t heightPixels,
70               BufferImage bitmap )
71   : fontId( id ),
72     index( glyphIndex ),
73     xOffset( offset ),
74     width( widthPixels ),
75     height( heightPixels ),
76     mBitmap( bitmap )
77   {
78   }
79
80   FontId fontId;
81   GlyphIndex index;
82   std::size_t xOffset;
83   std::size_t width;
84   std::size_t height;
85   BufferImage mBitmap;
86   TextureCoordinates coords;
87 };
88
89 } // unnamed namespace
90
91 struct BasicRenderer::Impl
92 {
93   /**
94    * @brief Create the renderer implementation.
95    */
96   Impl()
97   : mWidthL8( 0.0f ),
98     mHeightL8( 0.0f ),
99     mWidthBGRA8888( 0.0f ),
100     mHeightBGRA8888( 0.0f )
101   {
102     mFontClient = TextAbstraction::FontClient::Get();
103   }
104
105   /**
106    * @brief Reset the previous glyph calculations.
107    *
108    * @param[in] size The glyph space to reserve.
109    */
110   void Reset( std::size_t size )
111   {
112     mWidthL8 = 0.0f;
113     mHeightL8 = 0.0f;
114     mWidthBGRA8888 = 0.0f;
115     mHeightBGRA8888 = 0.0f;
116     mGlyphs.clear();
117     mGlyphs.reserve( size );
118     mAtlasL8.Reset();
119     mAtlasBGRA8888.Reset();
120   }
121
122   /**
123    * @brief Ccreate an Atlas, uploading the necessary glyph bitmaps
124    *
125    * @param[in] glyphs The glyphs to upload.
126    */
127   void CreateAtlases( const Vector<GlyphInfo>& glyphs )
128   {
129     // Clear previous atlas
130     Reset( glyphs.Count() );
131
132     for( unsigned int i=0; i<glyphs.Count(); ++i )
133     {
134       float width  = glyphs[i].width;
135       float height = glyphs[i].height;
136
137       if( width > 0 &&
138           height > 0 ) // skip whitespace
139       {
140         if( !GlyphFound( glyphs[i].fontId, glyphs[i].index ) )
141         {
142           AddGlyph( glyphs[i] );
143         }
144       }
145     }
146
147     mAtlasL8 = CreateAtlas( mWidthL8, mHeightL8, Pixel::L8 );
148     mAtlasBGRA8888 = CreateAtlas( mWidthBGRA8888, mHeightBGRA8888, Pixel::BGRA8888 );
149   }
150
151   Atlas CreateAtlas( unsigned int width, unsigned int height, Pixel::Format format )
152   {
153     Atlas atlas;
154
155     if( width > 0 && height > 0 )
156     {
157       atlas = Atlas::New( width, height, format );
158
159       for( unsigned int i=0; i<mGlyphs.size(); ++i )
160       {
161         AtlasGlyph& glyph = mGlyphs[i];
162
163         const Pixel::Format glyphFormat = glyph.mBitmap.GetPixelFormat();
164
165         if( format == glyphFormat )
166         {
167           atlas.Upload( glyph.mBitmap, glyph.xOffset, 0 );
168
169           TextureCoordinates& coords = glyph.coords;
170           coords.topLeft.x     = static_cast<float>(glyph.xOffset) / static_cast<float>(width);
171           coords.topLeft.y     = 0.0f;
172           coords.topRight.x    = static_cast<float>(glyph.xOffset + glyph.width) / static_cast<float>(width);
173           coords.topRight.y    = 0.0f;
174           coords.bottomLeft.x  = static_cast<float>(glyph.xOffset) / static_cast<float>(width);
175           coords.bottomLeft.y  = static_cast<float>(glyph.height) / static_cast<float>(height);
176           coords.bottomRight.x = static_cast<float>(glyph.xOffset + glyph.width) / static_cast<float>(width);
177           coords.bottomRight.y = static_cast<float>(glyph.height) / static_cast<float>(height);
178         }
179       }
180     }
181
182     return atlas;
183   }
184
185   /**
186    * @brief Check whether we already have the glyph.
187    */
188   bool GlyphFound( FontId fontId, GlyphIndex index ) const
189   {
190     for( unsigned int i=0; i<mGlyphs.size(); ++i )
191     {
192       const AtlasGlyph& glyph = mGlyphs[i];
193
194       if( fontId == glyph.fontId &&
195           index  == glyph.index )
196       {
197         return true;
198       }
199     }
200
201     return false;
202   }
203
204   /**
205    * @brief Add the glyph.
206    */
207   void AddGlyph( const GlyphInfo& glyphInfo )
208   {
209     BufferImage bitmap = mFontClient.CreateBitmap( glyphInfo.fontId, glyphInfo.index );
210
211     const Pixel::Format format = bitmap.GetPixelFormat();
212
213     if( Pixel::L8 == format )
214     {
215       mGlyphs.push_back( AtlasGlyph( glyphInfo.fontId, glyphInfo.index, mWidthL8, glyphInfo.width, glyphInfo.height, bitmap ) );
216
217       // Increase the Atlas width/height
218       mWidthL8 += glyphInfo.width + PADDING;
219       if( mHeightL8 < glyphInfo.height + PADDING )
220       {
221         mHeightL8 = glyphInfo.height + PADDING;
222       }
223     }
224     else if ( Pixel::BGRA8888 == format )
225     {
226        mGlyphs.push_back( AtlasGlyph( glyphInfo.fontId, glyphInfo.index, mWidthBGRA8888, glyphInfo.width, glyphInfo.height, bitmap ) );
227
228       // A separate Atlas is used for color Emojis
229       mWidthBGRA8888 += glyphInfo.width + PADDING;
230       if( mHeightBGRA8888 < glyphInfo.height + PADDING )
231       {
232         mHeightBGRA8888 = glyphInfo.height + PADDING;
233       }
234     }
235   }
236
237   /**
238    * @brief Get the texture coordinates for a glyph.
239    */
240   bool GetTextureCoordinates( Pixel::Format format, FontId fontId, GlyphIndex index, TextureCoordinates& coords )
241   {
242     for( unsigned int i=0; i<mGlyphs.size(); ++i )
243     {
244       const AtlasGlyph& glyph = mGlyphs[i];
245
246       const Pixel::Format glyphFormat = glyph.mBitmap.GetPixelFormat();
247
248       if( format == glyphFormat &&
249           fontId == glyph.fontId &&
250           index  == glyph.index )
251       {
252         coords = glyph.coords;
253         return true;
254       }
255     }
256
257     return false;
258   }
259
260   /**
261    * @brief Helper method to create a mesh with one quad per glyph.
262    *
263    * @param[in] glyphs The glyphs to display.
264    * @param[in] positions The 2D positions of the glyphs.
265    * @param[in] image The material uses this as a diffuse texture.
266    */
267   /*
268   Mesh CreateMesh( const Vector<GlyphInfo>& glyphs, const std::vector<Vector2>& positions, Pixel::Format format, Image image )
269   {
270     MeshData::VertexContainer vertices( 4 * glyphs.Count() ); // 1 quad per glyph
271
272     MeshData::FaceIndices faces;
273     faces.reserve( 6 * glyphs.Count() ); // 2 triangles per quad
274
275     for( unsigned int i=0; i<glyphs.Count(); ++i )
276     {
277       float width  = glyphs[i].width;
278       float height = glyphs[i].height;
279
280       if( width > 0 &&
281           height > 0 ) // skip whitespace
282       {
283         const Vector2& position = positions[i];
284
285         TextureCoordinates coords;
286         if( GetTextureCoordinates( format, glyphs[i].fontId, glyphs[i].index, coords ) )
287         {
288           vertices[ i*4 + 0 ] = MeshData::Vertex( Vector3( position.x + 0.0f*width, position.y + 0.0f*height, 0.0f ), coords.topLeft,     Vector3( 1.0f, 0.0f, 0.0f ) );
289           vertices[ i*4 + 1 ] = MeshData::Vertex( Vector3( position.x + 1.0f*width, position.y + 0.0f*height, 0.0f ), coords.topRight,    Vector3( 1.0f, 1.0f, 0.0f ) );
290           vertices[ i*4 + 2 ] = MeshData::Vertex( Vector3( position.x + 0.0f*width, position.y + 1.0f*height, 0.0f ), coords.bottomLeft,  Vector3( 0.0f, 1.0f, 0.0f ) );
291           vertices[ i*4 + 3 ] = MeshData::Vertex( Vector3( position.x + 1.0f*width, position.y + 1.0f*height, 0.0f ), coords.bottomRight, Vector3( 0.0f, 0.0f, 1.0f ) );
292
293           faces.push_back( i*4 + 0 ); faces.push_back( i*4 + 3 ); faces.push_back( i*4 + 1 );
294           faces.push_back( i*4 + 0 ); faces.push_back( i*4 + 2 ); faces.push_back( i*4 + 3 );
295         }
296       }
297     }
298
299     Material material = Material::New( "Material" );
300     material.SetDiffuseTexture( image );
301
302     // Create the mesh data from the vertices and faces
303     MeshData meshData;
304     meshData.SetHasColor( false );
305     meshData.SetMaterial( material );
306     meshData.SetVertices( vertices );
307     meshData.SetFaceIndices( faces );
308
309     // Create a mesh from the data
310     Dali::Mesh mesh = Mesh::New( meshData );
311     return mesh;
312   }
313   */
314   Actor mActor; ///< The actor which renders the text
315
316   Atlas mAtlasL8;
317   unsigned int mWidthL8;
318   unsigned int mHeightL8;
319
320   // A separate Atlas is used for color Emojis
321   Atlas mAtlasBGRA8888;
322   unsigned int mWidthBGRA8888;
323   unsigned int mHeightBGRA8888;
324
325   std::vector<AtlasGlyph> mGlyphs;
326
327   TextAbstraction::FontClient mFontClient;
328 };
329
330 Text::RendererPtr BasicRenderer::New()
331 {
332   return Text::RendererPtr( new BasicRenderer() );
333 }
334
335 Actor BasicRenderer::Render( Text::ViewInterface& view )
336 {
337   // Remove the previous text
338   UnparentAndReset( mImpl->mActor );
339
340   Text::Length numberOfGlyphs = view.GetNumberOfGlyphs();
341
342   if( numberOfGlyphs > 0 )
343   {
344     Vector<GlyphInfo> glyphs;
345     glyphs.Resize( numberOfGlyphs );
346
347     view.GetGlyphs( &glyphs[0], 0, numberOfGlyphs );
348
349     std::vector<Vector2> positions;
350     positions.resize( numberOfGlyphs );
351     view.GetGlyphPositions( &positions[0], 0, numberOfGlyphs );
352
353     mImpl->CreateAtlases( glyphs );
354
355     Actor actorL8;
356     if( mImpl->mAtlasL8 )
357     {
358       //actorL8 = MeshActor::New( mImpl->CreateMesh( glyphs, positions, Pixel::L8, mImpl->mAtlasL8 ) );
359       actorL8.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
360
361       ShaderEffect shader = BasicShader::New();
362       //actorL8.SetShaderEffect( shader );
363     }
364
365     Actor actorBGRA8888;
366     if( mImpl->mAtlasBGRA8888 )
367     {
368       //actorBGRA8888 = MeshActor::New( mImpl->CreateMesh( glyphs, positions, Pixel::BGRA8888, mImpl->mAtlasBGRA8888 ) );
369       actorBGRA8888.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
370
371       ShaderEffect shader = BgraShader::New();
372       //actorBGRA8888.SetShaderEffect( shader );
373     }
374
375     // If we have both monochrome & color glyphs, two mesh actors are returned in a container
376     if( actorL8 && actorBGRA8888 )
377     {
378       mImpl->mActor = ImageActor::New();
379       mImpl->mActor.Add( actorL8 );
380       mImpl->mActor.Add( actorBGRA8888 );
381     }
382     else
383     {
384       if( actorL8 )
385       {
386         mImpl->mActor = actorL8;
387       }
388       else if( actorBGRA8888 )
389       {
390         mImpl->mActor = actorBGRA8888;
391       }
392     }
393   }
394
395   return mImpl->mActor;
396 }
397
398 BasicRenderer::BasicRenderer()
399 {
400   mImpl = new Impl();
401 }
402
403 BasicRenderer::~BasicRenderer()
404 {
405   delete mImpl;
406 }