AnimatedImageVisual 35/103235/11
authorXiangyin Ma <x1.ma@samsung.com>
Wed, 7 Dec 2016 15:49:35 +0000 (15:49 +0000)
committerXiangyin Ma <x1.ma@samsung.com>
Fri, 16 Dec 2016 11:45:30 +0000 (11:45 +0000)
Change-Id: I6d00000865b02fbdd1f47880e68b3b554da61d1c

17 files changed:
automated-tests/resources/anim.gif [new file with mode: 0644]
automated-tests/src/dali-toolkit-internal/utc-Dali-VisualFactoryResolveUrl.cpp
automated-tests/src/dali-toolkit/utc-Dali-Visual.cpp
automated-tests/src/dali-toolkit/utc-Dali-VisualFactory.cpp
dali-toolkit/internal/file.list
dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp [new file with mode: 0644]
dali-toolkit/internal/visuals/animated-image/animated-image-visual.h [new file with mode: 0644]
dali-toolkit/internal/visuals/color/color-visual.cpp
dali-toolkit/internal/visuals/gradient/gradient-visual.cpp
dali-toolkit/internal/visuals/image/image-visual.cpp
dali-toolkit/internal/visuals/svg/svg-visual.cpp
dali-toolkit/internal/visuals/text/text-visual.cpp
dali-toolkit/internal/visuals/visual-factory-cache.cpp
dali-toolkit/internal/visuals/visual-factory-impl.cpp
dali-toolkit/internal/visuals/visual-factory-resolve-url.h
docs/content/images/visuals/animated-image-visual.gif [new file with mode: 0644]
docs/content/shared-javascript-and-cpp-documentation/visuals.md

diff --git a/automated-tests/resources/anim.gif b/automated-tests/resources/anim.gif
new file mode 100644 (file)
index 0000000..f66f076
Binary files /dev/null and b/automated-tests/resources/anim.gif differ
index f859b74..8235355 100644 (file)
@@ -30,8 +30,6 @@ int UtcDaliResolveUrlRegularImage(void)
 
   DALI_TEST_EQUALS( UrlType::REGULAR_IMAGE, ResolveUrlType("foobar.jpeg"), TEST_LOCATION );
 
 
   DALI_TEST_EQUALS( UrlType::REGULAR_IMAGE, ResolveUrlType("foobar.jpeg"), TEST_LOCATION );
 
-  DALI_TEST_EQUALS( UrlType::REGULAR_IMAGE, ResolveUrlType("foobar.gif"), TEST_LOCATION );
-
   DALI_TEST_EQUALS( UrlType::REGULAR_IMAGE, ResolveUrlType("foobar.PNG"), TEST_LOCATION );
 
   DALI_TEST_EQUALS( UrlType::REGULAR_IMAGE, ResolveUrlType("foobar.Png123"), TEST_LOCATION );
   DALI_TEST_EQUALS( UrlType::REGULAR_IMAGE, ResolveUrlType("foobar.PNG"), TEST_LOCATION );
 
   DALI_TEST_EQUALS( UrlType::REGULAR_IMAGE, ResolveUrlType("foobar.Png123"), TEST_LOCATION );
@@ -78,8 +76,6 @@ int UtcDaliResolveUrlNPatch(void)
 {
   tet_infoline( "UtcDaliResolveUrl N_PATCH" );
 
 {
   tet_infoline( "UtcDaliResolveUrl N_PATCH" );
 
-  DALI_TEST_EQUALS( UrlType::N_PATCH, ResolveUrlType("foobar.9.gif"), TEST_LOCATION );
-
   DALI_TEST_EQUALS( UrlType::N_PATCH, ResolveUrlType("foobar.#.png"), TEST_LOCATION );
 
   DALI_TEST_EQUALS( UrlType::N_PATCH, ResolveUrlType("foobar.9.9.bmp"), TEST_LOCATION );
   DALI_TEST_EQUALS( UrlType::N_PATCH, ResolveUrlType("foobar.#.png"), TEST_LOCATION );
 
   DALI_TEST_EQUALS( UrlType::N_PATCH, ResolveUrlType("foobar.9.9.bmp"), TEST_LOCATION );
@@ -94,3 +90,26 @@ int UtcDaliResolveUrlNPatch(void)
 
   END_TEST;
 }
 
   END_TEST;
 }
+
+int UtcDaliResolveUrlGif(void)
+{
+  tet_infoline( "UtcDaliResolveUrl GIF" );
+
+  DALI_TEST_EQUALS( UrlType::GIF, ResolveUrlType("foobar.gif"), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( UrlType::GIF, ResolveUrlType("foobar.gif.gif"), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( UrlType::GIF, ResolveUrlType("foobar.giF"), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( UrlType::GIF, ResolveUrlType("foobar.GIF"), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( UrlType::GIF, ResolveUrlType(".GiF"), TEST_LOCATION );
+
+  // GIFs aren't N-patch
+  DALI_TEST_EQUALS( UrlType::GIF, ResolveUrlType("foobar.9.gif"), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( UrlType::REGULAR_IMAGE, ResolveUrlType("gif.png"), TEST_LOCATION );
+  DALI_TEST_EQUALS( UrlType::REGULAR_IMAGE, ResolveUrlType("gif.gif1"), TEST_LOCATION );
+
+  END_TEST;
+}
index fae713a..4885bc2 100644 (file)
@@ -38,6 +38,7 @@ namespace
 const char* TEST_IMAGE_FILE_NAME =  TEST_RESOURCE_DIR "/gallery-small-1.jpg";
 const char* TEST_NPATCH_FILE_NAME =  "gallery_image_01.9.jpg";
 const char* TEST_SVG_FILE_NAME = TEST_RESOURCE_DIR "/svg1.svg";
 const char* TEST_IMAGE_FILE_NAME =  TEST_RESOURCE_DIR "/gallery-small-1.jpg";
 const char* TEST_NPATCH_FILE_NAME =  "gallery_image_01.9.jpg";
 const char* TEST_SVG_FILE_NAME = TEST_RESOURCE_DIR "/svg1.svg";
+const char* TEST_GIF_FILE_NAME = TEST_RESOURCE_DIR "/anim.gif";
 const char* TEST_OBJ_FILE_NAME = TEST_RESOURCE_DIR "/Cube.obj";
 const char* TEST_MTL_FILE_NAME = TEST_RESOURCE_DIR "/ToyRobot-Metal.mtl";
 const char* TEST_RESOURCE_LOCATION = TEST_RESOURCE_DIR "/";
 const char* TEST_OBJ_FILE_NAME = TEST_RESOURCE_DIR "/Cube.obj";
 const char* TEST_MTL_FILE_NAME = TEST_RESOURCE_DIR "/ToyRobot-Metal.mtl";
 const char* TEST_RESOURCE_LOCATION = TEST_RESOURCE_DIR "/";
@@ -292,6 +293,14 @@ int UtcDaliVisualSize(void)
   const float height = textVisual.GetHeightForWidth( 40.f );
   DALI_TEST_EQUALS( height, 40.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
 
   const float height = textVisual.GetHeightForWidth( 40.f );
   DALI_TEST_EQUALS( height, 40.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
 
+  //AnimatedImageVisual
+  Visual::Base animatedImageVisual = factory.CreateVisual( TEST_GIF_FILE_NAME, ImageDimensions() );
+  animatedImageVisual.SetTransformAndSize(DefaultTransform(), controlSize );
+  animatedImageVisual.GetNaturalSize(naturalSize);
+  // TEST_GIF_FILE: anim.gif
+  // resolution: 50*50, frame count: 4, frame delay: 0.2 second for each frame
+  DALI_TEST_EQUALS( naturalSize, Vector2(50.f, 50.f), TEST_LOCATION );
+
   END_TEST;
 }
 
   END_TEST;
 }
 
@@ -990,6 +999,45 @@ int UtcDaliVisualGetPropertyMap10(void)
   END_TEST;
 }
 
   END_TEST;
 }
 
+int UtcDaliVisualGetPropertyMap11(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualGetPropertyMap7: AnimatedImageVisual" );
+
+  // request SvgVisual with a property map
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  Visual::Base svgVisual = factory.CreateVisual( Property::Map()
+                                                 .Add( Visual::Property::TYPE,  Visual::IMAGE )
+                                                 .Add( ImageVisual::Property::URL, TEST_GIF_FILE_NAME ) );
+
+  Property::Map resultMap;
+  svgVisual.CreatePropertyMap( resultMap );
+  // check the property values from the returned map from a visual
+  Property::Value* value = resultMap.Find( Visual::Property::TYPE,  Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<int>() == Visual::IMAGE );
+
+  value = resultMap.Find( ImageVisual::Property::URL,  Property::STRING );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<std::string>() == TEST_GIF_FILE_NAME );
+
+  // request SvgVisual with an URL
+  Visual::Base svgVisual2 = factory.CreateVisual( TEST_GIF_FILE_NAME, ImageDimensions() );
+  resultMap.Clear();
+  svgVisual2.CreatePropertyMap( resultMap );
+  // check the property values from the returned map from a visual
+  value = resultMap.Find( Visual::Property::TYPE,  Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<int>() == Visual::IMAGE );
+
+  value = resultMap.Find( ImageVisual::Property::URL,  Property::STRING );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<std::string>() == TEST_GIF_FILE_NAME );
+
+  END_TEST;
+}
+
 int UtcDaliVisualGetPropertyMapBatchImageVisualNoAtlas(void)
 {
   ToolkitTestApplication application;
 int UtcDaliVisualGetPropertyMapBatchImageVisualNoAtlas(void)
 {
   ToolkitTestApplication application;
index b186ea4..0e9c014 100644 (file)
@@ -17,6 +17,7 @@
 #include <iostream>
 #include <stdlib.h>
 #include <dali-toolkit-test-suite-utils.h>
 #include <iostream>
 #include <stdlib.h>
 #include <dali-toolkit-test-suite-utils.h>
+#include <toolkit-timer.h>
 #include <toolkit-bitmap-loader.h>
 #include <toolkit-event-thread-callback.h>
 #include <dali/public-api/rendering/renderer.h>
 #include <toolkit-bitmap-loader.h>
 #include <toolkit-event-thread-callback.h>
 #include <dali/public-api/rendering/renderer.h>
@@ -44,6 +45,9 @@ const char* TEST_MTL_FILE_NAME = TEST_RESOURCE_DIR "/ToyRobot-Metal.mtl";
 const char* TEST_SIMPLE_OBJ_FILE_NAME = TEST_RESOURCE_DIR "/Cube-Points-Only.obj";
 const char* TEST_SIMPLE_MTL_FILE_NAME = TEST_RESOURCE_DIR "/ToyRobot-Metal-Simple.mtl";
 
 const char* TEST_SIMPLE_OBJ_FILE_NAME = TEST_RESOURCE_DIR "/Cube-Points-Only.obj";
 const char* TEST_SIMPLE_MTL_FILE_NAME = TEST_RESOURCE_DIR "/ToyRobot-Metal-Simple.mtl";
 
+// resolution: 50*50, frame count: 4, frame delay: 0.2 second for each frame
+const char* TEST_GIF_FILE_NAME = TEST_RESOURCE_DIR "/anim.gif";
+
 // resolution: 34*34, pixel format: RGBA8888
 static const char* gImage_34_RGBA = TEST_RESOURCE_DIR "/icon-edit.png";
 // resolution: 600*600, pixel format: RGB888
 // resolution: 34*34, pixel format: RGBA8888
 static const char* gImage_34_RGBA = TEST_RESOURCE_DIR "/icon-edit.png";
 // resolution: 600*600, pixel format: RGB888
@@ -2051,3 +2055,82 @@ int UtcDaliVisualFactoryGetBatchImageVisual3(void)
 
   END_TEST;
 }
 
   END_TEST;
 }
+
+int UtcDaliVisualFactoryGetAnimatedImageVisual(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualFactoryGetAnimatedImageVisual: Request animated image visual with a gif url" );
+
+  VisualFactory factory = VisualFactory::Get();
+  Visual::Base visual = factory.CreateVisual( TEST_GIF_FILE_NAME, ImageDimensions() );
+  DALI_TEST_CHECK( visual );
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  DummyControl actor = DummyControl::New();
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+  Stage::GetCurrent().Add( actor );
+
+  application.SendNotification();
+  application.Render();
+
+  // renderer is added to actor
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+
+  // test the uniforms which used to handle the atlas rect
+  // the four frames should be located inside atlas as follows: atlas size 100*100
+  // -------------
+  // |     |     |
+  // |  0  |  1  |
+  // -------------
+  // |     |     |
+  // |  2  |  3  |
+  // -------------
+
+  Renderer renderer = actor.GetRendererAt( 0u );
+  DALI_TEST_CHECK( renderer );
+
+  Property::Value atlasRectValue = renderer.GetProperty( renderer.GetPropertyIndex( "uAtlasRect" ) );
+  // take into consideration the half pixel correction
+  DALI_TEST_EQUALS( atlasRectValue.Get<Vector4>(), Vector4(0.5f, 0.5f, 49.5f, 49.5f)/100.f, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  // waiting for the resource uploading
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+  // Force the timer used by the animatedImageVisual to tick,
+  Dali::Timer timer = Timer::New( 0 );
+  timer.MockEmitSignal();
+  application.SendNotification();
+  application.Render();
+  atlasRectValue = renderer.GetProperty( renderer.GetPropertyIndex( "uAtlasRect" ) );
+  // take into consideration the half pixel correction
+  DALI_TEST_EQUALS( atlasRectValue.Get<Vector4>(), Vector4(50.5f, 0.5f, 99.5f, 49.5f)/100.f, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  // Force the timer used by the animatedImageVisual to tick,
+  timer.MockEmitSignal();
+  application.SendNotification();
+  application.Render();
+  atlasRectValue = renderer.GetProperty( renderer.GetPropertyIndex( "uAtlasRect" ) );
+  // take into consideration the half pixel correction
+  DALI_TEST_EQUALS( atlasRectValue.Get<Vector4>(), Vector4(0.5f, 50.5f, 49.5f, 99.5f)/100.f, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  // Force the timer used by the animatedImageVisual to tick,
+  timer.MockEmitSignal();
+  application.SendNotification();
+  application.Render();
+  atlasRectValue = renderer.GetProperty( renderer.GetPropertyIndex( "uAtlasRect" ) );
+  // take into consideration the half pixel correction
+  DALI_TEST_EQUALS( atlasRectValue.Get<Vector4>(), Vector4(50.5f, 50.5f, 99.5f, 99.5f)/100.f, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  // Test SetOffStage().
+  actor.Unparent();
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  END_TEST;
+}
index 7fa3af7..a4f49d9 100644 (file)
@@ -17,6 +17,7 @@ toolkit_src_files = \
    $(toolkit_src_dir)/visuals/visual-factory-cache.cpp \
    $(toolkit_src_dir)/visuals/visual-factory-impl.cpp \
    $(toolkit_src_dir)/visuals/visual-string-constants.cpp \
    $(toolkit_src_dir)/visuals/visual-factory-cache.cpp \
    $(toolkit_src_dir)/visuals/visual-factory-impl.cpp \
    $(toolkit_src_dir)/visuals/visual-string-constants.cpp \
+   $(toolkit_src_dir)/visuals/animated-image/animated-image-visual.cpp \
    $(toolkit_src_dir)/visuals/border/border-visual.cpp \
    $(toolkit_src_dir)/visuals/color/color-visual.cpp \
    $(toolkit_src_dir)/visuals/gradient/gradient.cpp \
    $(toolkit_src_dir)/visuals/border/border-visual.cpp \
    $(toolkit_src_dir)/visuals/color/color-visual.cpp \
    $(toolkit_src_dir)/visuals/gradient/gradient.cpp \
diff --git a/dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp b/dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp
new file mode 100644 (file)
index 0000000..5a3a154
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "animated-image-visual.h"
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/gif-loading.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/visuals/image-visual-properties.h>
+#include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
+#include <dali-toolkit/internal/visuals/visual-factory-impl.h>
+#include <dali-toolkit/internal/visuals/visual-factory-cache.h>
+#include <dali-toolkit/internal/visuals/visual-string-constants.h>
+#include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
+#include <dali-toolkit/internal/visuals/image/image-visual.h>
+#include <dali-toolkit/devel-api/image-loader/image-atlas.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+AnimatedImageVisualPtr AnimatedImageVisual::New( VisualFactoryCache& factoryCache, const std::string& imageUrl, const Property::Map& properties )
+{
+  AnimatedImageVisual* visual = new AnimatedImageVisual( factoryCache );
+  visual->mImageUrl = imageUrl;
+  visual->SetProperties( properties );
+
+  return visual;
+}
+
+AnimatedImageVisualPtr AnimatedImageVisual::New( VisualFactoryCache& factoryCache, const std::string& imageUrl )
+{
+  AnimatedImageVisual* visual = new AnimatedImageVisual( factoryCache );
+  visual->mImageUrl = imageUrl;
+
+  return visual;
+}
+
+AnimatedImageVisual::AnimatedImageVisual( VisualFactoryCache& factoryCache )
+: Visual::Base( factoryCache ),
+  mFrameDelayTimer(),
+  mImageUrl(),
+  mImageSize(),
+  mCurrentFrameIndex( 0 )
+{}
+
+AnimatedImageVisual::~AnimatedImageVisual()
+{
+}
+
+void AnimatedImageVisual::GetNaturalSize( Vector2& naturalSize )
+{
+  if( mImageSize.GetWidth() == 0 &&  mImageSize.GetHeight() == 0)
+  {
+    mImageSize = Dali::GetGifImageSize( mImageUrl );
+  }
+
+  naturalSize.width = mImageSize.GetWidth();
+  naturalSize.height = mImageSize.GetHeight();
+}
+
+void AnimatedImageVisual::DoCreatePropertyMap( Property::Map& map ) const
+{
+  map.Clear();
+  map.Insert( Toolkit::DevelVisual::Property::TYPE, Toolkit::Visual::IMAGE );
+  if( !mImageUrl.empty() )
+  {
+    map.Insert( Toolkit::ImageVisual::Property::URL, mImageUrl );
+  }
+}
+
+void AnimatedImageVisual::DoSetProperties( const Property::Map& propertyMap )
+{
+  // url already passed in from constructor
+}
+
+void AnimatedImageVisual::DoSetOnStage( Actor& actor )
+{
+  Texture texture = PrepareAnimatedImage();
+  if( texture ) // if the image loading is successful
+  {
+    Shader shader = ImageVisual::GetImageShader( mFactoryCache, true, true );
+    Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
+    TextureSet textureSet = TextureSet::New();
+    mImpl->mRenderer = Renderer::New( geometry, shader );
+    mImpl->mRenderer.SetTextures( textureSet );
+    textureSet.SetTexture( 0u, PrepareAnimatedImage() );
+    mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, mTextureRectContainer[0] );
+
+    // Register transform properties
+    mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
+
+    mCurrentFrameIndex = 0;
+    if( mFrameDelayContainer.Count() > 1 )
+    {
+      mFrameDelayTimer = Timer::New( mFrameDelayContainer[0] );
+      mFrameDelayTimer.TickSignal().Connect( this, &AnimatedImageVisual::DisplayNextFrame );
+      mFrameDelayTimer.Start();
+    }
+
+    actor.AddRenderer( mImpl->mRenderer );
+  }
+}
+
+void AnimatedImageVisual::DoSetOffStage( Actor& actor )
+{
+  if( !mImpl->mRenderer )
+  {
+    return;
+  }
+
+  if( mFrameDelayTimer )
+  {
+    mFrameDelayTimer.Stop();
+    mFrameDelayTimer.Reset();
+  }
+
+  mTextureRectContainer.Clear();
+  mFrameDelayContainer.Clear();
+
+  actor.RemoveRenderer( mImpl->mRenderer );
+  mImpl->mRenderer.Reset();
+}
+
+void AnimatedImageVisual::OnSetTransform()
+{
+  if( mImpl->mRenderer )
+  {
+    mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
+  }
+}
+
+Texture AnimatedImageVisual::PrepareAnimatedImage()
+{
+  // load from image file
+  std::vector<Dali::PixelData> pixelDataList;
+  if( Dali::LoadAnimatedGifFromFile( mImageUrl.c_str() , pixelDataList, mFrameDelayContainer ) )
+  {
+    mImageSize.SetWidth( pixelDataList[0].GetWidth() );
+    mImageSize.SetHeight( pixelDataList[0].GetHeight() );
+
+    return Toolkit::ImageAtlas::PackToAtlas( pixelDataList, mTextureRectContainer );
+  }
+
+  return Texture();
+}
+
+bool AnimatedImageVisual::DisplayNextFrame()
+{
+  mCurrentFrameIndex = (mCurrentFrameIndex+1) % mFrameDelayContainer.Count();
+  mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, mTextureRectContainer[mCurrentFrameIndex] );
+  if( mFrameDelayTimer.GetInterval() != mFrameDelayContainer[mCurrentFrameIndex] )
+  {
+    mFrameDelayTimer.SetInterval( mFrameDelayContainer[mCurrentFrameIndex] );
+  }
+
+  return true;
+}
+
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/visuals/animated-image/animated-image-visual.h b/dali-toolkit/internal/visuals/animated-image/animated-image-visual.h
new file mode 100644 (file)
index 0000000..15dff43
--- /dev/null
@@ -0,0 +1,156 @@
+#ifndef DALI_TOOLKIT_INTERNAL_ANIMATED_IMAGE_VISUAL_H
+#define DALI_TOOLKIT_INTERNAL_ANIMATED_IMAGE_VISUAL_H
+
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/intrusive-ptr.h>
+#include <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/math/vector4.h>
+#include <dali/public-api/adaptor-framework/timer.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/visuals/visual-base-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class AnimatedImageVisual;
+typedef IntrusivePtr< AnimatedImageVisual > AnimatedImageVisualPtr;
+
+/**
+ * The visual which renders an animated image
+ *
+ * The following property is essential
+ *
+ * | %Property Name           | Type             |
+ * |--------------------------|------------------|
+ * | url                      | STRING           |
+ *
+ */
+
+class AnimatedImageVisual : public Visual::Base, public ConnectionTracker
+{
+
+public:
+
+  /**
+   * @brief Create the animated image Visual using the image URL.
+   *
+   * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+   * @param[in] imageUrl The URL to svg resource to use
+   * @param[in] properties A Property::Map containing settings for this visual
+   * @return A smart-pointer to the newly allocated visual.
+   */
+  static AnimatedImageVisualPtr New( VisualFactoryCache& factoryCache, const std::string& imageUrl, const Property::Map& properties );
+
+  /**
+   * @brief Create the animated image visual using the image URL.
+   *
+   * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+   * @param[in] imageUrl The URL to animated image resource to use
+   */
+  static AnimatedImageVisualPtr New( VisualFactoryCache& factoryCache, const std::string& imageUrl );
+
+public:  // from Visual
+
+  /**
+   * @copydoc Visual::Base::GetNaturalSize
+   */
+  virtual void GetNaturalSize( Vector2& naturalSize );
+
+  /**
+   * @copydoc Visual::Base::CreatePropertyMap
+   */
+  virtual void DoCreatePropertyMap( Property::Map& map ) const;
+
+protected:
+
+  /**
+   * @brief Constructor.
+   *
+   * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+   */
+  AnimatedImageVisual( VisualFactoryCache& factoryCache );
+
+  /**
+   * @brief A reference counted object may only be deleted by calling Unreference().
+   */
+  virtual ~AnimatedImageVisual();
+
+  /**
+   * @copydoc Visual::Base::DoSetProperties
+   */
+  virtual void DoSetProperties( const Property::Map& propertyMap );
+
+  /**
+   * @copydoc Visual::Base::DoSetOnStage
+   */
+  virtual void DoSetOnStage( Actor& actor );
+
+  /**
+   * @copydoc Visual::Base::DoSetOffStage
+   */
+  virtual void DoSetOffStage( Actor& actor );
+
+  /**
+   * @copydoc Visual::Base::OnSetTransform
+   */
+  virtual void OnSetTransform();
+
+private:
+
+  /**
+   * Load the animated image and pack the frames into atlas.
+   * @return That atlas texture.
+   */
+  Texture PrepareAnimatedImage();
+
+  /**
+   * Display the next frame. It is called when the mFrameDelayTimes ticks.
+   */
+  bool DisplayNextFrame();
+
+  // Undefined
+  AnimatedImageVisual( const AnimatedImageVisual& animatedImageVisual );
+
+  // Undefined
+  AnimatedImageVisual& operator=( const AnimatedImageVisual& animatedImageVisual );
+
+private:
+
+  Timer mFrameDelayTimer;
+  Dali::Vector<Vector4> mTextureRectContainer;
+  Dali::Vector<uint32_t> mFrameDelayContainer;
+  std::string  mImageUrl;
+  ImageDimensions mImageSize;
+  uint32_t mCurrentFrameIndex;
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+#endif /* DALI_TOOLKIT_INTERNAL_ANIMATED_IMAGE_VISUAL_H */
index 08dfd20..5bc3c6e 100644 (file)
@@ -131,11 +131,6 @@ void ColorVisual::OnSetTransform()
 void ColorVisual::InitializeRenderer()
 {
   Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
 void ColorVisual::InitializeRenderer()
 {
   Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
-  if( !geometry )
-  {
-    geometry =  VisualFactoryCache::CreateQuadGeometry();
-    mFactoryCache.SaveGeometry( VisualFactoryCache::QUAD_GEOMETRY, geometry );
-  }
 
   Shader shader = mFactoryCache.GetShader( VisualFactoryCache::COLOR_SHADER );
   if( !shader )
 
   Shader shader = mFactoryCache.GetShader( VisualFactoryCache::COLOR_SHADER );
   if( !shader )
index 80c899f..7826984 100644 (file)
@@ -322,11 +322,6 @@ void GradientVisual::DoCreatePropertyMap( Property::Map& map ) const
 void GradientVisual::InitializeRenderer()
 {
   Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
 void GradientVisual::InitializeRenderer()
 {
   Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
-  if( !geometry )
-  {
-    geometry =  VisualFactoryCache::CreateQuadGeometry();
-    mFactoryCache.SaveGeometry( VisualFactoryCache::QUAD_GEOMETRY, geometry );
-  }
 
   Toolkit::GradientVisual::Units::Type gradientUnits = mGradient->GetGradientUnits();
   VisualFactoryCache::ShaderType shaderType = GetShaderType( mGradientType, gradientUnits );
 
   Toolkit::GradientVisual::Units::Type gradientUnits = mGradient->GetGradientUnits();
   VisualFactoryCache::ShaderType shaderType = GetShaderType( mGradientType, gradientUnits );
index 69a1094..b61c23b 100644 (file)
@@ -185,11 +185,6 @@ Geometry CreateGeometry( VisualFactoryCache& factoryCache, ImageDimensions gridS
   if( gridSize == ImageDimensions( 1, 1 ) )
   {
     geometry = factoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
   if( gridSize == ImageDimensions( 1, 1 ) )
   {
     geometry = factoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
-    if( !geometry )
-    {
-      geometry =  VisualFactoryCache::CreateQuadGeometry();
-      factoryCache.SaveGeometry( VisualFactoryCache::QUAD_GEOMETRY, geometry );
-    }
   }
   else
   {
   }
   else
   {
index 5dbb80f..955b84c 100644 (file)
@@ -100,11 +100,6 @@ void SvgVisual::DoSetOnStage( Actor& actor )
 {
   Shader shader = ImageVisual::GetImageShader( mFactoryCache, true, true );
   Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
 {
   Shader shader = ImageVisual::GetImageShader( mFactoryCache, true, true );
   Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
-  if( !geometry )
-  {
-    geometry =  mFactoryCache.CreateQuadGeometry();
-    mFactoryCache.SaveGeometry( VisualFactoryCache::QUAD_GEOMETRY, geometry );
-  }
   TextureSet textureSet = TextureSet::New();
   mImpl->mRenderer = Renderer::New( geometry, shader );
   mImpl->mRenderer.SetTextures( textureSet );
   TextureSet textureSet = TextureSet::New();
   mImpl->mRenderer = Renderer::New( geometry, shader );
   mImpl->mRenderer.SetTextures( textureSet );
index 2e7fa6d..4145bf7 100644 (file)
@@ -269,11 +269,6 @@ void TextVisual::DoSetOnStage( Actor& actor )
   mControl = actor;
 
   Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
   mControl = actor;
 
   Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
-  if( !geometry )
-  {
-    geometry =  VisualFactoryCache::CreateQuadGeometry();
-    mFactoryCache.SaveGeometry( VisualFactoryCache::QUAD_GEOMETRY , geometry );
-  }
 
   Shader shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_ATLAS_CLAMP );
   mFactoryCache.SaveShader( VisualFactoryCache::IMAGE_SHADER_ATLAS_DEFAULT_WRAP, shader );
 
   Shader shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_ATLAS_CLAMP );
   mFactoryCache.SaveShader( VisualFactoryCache::IMAGE_SHADER_ATLAS_DEFAULT_WRAP, shader );
index bf6814d..05e32ff 100644 (file)
@@ -52,6 +52,11 @@ VisualFactoryCache::~VisualFactoryCache()
 
 Geometry VisualFactoryCache::GetGeometry( GeometryType type )
 {
 
 Geometry VisualFactoryCache::GetGeometry( GeometryType type )
 {
+  if( !mGeometry[type] && type == QUAD_GEOMETRY )
+  {
+    mGeometry[type] = CreateQuadGeometry();
+  }
+
   return mGeometry[type];
 }
 
   return mGeometry[type];
 }
 
index 92cc53c..239f5c4 100644 (file)
@@ -40,6 +40,7 @@
 #include <dali-toolkit/internal/visuals/primitive/primitive-visual.h>
 #include <dali-toolkit/internal/visuals/svg/svg-visual.h>
 #include <dali-toolkit/internal/visuals/text/text-visual.h>
 #include <dali-toolkit/internal/visuals/primitive/primitive-visual.h>
 #include <dali-toolkit/internal/visuals/svg/svg-visual.h>
 #include <dali-toolkit/internal/visuals/text/text-visual.h>
+#include <dali-toolkit/internal/visuals/animated-image/animated-image-visual.h>
 #include <dali-toolkit/internal/visuals/wireframe/wireframe-visual.h>
 #include <dali-toolkit/internal/visuals/visual-factory-cache.h>
 #include <dali-toolkit/internal/visuals/visual-factory-resolve-url.h>
 #include <dali-toolkit/internal/visuals/wireframe/wireframe-visual.h>
 #include <dali-toolkit/internal/visuals/visual-factory-cache.h>
 #include <dali-toolkit/internal/visuals/visual-factory-resolve-url.h>
@@ -151,6 +152,10 @@ Toolkit::Visual::Base VisualFactory::CreateVisual( const Property::Map& property
           {
             visualPtr = SvgVisual::New( *( mFactoryCache.Get() ), imageUrl, propertyMap );
           }
           {
             visualPtr = SvgVisual::New( *( mFactoryCache.Get() ), imageUrl, propertyMap );
           }
+          else if( UrlType::GIF == type )
+          {
+            visualPtr = AnimatedImageVisual::New( *( mFactoryCache.Get() ), imageUrl, propertyMap );
+          }
           else // Regular image
           {
             bool batchingEnabled( false );
           else // Regular image
           {
             bool batchingEnabled( false );
@@ -259,6 +264,10 @@ Toolkit::Visual::Base VisualFactory::CreateVisual( const std::string& url, Image
   {
     visualPtr = SvgVisual::New( *( mFactoryCache.Get() ), url );
   }
   {
     visualPtr = SvgVisual::New( *( mFactoryCache.Get() ), url );
   }
+  else if( UrlType::GIF == type )
+  {
+    visualPtr = AnimatedImageVisual::New( *( mFactoryCache.Get() ), url );
+  }
   else // Regular image
   {
     visualPtr = ImageVisual::New( *( mFactoryCache.Get() ), url, size );
   else // Regular image
   {
     visualPtr = ImageVisual::New( *( mFactoryCache.Get() ), url, size );
index 1d3ffe3..2c1c45b 100644 (file)
@@ -37,7 +37,8 @@ namespace UrlType
   {
     REGULAR_IMAGE,
     N_PATCH,
   {
     REGULAR_IMAGE,
     N_PATCH,
-    SVG
+    SVG,
+    GIF
   };
 }
 
   };
 }
 
@@ -55,7 +56,9 @@ inline UrlType::Type ResolveUrlType( const std::string& url )
     // parsing from the end for better chance of early outs
     enum { SUFFIX, HASH, HASH_DOT } state = SUFFIX;
     char SVG[ 4 ] = { 'g', 'v', 's', '.' };
     // parsing from the end for better chance of early outs
     enum { SUFFIX, HASH, HASH_DOT } state = SUFFIX;
     char SVG[ 4 ] = { 'g', 'v', 's', '.' };
+    char GIF[ 4 ] = { 'f', 'i', 'g', '.' };
     unsigned int svgScore = 0;
     unsigned int svgScore = 0;
+    unsigned int gifScore = 0;
     int index = count;
     while( --index >= 0 )
     {
     int index = count;
     while( --index >= 0 )
     {
@@ -69,6 +72,14 @@ inline UrlType::Type ResolveUrlType( const std::string& url )
           return UrlType::SVG;
         }
       }
           return UrlType::SVG;
         }
       }
+      if( ( offsetFromEnd < sizeof(GIF) )&&( tolower( currentChar ) == GIF[ offsetFromEnd ] ) )
+      {
+        // early out if GIF
+        if( ++gifScore == sizeof(GIF) )
+        {
+          return UrlType::GIF;
+        }
+      }
       switch( state )
       {
         case SUFFIX:
       switch( state )
       {
         case SUFFIX:
diff --git a/docs/content/images/visuals/animated-image-visual.gif b/docs/content/images/visuals/animated-image-visual.gif
new file mode 100644 (file)
index 0000000..ddc3312
Binary files /dev/null and b/docs/content/images/visuals/animated-image-visual.gif differ
index 457d8e1..eaaaed5 100644 (file)
@@ -30,7 +30,7 @@ Visuals have a **transform** field in the property map to allow layouting within
 | Dali::Toolkit::Visual::Transform::Property::OFFSET | offset | VECTOR2 | No      | The offset of the visual. |
 | Dali::Toolkit::Visual::Transform::Property::SIZE | size | VECTOR2 | No      | The size of the visual. |
 | Dali::Toolkit::Visual::Transform::Property::OFFSET_SIZE_MODE | offsetSizeMode | VECTOR4 | No      | Whether the size or offset components are Relative or Absolute [More info](@ref offset-size-mode)|
 | Dali::Toolkit::Visual::Transform::Property::OFFSET | offset | VECTOR2 | No      | The offset of the visual. |
 | Dali::Toolkit::Visual::Transform::Property::SIZE | size | VECTOR2 | No      | The size of the visual. |
 | Dali::Toolkit::Visual::Transform::Property::OFFSET_SIZE_MODE | offsetSizeMode | VECTOR4 | No      | Whether the size or offset components are Relative or Absolute [More info](@ref offset-size-mode)|
-| Dali::Toolkit::Visual::Transform::Property::ORIGIN | origin | INTEGER or STRING | No      | The origin of the visual within the control's area. [More info](@ref align-type)] |
+| Dali::Toolkit::Visual::Transform::Property::ORIGIN | origin | INTEGER or STRING | No      | The origin of the visual within the control's area. [More info](@ref align-type) |
 | Dali::Toolkit::Visual::Transform::Property::ANCHOR_POINT | anchorPoint | INTEGER or STRING | No      | The anchor point of the visual. [More info](@ref align-type)|
  
 
 | Dali::Toolkit::Visual::Transform::Property::ANCHOR_POINT | anchorPoint | INTEGER or STRING | No      | The anchor point of the visual. [More info](@ref align-type)|
  
 
@@ -282,6 +282,7 @@ Depending on the extension of the image, a different visual is provided to rende
  + [Normal (Quad)](@ref image-visual)
  + [N-Patch](@ref n-patch-visual)
  + [SVG](@ref svg-visual)
  + [Normal (Quad)](@ref image-visual)
  + [N-Patch](@ref n-patch-visual)
  + [SVG](@ref svg-visual)
+ + [Animated Image]( @ref animated-image-visual )
  
 ___________________________
  
  
 ___________________________
  
@@ -440,6 +441,45 @@ control.background =
   url : "path-to-image.svg"
 };
 ~~~
   url : "path-to-image.svg"
 };
 ~~~
+
+___________________________________________________________________________________________________
+
+## Animated Image Visual {#animated-image-visual}
+
+Renders an animated image into the visual's quad geometry. Currently, only the GIF format is supported.
+
+![ ](../assets/img/visuals/animated-image-visual.gif)
+![ ](animated-image-visual.gif)
+
+#### Properties Supported
+
+**VisualType:** Dali::Toolkit::Visual::IMAGE, "IMAGE"
+
+| Property                                  | String | Type    | Required | Description                      |
+|-------------------------------------------|--------|:-------:|:--------:|----------------------------------|
+| Dali::Toolkit::ImageVisual::Property::URL | url    | STRING  | Yes      | The URL of the animated image.    |
+
+#### Usage
+
+~~~{.cpp}
+// C++
+Dali::Toolkit::Control control = Dali::Toolkit::Control::New();
+
+control.SetProperty( Control::Property::BACKGROUND,
+                     Property::Map().Add( Visual::Property::TYPE, Dali::Toolkit::Visual::IMAGE )
+                                    .Add( Dali::Toolkit::ImageVisual::Property::URL, "path-to-image.gif" ) );
+~~~
+
+~~~{.js}
+// JavaScript
+var control = new dali.Control( "Control" );
+
+control.background =
+{
+  visualType : "IMAGE",
+  url : "path-to-image.gif"
+};
+~~~
 ___________________________________________________________________________________________________
 
 ## Border Visual {#border-visual}
 ___________________________________________________________________________________________________
 
 ## Border Visual {#border-visual}