2996e58c5aac92fdc1b01a430c392a219d4f0838
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / renderers / svg / svg-visual.cpp
1 /*
2  * Copyright (c) 2016 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 "svg-visual.h"
20
21 // EXTERNAL INCLUDES
22 #include <dali/public-api/images/buffer-image.h>
23 #include <dali/public-api/common/stage.h>
24 #include <dali/public-api/math/vector4.h>
25 #include <dali/devel-api/images/atlas.h>
26 #include <dali/devel-api/images/texture-set-image.h>
27 #include <dali/integration-api/debug.h>
28
29 // INTERNAL INCLUDES
30 #include <dali-toolkit/third-party/nanosvg/nanosvg.h>
31 #include <dali-toolkit/internal/controls/renderers/svg/svg-rasterize-thread.h>
32 #include <dali-toolkit/internal/controls/renderers/image/image-visual.h>
33 #include <dali-toolkit/internal/controls/renderers/visual-factory-cache.h>
34 #include <dali-toolkit/internal/controls/renderers/visual-string-constants.h>
35 #include <dali-toolkit/internal/controls/renderers/visual-data-impl.h>
36
37
38 namespace
39 {
40 const char * const UNITS("px");
41
42 const Dali::Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
43 }
44
45 namespace Dali
46 {
47
48 namespace Toolkit
49 {
50
51 namespace Internal
52 {
53
54 SvgVisual::SvgVisual( VisualFactoryCache& factoryCache, ImageAtlasManager& atlasManager )
55 : Visual( factoryCache ),
56   mAtlasRect( FULL_TEXTURE_RECT ),
57   mAtlasManager( atlasManager ),
58   mParsedImage( NULL )
59 {
60   // the rasterized image is with pre-multiplied alpha format
61   mImpl->mFlags |= Impl::IS_PREMULTIPLIED_ALPHA;
62 }
63
64 SvgVisual::~SvgVisual()
65 {
66   if( mParsedImage )
67   {
68     nsvgDelete( mParsedImage );
69   }
70 }
71
72 bool SvgVisual::IsSvgUrl( const std::string& url )
73 {
74   return url.substr( url.find_last_of(".") + 1 ) == "svg";
75 }
76
77 void SvgVisual::DoInitialize( Actor& actor, const Property::Map& propertyMap )
78 {
79   Property::Value* imageURLValue = propertyMap.Find( IMAGE_URL_NAME );
80   if( imageURLValue )
81   {
82     std::string imageUrl;
83     if( imageURLValue->Get( imageUrl ) )
84     {
85       SetImage( imageUrl );
86     }
87     else
88     {
89       DALI_LOG_ERROR( "The property '%s' is not a string\n", IMAGE_URL_NAME );
90     }
91   }
92 }
93
94 void SvgVisual::DoSetOnStage( Actor& actor )
95 {
96   Shader shader = ImageVisual::GetImageShader( mFactoryCache );
97   Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
98   if( !geometry )
99   {
100     geometry =  mFactoryCache.CreateQuadGeometry();
101     mFactoryCache.SaveGeometry( VisualFactoryCache::QUAD_GEOMETRY, geometry );
102   }
103   TextureSet textureSet = TextureSet::New();
104   mImpl->mRenderer = Renderer::New( geometry, shader );
105   mImpl->mRenderer.SetTextures( textureSet );
106
107   if( mImpl->mSize != Vector2::ZERO && mParsedImage )
108   {
109     AddRasterizationTask( mImpl->mSize );
110   }
111 }
112
113 void SvgVisual::DoSetOffStage( Actor& actor )
114 {
115   mFactoryCache.GetSVGRasterizationThread()->RemoveTask( this );
116
117   actor.RemoveRenderer( mImpl->mRenderer );
118   mImpl->mRenderer.Reset();
119 }
120
121 void SvgVisual::GetNaturalSize( Vector2& naturalSize ) const
122 {
123   if( mParsedImage )
124   {
125     naturalSize.x = mParsedImage->width;
126     naturalSize.y = mParsedImage->height;
127   }
128   else
129   {
130     naturalSize = Vector2::ZERO;
131   }
132 }
133
134 void SvgVisual::SetSize( const Vector2& size )
135 {
136   if(mImpl->mSize != size && mParsedImage && GetIsOnStage() )
137   {
138     AddRasterizationTask( size );
139   }
140   mImpl->mSize = size;
141 }
142
143 void SvgVisual::DoCreatePropertyMap( Property::Map& map ) const
144 {
145   map.Clear();
146   map.Insert( RENDERER_TYPE, IMAGE_RENDERER );
147   if( !mImageUrl.empty() )
148   {
149     map.Insert( IMAGE_URL_NAME, mImageUrl );
150   }
151 }
152
153 void SvgVisual::SetImage( const std::string& imageUrl, ImageDimensions size )
154 {
155   if( mImageUrl != imageUrl )
156   {
157     mImageUrl = imageUrl;
158
159     NSVGimage* parsedImageOld = mParsedImage;
160
161     Vector2 dpi = Stage::GetCurrent().GetDpi();
162     float meanDpi = (dpi.height + dpi.width) * 0.5f;
163     mParsedImage = nsvgParseFromFile(mImageUrl.c_str(), UNITS, meanDpi);
164
165     if( size.GetWidth() != 0u && size.GetHeight() != 0u)
166     {
167       mImpl->mSize.x = size.GetWidth();
168       mImpl->mSize.y = size.GetHeight();
169     }
170
171     if( mImpl->mSize != Vector2::ZERO && GetIsOnStage() )
172     {
173       AddRasterizationTask( mImpl->mSize );
174     }
175
176     mFactoryCache.GetSVGRasterizationThread()->DeleteImage( parsedImageOld );
177   }
178 }
179
180 void SvgVisual::AddRasterizationTask( const Vector2& size )
181 {
182   if( mImpl->mRenderer && mParsedImage )
183   {
184     unsigned int width = static_cast<unsigned int>(size.width);
185     unsigned int height = static_cast<unsigned int>( size.height );
186     BufferImage image = BufferImage::New( width, height, Pixel::RGBA8888);
187
188     RasterizingTaskPtr newTask = new RasterizingTask( this, mParsedImage, width, height );
189     mFactoryCache.GetSVGRasterizationThread()->AddTask( newTask );
190   }
191 }
192
193 void SvgVisual::ApplyRasterizedImage( PixelData rasterizedPixelData )
194 {
195   if( GetIsOnStage()  )
196   {
197     TextureSet currentTextureSet = mImpl->mRenderer.GetTextures();
198     if( mAtlasRect != FULL_TEXTURE_RECT )
199     {
200       mAtlasManager.Remove( currentTextureSet, mAtlasRect );
201     }
202
203     Vector4 atlasRect;
204     TextureSet textureSet = mAtlasManager.Add(atlasRect, rasterizedPixelData );
205     if( textureSet ) // atlasing
206     {
207       if( textureSet != currentTextureSet )
208       {
209         mImpl->mRenderer.SetTextures( textureSet );
210       }
211       mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, atlasRect );
212       mAtlasRect = atlasRect;
213     }
214     else // no atlasing
215     {
216       Atlas texture = Atlas::New( rasterizedPixelData.GetWidth(), rasterizedPixelData.GetHeight() );
217       texture.Upload( rasterizedPixelData, 0, 0 );
218
219       if( mAtlasRect == FULL_TEXTURE_RECT )
220       {
221         textureSet = currentTextureSet;
222       }
223       else
224       {
225         textureSet = TextureSet::New();
226         mImpl->mRenderer.SetTextures( textureSet );
227
228         mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, FULL_TEXTURE_RECT );
229         mAtlasRect = FULL_TEXTURE_RECT;
230       }
231
232       if( textureSet )
233       {
234         TextureSetImage( textureSet, 0u, texture );
235       }
236     }
237   }
238 }
239
240
241
242 } // namespace Internal
243
244 } // namespace Toolkit
245
246 } // namespace Dali