[dali_2.3.24] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / page-turn-view / page-turn-view-impl.cpp
index 392f733..a5e9e95 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 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.
 #include <dali-toolkit/internal/controls/page-turn-view/page-turn-view-impl.h>
 
 // EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
 #include <dali/public-api/animation/animation.h>
-#include <dali/public-api/events/hit-test-algorithm.h>
+#include <dali/public-api/animation/constraint.h>
+#include <dali/public-api/object/type-registry-helper.h>
 #include <dali/public-api/object/type-registry.h>
-#include <dali/public-api/render-tasks/render-task-list.h>
+#include <cstring> // for strcmp
 
 // INTERNAL INCLUDES
-#include <dali-toolkit/public-api/controls/default-controls/solid-color-actor.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/internal/controls/control/control-data-impl.h>
+#include <dali-toolkit/internal/controls/page-turn-view/page-turn-book-spine-effect.h>
+#include <dali-toolkit/internal/controls/page-turn-view/page-turn-effect.h>
+#include <dali-toolkit/internal/visuals/visual-factory-cache.h>
+#include <dali-toolkit/internal/visuals/visual-string-constants.h>
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
 
 using namespace Dali;
 
-namespace //unnamed namespace
+namespace //Unnamed namespace
 {
-// To register type
-TypeRegistration mType( typeid(Toolkit::PageTurnView), typeid(Toolkit::Control), NULL );
+// properties set on shader, these properties have the constant value in regardless of the page status
+const char* const PROPERTY_SPINE_SHADOW("uSpineShadowParameter"); // uniform for both spine and turn effect
 
-// default grid density for page turn effect, 10 pixels by 10 pixels
-const float DEFAULT_GRID_DENSITY(10.0f);
+// properties set on actor, the value of these properties varies depending on the page status
+//    properties used in turn effect
+const char* const PROPERTY_TURN_DIRECTION("uIsTurningBack");       // uniform
+const char* const PROPERTY_COMMON_PARAMETERS("uCommonParameters"); //uniform
 
-// to bent the page, the minimal horizontal pan start position is pageSize.x * MINIMUM_START_POSITION_RATIO
+const char* const PROPERTY_PAN_DISPLACEMENT("panDisplacement"); // property used to constrain the uniforms
+const char* const PROPERTY_PAN_CENTER("panCenter");             // property used to constrain the uniforms
+
+// default grid density for page turn effect, 20 pixels by 20 pixels
+const float DEFAULT_GRID_DENSITY(20.0f);
+
+// to bent the page, the minimal horizontal pan start position is viewPageSize.x * MINIMUM_START_POSITION_RATIO
 const float MINIMUM_START_POSITION_RATIO(0.6f);
 
-// the maximum vertical displacement of pan gesture, if exceed, will reduce it: pageSize.y * MAXIMUM_VERTICAL_MOVEMENT_RATIO
+// the maximum vertical displacement of pan gesture, if exceed, will reduce it: viewPageSize.y * MAXIMUM_VERTICAL_MOVEMENT_RATIO
 const float MAXIMUM_VERTICAL_MOVEMENT_RATIO(0.15f);
 
-// when the x component of pan position reaches pageSize.x * PAGE_TURN_OVER_THRESHOLD_RATIO, page starts to turn over
+// when the x component of pan position reaches viewPageSize.x * PAGE_TURN_OVER_THRESHOLD_RATIO, page starts to turn over
 const float PAGE_TURN_OVER_THRESHOLD_RATIO(0.5f);
 
 // duration of animation, shorter for faster speed
@@ -55,7 +71,7 @@ const float PAGE_TURN_OVER_ANIMATION_DURATION(1.2f);
 const Vector2 DEFAULT_SPINE_SHADOW_PARAMETER(50.0f, 20.0f);
 
 // constants for shadow casting
-const float POINT_LIGHT_HEIGHT_RATIO(2.f);
+const float   POINT_LIGHT_HEIGHT_RATIO(2.f);
 const Vector4 DEFAULT_SHADOW_COLOR = Vector4(0.2f, 0.2f, 0.2f, 0.5f);
 
 // constraints ////////////////////////////////////////////////////////////////
@@ -68,30 +84,30 @@ const Vector4 DEFAULT_SHADOW_COLOR = Vector4(0.2f, 0.2f, 0.2f, 0.5f);
 struct OriginalCenterConstraint
 {
   OriginalCenterConstraint(const Vector2& originalCenter, const Vector2& offset)
-  : mOldCenter( originalCenter )
+  : mOldCenter(originalCenter)
   {
     mNewCenter = originalCenter + offset;
-    mDistance = offset.Length() * 0.5f;
-    mDirection = offset  / mDistance;
+    mDistance  = offset.Length() * 0.5f;
+    mDirection = offset / mDistance;
   }
 
-  Vector2 operator()(const Vector2& current, const PropertyInput& panDisplacement)
+  void operator()(Vector2& current, const PropertyInputContainer& inputs)
   {
-    float displacement = panDisplacement.GetFloat();
+    float displacement = inputs[0]->GetFloat();
 
-    if( displacement < mDistance )
+    if(displacement < mDistance)
     {
-      return mOldCenter + mDirection * displacement;
+      current = mOldCenter + mDirection * displacement;
     }
     else
     {
-      return mNewCenter + Vector2(0.25f*(displacement-mDistance), 0.f);
+      current = mNewCenter + Vector2(0.25f * (displacement - mDistance), 0.f);
     }
   }
 
   Vector2 mOldCenter;
   Vector2 mNewCenter;
-  float mDistance;
+  float   mDistance;
   Vector2 mDirection;
 };
 
@@ -103,35 +119,34 @@ struct OriginalCenterConstraint
  */
 struct RotationConstraint
 {
-  RotationConstraint( float distance, float pageWidth, bool isTurnBack )
-  : mDistance( distance*0.5f )
+  RotationConstraint(float distance, float pageWidth, bool isTurnBack)
+  : mDistance(distance * 0.5f)
   {
-    mStep = 1.f / pageWidth;
-    mSign = isTurnBack ? -1.0f : 1.0f;
-    mConst = isTurnBack ? -1.0f : 0.f;
-    mRotation = isTurnBack ? Quaternion( -Math::PI, Vector3::YAXIS ) : Quaternion( 0.f, Vector3::YAXIS );
+    mStep     = 1.f / pageWidth;
+    mSign     = isTurnBack ? -1.0f : 1.0f;
+    mConst    = isTurnBack ? -1.0f : 0.f;
+    mRotation = isTurnBack ? Quaternion(Radian(-Math::PI), Vector3::YAXIS) : Quaternion(Radian(0.f), Vector3::YAXIS);
   }
 
-  Quaternion operator()( const Quaternion& current, const PropertyInput& panDisplacement )
+  void operator()(Quaternion& current, const PropertyInputContainer& inputs)
   {
-    float displacement = panDisplacement.GetFloat();
-    float angle;
-    if( displacement < mDistance)
+    float displacement = inputs[0]->GetFloat();
+    if(displacement < mDistance)
     {
-      return mRotation;
+      current = mRotation;
     }
     else
     {
-      float coef = std::max(-1.0f, mStep*(mDistance-displacement));
-      angle = Math::PI*( mConst + mSign*coef );
-      return Quaternion( angle, Vector3::YAXIS );
+      float coef  = std::max(-1.0f, mStep * (mDistance - displacement));
+      float angle = Math::PI * (mConst + mSign * coef);
+      current     = Quaternion(Radian(angle), Vector3::YAXIS);
     }
   }
 
-  float mDistance;
-  float mStep;
-  float mConst;
-  float mSign;
+  float      mDistance;
+  float      mStep;
+  float      mConst;
+  float      mSign;
   Quaternion mRotation;
 };
 
@@ -143,30 +158,31 @@ struct RotationConstraint
  */
 struct CurrentCenterConstraint
 {
-  CurrentCenterConstraint( float pageWidth)
-  : mPageWidth( pageWidth )
+  CurrentCenterConstraint(float pageWidth)
+  : mPageWidth(pageWidth)
   {
     mThres = pageWidth * PAGE_TURN_OVER_THRESHOLD_RATIO * 0.5f;
   }
 
-  Vector2 operator()( const Vector2& current, const PropertyInput& center, const PropertyInput& originalCenter )
+  void operator()(Vector2& current, const PropertyInputContainer& inputs)
   {
-    Vector2 centerPosition = center.GetVector2();
-    if( centerPosition.x > 0.f )
+    const Vector2& centerPosition = inputs[0]->GetVector2();
+    if(centerPosition.x > 0.f)
     {
-      return Vector2( mThres+centerPosition.x*0.5f , centerPosition.y);
+      current.x = mThres + centerPosition.x * 0.5f;
+      current.y = centerPosition.y;
     }
     else
     {
-      Vector2 centerOrigin = originalCenter.GetVector2();
-      Vector2 direction = centerOrigin - Vector2(mThres, centerPosition.y);
-      float coef = 1.f+(centerPosition.x*2.f / mPageWidth);
-      // Todo: when coef <= 0, the page is flat, slow down the last moment of the page stretch by 10 times to avoid a small bounce
+      const Vector2& centerOrigin = inputs[1]->GetVector2();
+      Vector2        direction    = centerOrigin - Vector2(mThres, centerPosition.y);
+      float          coef         = 1.f + (centerPosition.x * 2.f / mPageWidth);
+      // when coef <= 0, the page is flat, slow down the last moment of the page stretch by 10 times to avoid a small bounce
       if(coef < 0.025f)
       {
-        coef = (coef+0.225f)/10.0f;
+        coef = (coef + 0.225f) / 10.0f;
       }
-      return centerOrigin - direction * coef;
+      current = centerOrigin - direction * coef;
     }
   }
 
@@ -176,114 +192,175 @@ struct CurrentCenterConstraint
 
 struct ShadowBlurStrengthConstraint
 {
-  ShadowBlurStrengthConstraint( float thres )
-  : mThres( thres )
-  {}
+  ShadowBlurStrengthConstraint(float thres)
+  : mThres(thres)
+  {
+  }
 
-  float operator()( const float current,  const PropertyInput& currentCenter, const PropertyInput& originalCenter, const PropertyInput& panDisplacement)
+  void operator()(float& blurStrength, const PropertyInputContainer& inputs)
   {
-    float displacement = panDisplacement.GetFloat();
-    float blurStrength;
-    if( EqualsZero(displacement))
+    float displacement = inputs[2]->GetFloat();
+    if(EqualsZero(displacement))
     {
-      Vector2 cur = currentCenter.GetVector2();
-      Vector2 ori = originalCenter.GetVector2();
-      blurStrength =  5.f*(ori-cur).Length() / mThres;
+      const Vector2& cur = inputs[0]->GetVector2();
+      const Vector2& ori = inputs[1]->GetVector2();
+      blurStrength       = 5.f * (ori - cur).Length() / mThres;
     }
     else
     {
-      blurStrength =  1.f - (displacement-2.f*mThres)/mThres;
+      blurStrength = 1.f - (displacement - 2.f * mThres) / mThres;
     }
 
-    blurStrength = blurStrength > 1.f ? 1.f : ( blurStrength < 0.f ? 0.f : blurStrength );
-    return blurStrength;
+    blurStrength = blurStrength > 1.f ? 1.f : (blurStrength < 0.f ? 0.f : blurStrength);
   }
 
   float mThres;
 };
 
-bool IsActorHittableFunction( Actor actor, Dali::HitTestAlgorithm::TraverseType type )
+} //unnamed namespace
+
+namespace Dali
+{
+namespace Toolkit
 {
-  bool hittable = false;
+namespace Internal
+{
+namespace
+{
+BaseHandle Create()
+{
+  // empty handle as we cannot create PageTurnView(but type registered for page turn signal)
+  return BaseHandle();
+}
+
+// Setup properties, signals and actions using the type-registry.
+DALI_TYPE_REGISTRATION_BEGIN(Toolkit::PageTurnView, Toolkit::Control, Create);
+
+DALI_PROPERTY_REGISTRATION(Toolkit, PageTurnView, "viewPageSize", VECTOR2, VIEW_PAGE_SIZE)
+DALI_PROPERTY_REGISTRATION(Toolkit, PageTurnView, "currentPageId", INTEGER, CURRENT_PAGE_ID)
+DALI_PROPERTY_REGISTRATION(Toolkit, PageTurnView, "spineShadow", VECTOR2, SPINE_SHADOW)
+
+DALI_SIGNAL_REGISTRATION(Toolkit, PageTurnView, "pageTurnStarted", SIGNAL_PAGE_TURN_STARTED)
+DALI_SIGNAL_REGISTRATION(Toolkit, PageTurnView, "pageTurnFinished", SIGNAL_PAGE_TURN_FINISHED)
+DALI_SIGNAL_REGISTRATION(Toolkit, PageTurnView, "pagePanStarted", SIGNAL_PAGE_PAN_STARTED)
+DALI_SIGNAL_REGISTRATION(Toolkit, PageTurnView, "pagePanFinished", SIGNAL_PAGE_PAN_FINISHED)
 
-  switch (type)
+DALI_TYPE_REGISTRATION_END()
+
+} // namespace
+
+// these several constants are also used in the derived classes
+const char* const PageTurnView::PROPERTY_TEXTURE_WIDTH("uTextureWidth");    // uniform name
+const char* const PageTurnView::PROPERTY_ORIGINAL_CENTER("originalCenter"); // property used to constrain the uniform
+const char* const PageTurnView::PROPERTY_CURRENT_CENTER("currentCenter");   // property used to constrain the uniform
+const int         PageTurnView::MAXIMUM_TURNING_NUM              = 4;
+const int         PageTurnView::NUMBER_OF_CACHED_PAGES_EACH_SIDE = MAXIMUM_TURNING_NUM + 1;
+const int         PageTurnView::NUMBER_OF_CACHED_PAGES           = NUMBER_OF_CACHED_PAGES_EACH_SIDE * 2;
+const float       PageTurnView::STATIC_PAGE_INTERVAL_DISTANCE    = 1.0f;
+
+PageTurnView::Page::Page()
+: isTurnBack(false)
+{
+  actor = Actor::New();
+  actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER_LEFT);
+  actor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER_LEFT);
+  actor.SetProperty(Actor::Property::VISIBLE, false);
+
+  propertyPanDisplacement = actor.RegisterProperty(PROPERTY_PAN_DISPLACEMENT, 0.f);
+  propertyPanCenter       = actor.RegisterProperty(PROPERTY_PAN_CENTER, Vector2::ZERO);
+
+  propertyOriginalCenter = actor.RegisterProperty(PROPERTY_ORIGINAL_CENTER, Vector2::ZERO);
+  propertyCurrentCenter  = actor.RegisterProperty(PROPERTY_CURRENT_CENTER, Vector2::ZERO);
+  Matrix zeroMatrix(true);
+  actor.RegisterProperty(PROPERTY_COMMON_PARAMETERS, zeroMatrix);
+  propertyTurnDirection = actor.RegisterProperty(PROPERTY_TURN_DIRECTION, -1.f);
+}
+
+void PageTurnView::Page::SetTexture(Texture texture)
+{
+  if(!textureSet)
   {
-    case Dali::HitTestAlgorithm::CHECK_ACTOR:
-    {
-      // Check whether the actor is visible and not fully transparent.
-      Property::Index propertyActorHittable = actor.GetPropertyIndex(Toolkit::PageFactory::ACTOR_HITTABLE);
-      if( actor.IsSensitive()
-       && actor.IsVisible()
-       && actor.GetCurrentWorldColor().a > 0.01f// not FULLY_TRANSPARENT
-       && ( propertyActorHittable != Property::INVALID_INDEX &&
-            actor.GetProperty<bool>( propertyActorHittable ) ) )
-      {
-         hittable = true;
-      }
-      break;
-    }
-    case Dali::HitTestAlgorithm::DESCEND_ACTOR_TREE:
-    {
-      if( actor.IsSensitive() && actor.IsVisible() ) // Actor is visible, if not visible then none of its children are visible.
-      {
-        hittable = true;
-      }
-      break;
-    }
-    default:
+    textureSet = TextureSet::New();
+  }
+  textureSet.SetTexture(0u, texture);
+}
+
+void PageTurnView::Page::UseEffect(Shader newShader)
+{
+  shader = newShader;
+  if(renderer)
+  {
+    renderer.SetShader(shader);
+  }
+}
+
+void PageTurnView::Page::UseEffect(Shader newShader, Geometry geometry)
+{
+  UseEffect(newShader);
+
+  if(!renderer)
+  {
+    renderer = Renderer::New(geometry, shader);
+
+    if(!textureSet)
     {
-      break;
+      textureSet = TextureSet::New();
     }
+
+    renderer.SetTextures(textureSet);
+    renderer.SetProperty(Renderer::Property::DEPTH_WRITE_MODE, DepthWriteMode::ON);
+    actor.AddRenderer(renderer);
   }
+}
 
-  return hittable;
+void PageTurnView::Page::ChangeTurnDirection()
+{
+  isTurnBack = !isTurnBack;
+  actor.SetProperty(propertyTurnDirection, isTurnBack ? 1.f : -1.f);
 }
 
-} //unnamed namespace
+void PageTurnView::Page::SetPanDisplacement(float value)
+{
+  actor.SetProperty(propertyPanDisplacement, value);
+}
 
-namespace Dali
+void PageTurnView::Page::SetPanCenter(const Vector2& value)
 {
+  actor.SetProperty(propertyPanCenter, value);
+}
 
-namespace Toolkit
+void PageTurnView::Page::SetOriginalCenter(const Vector2& value)
 {
+  actor.SetProperty(propertyOriginalCenter, value);
+}
 
-namespace Internal
+void PageTurnView::Page::SetCurrentCenter(const Vector2& value)
 {
+  actor.SetProperty(propertyCurrentCenter, value);
+}
 
-// these several constants are also used in the derived classes
-const int PageTurnView::MAXIMUM_TURNING_NUM = 4;
-const int PageTurnView::NUMBER_OF_CACHED_PAGES_EACH_SIDE = MAXIMUM_TURNING_NUM + 1;
-const int PageTurnView::NUMBER_OF_CACHED_PAGES = NUMBER_OF_CACHED_PAGES_EACH_SIDE*2;
-const float PageTurnView::STATIC_PAGE_INTERVAL_DISTANCE = 1.0f;
-
-PageTurnView::PageTurnView( PageFactory& pageFactory, const Vector2& pageSize )
-: Control( REQUIRES_TOUCH_EVENTS ),
-  mPageFactory( pageFactory ),
-  mPageSize( pageSize ),
-  mTotalPageCount( 0 ),
-  mIsEditMode( false ),
-  mNeedOffscreenRendering( false ),
-  mPanning( false ),
-  mSpineShadowParameter( DEFAULT_SPINE_SHADOW_PARAMETER ),
-  mCurrentPageIndex( 0 ),
-  mIndex( 0 ),
-  mPress( false ),
-  mPageUpdated( true ),
-  mDistanceUpCorner( 0.f ),
-  mDistanceBottomCorner( 0.f ),
-  mPanDisplacement( 0.f ),
-  mConstraints( false ),
+PageTurnView::PageTurnView(PageFactory& pageFactory, const Vector2& viewPageSize)
+: Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT)),
+  mPageFactory(&pageFactory),
+  mPageSize(viewPageSize),
+  mSpineShadowParameter(DEFAULT_SPINE_SHADOW_PARAMETER),
+  mDistanceUpCorner(0.f),
+  mDistanceBottomCorner(0.f),
+  mPanDisplacement(0.f),
+  mTotalPageCount(0),
+  mCurrentPageIndex(0),
+  mTurningPageIndex(0),
+  mIndex(0),
+  mSlidingCount(0),
+  mAnimatingCount(0),
+  mConstraints(false),
+  mPress(false),
+  mPageUpdated(true),
   mPageTurnStartedSignal(),
   mPageTurnFinishedSignal(),
   mPagePanStartedSignal(),
   mPagePanFinishedSignal()
 {
-  mPageActors.resize( NUMBER_OF_CACHED_PAGES );
-  mIsAnimating.resize( MAXIMUM_TURNING_NUM );
-  mIsSliding.resize( MAXIMUM_TURNING_NUM );
-  mTurnEffect.resize( MAXIMUM_TURNING_NUM );
-  mPropertyPanDisplacement.resize( MAXIMUM_TURNING_NUM );
-  mPropertyCurrentCenter.resize( MAXIMUM_TURNING_NUM );
 }
 
 PageTurnView::~PageTurnView()
@@ -292,182 +369,166 @@ PageTurnView::~PageTurnView()
 
 void PageTurnView::OnInitialize()
 {
-   // create the two book spine effect for static images, left and right side pages respectively
-  mSpineEffectFront = PageTurnBookSpineEffect::New();
-  mSpineEffectFront.SetIsBackImageVisible( false );
-  mSpineEffectFront.SetPageWidth( mPageSize.width );
-  mSpineEffectFront.SetShadowWidth( 0.f );
-  mSpineEffectFront.SetSpineShadowParameter( mSpineShadowParameter );
-
-  mSpineEffectBack = PageTurnBookSpineEffect::New();
-  mSpineEffectBack.SetIsBackImageVisible( true );
-  mSpineEffectBack.SetPageWidth( mPageSize.width );
-  mSpineEffectBack.SetShadowWidth( 0.f );
-  mSpineEffectBack.SetSpineShadowParameter( mSpineShadowParameter );
-
-  // create the page turn effect objects
-  for( int i = 0; i < MAXIMUM_TURNING_NUM; i++ )
+  // create the book spine effect for static pages
+  Property::Map spineEffectMap = CreatePageTurnBookSpineEffect();
+  mSpineEffectShader           = CreateShader(spineEffectMap);
+  mSpineEffectShader.RegisterProperty(PROPERTY_SPINE_SHADOW, mSpineShadowParameter);
+  // create the turn effect for turning pages
+  Property::Map turnEffectMap = CreatePageTurnEffect();
+  mTurnEffectShader           = CreateShader(turnEffectMap);
+  mTurnEffectShader.RegisterProperty(PROPERTY_SPINE_SHADOW, mSpineShadowParameter);
+
+  // create the grid geometry for pages
+  uint16_t width  = static_cast<uint16_t>(mPageSize.width / DEFAULT_GRID_DENSITY + 0.5f);
+  uint16_t height = static_cast<uint16_t>(mPageSize.height / DEFAULT_GRID_DENSITY + 0.5f);
+  mGeometry       = VisualFactoryCache::CreateGridGeometry(Uint16Pair(width, height));
+
+  mPages.reserve(NUMBER_OF_CACHED_PAGES);
+  for(int i = 0; i < NUMBER_OF_CACHED_PAGES; i++)
   {
-    mTurnEffect[i] = Toolkit::PageTurnEffect::New( false );
-    mTurnEffect[i].SetProperty( ShaderEffect::GRID_DENSITY, Property::Value( DEFAULT_GRID_DENSITY ) );
-    mTurnEffect[i].SetPageSize( mPageSize );
-    mTurnEffect[i].SetShadowWidth(0.f);
-    mTurnEffect[i].SetSpineShadowParameter( mSpineShadowParameter );
-    mIsAnimating[i] = false;
-    mIsSliding[i] = false;
-    mPropertyPanDisplacement[i] = Self().RegisterProperty("PAN_DISPLACEMENT_PROPERTY_"+i, 0.0f);
-    mPropertyCurrentCenter[i] = Self().RegisterProperty("CURRENT_CENTER_PROPERTY_"+i, Vector2(0.0f,0.0f));
+    mPages.push_back(Page());
+    mPages[i].actor.SetProperty(Actor::Property::SIZE, mPageSize);
+    Self().Add(mPages[i].actor);
   }
 
+  // create the layer for turning pages
   mTurningPageLayer = Layer::New();
-  mTurningPageLayer.SetAnchorPoint( AnchorPoint::CENTER_LEFT );
-  // Set control size and the parent origin of turningPageLayer
-  OnPageTurnViewInitialize();
+  mTurningPageLayer.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER_LEFT);
+  mTurningPageLayer.SetProperty(Layer::Property::BEHAVIOR, Layer::LAYER_3D);
+  mTurningPageLayer.Raise();
 
-  mRootOnScreen = Actor::New();
-  mRootOnScreen.SetPositionInheritanceMode( USE_PARENT_POSITION );
-  mRootOnScreen.SetSize( mControlSize );
-  Self().Add( mRootOnScreen );
-  mRootOnScreen.Add(mTurningPageLayer);
+  // Set control size and the parent origin of page layers
+  OnPageTurnViewInitialize();
 
-  mTotalPageCount = static_cast<int>( mPageFactory.GetNumberOfPages() );
-  mNeedOffscreenRendering = mPageFactory.IsOffscreenRenderingNeeded();
-  if( mNeedOffscreenRendering )
-  {
-    SetupRenderTasks();
-  }
+  Self().Add(mTurningPageLayer);
 
+  mTotalPageCount = static_cast<int>(mPageFactory->GetNumberOfPages());
   // add pages to the scene, and set depth for the stacked pages
-  for( int i = 0; i < NUMBER_OF_CACHED_PAGES_EACH_SIDE; i++ )
+  for(int i = 0; i < NUMBER_OF_CACHED_PAGES_EACH_SIDE; i++)
   {
-    AddPage( i );
-    if(mPageActors[i])
-    {
-      mPageActors[i].SetZ( -static_cast<float>( i )*STATIC_PAGE_INTERVAL_DISTANCE );
-    }
+    AddPage(i);
+    mPages[i].actor.SetProperty(Actor::Property::POSITION_Z, -static_cast<float>(i) * STATIC_PAGE_INTERVAL_DISTANCE);
   }
+  mPages[0].actor.SetProperty(Actor::Property::VISIBLE, true);
 
   // enable the pan gesture which is attached to the control
-  EnableGestureDetection(Gesture::Type(Gesture::Pan));
+  EnableGestureDetection(GestureType::Value(GestureType::PAN));
 
-  mPageFactory.PageRefreshSignal().Connect(this, &PageTurnView::RenderPage);
+  Self().SetProperty(DevelControl::Property::ACCESSIBILITY_ROLE, Dali::Accessibility::Role::PAGE_TAB_LIST);
 }
 
-void PageTurnView::SetupRenderTasks()
+Shader PageTurnView::CreateShader(const Property::Map& shaderMap)
 {
-  mPageSourceActor.resize( NUMBER_OF_CACHED_PAGES );
-  mOffscreenTask.resize( NUMBER_OF_CACHED_PAGES );
-  mRenderedPage.resize( NUMBER_OF_CACHED_PAGES );
-
-  mCameraActor = CameraActor::New(mControlSize);
-  mCameraActor.SetParentOrigin(ParentOrigin::CENTER);
-  mCameraActor.SetPositionInheritanceMode( DONT_INHERIT_POSITION );
-  mCameraActor.SetInheritScale( false );
-  Self().Add(mCameraActor);
-
-  RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
-  for(int i=0; i<NUMBER_OF_CACHED_PAGES; i++)
+  Shader           shader;
+  Property::Value* shaderValue = shaderMap.Find(Toolkit::Visual::Property::SHADER, CUSTOM_SHADER);
+  Property::Map    shaderSource;
+  if(shaderValue && shaderValue->Get(shaderSource))
+  {
+    std::string      vertexShader;
+    Property::Value* vertexShaderValue = shaderSource.Find(Toolkit::Visual::Shader::Property::VERTEX_SHADER, CUSTOM_VERTEX_SHADER);
+    if(!vertexShaderValue || !vertexShaderValue->Get(vertexShader))
+    {
+      DALI_LOG_ERROR("PageTurnView::CreateShader failed: vertex shader source is not available.\n");
+    }
+    std::string      fragmentShader;
+    Property::Value* fragmentShaderValue = shaderSource.Find(Toolkit::Visual::Shader::Property::FRAGMENT_SHADER, CUSTOM_FRAGMENT_SHADER);
+    if(!fragmentShaderValue || !fragmentShaderValue->Get(fragmentShader))
+    {
+      DALI_LOG_ERROR("PageTurnView::CreateShader failed: fragment shader source is not available.\n");
+    }
+    shader = Shader::New(vertexShader, fragmentShader);
+  }
+  else
   {
-    mPageSourceActor[i] = Actor::New();
-    mPageSourceActor[i].SetParentOrigin(ParentOrigin::CENTER);
-    mPageSourceActor[i].SetColorMode( USE_OWN_COLOR );
-    mPageSourceActor[i].SetPositionInheritanceMode( DONT_INHERIT_POSITION );
-    mPageSourceActor[i].SetInheritScale( false );
-    Self().Add( mPageSourceActor[i] );
-    mPageSourceActor[i].SetSensitive( false );
-
-    mRenderedPage[i] = FrameBufferImage::New( mControlSize.width, mControlSize.height, Pixel::RGB8888, Image::UNUSED );
-    mOffscreenTask[i] = taskList.CreateTask();
-    mOffscreenTask[i].SetRefreshRate( RenderTask::REFRESH_ONCE );
-    mOffscreenTask[i].SetCameraActor(mCameraActor);
-    mOffscreenTask[i].SetSourceActor( mPageSourceActor[i] );
-    mOffscreenTask[i].SetExclusive(true);
-    mOffscreenTask[i].SetInputEnabled( false );
-    mOffscreenTask[i].SetClearEnabled( true );
-    mOffscreenTask[i].SetClearColor( Vector4(0.f,0.f,0.f,0.f) );
-    mOffscreenTask[i].SetTargetFrameBuffer( mRenderedPage[i] );
-    mOffscreenTask[i].SetScreenToFrameBufferMappingActor( Self() );
-   }
+    DALI_LOG_ERROR("PageTurnView::CreateShader failed: shader source is not available.\n");
+  }
+
+  return shader;
 }
 
 void PageTurnView::SetupShadowView()
 {
-  mShadowView = Toolkit::ShadowView::New( 0.25f, 0.25f );
-  Vector3 origin = mTurningPageLayer.GetCurrentParentOrigin();
-  mShadowView.SetParentOrigin( origin );
-  mShadowView.SetAnchorPoint( origin );
-  mShadowView.SetPointLightFieldOfView( Math::PI / 2.0f);
+  mShadowView    = Toolkit::ShadowView::New(0.25f, 0.25f);
+  Vector3 origin = mTurningPageLayer.GetCurrentProperty<Vector3>(Actor::Property::PARENT_ORIGIN);
+  mShadowView.SetProperty(Actor::Property::PARENT_ORIGIN, origin);
+  mShadowView.SetProperty(Actor::Property::ANCHOR_POINT, origin);
+  mShadowView.SetPointLightFieldOfView(Math::PI / 2.0f);
   mShadowView.SetShadowColor(DEFAULT_SHADOW_COLOR);
 
-  mShadowLayer = Layer::New();
-  mShadowLayer.SetPositionInheritanceMode( USE_PARENT_POSITION );
-  mRootOnScreen.Add(mShadowLayer);
-  mShadowLayer.Raise();
-
-  mShadowPlane = CreateSolidColorActor( Vector4 (0.0f, 0.0f, 0.0f, 0.0f) );
-  mShadowPlane.SetPositionInheritanceMode( USE_PARENT_POSITION_PLUS_LOCAL_POSITION );
-  mShadowPlane.SetSize( mControlSize );
-  mShadowLayer.Add( mShadowPlane );
-  mShadowView.SetShadowPlane( mShadowPlane );
+  mShadowPlaneBackground = Actor::New();
+  mShadowPlaneBackground.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+  mShadowPlaneBackground.SetProperty(Actor::Property::SIZE, mControlSize);
+  Self().Add(mShadowPlaneBackground);
+  mShadowView.SetShadowPlaneBackground(mShadowPlaneBackground);
 
   mPointLight = Actor::New();
-  mPointLight.SetAnchorPoint( origin );
-  mPointLight.SetParentOrigin( origin );
-  mPointLight.SetPosition( 0.f, 0.f, mPageSize.width*POINT_LIGHT_HEIGHT_RATIO );
-  mRootOnScreen.Add( mPointLight );
-  mShadowView.SetPointLight( mPointLight );
+  mPointLight.SetProperty(Actor::Property::ANCHOR_POINT, origin);
+  mPointLight.SetProperty(Actor::Property::PARENT_ORIGIN, origin);
+  mPointLight.SetProperty(Actor::Property::POSITION, Vector3(0.f, 0.f, mPageSize.width * POINT_LIGHT_HEIGHT_RATIO));
+  Self().Add(mPointLight);
+  mShadowView.SetPointLight(mPointLight);
 
-  mTurningPageLayer.Add( mShadowView );
+  mTurningPageLayer.Add(mShadowView);
   mShadowView.Activate();
 }
 
-void PageTurnView::OnControlStageConnection()
+void PageTurnView::OnSceneConnection(int depth)
 {
   SetupShadowView();
-  mTurningPageLayer.RaiseToTop();
+
+  Control::OnSceneConnection(depth);
 }
 
-void PageTurnView::OnControlStageDisconnection()
+void PageTurnView::OnSceneDisconnection()
 {
   if(mShadowView)
   {
-    Self().Remove(mPointLight);
-    Self().Remove(mShadowLayer);
-    mTurningPageLayer.Remove( mShadowView );
+    mShadowView.RemoveConstraints();
+    mPointLight.Unparent();
+    mShadowPlaneBackground.Unparent();
+    mShadowView.Unparent();
   }
 
   // make sure the status of the control is updated correctly when the pan gesture is interrupted
-  if(mPanning)
+  StopTurning();
+
+  Control::OnSceneDisconnection();
+}
+
+void PageTurnView::SetPageSize(const Vector2& viewPageSize)
+{
+  mPageSize = viewPageSize;
+
+  if(mPointLight)
   {
-    mPanning = false;
+    mPointLight.SetProperty(Actor::Property::POSITION, Vector3(0.f, 0.f, mPageSize.width * POINT_LIGHT_HEIGHT_RATIO));
+  }
 
-    mRootOnScreen.Add(mPanActor);
-    mIsAnimating[mIndex] = false;
-    mPanActor.RemoveConstraints();
-    mTurnEffect[mIndex].RemoveConstraints();
-    mPageUpdated = true;
+  for(size_t i = 0; i < mPages.size(); i++)
+  {
+    mPages[i].actor.SetProperty(Actor::Property::SIZE, mPageSize);
+  }
+
+  OnPageTurnViewInitialize();
 
-    SetSpineEffect( mPanActor, mIsTurnBack[mPanActor] );
+  if(mShadowPlaneBackground)
+  {
+    mShadowPlaneBackground.SetProperty(Actor::Property::SIZE, mControlSize);
   }
 }
 
-void PageTurnView::OnControlSizeSet( const Vector3& size )
+Vector2 PageTurnView::GetPageSize()
 {
-  // disable the SetSize of the control from the application
-  Self().SetSize( mControlSize );
+  return mPageSize;
 }
 
-void PageTurnView::SetSpineShadowParameter( const Vector2& spineShadowParameter )
+void PageTurnView::SetSpineShadowParameter(const Vector2& spineShadowParameter)
 {
   mSpineShadowParameter = spineShadowParameter;
 
   // set spine shadow parameter to all the shader effects
-  mSpineEffectFront.SetSpineShadowParameter( mSpineShadowParameter );
-  mSpineEffectBack.SetSpineShadowParameter( mSpineShadowParameter );
-  for( int i = 0; i < MAXIMUM_TURNING_NUM; i++ )
-  {
-    mTurnEffect[i].SetSpineShadowParameter( mSpineShadowParameter );
-  }
+  mSpineEffectShader.RegisterProperty(PROPERTY_SPINE_SHADOW, mSpineShadowParameter);
+  mTurnEffectShader.RegisterProperty(PROPERTY_SPINE_SHADOW, mSpineShadowParameter);
 }
 
 Vector2 PageTurnView::GetSpineShadowParameter()
@@ -475,26 +536,31 @@ Vector2 PageTurnView::GetSpineShadowParameter()
   return mSpineShadowParameter;
 }
 
-void PageTurnView::GoToPage( unsigned int pageId )
+void PageTurnView::GoToPage(unsigned int pageId)
 {
-  int pageIdx = static_cast<int>(pageId);
+  int pageIdx = Clamp(static_cast<int>(pageId), 0, mTotalPageCount - 1);
+
+  if(mCurrentPageIndex == pageIdx)
+  {
+    return;
+  }
+
+  // if any animation ongoing, stop it.
+  StopTurning();
+
   // record the new current page index
   mCurrentPageIndex = pageIdx;
 
-  // clear the old pages
-  for(int i = 0; i < NUMBER_OF_CACHED_PAGES; i++ )
+  // add the current page and the pages right before and after it
+  for(int i = pageIdx - NUMBER_OF_CACHED_PAGES_EACH_SIDE; i < pageIdx + NUMBER_OF_CACHED_PAGES_EACH_SIDE; i++)
   {
-    if( mPageActors[i] )
-    {
-      mPageActors[i].Unparent();
-      mPageActors[i].Reset();
-    }
+    AddPage(i);
   }
 
-  // add the current page and the pages right before and after it
-  for( int i = pageIdx - NUMBER_OF_CACHED_PAGES_EACH_SIDE; i < pageIdx + NUMBER_OF_CACHED_PAGES_EACH_SIDE; i++ )
+  mPages[pageId % NUMBER_OF_CACHED_PAGES].actor.SetProperty(Actor::Property::VISIBLE, true);
+  if(pageId > 0)
   {
-    AddPage( i );
+    mPages[(pageId - 1) % NUMBER_OF_CACHED_PAGES].actor.SetProperty(Actor::Property::VISIBLE, true);
   }
   // set ordered depth to the stacked pages
   OrganizePageDepth();
@@ -502,239 +568,84 @@ void PageTurnView::GoToPage( unsigned int pageId )
 
 unsigned int PageTurnView::GetCurrentPage()
 {
-  DALI_ASSERT_ALWAYS( mCurrentPageIndex >= 0 );
-  return static_cast< unsigned int >( mCurrentPageIndex );
-}
-
-Actor PageTurnView::EnterEditMode()
-{
-  if( mNeedOffscreenRendering )
-  {
-    DALI_ASSERT_ALWAYS( mCurrentPageIndex >= 0 );
-
-    mIsEditMode = true;
-
-    int index = mCurrentPageIndex % NUMBER_OF_CACHED_PAGES;
-    mOffscreenTask[index].SetInputEnabled( true );
-    mPageSourceActor[index].SetSensitive( true );
-    mOffscreenTask[index].SetRefreshRate( RenderTask::REFRESH_ALWAYS );
-
-    mRootOnScreen.SetSensitive(false);
-
-    return mPageSourceActor[index].GetChildAt( 0 );
-  }
-  else
-  {
-    return Actor();
-  }
+  DALI_ASSERT_ALWAYS(mCurrentPageIndex >= 0);
+  return static_cast<unsigned int>(mCurrentPageIndex);
 }
 
-void PageTurnView::LeaveEditMode()
+void PageTurnView::AddPage(int pageIndex)
 {
-  if( mNeedOffscreenRendering )
+  if(pageIndex > -1 && pageIndex < mTotalPageCount) // whether the page is available from the page factory
   {
-    DALI_ASSERT_ALWAYS( mCurrentPageIndex >= 0 );
-
-    mIsEditMode = false;
-
-    int index = mCurrentPageIndex % NUMBER_OF_CACHED_PAGES;
-    mOffscreenTask[index].SetInputEnabled( false );
-    mPageSourceActor[index].SetSensitive( false );
-    mOffscreenTask[index].SetRefreshRate( RenderTask::REFRESH_ONCE );
-
-    mRootOnScreen.SetSensitive(true);
-  }
-}
+    int index = pageIndex % NUMBER_OF_CACHED_PAGES;
 
-Actor PageTurnView::GetHitActor( Vector2& screenCoordinates, Vector2& actorCoordinates )
-{
-  if( mNeedOffscreenRendering && mCurrentPageIndex < mTotalPageCount)
-  {
-    int index = mCurrentPageIndex % NUMBER_OF_CACHED_PAGES;
+    Texture newPage;
+    newPage = mPageFactory->NewPage(pageIndex);
+    DALI_ASSERT_ALWAYS(newPage && "must pass in valid texture");
 
-    Dali::HitTestAlgorithm::Results results;
-    if( !mOffscreenTask[index].GetInputEnabled() )
+    bool isLeftSide = (pageIndex < mCurrentPageIndex);
+    if(mPages[index].isTurnBack != isLeftSide)
     {
-      mOffscreenTask[index].SetInputEnabled( true );
-      mPageSourceActor[index].SetSensitive( true );
-      Dali::HitTestAlgorithm::HitTest( mOffscreenTask[index], screenCoordinates, results, IsActorHittableFunction );
-      mOffscreenTask[index].SetInputEnabled( false );
-      mPageSourceActor[index].SetSensitive( false );
+      mPages[index].ChangeTurnDirection();
     }
-    else
-    {
-      Dali::HitTestAlgorithm::HitTest( mOffscreenTask[index], screenCoordinates, results, IsActorHittableFunction );
-    }
-    actorCoordinates = results.actorCoordinates;
-    return results.actor;
-  }
-  else
-  {
-    return Actor();
-  }
-}
 
-void PageTurnView::AddPage( int pageIndex )
-{
-  if(pageIndex > -1  && pageIndex < mTotalPageCount) // whether the page is available from the page factory
-  {
-    int index = pageIndex % NUMBER_OF_CACHED_PAGES;
-    ImageActor newPage;
-    if( mNeedOffscreenRendering )
-    {
-      Actor source = mPageFactory.NewPage( pageIndex );
-      if( mPageSourceActor[index].GetChildCount() > 0 )
-      {
-        mPageSourceActor[index].Remove( mPageSourceActor[index].GetChildAt( 0 ) );
-      }
-      mPageSourceActor[index].Add( source );
-      mOffscreenTask[index].SetRefreshRate( RenderTask::REFRESH_ONCE );
-      newPage = NewPageFromRenderBuffer( pageIndex );
-    }
-    else
-    {
-      newPage= ImageActor::DownCast( mPageFactory.NewPage( pageIndex ) );
-      DALI_ASSERT_ALWAYS( newPage );
-    }
-    newPage.SetAnchorPoint( AnchorPoint::CENTER_LEFT );
-    newPage.SetParentOrigin( ParentOrigin::CENTER_LEFT );
-    newPage.SetSize( mPageSize );
-    mRootOnScreen.Add( newPage );
-    mPageActors[index] = newPage;
-
-    bool isLeftSide = ( pageIndex < mCurrentPageIndex );
-    mIsTurnBack[ newPage ] = isLeftSide;
-    if( isLeftSide )
-    {
-      // new page is added to the left side, so need to rotate it 180 degrees
-      newPage.RotateBy( Degree(-180.0f ), Vector3::YAXIS );
-    }
-    else
-    {
-      SetShaderEffect( newPage, mSpineEffectFront);
-    }
+    float degree = isLeftSide ? 180.f : 0.f;
+    mPages[index].actor.SetProperty(Actor::Property::ORIENTATION, Quaternion(Degree(degree), Vector3::YAXIS));
+    mPages[index].actor.SetProperty(Actor::Property::VISIBLE, false);
+    mPages[index].UseEffect(mSpineEffectShader, mGeometry);
+    mPages[index].SetTexture(newPage);
 
     // For Portrait, nothing to do
-    // For Landscape, set spineEffectBack to the new effect if it is in the left side, and set properties to the back image actor if it exists
-    OnAddPage( newPage, isLeftSide );
+    // For Landscape, set the parent origin to CENTER
+    OnAddPage(mPages[index].actor, isLeftSide);
   }
 }
 
-void PageTurnView::RemovePage( int pageIndex )
+void PageTurnView::RemovePage(int pageIndex)
 {
-  if( pageIndex > -1 && pageIndex < mTotalPageCount)
+  if(pageIndex > -1 && pageIndex < mTotalPageCount)
   {
     int index = pageIndex % NUMBER_OF_CACHED_PAGES;
-    mPageActors[index].Unparent();
-    mIsTurnBack.erase( mPageActors[index] );
-    mPageActors[index].Reset();
-    if( mNeedOffscreenRendering )
-    {
-      mPageSourceActor[index].Remove( mPageSourceActor[index].GetChildAt( 0 ) );
-    }
-  }
-}
-
-void PageTurnView::RenderPage( int pageIndex )
-{
-  if( pageIndex > std::max(-1, mCurrentPageIndex - NUMBER_OF_CACHED_PAGES_EACH_SIDE -1)
-   && pageIndex < std::min(mTotalPageCount, mCurrentPageIndex + NUMBER_OF_CACHED_PAGES_EACH_SIDE))
-  {
-    int index = pageIndex % NUMBER_OF_CACHED_PAGES;
-    mOffscreenTask[index].SetRefreshRate( RenderTask::REFRESH_ONCE );
-  }
-}
-
-void PageTurnView::RefreshAll()
-{
-  mTotalPageCount = static_cast<int>( mPageFactory.GetNumberOfPages() );
-  if( mTotalPageCount > 0 )
-  {
-    if(mCurrentPageIndex < mTotalPageCount)
-    {
-      GoToPage( mCurrentPageIndex );
-    }
-    else
-    {
-      GoToPage( mCurrentPageIndex-- );
-    }
+    mPages[index].actor.SetProperty(Actor::Property::VISIBLE, false);
   }
 }
 
-void PageTurnView::RefreshCurrentPage()
+void PageTurnView::OnPan(const PanGesture& gesture)
 {
-  RenderPage( mCurrentPageIndex );
-}
-
-void PageTurnView::OnPan( const PanGesture& gesture )
-{
-  if( mIsEditMode )
-  {
-    // when interrupted by the call of DisplayCurrentPageSourceActor(),
-    // make sure the panFinished is always called before stopping to responding the gesture
-    // so the status of the control is updated correctly
-    if(mPanning)
-    {
-      mPanning = false;
-      PanFinished( SetPanPosition( gesture.position ), gesture.GetSpeed() );
-    }
-
-    return;
-  }
   // the pan gesture is attached to control itself instead of each page
-  switch( gesture.state )
+  switch(gesture.GetState())
   {
-    case Gesture::Started:
+    case GestureState::STARTED:
     {
-      mPanning = true;
-      // to find out whether the undergoing turning page number already reaches the maximum allowed
-      // and get one idle index when it is animatable
-      bool animatable = false;
-      for( int i = 0; i < MAXIMUM_TURNING_NUM; i++ )
-      {
-        if( !mIsAnimating[mIndex] )
-        {
-          animatable = true;
-          break;
-        }
-        if( mIsSliding[mIndex] )
-        {
-          animatable = false;
-          break;
-        }
-        mIndex++;
-        mIndex = mIndex % MAXIMUM_TURNING_NUM;
-      }
-
-      if( mPageUpdated && animatable )
+      // check whether the undergoing turning page number already reaches the maximum allowed
+      if(mPageUpdated && mAnimatingCount < MAXIMUM_TURNING_NUM && mSlidingCount < 1)
       {
-        SetPanActor( gesture.position ); // determine which page actor is panned
-        if(mPanActor && mPanActor.GetParent() != mRootOnScreen) // if the page is added to turning layer,it is undergoing an animation currently
+        const Vector2& position = gesture.GetPosition();
+        SetPanActor(position);                                                                                        // determine which page actor is panned
+        if(mTurningPageIndex != -1 && mPages[mTurningPageIndex % NUMBER_OF_CACHED_PAGES].actor.GetParent() != Self()) // if the page is added to turning layer,it is undergoing an animation currently
         {
-          mPanActor.Reset();
+          mTurningPageIndex = -1;
         }
-        PanStarted( SetPanPosition( gesture.position ) );  // pass in the pan position in the local page coordinate
+        PanStarted(SetPanPosition(position)); // pass in the pan position in the local page coordinate
       }
       else
       {
-        mPanActor.Reset();
+        mTurningPageIndex = -1;
       }
       break;
     }
-    case Gesture::Continuing:
+    case GestureState::CONTINUING:
     {
-      PanContinuing( SetPanPosition( gesture.position ) ); // pass in the pan position in the local page coordinate
+      PanContinuing(SetPanPosition(gesture.GetPosition())); // pass in the pan position in the local page coordinate
       break;
     }
-    case Gesture::Finished:
-    case Gesture::Cancelled:
+    case GestureState::FINISHED:
+    case GestureState::CANCELLED:
     {
-      mPanning = false;
-      PanFinished( SetPanPosition( gesture.position ), gesture.GetSpeed() );
+      PanFinished(SetPanPosition(gesture.GetPosition()), gesture.GetSpeed());
       break;
     }
-    case Gesture::Clear:
-    case Gesture::Possible:
+    case GestureState::CLEAR:
+    case GestureState::POSSIBLE:
     default:
     {
       break;
@@ -742,72 +653,75 @@ void PageTurnView::OnPan( const PanGesture& gesture )
   }
 }
 
-void PageTurnView::PanStarted( const Vector2& gesturePosition )
+void PageTurnView::PanStarted(const Vector2& gesturePosition)
 {
   mPressDownPosition = gesturePosition;
 
-  if( !mPanActor )
+  if(mTurningPageIndex == -1)
   {
     return;
   }
 
+  mIndex = mTurningPageIndex % NUMBER_OF_CACHED_PAGES;
+
   mOriginalCenter = gesturePosition;
-  mTurnEffect[mIndex].SetIsTurningBack( mIsTurnBack[ mPanActor] );
-  mPress = false;
-  mPageUpdated = false;
+  mPress          = false;
+  mPageUpdated    = false;
 
   // Guard against destruction during signal emission
-  Toolkit::PageTurnView handle( GetOwner() );
-  mPagePanStartedSignal.Emit( handle );
+  Toolkit::PageTurnView handle(GetOwner());
+  mPagePanStartedSignal.Emit(handle);
 }
 
-void PageTurnView::PanContinuing( const Vector2& gesturePosition )
+void PageTurnView::PanContinuing(const Vector2& gesturePosition)
 {
-  if( !mPanActor )
+  if(mTurningPageIndex == -1)
   {
     return;
   }
 
   // Guard against destruction during signal emission
-  Toolkit::PageTurnView handle( GetOwner() );
+  Toolkit::PageTurnView handle(GetOwner());
 
   if(!mPress)
   {
     // when the touch down position is near the spine
     // or when the panning goes outwards or some other position which would tear the paper in real situation
     // we change the start position into the current panning position and update the shader parameters
-    if( mOriginalCenter.x <  mPageSize.width*MINIMUM_START_POSITION_RATIO
-        || gesturePosition.x > mOriginalCenter.x-1.0f
-        || ( ( gesturePosition.x/mOriginalCenter.x > gesturePosition.y/mOriginalCenter.y ) &&
-             ( gesturePosition.x/mOriginalCenter.x > (gesturePosition.y-mPageSize.height )/(mOriginalCenter.y-mPageSize.height ) ) ) )
+    if(mOriginalCenter.x < mPageSize.width * MINIMUM_START_POSITION_RATIO || gesturePosition.x > mOriginalCenter.x - 1.0f || ((gesturePosition.x / mOriginalCenter.x > gesturePosition.y / mOriginalCenter.y) && (gesturePosition.x / mOriginalCenter.x > (gesturePosition.y - mPageSize.height) / (mOriginalCenter.y - mPageSize.height))))
     {
       mOriginalCenter = gesturePosition;
     }
     else
     {
-      mDistanceUpCorner = mOriginalCenter.Length();
-      mDistanceBottomCorner = ( mOriginalCenter - Vector2( 0.0f, mPageSize.height ) ).Length();
-      mShadowView.Add( mPanActor );
-      SetShaderEffect( mPanActor, mTurnEffect[mIndex] );
-      mTurnEffect[mIndex].SetOriginalCenter( mOriginalCenter );
+      mDistanceUpCorner     = mOriginalCenter.Length();
+      mDistanceBottomCorner = (mOriginalCenter - Vector2(0.0f, mPageSize.height)).Length();
+      mShadowView.Add(mPages[mIndex].actor);
+      mPages[mIndex].UseEffect(mTurnEffectShader);
+      mPages[mIndex].SetOriginalCenter(mOriginalCenter);
       mCurrentCenter = mOriginalCenter;
-      mTurnEffect[mIndex].SetCurrentCenter( mCurrentCenter );
+      mPages[mIndex].SetCurrentCenter(mCurrentCenter);
       mPanDisplacement = 0.f;
-      mConstraints = true;
-      mPress = true;
-      mIsAnimating[mIndex] = true;
+      mConstraints     = false;
+      mPress           = true;
+      mAnimatingCount++;
 
-      mPageTurnStartedSignal.Emit( handle, static_cast<unsigned int>(mCurrentPageIndex + ( ( mIsTurnBack[mPanActor] ) ? -1 : 0 ) ), !mIsTurnBack[mPanActor] );
+      mPageTurnStartedSignal.Emit(handle, static_cast<unsigned int>(mTurningPageIndex), !mPages[mIndex].isTurnBack);
+      int id = mTurningPageIndex + (mPages[mIndex].isTurnBack ? -1 : 1);
+      if(id >= 0 && id < mTotalPageCount)
+      {
+        mPages[id % NUMBER_OF_CACHED_PAGES].actor.SetProperty(Actor::Property::VISIBLE, true);
+      }
 
       mShadowView.RemoveConstraints();
       Actor self = Self();
-      self.SetProperty( mPropertyPanDisplacement[mIndex], 0.f );
-      Constraint shadowBlurStrengthConstraint = Constraint::New<float>( mShadowView.GetBlurStrengthPropertyIndex(),
-                                                                        Source(mTurnEffect[mIndex],  mTurnEffect[mIndex].GetPropertyIndex(mTurnEffect[mIndex].PageTurnEffect::GetCurrentCenterPropertyName())),
-                                                                        Source(mTurnEffect[mIndex],  mTurnEffect[mIndex].GetPropertyIndex(mTurnEffect[mIndex].PageTurnEffect::GetOriginalCenterPropertyName())),
-                                                                        Source( self, mPropertyPanDisplacement[mIndex] ),
-                                                                        ShadowBlurStrengthConstraint( mPageSize.width*PAGE_TURN_OVER_THRESHOLD_RATIO ) );
-      mShadowView.ApplyConstraint( shadowBlurStrengthConstraint  );
+      mPages[mIndex].SetPanDisplacement(0.f);
+
+      Constraint shadowBlurStrengthConstraint = Constraint::New<float>(mShadowView, mShadowView.GetBlurStrengthPropertyIndex(), ShadowBlurStrengthConstraint(mPageSize.width * PAGE_TURN_OVER_THRESHOLD_RATIO));
+      shadowBlurStrengthConstraint.AddSource(Source(mPages[mIndex].actor, mPages[mIndex].propertyCurrentCenter));
+      shadowBlurStrengthConstraint.AddSource(Source(mPages[mIndex].actor, mPages[mIndex].propertyOriginalCenter));
+      shadowBlurStrengthConstraint.AddSource(Source(mPages[mIndex].actor, mPages[mIndex].propertyPanDisplacement));
+      shadowBlurStrengthConstraint.Apply();
     }
   }
   else
@@ -817,230 +731,255 @@ void PageTurnView::PanContinuing( const Vector2& gesturePosition )
     // Test whether the new current center would tear the paper from the top pine in real situation
     // we do not forbid this totally, which would restrict the panning gesture too much
     // instead, set it to the nearest allowable position
-    float distanceUpCorner = currentCenter.Length();
-    float distanceBottomCorner = ( currentCenter-Vector2( 0.0f, mPageSize.height ) ).Length();
-    if( distanceUpCorner > mDistanceUpCorner )
+    float distanceUpCorner     = currentCenter.Length();
+    float distanceBottomCorner = (currentCenter - Vector2(0.0f, mPageSize.height)).Length();
+    if(distanceUpCorner > mDistanceUpCorner)
     {
-      currentCenter = currentCenter*mDistanceUpCorner/distanceUpCorner;
+      currentCenter = currentCenter * mDistanceUpCorner / distanceUpCorner;
     }
     // would tear the paper from the bottom spine in real situation
-    if( distanceBottomCorner > mDistanceBottomCorner )
+    if(distanceBottomCorner > mDistanceBottomCorner)
     {
-      currentCenter = ( ( currentCenter - Vector2( 0.0f, mPageSize.height ) )*mDistanceBottomCorner/distanceBottomCorner + Vector2(0.0f,mPageSize.height ) );
+      currentCenter = ((currentCenter - Vector2(0.0f, mPageSize.height)) * mDistanceBottomCorner / distanceBottomCorner + Vector2(0.0f, mPageSize.height));
     }
     // If direction has a very high y component, reduce it.
     Vector2 curveDirection = currentCenter - mOriginalCenter;
-    if( fabs( curveDirection.y ) > fabs( curveDirection.x ) )
+    if(fabs(curveDirection.y) > fabs(curveDirection.x))
     {
-      currentCenter.y = mOriginalCenter.y + ( currentCenter.y - mOriginalCenter.y ) * fabs( curveDirection.x/curveDirection.y );
+      currentCenter.y = mOriginalCenter.y + (currentCenter.y - mOriginalCenter.y) * fabs(curveDirection.x / curveDirection.y);
     }
     // If the vertical distance is high, reduce it
     float yShift = currentCenter.y - mOriginalCenter.y;
-    if( fabs( yShift ) > mPageSize.height * MAXIMUM_VERTICAL_MOVEMENT_RATIO )
+    if(fabs(yShift) > mPageSize.height * MAXIMUM_VERTICAL_MOVEMENT_RATIO)
     {
-      currentCenter.y = mOriginalCenter.y + yShift*mPageSize.height*MAXIMUM_VERTICAL_MOVEMENT_RATIO/fabs(yShift );
+      currentCenter.y = mOriginalCenter.y + yShift * mPageSize.height * MAXIMUM_VERTICAL_MOVEMENT_RATIO / fabs(yShift);
     }
 
     // use contraints to control the page shape and rotation when the pan position is near the spine
-    if( currentCenter.x <= mPageSize.width*PAGE_TURN_OVER_THRESHOLD_RATIO && mOriginalCenter.x > mPageSize.width*PAGE_TURN_OVER_THRESHOLD_RATIO )
+    if(currentCenter.x <= mPageSize.width * PAGE_TURN_OVER_THRESHOLD_RATIO && mOriginalCenter.x > mPageSize.width * PAGE_TURN_OVER_THRESHOLD_RATIO)
     {
       // set the property values used by the constraints
-      mPanDisplacement = mPageSize.width*PAGE_TURN_OVER_THRESHOLD_RATIO - currentCenter.x;
-      Self().SetProperty( mPropertyPanDisplacement[mIndex], mPanDisplacement );
-      Self().SetProperty( mPropertyCurrentCenter[mIndex], currentCenter );
+      mPanDisplacement = mPageSize.width * PAGE_TURN_OVER_THRESHOLD_RATIO - currentCenter.x;
+      mPages[mIndex].SetPanDisplacement(mPanDisplacement);
+      mPages[mIndex].SetPanCenter(currentCenter);
 
       // set up the OriginalCenterConstraint and CurrentCebterConstraint to the PageTurnEdffect
       // also set up the RotationConstraint to the page actor
-      if( mConstraints )
+      if(!mConstraints)
       {
         Vector2 corner;
         // the corner position need to be a little far away from the page edge to ensure the whole page is lift up
-        if( currentCenter.y >= mOriginalCenter.y )
+        if(currentCenter.y >= mOriginalCenter.y)
         {
-          corner = Vector2( 1.1f*mPageSize.width, 0.f );
+          corner = Vector2(1.1f * mPageSize.width, 0.f);
         }
         else
         {
-          corner = mPageSize*1.1f;
+          corner = mPageSize * 1.1f;
         }
 
-        Vector2 offset( currentCenter-mOriginalCenter );
-        float k = - ( (mOriginalCenter.x-corner.x)*offset.x + (mOriginalCenter.y-corner.y)*offset.y )
-                   /( offset.x*offset.x + offset.y*offset.y );
+        Vector2 offset(currentCenter - mOriginalCenter);
+        float   k = -((mOriginalCenter.x - corner.x) * offset.x + (mOriginalCenter.y - corner.y) * offset.y) / (offset.x * offset.x + offset.y * offset.y);
         offset *= k;
         Actor self = Self();
-        Source source(self, mPropertyPanDisplacement[mIndex]);
-
-        Property::Index shaderOriginalCenterPropertyIndex = mTurnEffect[mIndex].GetPropertyIndex(mTurnEffect[mIndex].PageTurnEffect::GetOriginalCenterPropertyName());
-        Constraint originalCenterConstraint = Constraint::New<Vector2>( shaderOriginalCenterPropertyIndex ,
-                                                                        source,
-                                                                        OriginalCenterConstraint( mOriginalCenter, offset ));
-        mTurnEffect[mIndex].ApplyConstraint( originalCenterConstraint );
-
-        Property::Index shaderCurrentCenterPropertyIndex = mTurnEffect[mIndex].GetPropertyIndex(mTurnEffect[mIndex].PageTurnEffect::GetCurrentCenterPropertyName());
-        Constraint currentCenterConstraint = Constraint::New<Vector2>( shaderCurrentCenterPropertyIndex,
-                                                                       Source(self, mPropertyCurrentCenter[mIndex]),
-                                                                       Source(mTurnEffect[mIndex], shaderOriginalCenterPropertyIndex),
-                                                                       CurrentCenterConstraint(mPageSize.width));
-        mTurnEffect[mIndex].ApplyConstraint( currentCenterConstraint );
-
-        GetImpl( mTurnEffect[mIndex] ).ApplyInternalConstraint();
-
-        float distance = offset.Length();
-        Constraint rotationConstraint = Constraint::New<Quaternion>( Actor::ROTATION,
-                                                                     Source( self, mPropertyPanDisplacement[mIndex] ),
-                                                                     RotationConstraint(distance, mPageSize.width, mIsTurnBack[mPanActor]));
-        mPanActor.ApplyConstraint( rotationConstraint );
-
-        mConstraints = false;
+
+        Constraint originalCenterConstraint = Constraint::New<Vector2>(mPages[mIndex].actor, mPages[mIndex].propertyOriginalCenter, OriginalCenterConstraint(mOriginalCenter, offset));
+        originalCenterConstraint.AddSource(Source(mPages[mIndex].actor, mPages[mIndex].propertyPanDisplacement));
+        originalCenterConstraint.Apply();
+
+        Constraint currentCenterConstraint = Constraint::New<Vector2>(mPages[mIndex].actor, mPages[mIndex].propertyCurrentCenter, CurrentCenterConstraint(mPageSize.width));
+        currentCenterConstraint.AddSource(Source(mPages[mIndex].actor, mPages[mIndex].propertyPanCenter));
+        currentCenterConstraint.AddSource(Source(mPages[mIndex].actor, mPages[mIndex].propertyOriginalCenter));
+        currentCenterConstraint.Apply();
+
+        PageTurnApplyInternalConstraint(mPages[mIndex].actor, mPageSize.height);
+
+        float      distance           = offset.Length();
+        Constraint rotationConstraint = Constraint::New<Quaternion>(mPages[mIndex].actor, Actor::Property::ORIENTATION, RotationConstraint(distance, mPageSize.width, mPages[mIndex].isTurnBack));
+        rotationConstraint.AddSource(Source(mPages[mIndex].actor, mPages[mIndex].propertyPanDisplacement));
+        rotationConstraint.Apply();
+
+        mConstraints = true;
       }
     }
     else
     {
-      if(!mConstraints) // remove the constraint is the pan position move back to far away from the spine
+      if(mConstraints) // remove the constraint is the pan position move back to far away from the spine
       {
-        mPanActor.RemoveConstraints();
-        mTurnEffect[mIndex].RemoveConstraints();
-        mTurnEffect[mIndex].SetOriginalCenter( mOriginalCenter );
-        mConstraints = true;
+        mPages[mIndex].actor.RemoveConstraints();
+        mPages[mIndex].SetOriginalCenter(mOriginalCenter);
+        mConstraints     = false;
         mPanDisplacement = 0.f;
       }
 
-      mTurnEffect[mIndex].SetCurrentCenter( currentCenter );
+      mPages[mIndex].SetCurrentCenter(currentCenter);
       mCurrentCenter = currentCenter;
-      GetImpl( mTurnEffect[mIndex] ).ApplyInternalConstraint();
+      PageTurnApplyInternalConstraint(mPages[mIndex].actor, mPageSize.height);
     }
   }
 }
 
-void PageTurnView::PanFinished( const Vector2& gesturePosition, float gestureSpeed )
+void PageTurnView::PanFinished(const Vector2& gesturePosition, float gestureSpeed)
 {
   // Guard against destruction during signal emission
-  Toolkit::PageTurnView handle( GetOwner() );
+  Toolkit::PageTurnView handle(GetOwner());
 
-  if( !mPanActor )
+  if(mTurningPageIndex == -1)
   {
-    if(!mIsAnimating[mIndex])
+    if(mAnimatingCount < MAXIMUM_TURNING_NUM && mSlidingCount < 1)
     {
-      OnPossibleOutwardsFlick( gesturePosition, gestureSpeed );
+      OnPossibleOutwardsFlick(gesturePosition, gestureSpeed);
     }
+
     return;
   }
 
-  mPagePanFinishedSignal.Emit( handle );
+  mPagePanFinishedSignal.Emit(handle);
 
-  ImageActor actor = mPanActor;
   if(mPress)
   {
-    if(!mConstraints) // if with constraints, the pan finished position is near spine, set up an animation to turn the page over
+    if(mConstraints) // if with constraints, the pan finished position is near spine, set up an animation to turn the page over
     {
       // update the pages here instead of in the TurnedOver callback function
       // as new page is allowed to respond to the pan gesture before other pages finishing animation
-      if(mIsTurnBack[actor])
+      if(mPages[mIndex].isTurnBack)
       {
         mCurrentPageIndex--;
-        RemovePage( mCurrentPageIndex+NUMBER_OF_CACHED_PAGES_EACH_SIDE );
-        AddPage( mCurrentPageIndex-NUMBER_OF_CACHED_PAGES_EACH_SIDE );
+        RemovePage(mCurrentPageIndex + NUMBER_OF_CACHED_PAGES_EACH_SIDE);
+        AddPage(mCurrentPageIndex - NUMBER_OF_CACHED_PAGES_EACH_SIDE);
       }
       else
       {
         mCurrentPageIndex++;
-        RemovePage( mCurrentPageIndex-NUMBER_OF_CACHED_PAGES_EACH_SIDE-1 );
-        AddPage( mCurrentPageIndex+NUMBER_OF_CACHED_PAGES_EACH_SIDE-1 );
+        RemovePage(mCurrentPageIndex - NUMBER_OF_CACHED_PAGES_EACH_SIDE - 1);
+        AddPage(mCurrentPageIndex + NUMBER_OF_CACHED_PAGES_EACH_SIDE - 1);
       }
       OrganizePageDepth();
 
       // set up an animation to turn the page over
-      Actor self = Self();
-      float width = mPageSize.width*(1.f+PAGE_TURN_OVER_THRESHOLD_RATIO);
-      Animation animation = Animation::New( std::max(0.1f,PAGE_TURN_OVER_ANIMATION_DURATION * (1.0f - mPanDisplacement / width)) );
-      animation.AnimateTo( Property(self, mPropertyPanDisplacement[mIndex]),
-                           width,AlphaFunctions::EaseOutSine33);
-      animation.AnimateTo( Property(self, mPropertyCurrentCenter[mIndex]),
-                           Vector2(-mPageSize.width, 0.5f*mPageSize.height), AlphaFunctions::EaseOutSine33);
-      mAnimationActorPair[animation] = actor;
-      mAnimationIndexPair[animation] = mIndex;
+      float     width     = mPageSize.width * (1.f + PAGE_TURN_OVER_THRESHOLD_RATIO);
+      Animation animation = Animation::New(std::max(0.1f, PAGE_TURN_OVER_ANIMATION_DURATION * (1.0f - mPanDisplacement / width)));
+      animation.AnimateTo(Property(mPages[mIndex].actor, mPages[mIndex].propertyPanDisplacement),
+                          width,
+                          AlphaFunction::EASE_OUT_SINE);
+      animation.AnimateTo(Property(mPages[mIndex].actor, mPages[mIndex].propertyPanCenter),
+                          Vector2(-mPageSize.width * 1.1f, 0.5f * mPageSize.height),
+                          AlphaFunction::EASE_OUT_SINE);
+      mAnimationPageIdPair[animation] = mTurningPageIndex;
       animation.Play();
-      animation.FinishedSignal().Connect( this, &PageTurnView::TurnedOver );
+      animation.FinishedSignal().Connect(this, &PageTurnView::TurnedOver);
     }
     else // the pan finished position is far away from the spine, set up an animation to slide the page back instead of turning over
     {
-      Animation animation= Animation::New( PAGE_SLIDE_BACK_ANIMATION_DURATION * (mOriginalCenter.x - mCurrentCenter.x) / mPageSize.width / PAGE_TURN_OVER_THRESHOLD_RATIO );
-      animation.AnimateTo( Property( mTurnEffect[mIndex], mTurnEffect[mIndex].PageTurnEffect::GetCurrentCenterPropertyName() ),
-                           mOriginalCenter, AlphaFunctions::Linear );
-      mAnimationActorPair[animation] = actor;
-      mAnimationIndexPair[animation] = mIndex;
+      Animation animation = Animation::New(PAGE_SLIDE_BACK_ANIMATION_DURATION * (mOriginalCenter.x - mCurrentCenter.x) / mPageSize.width / PAGE_TURN_OVER_THRESHOLD_RATIO);
+      animation.AnimateTo(Property(mPages[mIndex].actor, mPages[mIndex].propertyCurrentCenter),
+                          mOriginalCenter,
+                          AlphaFunction::LINEAR);
+      mAnimationPageIdPair[animation] = mTurningPageIndex;
       animation.Play();
-      mIsSliding[mIndex] = true;
-      animation.FinishedSignal().Connect( this, &PageTurnView::SliddenBack );
+      mSlidingCount++;
+      animation.FinishedSignal().Connect(this, &PageTurnView::SliddenBack);
 
-      mPageTurnStartedSignal.Emit( handle, static_cast<unsigned int>( mCurrentPageIndex + ( ( mIsTurnBack[mPanActor] ) ? -1 : 0 ) ), mIsTurnBack[mPanActor] );
+      mPageTurnStartedSignal.Emit(handle, static_cast<unsigned int>(mTurningPageIndex), mPages[mIndex].isTurnBack);
     }
   }
   else
   {
     // In portrait view, an outwards flick should turn the previous page back
     // In landscape view, nothing to do
-    OnPossibleOutwardsFlick( gesturePosition, gestureSpeed );
+    OnPossibleOutwardsFlick(gesturePosition, gestureSpeed);
   }
-
   mPageUpdated = true;
 }
 
-void PageTurnView::TurnedOver( Animation& animation )
+void PageTurnView::TurnedOver(Animation& animation)
 {
-  ImageActor actor = mAnimationActorPair[animation];
-  mIsTurnBack[actor] = !mIsTurnBack[actor];
-  actor.RemoveConstraints();
-  mRootOnScreen.Add(actor);
-  int index = mAnimationIndexPair[animation];
-  mIsAnimating[index] = false;
-  mTurnEffect[index].RemoveConstraints();
-  mAnimationIndexPair.erase( animation );
-  mAnimationActorPair.erase( animation );
-
-  SetSpineEffect( actor, mIsTurnBack[actor] );
+  int pageId = mAnimationPageIdPair[animation];
+  int index  = pageId % NUMBER_OF_CACHED_PAGES;
+
+  mPages[index].ChangeTurnDirection();
+  mPages[index].actor.RemoveConstraints();
+  Self().Add(mPages[index].actor);
+  mAnimatingCount--;
+  mAnimationPageIdPair.erase(animation);
+
+  float degree = mPages[index].isTurnBack ? 180.f : 0.f;
+  mPages[index].actor.SetProperty(Actor::Property::ORIENTATION, Quaternion(Degree(degree), Vector3::YAXIS));
+  mPages[index].UseEffect(mSpineEffectShader);
+
+  int id = pageId + (mPages[index].isTurnBack ? -1 : 1);
+  if(id >= 0 && id < mTotalPageCount)
+  {
+    mPages[id % NUMBER_OF_CACHED_PAGES].actor.SetProperty(Actor::Property::VISIBLE, false);
+  }
+
+  OnTurnedOver(mPages[index].actor, mPages[index].isTurnBack);
 
   // Guard against destruction during signal emission
-  Toolkit::PageTurnView handle( GetOwner() );
-  mPageTurnFinishedSignal.Emit( handle, static_cast<unsigned int>( mCurrentPageIndex + ( ( mIsTurnBack[actor] ) ? -1 : 0 ) ), mIsTurnBack[actor] );
+  Toolkit::PageTurnView handle(GetOwner());
+  mPageTurnFinishedSignal.Emit(handle, static_cast<unsigned int>(pageId), mPages[index].isTurnBack);
 }
 
-void PageTurnView::SliddenBack( Animation& animation )
+void PageTurnView::SliddenBack(Animation& animation)
 {
-  ImageActor actor = mAnimationActorPair[animation];
-  mRootOnScreen.Add(actor);
-  int index = mAnimationIndexPair[animation];
-  mIsSliding[index] = false;
-  mIsAnimating[index] = false;
-  mAnimationIndexPair.erase( animation );
-  mAnimationActorPair.erase( animation );
+  int pageId = mAnimationPageIdPair[animation];
+  int index  = pageId % NUMBER_OF_CACHED_PAGES;
+  Self().Add(mPages[index].actor);
+  mSlidingCount--;
+  mAnimatingCount--;
+  mAnimationPageIdPair.erase(animation);
 
-  SetSpineEffect( actor, mIsTurnBack[actor] );
+  mPages[index].UseEffect(mSpineEffectShader);
+
+  int id = pageId + (mPages[index].isTurnBack ? -1 : 1);
+  if(id >= 0 && id < mTotalPageCount)
+  {
+    mPages[id % NUMBER_OF_CACHED_PAGES].actor.SetProperty(Actor::Property::VISIBLE, false);
+  }
 
   // Guard against destruction during signal emission
-  Toolkit::PageTurnView handle( GetOwner() );
-  mPageTurnFinishedSignal.Emit( handle, static_cast<unsigned int>( mCurrentPageIndex + ( ( mIsTurnBack[mPanActor] ) ? -1 : 0 ) ), mIsTurnBack[actor] );
+  Toolkit::PageTurnView handle(GetOwner());
+  mPageTurnFinishedSignal.Emit(handle, static_cast<unsigned int>(pageId), mPages[index].isTurnBack);
 }
 
 void PageTurnView::OrganizePageDepth()
 {
-  for( int i=0; i<NUMBER_OF_CACHED_PAGES_EACH_SIDE;i++ )
+  for(int i = 0; i < NUMBER_OF_CACHED_PAGES_EACH_SIDE; i++)
   {
-    if(mCurrentPageIndex+i < mTotalPageCount)
+    if(mCurrentPageIndex + i < mTotalPageCount)
     {
-      mPageActors[( mCurrentPageIndex+i )%NUMBER_OF_CACHED_PAGES].SetZ( -static_cast<float>( i )*STATIC_PAGE_INTERVAL_DISTANCE );
+      mPages[(mCurrentPageIndex + i) % NUMBER_OF_CACHED_PAGES].actor.SetProperty(Actor::Property::POSITION_Z, -static_cast<float>(i) * STATIC_PAGE_INTERVAL_DISTANCE);
     }
-    if( mCurrentPageIndex >= i + 1 )
+    if(mCurrentPageIndex >= i + 1)
     {
-      mPageActors[( mCurrentPageIndex-i-1 )%NUMBER_OF_CACHED_PAGES].SetZ( -static_cast<float>( i )*STATIC_PAGE_INTERVAL_DISTANCE );
+      mPages[(mCurrentPageIndex - i - 1) % NUMBER_OF_CACHED_PAGES].actor.SetProperty(Actor::Property::POSITION_Z, -static_cast<float>(i) * STATIC_PAGE_INTERVAL_DISTANCE);
     }
   }
 }
 
-void PageTurnView::SetShaderEffect( ImageActor actor, ShaderEffect shaderEffect )
+void PageTurnView::StopTurning()
 {
-  SetShaderEffectRecursively( actor, shaderEffect );
+  mAnimatingCount = 0;
+  mSlidingCount   = 0;
+
+  if(!mPageUpdated)
+  {
+    int index = mTurningPageIndex % NUMBER_OF_CACHED_PAGES;
+    Self().Add(mPages[index].actor);
+    mPages[index].actor.RemoveConstraints();
+    mPages[index].UseEffect(mSpineEffectShader);
+    float degree = mTurningPageIndex == mCurrentPageIndex ? 0.f : 180.f;
+    mPages[index].actor.SetProperty(Actor::Property::ORIENTATION, Quaternion(Degree(degree), Vector3::YAXIS));
+    mPageUpdated = true;
+  }
+
+  if(!mAnimationPageIdPair.empty())
+  {
+    for(std::map<Animation, int>::iterator it = mAnimationPageIdPair.begin(); it != mAnimationPageIdPair.end(); ++it)
+    {
+      static_cast<Animation>(it->first).SetCurrentProgress(1.f);
+    }
+  }
 }
 
 Toolkit::PageTurnView::PageTurnSignal& PageTurnView::PageTurnStartedSignal()
@@ -1063,6 +1002,99 @@ Toolkit::PageTurnView::PagePanSignal& PageTurnView::PagePanFinishedSignal()
   return mPagePanFinishedSignal;
 }
 
+bool PageTurnView::DoConnectSignal(BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor)
+{
+  Dali::BaseHandle handle(object);
+
+  bool                  connected(true);
+  Toolkit::PageTurnView pageTurnView = Toolkit::PageTurnView::DownCast(handle);
+
+  if(0 == strcmp(signalName.c_str(), SIGNAL_PAGE_TURN_STARTED))
+  {
+    pageTurnView.PageTurnStartedSignal().Connect(tracker, functor);
+  }
+  else if(0 == strcmp(signalName.c_str(), SIGNAL_PAGE_TURN_FINISHED))
+  {
+    pageTurnView.PageTurnFinishedSignal().Connect(tracker, functor);
+  }
+  else if(0 == strcmp(signalName.c_str(), SIGNAL_PAGE_PAN_STARTED))
+  {
+    pageTurnView.PagePanStartedSignal().Connect(tracker, functor);
+  }
+  else if(0 == strcmp(signalName.c_str(), SIGNAL_PAGE_PAN_FINISHED))
+  {
+    pageTurnView.PagePanFinishedSignal().Connect(tracker, functor);
+  }
+  else
+  {
+    // signalName does not match any signal
+    connected = false;
+  }
+
+  return connected;
+}
+
+void PageTurnView::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value)
+{
+  Toolkit::PageTurnView pageTurnView = Toolkit::PageTurnView::DownCast(Dali::BaseHandle(object));
+
+  if(pageTurnView)
+  {
+    PageTurnView& pageTurnViewImpl(GetImplementation(pageTurnView));
+
+    switch(index)
+    {
+      case Toolkit::PageTurnView::Property::VIEW_PAGE_SIZE:
+      {
+        pageTurnViewImpl.SetPageSize(value.Get<Vector2>());
+        break;
+      }
+      case Toolkit::PageTurnView::Property::CURRENT_PAGE_ID:
+      {
+        pageTurnViewImpl.GoToPage(value.Get<int>());
+        break;
+      }
+      case Toolkit::PageTurnView::Property::SPINE_SHADOW:
+      {
+        pageTurnViewImpl.SetSpineShadowParameter(value.Get<Vector2>());
+        break;
+      }
+    }
+  }
+}
+
+Property::Value PageTurnView::GetProperty(BaseObject* object, Property::Index index)
+{
+  Property::Value value;
+
+  Toolkit::PageTurnView pageTurnView = Toolkit::PageTurnView::DownCast(Dali::BaseHandle(object));
+
+  if(pageTurnView)
+  {
+    PageTurnView& pageTurnViewImpl(GetImplementation(pageTurnView));
+
+    switch(index)
+    {
+      case Toolkit::PageTurnView::Property::VIEW_PAGE_SIZE:
+      {
+        value = pageTurnViewImpl.GetPageSize();
+        break;
+      }
+      case Toolkit::PageTurnView::Property::CURRENT_PAGE_ID:
+      {
+        value = static_cast<int>(pageTurnViewImpl.GetCurrentPage());
+        break;
+      }
+      case Toolkit::PageTurnView::Property::SPINE_SHADOW:
+      {
+        value = pageTurnViewImpl.GetSpineShadowParameter();
+        break;
+      }
+    }
+  }
+  return value;
+}
+
 } // namespace Internal
 
 } // namespace Toolkit