[dali_1.1.7] Merge branch 'devel/master' 39/50039/1
authorLee Morgan <Lee.morgan@partner.samsung.com>
Fri, 23 Oct 2015 10:00:59 +0000 (11:00 +0100)
committerLee Morgan <Lee.morgan@partner.samsung.com>
Fri, 23 Oct 2015 10:01:00 +0000 (11:01 +0100)
Change-Id: I51e2dd26cb5e210757d50acdfe40e664cc572206

122 files changed:
automated-tests/src/dali-toolkit/utc-Dali-ItemView.cpp
automated-tests/src/dali-toolkit/utc-Dali-RendererFactory.cpp
automated-tests/src/dali-toolkit/utc-Dali-ScrollView.cpp
automated-tests/src/dali-toolkit/utc-Dali-ShaderEffects.cpp
build/tizen/dali-toolkit/Makefile.am
dali-toolkit/devel-api/shader-effects/dissolve-effect.h
dali-toolkit/devel-api/shader-effects/distance-field-effect.h
dali-toolkit/devel-api/shader-effects/motion-blur-effect.h
dali-toolkit/devel-api/shader-effects/motion-stretch-effect.h
dali-toolkit/internal/builder/builder-set-property.cpp
dali-toolkit/internal/controls/bubble-effect/bubble-emitter-impl.cpp
dali-toolkit/internal/controls/bubble-effect/bubble-emitter-impl.h
dali-toolkit/internal/controls/gaussian-blur-view/gaussian-blur-view-impl.cpp
dali-toolkit/internal/controls/image-view/image-view-impl.cpp
dali-toolkit/internal/controls/model3d-view/model3d-view-impl.cpp
dali-toolkit/internal/controls/page-turn-view/page-turn-view-impl.cpp
dali-toolkit/internal/controls/renderers/control-renderer-data-impl.h
dali-toolkit/internal/controls/renderers/control-renderer-impl.cpp
dali-toolkit/internal/controls/renderers/gradient/gradient-renderer.cpp
dali-toolkit/internal/controls/renderers/image/image-renderer.cpp
dali-toolkit/internal/controls/renderers/image/image-renderer.h
dali-toolkit/internal/controls/renderers/npatch/npatch-renderer.cpp
dali-toolkit/internal/controls/renderers/npatch/npatch-renderer.h
dali-toolkit/internal/controls/renderers/renderer-factory-cache.cpp
dali-toolkit/internal/controls/renderers/renderer-factory-cache.h
dali-toolkit/internal/controls/renderers/renderer-factory-impl.cpp
dali-toolkit/internal/controls/renderers/renderer-factory-impl.h
dali-toolkit/internal/controls/scroll-bar/scroll-bar-impl.cpp
dali-toolkit/internal/controls/scroll-bar/scroll-bar-impl.h
dali-toolkit/internal/controls/scrollable/bouncing-effect-actor.cpp
dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.cpp
dali-toolkit/internal/controls/scrollable/scroll-view/scroll-overshoot-indicator-impl.cpp
dali-toolkit/internal/controls/scrollable/scroll-view/scroll-overshoot-indicator-impl.h
dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.cpp
dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.h
dali-toolkit/internal/controls/scrollable/scrollable-impl.cpp
dali-toolkit/internal/controls/scrollable/scrollable-impl.h
dali-toolkit/internal/file.list
dali-toolkit/internal/text/decorator/text-decorator.cpp
dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.cpp
dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.h
dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.cpp
dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h
dali-toolkit/internal/text/rendering/atlas/atlas-manager-impl.cpp [moved from dali-toolkit/internal/atlas-manager/atlas-manager-impl.cpp with 50% similarity]
dali-toolkit/internal/text/rendering/atlas/atlas-manager-impl.h [moved from dali-toolkit/internal/atlas-manager/atlas-manager-impl.h with 81% similarity]
dali-toolkit/internal/text/rendering/atlas/atlas-manager.cpp [moved from dali-toolkit/internal/atlas-manager/atlas-manager.cpp with 83% similarity]
dali-toolkit/internal/text/rendering/atlas/atlas-manager.h [moved from dali-toolkit/internal/atlas-manager/atlas-manager.h with 62% similarity]
dali-toolkit/internal/text/rendering/atlas/atlas-mesh-factory.cpp [new file with mode: 0644]
dali-toolkit/internal/text/rendering/atlas/atlas-mesh-factory.h [new file with mode: 0644]
dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp
dali-toolkit/internal/text/text-controller-impl.cpp
dali-toolkit/internal/text/text-controller.cpp
dali-toolkit/public-api/dali-toolkit-version.cpp
dali-toolkit/styles/480x800/dali-toolkit-default-theme.json
dali-toolkit/styles/720x1280/dali-toolkit-default-theme.json
dali-toolkit/styles/images-common/00_popup_bg.9.png [moved from dali-toolkit/images-common/00_popup_bg.9.png with 100% similarity]
dali-toolkit/styles/images-common/00_popup_bg.png [moved from dali-toolkit/images-common/00_popup_bg.png with 100% similarity]
dali-toolkit/styles/images-common/00_popup_bottom_bg.png [moved from dali-toolkit/images-common/00_popup_bottom_bg.png with 100% similarity]
dali-toolkit/styles/images-common/00_popup_bubble_bg.png [moved from dali-toolkit/images-common/00_popup_bubble_bg.png with 100% similarity]
dali-toolkit/styles/images-common/00_popup_bubble_tail_bottom.png [moved from dali-toolkit/images-common/00_popup_bubble_tail_bottom.png with 100% similarity]
dali-toolkit/styles/images-common/00_popup_button_bg.png [moved from dali-toolkit/images-common/00_popup_button_bg.png with 100% similarity]
dali-toolkit/styles/images-common/00_popup_button_pressed.png [moved from dali-toolkit/images-common/00_popup_button_pressed.png with 100% similarity]
dali-toolkit/styles/images-common/B16-8_TTS_focus.png [moved from dali-toolkit/images-common/B16-8_TTS_focus.png with 100% similarity]
dali-toolkit/styles/images-common/broken.png [new file with mode: 0644]
dali-toolkit/styles/images-common/button-disabled.9.png [moved from dali-toolkit/images-common/button-disabled.9.png with 100% similarity]
dali-toolkit/styles/images-common/button-down-disabled.9.png [moved from dali-toolkit/images-common/button-down-disabled.9.png with 100% similarity]
dali-toolkit/styles/images-common/button-down.9.png [moved from dali-toolkit/images-common/button-down.9.png with 100% similarity]
dali-toolkit/styles/images-common/button-up.9.png [moved from dali-toolkit/images-common/button-up.9.png with 100% similarity]
dali-toolkit/styles/images-common/checkbox-selected-diabled.png [moved from dali-toolkit/images-common/checkbox-selected-diabled.png with 100% similarity]
dali-toolkit/styles/images-common/checkbox-selected.png [moved from dali-toolkit/images-common/checkbox-selected.png with 100% similarity]
dali-toolkit/styles/images-common/checkbox-unselected-disabled.png [moved from dali-toolkit/images-common/checkbox-unselected-disabled.png with 100% similarity]
dali-toolkit/styles/images-common/checkbox-unselected.png [moved from dali-toolkit/images-common/checkbox-unselected.png with 100% similarity]
dali-toolkit/styles/images-common/copy_paste_icon_clipboard.png [moved from dali-toolkit/images-common/copy_paste_icon_clipboard.png with 100% similarity]
dali-toolkit/styles/images-common/copy_paste_icon_copy.png [moved from dali-toolkit/images-common/copy_paste_icon_copy.png with 100% similarity]
dali-toolkit/styles/images-common/copy_paste_icon_cut.png [moved from dali-toolkit/images-common/copy_paste_icon_cut.png with 100% similarity]
dali-toolkit/styles/images-common/copy_paste_icon_paste.png [moved from dali-toolkit/images-common/copy_paste_icon_paste.png with 100% similarity]
dali-toolkit/styles/images-common/copy_paste_icon_select.png [moved from dali-toolkit/images-common/copy_paste_icon_select.png with 100% similarity]
dali-toolkit/styles/images-common/copy_paste_icon_select_all.png [moved from dali-toolkit/images-common/copy_paste_icon_select_all.png with 100% similarity]
dali-toolkit/styles/images-common/cursor_handler_ball_center.png [moved from dali-toolkit/images-common/cursor_handler_ball_center.png with 100% similarity]
dali-toolkit/styles/images-common/file.list [moved from dali-toolkit/images-common/file.list with 100% similarity]
dali-toolkit/styles/images-common/insertpoint-icon-pressed.png [moved from dali-toolkit/images-common/insertpoint-icon-pressed.png with 100% similarity]
dali-toolkit/styles/images-common/insertpoint-icon.png [moved from dali-toolkit/images-common/insertpoint-icon.png with 100% similarity]
dali-toolkit/styles/images-common/keyboard_focus.png [moved from dali-toolkit/images-common/keyboard_focus.png with 100% similarity]
dali-toolkit/styles/images-common/magnifier.png [moved from dali-toolkit/images-common/magnifier.png with 100% similarity]
dali-toolkit/styles/images-common/popup_bg.png [moved from dali-toolkit/images-common/popup_bg.png with 100% similarity]
dali-toolkit/styles/images-common/popup_bubble_bg.#.png [moved from dali-toolkit/images-common/popup_bubble_bg.#.png with 100% similarity]
dali-toolkit/styles/images-common/popup_bubble_bg_ef.#.png [moved from dali-toolkit/images-common/popup_bubble_bg_ef.#.png with 100% similarity]
dali-toolkit/styles/images-common/popup_bubble_bg_line.#.png [moved from dali-toolkit/images-common/popup_bubble_bg_line.#.png with 100% similarity]
dali-toolkit/styles/images-common/popup_bubble_tail_bottom.png [moved from dali-toolkit/images-common/popup_bubble_tail_bottom.png with 100% similarity]
dali-toolkit/styles/images-common/popup_bubble_tail_bottom_ef.png [moved from dali-toolkit/images-common/popup_bubble_tail_bottom_ef.png with 100% similarity]
dali-toolkit/styles/images-common/popup_bubble_tail_bottom_line.png [moved from dali-toolkit/images-common/popup_bubble_tail_bottom_line.png with 100% similarity]
dali-toolkit/styles/images-common/popup_bubble_tail_top.png [moved from dali-toolkit/images-common/popup_bubble_tail_top.png with 100% similarity]
dali-toolkit/styles/images-common/popup_bubble_tail_top_ef.png [moved from dali-toolkit/images-common/popup_bubble_tail_top_ef.png with 100% similarity]
dali-toolkit/styles/images-common/popup_bubble_tail_top_line.png [moved from dali-toolkit/images-common/popup_bubble_tail_top_line.png with 100% similarity]
dali-toolkit/styles/images-common/popup_scroll.png [moved from dali-toolkit/images-common/popup_scroll.png with 100% similarity]
dali-toolkit/styles/images-common/popup_tail_down.png [moved from dali-toolkit/images-common/popup_tail_down.png with 100% similarity]
dali-toolkit/styles/images-common/popup_tail_left.png [moved from dali-toolkit/images-common/popup_tail_left.png with 100% similarity]
dali-toolkit/styles/images-common/popup_tail_right.png [moved from dali-toolkit/images-common/popup_tail_right.png with 100% similarity]
dali-toolkit/styles/images-common/popup_tail_up.png [moved from dali-toolkit/images-common/popup_tail_up.png with 100% similarity]
dali-toolkit/styles/images-common/radio-button-selected-disabled.png [moved from dali-toolkit/images-common/radio-button-selected-disabled.png with 100% similarity]
dali-toolkit/styles/images-common/radio-button-selected.png [moved from dali-toolkit/images-common/radio-button-selected.png with 100% similarity]
dali-toolkit/styles/images-common/radio-button-unselected-disabled.png [moved from dali-toolkit/images-common/radio-button-unselected-disabled.png with 100% similarity]
dali-toolkit/styles/images-common/radio-button-unselected.png [moved from dali-toolkit/images-common/radio-button-unselected.png with 100% similarity]
dali-toolkit/styles/images-common/selection-popup-bg.9.png [moved from dali-toolkit/images-common/selection-popup-bg.9.png with 100% similarity]
dali-toolkit/styles/images-common/selection_handle_ball_left.png [moved from dali-toolkit/images-common/selection_handle_ball_left.png with 100% similarity]
dali-toolkit/styles/images-common/selection_handle_ball_right.png [moved from dali-toolkit/images-common/selection_handle_ball_right.png with 100% similarity]
dali-toolkit/styles/images-common/selection_marker_left.png [moved from dali-toolkit/images-common/selection_marker_left.png with 100% similarity]
dali-toolkit/styles/images-common/selection_marker_right.png [moved from dali-toolkit/images-common/selection_marker_right.png with 100% similarity]
dali-toolkit/styles/images-common/slider-popup-arrow.png [moved from dali-toolkit/images-common/slider-popup-arrow.png with 100% similarity]
dali-toolkit/styles/images-common/slider-popup.9.png [moved from dali-toolkit/images-common/slider-popup.9.png with 100% similarity]
dali-toolkit/styles/images-common/slider-popup.png [moved from dali-toolkit/images-common/slider-popup.png with 100% similarity]
dali-toolkit/styles/images-common/slider-skin-handle.png [moved from dali-toolkit/images-common/slider-skin-handle.png with 100% similarity]
dali-toolkit/styles/images-common/slider-skin-progress.9.png [moved from dali-toolkit/images-common/slider-skin-progress.9.png with 100% similarity]
dali-toolkit/styles/images-common/slider-skin-progress.png [moved from dali-toolkit/images-common/slider-skin-progress.png with 100% similarity]
dali-toolkit/styles/images-common/slider-skin.9.png [moved from dali-toolkit/images-common/slider-skin.9.png with 100% similarity]
dali-toolkit/styles/images-common/slider-skin.png [moved from dali-toolkit/images-common/slider-skin.png with 100% similarity]
dali-toolkit/styles/images-common/text-input-selection-handle-left-press.png [moved from dali-toolkit/images-common/text-input-selection-handle-left-press.png with 100% similarity]
dali-toolkit/styles/images-common/text-input-selection-handle-left.png [moved from dali-toolkit/images-common/text-input-selection-handle-left.png with 100% similarity]
dali-toolkit/styles/images-common/text-input-selection-handle-right-press.png [moved from dali-toolkit/images-common/text-input-selection-handle-right-press.png with 100% similarity]
dali-toolkit/styles/images-common/text-input-selection-handle-right.png [moved from dali-toolkit/images-common/text-input-selection-handle-right.png with 100% similarity]
docs/content/programming-guide/styling.h
packaging/dali-toolkit.spec

index b85524d..2c49895 100644 (file)
@@ -704,11 +704,11 @@ int UtcDaliItemViewReplaceItemsP(void)
 
   for( unsigned int i = 0u; i < 10; ++i )
   {
-    Actor child = view.GetChildAt( i );
+    Actor child = view.GetItem( i );
     Actor newActor = Actor::New();
     newActor.SetName("Replaced");
 
-    replaceList.push_back( Item( view.GetItemId(child), newActor ) );
+    replaceList.push_back( Item( i, newActor ) );
   }
 
   if( !replaceList.empty() )
index a570b72..3b603b0 100644 (file)
@@ -27,6 +27,8 @@ using namespace Dali::Toolkit;
 
 namespace
 {
+typedef NinePatchImage::StretchRanges StretchRanges;
+
 const char* TEST_IMAGE_FILE_NAME =  "gallery_image_01.jpg";
 const char* TEST_NPATCH_FILE_NAME =  "gallery_image_01.9.jpg";
 
@@ -63,27 +65,38 @@ void InitialiseRegionsToZeroAlpha( Integration::Bitmap* image, unsigned int imag
   }
 }
 
-void AddStretchRegionsToImage( Integration::Bitmap* image, unsigned int imageWidth, unsigned int imageHeight, const Vector4& requiredStretchBorder, Pixel::Format pixelFormat )
+void AddStretchRegionsToImage( Integration::Bitmap* image, unsigned int imageWidth, unsigned int imageHeight, const StretchRanges& stretchRangesX, const StretchRanges& stretchRangesY, Pixel::Format pixelFormat )
 {
   PixelBuffer* pixbuffer = image->GetBuffer();
   unsigned int bytesPerPixel = GetBytesPerPixel( pixelFormat );
 
-  for( unsigned int column = requiredStretchBorder.x; column < imageWidth - requiredStretchBorder.z; ++column )
+  for(StretchRanges::ConstIterator it = stretchRangesX.Begin(); it != stretchRangesX.End(); ++it)
   {
-    unsigned int pixelOffset = column * bytesPerPixel;
-    pixbuffer[ pixelOffset ] = 0x00;
-    pixbuffer[ pixelOffset + 1 ] = 0x00;
-    pixbuffer[ pixelOffset + 2 ] = 0x00;
-    pixbuffer[ pixelOffset + 3 ] = 0xFF;
+    const Uint16Pair& range = *it;
+    //since the stretch range is in the cropped image space, we need to offset by 1 to get it to the uncropped image space
+    for( unsigned int column = range.GetX() + 1u; column < range.GetY() + 1u; ++column )
+    {
+      unsigned int pixelOffset = column * bytesPerPixel;
+      pixbuffer[ pixelOffset ] = 0x00;
+      pixbuffer[ pixelOffset + 1 ] = 0x00;
+      pixbuffer[ pixelOffset + 2 ] = 0x00;
+      pixbuffer[ pixelOffset + 3 ] = 0xFF;
+    }
   }
 
-  for( unsigned int row = requiredStretchBorder.y; row < imageHeight - requiredStretchBorder.w; ++row )
+
+  for(StretchRanges::ConstIterator it = stretchRangesY.Begin(); it != stretchRangesY.End(); ++it)
   {
-    unsigned int pixelOffset = row * imageWidth * bytesPerPixel;
-    pixbuffer[ pixelOffset ] = 0x00;
-    pixbuffer[ pixelOffset + 1 ] = 0x00;
-    pixbuffer[ pixelOffset + 2 ] = 0x00;
-    pixbuffer[ pixelOffset + 3 ] = 0xFF;
+    const Uint16Pair& range = *it;
+    //since the stretch range is in the cropped image space, we need to offset by 1 to get it to the uncropped image space
+    for( unsigned int row = range.GetX() + 1u; row < range.GetY() + 1u; ++row )
+    {
+      unsigned int pixelOffset = row * imageWidth * bytesPerPixel;
+      pixbuffer[ pixelOffset ] = 0x00;
+      pixbuffer[ pixelOffset + 1 ] = 0x00;
+      pixbuffer[ pixelOffset + 2 ] = 0x00;
+      pixbuffer[ pixelOffset + 3 ] = 0xFF;
+    }
   }
 }
 
@@ -120,7 +133,8 @@ void AddChildRegionsToImage( Integration::Bitmap* image, unsigned int imageWidth
 Integration::ResourcePointer CustomizeNinePatch( TestApplication& application,
                                                  unsigned int ninePatchImageWidth,
                                                  unsigned int ninePatchImageHeight,
-                                                 const Vector4& requiredStretchBorder,
+                                                 const StretchRanges& stretchRangesX,
+                                                 const StretchRanges& stretchRangesY,
                                                  bool addChildRegion = false,
                                                  Vector4 requiredChildRegion = Vector4::ZERO )
 {
@@ -136,7 +150,7 @@ Integration::ResourcePointer CustomizeNinePatch( TestApplication& application,
   InitialiseRegionsToZeroAlpha( bitmap, ninePatchImageWidth, ninePatchImageHeight, pixelFormat );
 
   tet_infoline("Add Stretch regions to Bitmap");
-  AddStretchRegionsToImage( bitmap, ninePatchImageWidth, ninePatchImageHeight, requiredStretchBorder, pixelFormat );
+  AddStretchRegionsToImage( bitmap, ninePatchImageWidth, ninePatchImageHeight, stretchRangesX, stretchRangesY, pixelFormat );
 
   if( addChildRegion )
   {
@@ -151,6 +165,40 @@ Integration::ResourcePointer CustomizeNinePatch( TestApplication& application,
   return resourcePtr;
 }
 
+void TestControlRendererRender( ToolkitTestApplication& application, Actor& actor, ControlRenderer& controlRenderer, Integration::ResourcePointer resourcePtr = Integration::ResourcePointer(), std::size_t expectedSamplers = 0)
+{
+  actor.SetSize( 200.f, 200.f );
+  Stage::GetCurrent().Add( actor );
+  controlRenderer.SetSize( Vector2(200.f, 200.f) );
+  controlRenderer.SetOnStage( actor );
+
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+  DALI_TEST_CHECK( actor.GetRendererAt(0u).GetMaterial().GetNumberOfTextures() == expectedSamplers );
+
+  application.SendNotification();
+  application.Render();
+
+  if( resourcePtr )
+  {
+    Integration::ResourceRequest* request = application.GetPlatform().GetRequest();
+    if(request)
+    {
+      application.GetPlatform().SetResourceLoaded(request->GetId(), request->GetType()->id, resourcePtr );
+    }
+  }
+
+  application.Render();
+  application.SendNotification();
+
+  if( resourcePtr )
+  {
+    DALI_TEST_CHECK(application.GetPlatform().WasCalled(TestPlatformAbstraction::LoadResourceFunc));
+  }
+
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+
+}
+
 } // namespace
 
 
@@ -234,19 +282,10 @@ int UtcDaliRendererFactoryGetColorRenderer1(void)
   DALI_TEST_CHECK( controlRenderer );
 
   Actor actor = Actor::New();
-  actor.SetSize(200.f, 200.f);
-  Stage::GetCurrent().Add( actor );
-  controlRenderer.SetSize(Vector2(200.f, 200.f));
-  controlRenderer.SetOnStage( actor );
-
-  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
-
-  TestGlAbstraction& gl = application.GetGlAbstraction();
-
-  application.SendNotification();
-  application.Render(0);
+  TestControlRendererRender( application, actor, controlRenderer );
 
   Vector4 actualValue(Vector4::ZERO);
+  TestGlAbstraction& gl = application.GetGlAbstraction();
   DALI_TEST_CHECK( gl.GetUniformValue<Vector4>( "uBlendColor", actualValue ) );
   DALI_TEST_EQUALS( actualValue, testColor, TEST_LOCATION );
 
@@ -266,19 +305,10 @@ int UtcDaliRendererFactoryGetColorRenderer2(void)
   DALI_TEST_CHECK( controlRenderer );
 
   Actor actor = Actor::New();
-  actor.SetSize(200.f, 200.f);
-  Stage::GetCurrent().Add( actor );
-  controlRenderer.SetSize(Vector2(200.f, 200.f));
-  controlRenderer.SetOnStage( actor );
-
-  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
-
-  TestGlAbstraction& gl = application.GetGlAbstraction();
-
-  application.SendNotification();
-  application.Render(0);
+  TestControlRendererRender( application, actor, controlRenderer );
 
   Vector4 actualValue(Vector4::ZERO);
+  TestGlAbstraction& gl = application.GetGlAbstraction();
   DALI_TEST_CHECK( gl.GetUniformValue<Vector4>( "uBlendColor", actualValue ) );
   DALI_TEST_EQUALS( actualValue, testColor, TEST_LOCATION );
 
@@ -402,20 +432,9 @@ int UtcDaliRendererFactoryGetLinearGradientRenderer(void)
   ControlRenderer controlRenderer = factory.GetControlRenderer(propertyMap);
   DALI_TEST_CHECK( controlRenderer );
 
-  Actor actor = Actor::New();
-  Vector2 size(200.f, 200.f);
-  actor.SetSize(size);
-  Stage::GetCurrent().Add( actor );
-  controlRenderer.SetOnStage( actor );
-  controlRenderer.SetSize(size);
-
-  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
-
   // A lookup texture is generated and pass to shader as sampler
-  DALI_TEST_CHECK( actor.GetRendererAt(0u).GetMaterial().GetNumberOfSamplers() == 1u );
-
-  application.SendNotification();
-  application.Render(0);
+  Actor actor = Actor::New();
+  TestControlRendererRender( application, actor, controlRenderer, Integration::ResourcePointer(), 1u );
 
   controlRenderer.SetOffStage( actor );
   DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
@@ -453,26 +472,15 @@ int UtcDaliRendererFactoryGetRadialGradientRenderer(void)
   ControlRenderer controlRenderer = factory.GetControlRenderer(propertyMap);
   DALI_TEST_CHECK( controlRenderer );
 
-  Actor actor = Actor::New();
-  Vector2 size(200.f, 200.f);
-  actor.SetSize(size);
-  Stage::GetCurrent().Add( actor );
-  controlRenderer.SetSize(size);
-  controlRenderer.SetOnStage( actor );
-
-  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
-
   // A lookup texture is generated and pass to shader as sampler
-  DALI_TEST_CHECK( actor.GetRendererAt(0u).GetMaterial().GetNumberOfSamplers() == 1u );
-
-  TestGlAbstraction& gl = application.GetGlAbstraction();
-  application.SendNotification();
-  application.Render(0);
+  Actor actor = Actor::New();
+  TestControlRendererRender( application, actor, controlRenderer, Integration::ResourcePointer(), 1u );
 
   Matrix3 alignMatrix( radius, 0.f, 0.f, 0.f, radius, 0.f, center.x, center.y, 1.f );
   alignMatrix.Invert();
 
   Matrix3 actualValue( Matrix3::IDENTITY );
+  TestGlAbstraction& gl = application.GetGlAbstraction();
   DALI_TEST_CHECK( gl.GetUniformValue<Matrix3>( "uAlignmentMatrix", actualValue ) );
   DALI_TEST_EQUALS( actualValue, alignMatrix, Math::MACHINE_EPSILON_100, TEST_LOCATION );
 
@@ -495,31 +503,9 @@ int UtcDaliRendererFactoryGetImageRenderer1(void)
   DALI_TEST_CHECK( controlRenderer );
 
   Actor actor = Actor::New();
-  actor.SetSize( 200.f, 200.f );
-  Stage::GetCurrent().Add( actor );
-  controlRenderer.SetSize( Vector2(200.f, 200.f) );
-  controlRenderer.SetOnStage( actor );
-
-  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
-  DALI_TEST_CHECK( actor.GetRendererAt(0u).GetMaterial().GetNumberOfSamplers() == 1u );
+  TestControlRendererRender( application, actor, controlRenderer, Integration::ResourcePointer(Integration::Bitmap::New(Integration::Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::OWNED_DISCARD)), 1u );
 
   TestGlAbstraction& gl = application.GetGlAbstraction();
-  application.SendNotification();
-  application.Render();
-
-  Integration::ResourceRequest* request = application.GetPlatform().GetRequest();
-  if(request)
-  {
-    application.GetPlatform().SetResourceLoaded(request->GetId(), request->GetType()->id, Integration::ResourcePointer(Integration::Bitmap::New(Integration::Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::OWNED_DISCARD)));
-  }
-
-  application.Render();
-  application.SendNotification();
-
-  DALI_TEST_CHECK(application.GetPlatform().WasCalled(TestPlatformAbstraction::LoadResourceFunc));
-
-  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
-
   int textureUnit = -1;
   DALI_TEST_CHECK( gl.GetUniformValue< int >( "sTexture", textureUnit ) );
   DALI_TEST_EQUALS( textureUnit, 0, TEST_LOCATION );
@@ -542,29 +528,9 @@ int UtcDaliRendererFactoryGetImageRenderer2(void)
   ControlRenderer controlRenderer = factory.GetControlRenderer( image );
 
   Actor actor = Actor::New();
-  actor.SetSize( 200.f, 200.f );
-  Stage::GetCurrent().Add( actor );
-  controlRenderer.SetSize( Vector2(200.f, 200.f) );
-  controlRenderer.SetOnStage( actor );
-
-  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
-  DALI_TEST_CHECK( actor.GetRendererAt(0u).GetMaterial().GetNumberOfSamplers() == 1u );
+  TestControlRendererRender( application, actor, controlRenderer, Integration::ResourcePointer(Integration::Bitmap::New(Integration::Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::OWNED_DISCARD)), 1u );
 
   TestGlAbstraction& gl = application.GetGlAbstraction();
-  application.SendNotification();
-  application.Render();
-
-  Integration::ResourceRequest* request = application.GetPlatform().GetRequest();
-  if(request)
-  {
-    application.GetPlatform().SetResourceLoaded(request->GetId(), request->GetType()->id, Integration::ResourcePointer(Integration::Bitmap::New(Integration::Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::OWNED_DISCARD)));
-  }
-
-  application.Render();
-  application.SendNotification();
-
-  DALI_TEST_CHECK(application.GetPlatform().WasCalled(TestPlatformAbstraction::LoadResourceFunc));
-
   int textureUnit = -1;
   DALI_TEST_CHECK( gl.GetUniformValue< int >( "sTexture", textureUnit ) );
   DALI_TEST_EQUALS( textureUnit, 0, TEST_LOCATION );
@@ -575,99 +541,173 @@ int UtcDaliRendererFactoryGetImageRenderer2(void)
 int UtcDaliRendererFactoryGetNPatchRenderer1(void)
 {
   ToolkitTestApplication application;
-  tet_infoline( "UtcDaliRendererFactoryGetNPatchRenderer1: Request n-patch renderer with a Property::Map" );
+  tet_infoline( "UtcDaliRendererFactoryGetNPatchRenderer1: Request 9-patch renderer with a Property::Map" );
 
   RendererFactory factory = RendererFactory::Get();
   DALI_TEST_CHECK( factory );
 
   const unsigned int ninePatchImageHeight = 18;
   const unsigned int ninePatchImageWidth = 28;
-  const Vector4 requiredStretchBorder( 3, 4, 5, 6 );
-  Integration::ResourcePointer ninePatchResource = CustomizeNinePatch( application, ninePatchImageWidth, ninePatchImageHeight, requiredStretchBorder );
+  StretchRanges stretchRangesX;
+  stretchRangesX.PushBack( Uint16Pair( 2, 3 ) );
+  StretchRanges stretchRangesY;
+  stretchRangesY.PushBack( Uint16Pair( 4, 5 ) );
+  Integration::ResourcePointer ninePatchResource = CustomizeNinePatch( application, ninePatchImageWidth, ninePatchImageHeight, stretchRangesX, stretchRangesY );
 
   Property::Map propertyMap;
   propertyMap.Insert( "renderer-type", "n-patch-renderer" );
   propertyMap.Insert( "image-url", TEST_NPATCH_FILE_NAME );
+  {
+    tet_infoline( "whole grid" );
+    ControlRenderer controlRenderer = factory.GetControlRenderer( propertyMap );
+    DALI_TEST_CHECK( controlRenderer );
 
-  ControlRenderer controlRenderer = factory.GetControlRenderer( propertyMap );
-  DALI_TEST_CHECK( controlRenderer );
+    Actor actor = Actor::New();
+    TestControlRendererRender( application, actor, controlRenderer, ninePatchResource, 1u );
 
-  Actor actor = Actor::New();
-  actor.SetSize( 200.f, 200.f );
-  Stage::GetCurrent().Add( actor );
-  controlRenderer.SetSize( Vector2(200.f, 200.f) );
-  controlRenderer.SetOnStage( actor );
+    TestGlAbstraction& gl = application.GetGlAbstraction();
+    int textureUnit = -1;
+    DALI_TEST_CHECK( gl.GetUniformValue< int >( "sTexture", textureUnit ) );
+    DALI_TEST_EQUALS( textureUnit, 0, TEST_LOCATION );
+  }
 
-  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
-  DALI_TEST_CHECK( actor.GetRendererAt(0u).GetMaterial().GetNumberOfSamplers() == 1u );
+  propertyMap.Insert( "border-only", true );
+  {
+    tet_infoline( "border only" );
+    ControlRenderer controlRenderer = factory.GetControlRenderer( propertyMap );
+    DALI_TEST_CHECK( controlRenderer );
 
-  TestGlAbstraction& gl = application.GetGlAbstraction();
-  application.SendNotification();
-  application.Render();
+    Actor actor = Actor::New();
+    TestControlRendererRender( application, actor, controlRenderer, ninePatchResource, 1u );
 
-  Integration::ResourceRequest* request = application.GetPlatform().GetRequest();
-  if(request)
-  {
-    application.GetPlatform().SetResourceLoaded(request->GetId(), request->GetType()->id, ninePatchResource );
+    TestGlAbstraction& gl = application.GetGlAbstraction();
+    int textureUnit = -1;
+    DALI_TEST_CHECK( gl.GetUniformValue< int >( "sTexture", textureUnit ) );
+    DALI_TEST_EQUALS( textureUnit, 0, TEST_LOCATION );
   }
 
-  application.Render();
-  application.SendNotification();
+  END_TEST;
+}
 
-  DALI_TEST_CHECK(application.GetPlatform().WasCalled(TestPlatformAbstraction::LoadResourceFunc));
+int UtcDaliRendererFactoryGetNPatchRenderer2(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliRendererFactoryGetNPatchRenderer2: Request n-patch renderer with a Property::Map" );
 
-  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+  RendererFactory factory = RendererFactory::Get();
+  DALI_TEST_CHECK( factory );
 
-  int textureUnit = -1;
-  DALI_TEST_CHECK( gl.GetUniformValue< int >( "sTexture", textureUnit ) );
-  DALI_TEST_EQUALS( textureUnit, 0, TEST_LOCATION );
+  const unsigned int ninePatchImageWidth = 18;
+  const unsigned int ninePatchImageHeight = 28;
+  StretchRanges stretchRangesX;
+  stretchRangesX.PushBack( Uint16Pair( 2, 3 ) );
+  stretchRangesX.PushBack( Uint16Pair( 5, 7 ) );
+  stretchRangesX.PushBack( Uint16Pair( 12, 15 ) );
+  StretchRanges stretchRangesY;
+  stretchRangesY.PushBack( Uint16Pair( 4, 5 ) );
+  stretchRangesY.PushBack( Uint16Pair( 8, 12 ) );
+  stretchRangesY.PushBack( Uint16Pair( 15, 16 ) );
+  stretchRangesY.PushBack( Uint16Pair( 25, 27 ) );
+  Integration::ResourcePointer ninePatchResource = CustomizeNinePatch( application, ninePatchImageWidth, ninePatchImageHeight, stretchRangesX, stretchRangesY );
 
-  controlRenderer.SetOffStage( actor );
-  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+  Property::Map propertyMap;
+  propertyMap.Insert( "renderer-type", "n-patch-renderer" );
+  propertyMap.Insert( "image-url", TEST_NPATCH_FILE_NAME );
+  {
+    ControlRenderer controlRenderer = factory.GetControlRenderer( propertyMap );
+    DALI_TEST_CHECK( controlRenderer );
+
+    Actor actor = Actor::New();
+    TestControlRendererRender( application, actor, controlRenderer, ninePatchResource, 1u );
+
+    TestGlAbstraction& gl = application.GetGlAbstraction();
+    int textureUnit = -1;
+    DALI_TEST_CHECK( gl.GetUniformValue< int >( "sTexture", textureUnit ) );
+    DALI_TEST_EQUALS( textureUnit, 0, TEST_LOCATION );
+
+    controlRenderer.SetOffStage( actor );
+    DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+  }
+
+  propertyMap.Insert( "border-only", true );
+  {
+    tet_infoline( "border only" );
+    ControlRenderer controlRenderer = factory.GetControlRenderer( propertyMap );
+    DALI_TEST_CHECK( controlRenderer );
+
+    Actor actor = Actor::New();
+    TestControlRendererRender( application, actor, controlRenderer, ninePatchResource, 1u );
+
+    TestGlAbstraction& gl = application.GetGlAbstraction();
+    int textureUnit = -1;
+    DALI_TEST_CHECK( gl.GetUniformValue< int >( "sTexture", textureUnit ) );
+    DALI_TEST_EQUALS( textureUnit, 0, TEST_LOCATION );
+
+    controlRenderer.SetOffStage( actor );
+    DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+  }
 
   END_TEST;
 }
 
-int UtcDaliRendererFactoryGetNPatchRenderer2(void)
+int UtcDaliRendererFactoryGetNPatchRenderer3(void)
 {
   ToolkitTestApplication application;
-  tet_infoline( "UtcDaliRendererFactoryGetNPatchRenderer2: Request n-patch renderer with an image url" );
+  tet_infoline( "UtcDaliRendererFactoryGetNPatchRenderer3: Request 9-patch renderer with an image url" );
 
   RendererFactory factory = RendererFactory::Get();
   DALI_TEST_CHECK( factory );
 
   const unsigned int ninePatchImageHeight = 18;
   const unsigned int ninePatchImageWidth = 28;
-  const Vector4 requiredStretchBorder( 3, 4, 5, 6 );
-  Integration::ResourcePointer ninePatchResource = CustomizeNinePatch( application, ninePatchImageWidth, ninePatchImageHeight, requiredStretchBorder );
+  StretchRanges stretchRangesX;
+  stretchRangesX.PushBack( Uint16Pair( 2, 3 ) );
+  StretchRanges stretchRangesY;
+  stretchRangesY.PushBack( Uint16Pair( 4, 5 ) );
+  Integration::ResourcePointer ninePatchResource = CustomizeNinePatch( application, ninePatchImageWidth, ninePatchImageHeight, stretchRangesX, stretchRangesY );
 
   ControlRenderer controlRenderer = factory.GetControlRenderer( TEST_NPATCH_FILE_NAME );
   DALI_TEST_CHECK( controlRenderer );
 
   Actor actor = Actor::New();
-  actor.SetSize( 200.f, 200.f );
-  Stage::GetCurrent().Add( actor );
-  controlRenderer.SetSize( Vector2(200.f, 200.f) );
-  controlRenderer.SetOnStage( actor );
-
-  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
-  DALI_TEST_CHECK( actor.GetRendererAt(0u).GetMaterial().GetNumberOfSamplers() == 1u );
+  TestControlRendererRender( application, actor, controlRenderer, ninePatchResource, 1u );
 
   TestGlAbstraction& gl = application.GetGlAbstraction();
-  application.SendNotification();
-  application.Render();
+  int textureUnit = -1;
+  DALI_TEST_CHECK( gl.GetUniformValue< int >( "sTexture", textureUnit ) );
+  DALI_TEST_EQUALS( textureUnit, 0, TEST_LOCATION );
 
-  Integration::ResourceRequest* request = application.GetPlatform().GetRequest();
-  if(request)
-  {
-    application.GetPlatform().SetResourceLoaded(request->GetId(), request->GetType()->id, ninePatchResource );
-  }
+  END_TEST;
+}
 
-  application.Render();
-  application.SendNotification();
+int UtcDaliRendererFactoryGetNPatchRenderer4(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliRendererFactoryGetNPatchRenderer4: Request n-patch renderer with an image url" );
+
+  RendererFactory factory = RendererFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  const unsigned int ninePatchImageHeight = 18;
+  const unsigned int ninePatchImageWidth = 28;
+  StretchRanges stretchRangesX;
+  stretchRangesX.PushBack( Uint16Pair( 2, 3 ) );
+  stretchRangesX.PushBack( Uint16Pair( 5, 7 ) );
+  stretchRangesX.PushBack( Uint16Pair( 12, 15 ) );
+  StretchRanges stretchRangesY;
+  stretchRangesY.PushBack( Uint16Pair( 4, 5 ) );
+  stretchRangesY.PushBack( Uint16Pair( 8, 12 ) );
+  stretchRangesY.PushBack( Uint16Pair( 15, 16 ) );
+  stretchRangesY.PushBack( Uint16Pair( 25, 27 ) );
+  Integration::ResourcePointer ninePatchResource = CustomizeNinePatch( application, ninePatchImageWidth, ninePatchImageHeight, stretchRangesX, stretchRangesY );
+
+  ControlRenderer controlRenderer = factory.GetControlRenderer( TEST_NPATCH_FILE_NAME );
+  DALI_TEST_CHECK( controlRenderer );
 
-  DALI_TEST_CHECK(application.GetPlatform().WasCalled(TestPlatformAbstraction::LoadResourceFunc));
+  Actor actor = Actor::New();
+  TestControlRendererRender( application, actor, controlRenderer, ninePatchResource, 1u );
 
+  TestGlAbstraction& gl = application.GetGlAbstraction();
   int textureUnit = -1;
   DALI_TEST_CHECK( gl.GetUniformValue< int >( "sTexture", textureUnit ) );
   DALI_TEST_EQUALS( textureUnit, 0, TEST_LOCATION );
@@ -689,18 +729,10 @@ int UtcDaliRendererFactoryGetNPatchRendererN1(void)
   DALI_TEST_CHECK( controlRenderer );
 
   Actor actor = Actor::New();
-  actor.SetSize( 200.f, 200.f );
-  Stage::GetCurrent().Add( actor );
-  controlRenderer.SetSize( Vector2(200.f, 200.f) );
-  controlRenderer.SetOnStage( actor );
-
-  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
-  DALI_TEST_CHECK( actor.GetRendererAt(0u).GetMaterial().GetNumberOfSamplers() == 1u );
+  //The testkit still has to load a bitmap for the broken renderer image
+  TestControlRendererRender( application, actor, controlRenderer, Integration::ResourcePointer(Integration::Bitmap::New(Integration::Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::OWNED_DISCARD)), 1u );
 
   TestGlAbstraction& gl = application.GetGlAbstraction();
-  application.SendNotification();
-  application.Render();
-
   int textureUnit = -1;
   DALI_TEST_CHECK( gl.GetUniformValue< int >( "sTexture", textureUnit ) );
   DALI_TEST_EQUALS( textureUnit, 0, TEST_LOCATION );
@@ -726,18 +758,10 @@ int UtcDaliRendererFactoryGetNPatchRendererN2(void)
   DALI_TEST_CHECK( controlRenderer );
 
   Actor actor = Actor::New();
-  actor.SetSize( 200.f, 200.f );
-  Stage::GetCurrent().Add( actor );
-  controlRenderer.SetSize( Vector2(200.f, 200.f) );
-  controlRenderer.SetOnStage( actor );
-
-  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
-  DALI_TEST_CHECK( actor.GetRendererAt(0u).GetMaterial().GetNumberOfSamplers() == 1u );
+  //The testkit still has to load a bitmap for the broken renderer image
+  TestControlRendererRender( application, actor, controlRenderer, Integration::ResourcePointer(Integration::Bitmap::New(Integration::Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::OWNED_DISCARD)), 1u );
 
   TestGlAbstraction& gl = application.GetGlAbstraction();
-  application.SendNotification();
-  application.Render();
-
   int textureUnit = -1;
   DALI_TEST_CHECK( gl.GetUniformValue< int >( "sTexture", textureUnit ) );
   DALI_TEST_EQUALS( textureUnit, 0, TEST_LOCATION );
@@ -750,23 +774,17 @@ int UtcDaliRendererFactoryResetRenderer1(void)
   ToolkitTestApplication application;
   tet_infoline( "UtcDaliRendererFactoryResetRenderer1" );
 
-  Actor actor = Actor::New();
-  actor.SetSize(200.f, 200.f);
-  Stage::GetCurrent().Add( actor );
-
   RendererFactory factory = RendererFactory::Get();
   DALI_TEST_CHECK( factory );
 
   ControlRenderer controlRenderer = factory.GetControlRenderer( Color::RED );
   DALI_TEST_CHECK( controlRenderer );
-  controlRenderer.SetSize(Vector2(200.f, 200.f));
-  controlRenderer.SetOnStage( actor );
-  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
 
-  TestGlAbstraction& gl = application.GetGlAbstraction();
-  application.SendNotification();
-  application.Render(0);
+  Actor actor = Actor::New();
+  TestControlRendererRender( application, actor, controlRenderer );
+
   Vector4 actualValue(Vector4::ZERO);
+  TestGlAbstraction& gl = application.GetGlAbstraction();
   DALI_TEST_CHECK( gl.GetUniformValue<Vector4>( "uBlendColor", actualValue ) );
   DALI_TEST_EQUALS( actualValue, Color::RED, TEST_LOCATION );
 
@@ -788,8 +806,6 @@ int UtcDaliRendererFactoryResetRenderer1(void)
   controlRenderer.SetOnStage( actor2 );
   application.SendNotification();
   application.Render(0);
-  Image samplerImage = actor2.GetRendererAt(0u).GetMaterial().GetSamplerAt(0u).GetImage();
-  DALI_TEST_CHECK( BufferImage::DownCast( samplerImage ) );
 
   END_TEST;
 }
@@ -814,16 +830,12 @@ int UtcDaliRendererFactoryResetRenderer2(void)
 
   application.SendNotification();
   application.Render(0);
-  Image samplerImage = actor.GetRendererAt(0u).GetMaterial().GetSamplerAt(0u).GetImage();
-  DALI_TEST_CHECK( ResourceImage::DownCast( samplerImage ) );
 
   Image bufferImage = CreateBufferImage( 100, 200, Vector4( 1.f, 1.f, 1.f, 1.f ) );
   bool isNewRenderer = factory.ResetRenderer( controlRenderer, bufferImage );
   DALI_TEST_CHECK( !isNewRenderer );
   application.SendNotification();
   application.Render(0);
-  samplerImage = actor.GetRendererAt(0u).GetMaterial().GetSamplerAt(0u).GetImage();
-  DALI_TEST_CHECK( BufferImage::DownCast( samplerImage ) );
 
   isNewRenderer = factory.ResetRenderer( controlRenderer, Color::RED );
   DALI_TEST_CHECK( isNewRenderer );
index cf3e163..3f9879e 100644 (file)
@@ -882,6 +882,7 @@ int UtcDaliToolkitScrollViewScrollSensitive(void)
 
   // Set up a scrollView...
   ScrollView scrollView = ScrollView::New();
+  scrollView.SetOvershootEnabled(true);
   Stage::GetCurrent().Add( scrollView );
   Vector2 stageSize = Stage::GetCurrent().GetSize();
   scrollView.SetSize(stageSize);
@@ -1093,6 +1094,7 @@ int UtcDaliToolkitScrollViewOvershoot(void)
 
   // Set up a scrollView...
   ScrollView scrollView = ScrollView::New();
+  scrollView.SetOvershootEnabled(true);
   Stage::GetCurrent().Add( scrollView );
   Vector2 stageSize = Stage::GetCurrent().GetSize();
   scrollView.SetSize(stageSize);
@@ -2285,3 +2287,63 @@ int UtcDaliToolkitScrollViewConstraintsWrap(void)
 
   END_TEST;
 }
+
+// Non-API test (so no P or N variant).
+int UtcDaliToolkitScrollViewGesturePageLimit(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliToolkitScrollViewGesturePageLimit" );
+
+  // Set up a scrollView.
+  ScrollView scrollView = ScrollView::New();
+
+  // Do not rely on stage size for UTC tests.
+  Vector2 pageSize( 720.0f, 1280.0f );
+  scrollView.SetResizePolicy( ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS );
+  scrollView.SetSize( pageSize );
+  scrollView.SetParentOrigin( ParentOrigin::CENTER );
+  scrollView.SetAnchorPoint( AnchorPoint::CENTER );
+  scrollView.SetPosition( 0.0f, 0.0f, 0.0f );
+
+  // Position rulers.
+  // We set the X ruler to fixed to give us pages to snap to.
+  Dali::Toolkit::FixedRuler* rulerX = new Dali::Toolkit::FixedRuler( pageSize.width );
+  // Note: The 3x page width is arbitary, but we need enough to show that we are
+  // capping page movement by the page limiter, and not the domain.
+  rulerX->SetDomain( Dali::Toolkit::RulerDomain( 0.0f, pageSize.width * 3.0f, false ) );
+  Dali::Toolkit::RulerPtr rulerY = new Dali::Toolkit::DefaultRuler();
+  rulerY->Disable();
+  scrollView.SetRulerX( rulerX );
+  scrollView.SetRulerY( rulerY );
+
+  scrollView.SetWrapMode( false );
+  scrollView.SetScrollSensitive( true );
+
+  Stage::GetCurrent().Add( scrollView );
+
+  // Set up a gesture to perform.
+  Vector2 startPos( 50.0f, 0.0f );
+  Vector2 direction( -5.0f, 0.0f );
+  int frames = 200;
+
+  // Force starting position.
+  scrollView.ScrollTo( startPos, 0.0f );
+  Wait( application );
+
+  // Deliberately skip the "Finished" part of the gesture, so we can read the coordinates before the snap begins.
+  Vector2 currentPos( PerformGestureDiagonalSwipe( application, startPos, direction, frames - 1, false ) );
+
+  // Confirm the final X coord has not moved more than one page from the start X position.
+  DALI_TEST_GREATER( ( startPos.x + pageSize.width ), scrollView.GetCurrentScrollPosition().x, TEST_LOCATION );
+
+  // Finish the gesture and wait for the snap.
+  currentPos += direction;
+  SendPan( application, Gesture::Finished, currentPos );
+  // We add RENDER_FRAME_INTERVAL on to wait for an extra frame (for the last "finished" gesture to complete first.
+  Wait( application, RENDER_DELAY_SCROLL + RENDER_FRAME_INTERVAL );
+
+  // Confirm the final X coord has snapped to exactly one page ahead of the start page.
+  DALI_TEST_EQUALS( pageSize.width, scrollView.GetCurrentScrollPosition().x, Math::MACHINE_EPSILON_0, TEST_LOCATION );
+
+  END_TEST;
+}
index 33dfee4..fde3088 100644 (file)
@@ -198,12 +198,38 @@ int UtcDaliCreateDissolveLocalEffect(void)
   END_TEST;
 }
 
-int UtcDaliCreateDistanceFieldEffect(void)
+int UtcDaliCreateDissolveEffect(void)
 {
   ToolkitTestApplication application;
 
-  ShaderEffect effect = Toolkit::CreateDistanceFieldEffect();
-  DALI_TEST_CHECK( effect );
+  Property::Map effect = Toolkit::CreateDistanceFieldEffect();
+  DALI_TEST_CHECK( !effect.Empty() );
+
+  Property::Value* customShaderValue = effect.Find( "shader" );
+  DALI_TEST_CHECK( customShaderValue );
+
+  Property::Map customShader;
+  DALI_TEST_CHECK( customShaderValue->Get( customShader ) );
+
+  Property::Value* vertexShaderValue = customShader.Find( "vertex-shader" );
+  DALI_TEST_CHECK( !vertexShaderValue );
+
+  Property::Value* fragmentShaderValue = customShader.Find( "fragment-shader" );
+  DALI_TEST_CHECK( fragmentShaderValue );
+
+  std::string fragmentShader;
+  DALI_TEST_CHECK( fragmentShaderValue->Get( fragmentShader ) );
+  DALI_TEST_CHECK( !fragmentShader.empty() );
+
+  Property::Value* gridXValue = customShader.Find( "subdivide-grid-x" );
+  DALI_TEST_CHECK( !gridXValue );
+
+  Property::Value* hintsValue = customShader.Find( "hints" );
+  DALI_TEST_CHECK( hintsValue );
+
+  std::string hints;
+  DALI_TEST_CHECK( hintsValue->Get( hints ) );
+  DALI_TEST_CHECK( hints == "output-is-transparent" );
 
   END_TEST;
 }
@@ -254,12 +280,61 @@ int UtcDaliCreateMotionBlurEffect(void)
 {
   ToolkitTestApplication application;
 
-  unsigned int sampleCount(4);
-  ShaderEffect effect = Toolkit::CreateMotionBlurEffect(sampleCount);
-  DALI_TEST_CHECK( effect );
+  Property::Map effect = Toolkit::CreateMotionBlurEffect();
+  DALI_TEST_CHECK( !effect.Empty() );
+
+  Property::Value* customShaderValue = effect.Find( "shader" );
+  DALI_TEST_CHECK( customShaderValue );
+
+  Property::Map customShader;
+  DALI_TEST_CHECK( customShaderValue->Get( customShader ) );
 
-  Property::Value value = effect.GetProperty( effect.GetPropertyIndex("uNumSamples"));
-  DALI_TEST_EQUALS( value.Get<float>(), (float)sampleCount, TEST_LOCATION );
+  Property::Value* vertexShaderValue = customShader.Find( "vertex-shader" );
+  DALI_TEST_CHECK( vertexShaderValue );
+
+  std::string vertexShader;
+  DALI_TEST_CHECK( vertexShaderValue->Get( vertexShader ) );
+  DALI_TEST_CHECK( !vertexShader.empty() );
+
+  Property::Value* fragmentShaderValue = customShader.Find( "fragment-shader" );
+  DALI_TEST_CHECK( fragmentShaderValue );
+
+  std::string fragmentShader;
+  DALI_TEST_CHECK( fragmentShaderValue->Get( fragmentShader ) );
+  DALI_TEST_CHECK( !fragmentShader.empty() );
+
+  Property::Value* gridXValue = customShader.Find( "subdivide-grid-x" );
+  DALI_TEST_CHECK( gridXValue );
+
+  int gridX = 0;
+  DALI_TEST_CHECK( gridXValue->Get( gridX ) );
+  DALI_TEST_CHECK( gridX > 1 );
+
+  Property::Value* gridYValue = customShader.Find( "subdivide-grid-y" );
+  DALI_TEST_CHECK( gridYValue );
+
+  int gridY = 0;
+  DALI_TEST_CHECK( gridYValue->Get( gridY ) );
+  DALI_TEST_CHECK( gridY > 1 );
+
+  Property::Value* hintsValue = customShader.Find( "hints" );
+  DALI_TEST_CHECK( hintsValue );
+
+  std::string hints;
+  DALI_TEST_CHECK( hintsValue->Get( hints ) );
+  DALI_TEST_CHECK( hints == "output-is-transparent" );
+
+  unsigned int sampleCount( 4 );
+  Actor actor = Actor::New();
+  Toolkit::SetMotionBlurProperties( actor, sampleCount );
+  DALI_TEST_CHECK( actor.GetPropertyIndex( "uBlurTexCoordScale" ) != Property::INVALID_INDEX );
+  DALI_TEST_CHECK( actor.GetPropertyIndex( "uGeometryStretchFactor" ) != Property::INVALID_INDEX );
+  DALI_TEST_CHECK( actor.GetPropertyIndex( "uSpeedScalingFactor" ) != Property::INVALID_INDEX );
+  DALI_TEST_CHECK( actor.GetPropertyIndex( "uObjectFadeStart" ) != Property::INVALID_INDEX );
+  DALI_TEST_CHECK( actor.GetPropertyIndex( "uObjectFadeEnd" ) != Property::INVALID_INDEX );
+  DALI_TEST_CHECK( actor.GetPropertyIndex( "uAlphaScale" ) != Property::INVALID_INDEX );
+  DALI_TEST_CHECK( actor.GetPropertyIndex( "uNumSamples" ) != Property::INVALID_INDEX );
+  DALI_TEST_CHECK( actor.GetPropertyIndex( "uModelLastFrame" ) != Property::INVALID_INDEX );
 
   END_TEST;
 }
@@ -268,8 +343,58 @@ int UtcDaliCreateMotionStretchEffect(void)
 {
   ToolkitTestApplication application;
 
-  ShaderEffect effect = Toolkit::CreateMotionStretchEffect();
-  DALI_TEST_CHECK( effect );
+  Property::Map effect = Toolkit::CreateMotionStretchEffect();
+  DALI_TEST_CHECK( !effect.Empty() );
+
+  Property::Value* customShaderValue = effect.Find( "shader" );
+  DALI_TEST_CHECK( customShaderValue );
+
+  Property::Map customShader;
+  DALI_TEST_CHECK( customShaderValue->Get( customShader ) );
+
+  Property::Value* vertexShaderValue = customShader.Find( "vertex-shader" );
+  DALI_TEST_CHECK( vertexShaderValue );
+
+  std::string vertexShader;
+  DALI_TEST_CHECK( vertexShaderValue->Get( vertexShader ) );
+  DALI_TEST_CHECK( !vertexShader.empty() );
+
+  Property::Value* fragmentShaderValue = customShader.Find( "fragment-shader" );
+  DALI_TEST_CHECK( fragmentShaderValue );
+
+  std::string fragmentShader;
+  DALI_TEST_CHECK( fragmentShaderValue->Get( fragmentShader ) );
+  DALI_TEST_CHECK( !fragmentShader.empty() );
+
+  Property::Value* gridXValue = customShader.Find( "subdivide-grid-x" );
+  DALI_TEST_CHECK( gridXValue );
+
+  int gridX = 0;
+  DALI_TEST_CHECK( gridXValue->Get( gridX ) );
+  DALI_TEST_CHECK( gridX > 1 );
+
+  Property::Value* gridYValue = customShader.Find( "subdivide-grid-y" );
+  DALI_TEST_CHECK( gridYValue );
+
+  int gridY = 0;
+  DALI_TEST_CHECK( gridYValue->Get( gridY ) );
+  DALI_TEST_CHECK( gridY > 1 );
+
+  Property::Value* hintsValue = customShader.Find( "hints" );
+  DALI_TEST_CHECK( hintsValue );
+
+  std::string hints;
+  DALI_TEST_CHECK( hintsValue->Get( hints ) );
+  DALI_TEST_CHECK( hints == "output-is-transparent" );
+
+  Actor actor = Actor::New();
+  Toolkit::SetMotionStretchProperties( actor );
+  DALI_TEST_CHECK( actor.GetPropertyIndex( "uGeometryStretchFactor" ) != Property::INVALID_INDEX );
+  DALI_TEST_CHECK( actor.GetPropertyIndex( "uSpeedScalingFactor" ) != Property::INVALID_INDEX );
+  DALI_TEST_CHECK( actor.GetPropertyIndex( "uObjectFadeStart" ) != Property::INVALID_INDEX );
+  DALI_TEST_CHECK( actor.GetPropertyIndex( "uObjectFadeEnd" ) != Property::INVALID_INDEX );
+  DALI_TEST_CHECK( actor.GetPropertyIndex( "uAlphaScale" ) != Property::INVALID_INDEX );
+  DALI_TEST_CHECK( actor.GetPropertyIndex( "uModelLastFrame" ) != Property::INVALID_INDEX );
 
   END_TEST;
 }
index d44e4b4..50bd34e 100644 (file)
@@ -16,7 +16,7 @@
 
 # Build the Dali Toolkit library
 
-toolkit_images_dir = ../../../dali-toolkit/images-common
+toolkit_images_dir = ../../../dali-toolkit/styles/images-common
 toolkit_sounds_dir = ../../../dali-toolkit/sounds
 toolkit_src_dir    = ../../../dali-toolkit/internal
 public_api_src_dir = ../../../dali-toolkit/public-api
@@ -25,9 +25,9 @@ devel_api_src_dir  = ../../../dali-toolkit/devel-api
 toolkit_styles_dir = $(STYLE_DIR)
 toolkit_style_images_dir = $(STYLE_DIR)/images
 
-include ../../../dali-toolkit/images-common/file.list
 include ../../../dali-toolkit/sounds/file.list
 include ../../../dali-toolkit/styles/file.list
+include ../../../dali-toolkit/styles/images-common/file.list
 include ../../../dali-toolkit/internal/file.list
 include ../../../dali-toolkit/public-api/file.list
 include ../../../dali-toolkit/devel-api/file.list
index 95cccc8..e160532 100644 (file)
@@ -150,7 +150,7 @@ inline void DissolveEffectSetCentralLine( Actor& actor, const Vector2& position,
  *    "uPercentage" - This value is proportional to the distortion applied; a value of zero means no distortion.
  *
  *  @param[in] useHighPrecision True if using high precision in fragment shader for fully random noise, false otherwise
- *  @return A handle to a newly allocated ShaderEffect
+ *  @return The newly created Property::Map with the dissolve effect
  */
 
 inline Property::Map CreateDissolveEffect( bool useHighPrecision = true )
index c3b2669..aaeb537 100644 (file)
@@ -19,6 +19,7 @@
  */
 
 // EXTERNAL INCLUDES
+#include <string.h>
 #include <dali/public-api/shader-effects/shader-effect.h>
 
 namespace Dali
@@ -32,10 +33,8 @@ namespace Toolkit
  *
  * DistanceFieldEffect is a custom shader effect to achieve distance field on Image actors
  *
- * Animatable/Constrainable uniforms:
+ * Animatable/Constrainable uniforms - These will need to be registered to the actor as a custom property to take into effect:
  *
- *  "uSmoothing"    - Soft edge smoothing. Specify the distance field value for the center of the edge.
-
  *  "uDoGlow"       - The glow state. If true, glow is enabled
  *  "uGlowBoundary" - The glow boundary factor
  *  "uGlowColor"    - The glow color multiplier
@@ -50,132 +49,127 @@ namespace Toolkit
  *                    First value [0-1] Specifies the distance field value for the center of the outline.
  *                    Second value [0-1] Specifies the softness/width/anti-aliasing of the outlines inner edge.
  *
- * @return A handle to a newly allocated ShaderEffect
+ *  @return The newly created Property::Map with the distance field effect
  */
-inline ShaderEffect CreateDistanceFieldEffect()
+inline Dali::Property::Map CreateDistanceFieldEffect()
 {
-  std::string fragmentShaderPrefix(
-      "#extension GL_OES_standard_derivatives : enable\n"
-      "\n"
-  );
-
-  std::string fragmentShader(
-      "uniform mediump float uSmoothing;\n"
-      "uniform mediump float uGlowBoundary;\n"
-      "uniform mediump vec2  uOutlineParams;\n"
-      "uniform lowp    vec4  uOutlineColor;\n"
-      "uniform lowp    vec4  uShadowColor;\n"
-      "uniform mediump vec2  uShadowOffset;\n"
-      "uniform lowp    vec4  uGlowColor;\n"
-      "uniform lowp    float uDoOutline;\n"
-      "uniform lowp    float uDoShadow;\n"
-      "uniform lowp    float uDoGlow;\n"
-      "\n"
-      "void main()\n"
-      "{\n"
-      "  // sample distance field\n"
-      "  mediump float distance = texture2D(sTexture, vTexCoord).a;\n"
-      "  mediump float smoothWidth = fwidth(distance);\n"
-      "  mediump float alphaFactor = smoothstep(uSmoothing - smoothWidth, uSmoothing + smoothWidth, distance);\n"
-      "  lowp    vec4  color;\n"
-      "  if (uDoShadow == 0.0)\n"
-      "  {\n"
-      "    mediump float alpha = uColor.a * alphaFactor;\n"
-      "    lowp    vec4  rgb = uColor;\n"
-      "\n"
-      "    if (uDoOutline > 0.0)\n"
-      "    {\n"
-      "      mediump float outlineWidth = uOutlineParams[1] + smoothWidth;\n"
-      "      mediump float outlineBlend = smoothstep(uOutlineParams[0] - outlineWidth, uOutlineParams[0] + outlineWidth, distance);\n"
-      "      alpha = smoothstep(uSmoothing - smoothWidth, uSmoothing + smoothWidth, distance);\n"
-      "      rgb = mix(uOutlineColor, uColor, outlineBlend);\n"
-      "    }\n"
-      "\n"
-      "    if (uDoGlow > 0.0)\n"
-      "    {\n"
-      "      rgb = mix(uGlowColor, rgb, alphaFactor);\n"
-      "      alpha = smoothstep(uGlowBoundary, uSmoothing, distance);\n"
-      "    }\n"
-      "\n"
-      "    // set fragment color\n"
-      "    color = vec4(rgb.rgb, alpha);\n"
-      "  }\n"
-      "\n"
-      "  else // (uDoShadow > 0.0)\n"
-      "  {\n"
-      "    mediump float shadowDistance = texture2D(sTexture, vTexCoord - uShadowOffset).a;\n"
-      "    mediump float inText = alphaFactor;\n"
-      "    mediump float inShadow = smoothstep(uSmoothing - smoothWidth, uSmoothing + smoothWidth, shadowDistance);\n"
-      "\n"
-      "    // inside object, outside shadow\n"
-      "    if (inText == 1.0)\n"
-      "    {\n"
-      "      color = uColor;\n"
-      "    }\n"
-      "    // inside object, outside shadow\n"
-      "    else if ((inText != 0.0) && (inShadow == 0.0))\n"
-      "    {\n"
-      "      color = uColor;\n"
-      "      color.a *= inText;\n"
-      "    }\n"
-      "    // outside object, completely inside shadow\n"
-      "    else if ((inText == 0.0) && (inShadow == 1.0))\n"
-      "    {\n"
-      "      color = uShadowColor;\n"
-      "    }\n"
-      "    // inside object, completely inside shadow\n"
-      "    else if ((inText != 0.0) && (inShadow == 1.0))\n"
-      "    {\n"
-      "      color = mix(uShadowColor, uColor, inText);\n"
-      "      color.a = uShadowColor.a;\n"
-      "    }\n"
-      "    // inside object, inside shadow's border\n"
-      "    else if ((inText != 0.0) && (inShadow != 0.0))\n"
-      "    {\n"
-      "      color = mix(uShadowColor, uColor, inText);\n"
-      "      color.a *= max(inText, inShadow);\n"
-      "    }\n"
-      "    // inside shadow's border\n"
-      "    else if (inShadow != 0.0)\n"
-      "    {\n"
-      "      color = uShadowColor;\n"
-      "      color.a *= inShadow;\n"
-      "    }\n"
-      "    // outside shadow and object\n"
-      "    else \n"
-      "    {\n"
-      "      color.a = 0.0;\n"
-      "    }\n"
-      "\n"
-      "  }\n"
-      "\n"
-      "  gl_FragColor = color;\n"
-      "\n"
-      "}\n"
+  const char* fragmentShaderPrefix( "#extension GL_OES_standard_derivatives : enable\n" );
+
+  const char* fragmentShader( DALI_COMPOSE_SHADER(
+      varying mediump vec2 vTexCoord;\n
+      \n
+      uniform mediump float uGlowBoundary;\n
+      uniform mediump vec2  uOutlineParams;\n
+      uniform lowp    vec4  uOutlineColor;\n
+      uniform lowp    vec4  uShadowColor;\n
+      uniform mediump vec2  uShadowOffset;\n
+      uniform lowp    vec4  uGlowColor;\n
+      uniform lowp    float uDoOutline;\n
+      uniform lowp    float uDoShadow;\n
+      uniform lowp    float uDoGlow;\n
+      \n
+      uniform sampler2D sTexture;\n
+      uniform lowp vec4 uColor;\n
+      \n
+      void main()\n
+      {\n
+        // sample distance field\n
+        mediump float smoothing = 0.5;\n
+
+        mediump float distance = texture2D(sTexture, vTexCoord).a;\n
+        mediump float smoothWidth = fwidth(distance);\n
+        mediump float alphaFactor = smoothstep(smoothing - smoothWidth, smoothing + smoothWidth, distance);\n
+        lowp    vec4  color;\n
+        if (uDoShadow == 0.0)\n
+        {\n
+          mediump float alpha = uColor.a * alphaFactor;\n
+          lowp    vec4  rgb = uColor;\n
+          \n
+          if (uDoOutline > 0.0)\n
+          {\n
+            mediump float outlineWidth = uOutlineParams[1] + smoothWidth;\n
+            mediump float outlineBlend = smoothstep(uOutlineParams[0] - outlineWidth, uOutlineParams[0] + outlineWidth, distance);\n
+            alpha = smoothstep(smoothing - smoothWidth, smoothing + smoothWidth, distance);\n
+            rgb = mix(uOutlineColor, uColor, outlineBlend);\n
+          }\n
+          \n
+          if (uDoGlow > 0.0)\n
+          {\n
+            rgb = mix(uGlowColor, rgb, alphaFactor);\n
+            alpha = smoothstep(uGlowBoundary, smoothing, distance);\n
+          }\n
+          \n
+          // set fragment color\n
+          color = vec4(rgb.rgb, alpha);\n
+        }\n
+        \n
+        else // (uDoShadow > 0.0)\n
+        {\n
+          mediump float shadowDistance = texture2D(sTexture, vTexCoord - uShadowOffset).a;\n
+          mediump float inText = alphaFactor;\n
+          mediump float inShadow = smoothstep(smoothing - smoothWidth, smoothing + smoothWidth, shadowDistance);\n
+          \n
+          // inside object, outside shadow\n
+          if (inText == 1.0)\n
+          {\n
+            color = uColor;\n
+          }\n
+          // inside object, outside shadow\n
+          else if ((inText != 0.0) && (inShadow == 0.0))\n
+          {\n
+            color = uColor;\n
+            color.a *= inText;\n
+          }\n
+          // outside object, completely inside shadow\n
+          else if ((inText == 0.0) && (inShadow == 1.0))\n
+          {\n
+            color = uShadowColor;\n
+          }\n
+          // inside object, completely inside shadow\n
+          else if ((inText != 0.0) && (inShadow == 1.0))\n
+          {\n
+            color = mix(uShadowColor, uColor, inText);\n
+            color.a = uShadowColor.a;\n
+          }\n
+          // inside object, inside shadow's border\n
+          else if ((inText != 0.0) && (inShadow != 0.0))\n
+          {\n
+            color = mix(uShadowColor, uColor, inText);\n
+            color.a *= max(inText, inShadow);\n
+          }\n
+          // inside shadow's border\n
+          else if (inShadow != 0.0)\n
+          {\n
+            color = uShadowColor;\n
+            color.a *= inShadow;\n
+          }\n
+          // outside shadow and object\n
+          else \n
+          {\n
+            color.a = 0.0;\n
+          }\n
+          \n
+        }\n
+        \n
+        gl_FragColor = color;\n
+        \n
+      } )
   );
 
-  // Create the implementation, temporarily owned on stack
-  Dali::ShaderEffect shaderEffect =  Dali::ShaderEffect::NewWithPrefix(
-      "", "",
-      fragmentShaderPrefix, fragmentShader,
-      ShaderEffect::GeometryHints( ShaderEffect::HINT_BLENDING));
+  Property::Map map;
 
-  shaderEffect.SetUniform("uSmoothing",0.5f);
-  shaderEffect.SetUniform("uOutlineColor",Color::BLACK);
-  shaderEffect.SetUniform("uOutlineParams",Vector2(0.51f, 0.0f));
-  shaderEffect.SetUniform("uGlowBoundary",0.4f);
-  shaderEffect.SetUniform("uGlowColor",Color::GREEN);
-  shaderEffect.SetUniform("uShadowColor",Vector4(0.0f, 0.0f, 0.0f, 0.4f));
+  Property::Map customShader;
 
-  // TODO: find a way to set the shadow offset in texel coordinates instead of UVs.
-  shaderEffect.SetUniform("uShadowOffset",Vector2(0.05f, 0.05f));
+  std::string fragmentShaderString;
+  fragmentShaderString.reserve( strlen( fragmentShaderPrefix ) + strlen( fragmentShader ) );
+  fragmentShaderString.append( fragmentShaderPrefix );
+  fragmentShaderString.append( fragmentShader );
 
-  // Default:
-  shaderEffect.SetUniform("uDoOutline",false);
-  shaderEffect.SetUniform("uDoGlow",false);
-  shaderEffect.SetUniform("uDoShadow",false);
+  customShader[ "fragment-shader" ] = fragmentShaderString;
+  customShader[ "hints" ] = "output-is-transparent";
 
-  return shaderEffect;
+  map[ "shader" ] = customShader;
+  return map;
 }
 
 
index a4aaa7f..aede5f1 100644 (file)
@@ -29,27 +29,33 @@ namespace Toolkit
 {
 
 /**
+ * @brief Set the properties for the motion blur
+ *
+ * @param numBlurSamples Number of samples used by the shader
+ */
+inline void SetMotionBlurProperties( Actor& actor, unsigned int numBlurSamples = 8 )
+{
+  actor.RegisterProperty( "uBlurTexCoordScale", 0.125f );
+  actor.RegisterProperty( "uGeometryStretchFactor", 0.05f );
+  actor.RegisterProperty( "uSpeedScalingFactor", 0.5f );
+  actor.RegisterProperty( "uObjectFadeStart", Vector2( 0.25f, 0.25f ) );
+  actor.RegisterProperty( "uObjectFadeEnd", Vector2( 0.5f, 0.5f ) );
+  actor.RegisterProperty( "uAlphaScale", 0.75f );
+  actor.RegisterProperty( "uNumSamples", static_cast<float>( numBlurSamples ) );
+  actor.RegisterProperty( "uRecipNumSamples", 1.0f / static_cast<float>( numBlurSamples ) );
+  actor.RegisterProperty( "uRecipNumSamplesMinusOne", 1.0f / static_cast<float>( numBlurSamples - 1.0f ) );
+  Property::Index uModelProperty = actor.RegisterProperty( "uModelLastFrame", Matrix::IDENTITY );
+
+  Constraint constraint = Constraint::New<Matrix>( actor, uModelProperty, EqualToConstraint() );
+  constraint.AddSource( Source( actor , Actor::Property::WORLD_MATRIX ) );
+  constraint.Apply();
+}
+
+/**
  * @brief Create a new MotionBlurEffect
  *
  * Motion blur shader works on a per object basis. Objects will
- * blur when they move, or if the camera moves. Can be applied to ImageActor or
- * TextActor only.
- *
- * Usage example:-
- *
- * // Create shader used for doing motion blur\n
- * ShaderEffect MotionBlurEffect = CreateMotionBlurEffect();
- *
- * // set actor shader to the blur one\n
- * Actor actor = Actor::New( ... );\n
- * actor.SetShaderEffect( MotionBlurEffect );
- *
- * // Constrain "uModelLastFrame" to be the same as the actor's world matrix\n
- * Dali::Property::Index uModelProperty = MotionBlurEffect.GetPropertyIndex( "uModelLastFrame" );
- * Constraint constraint = Constraint::New<Matrix>( MotionBlurEffect, uModelProperty, EqualToConstraint() );\n
- * constraint.AddSource( Source( actor , Actor::Property::WORLD_MATRIX ) );\n
- * constraint.Apply();\n
- *
+ * blur when they move, or if the camera moves.
  *
  * Animatable/Constrainable uniforms:
  *  "uBlurTexCoordScale"      - This scales the offset for texture samples along the motion velocity vector.
@@ -83,26 +89,24 @@ namespace Toolkit
  *                              at the cost of performance.
  *  "uModelLastFrame"         - The model to world space transformation matrix of the actor in the previous frame.
  *
- * @param numBlurSamples Number of samples used by the shader
- * @return A handle to a newly allocated ShaderEffect
+ * @return The newly created Property::Map with the motion blur effect
  */
-inline ShaderEffect CreateMotionBlurEffect( unsigned int numBlurSamples = 8 )
+inline Property::Map CreateMotionBlurEffect()
 {
-  // Dali vertexSource prefix for reference:
-  // precision highp float;
-  // attribute vec3  aPosition;
-  // attribute vec2  aTexCoord;
-  // uniform   mat4  uMvpMatrix;
-  // uniform   mat4  uModelView;
-  // uniform   mat3  uNormalMatrix;
-  // uniform   mat4  uProjection;
-  // uniform   vec4  uColor;
-  // varying   vec2  vTexCoord;
   std::string vertexSource;
   vertexSource =
       "precision mediump float;\n"
+
+      "attribute vec2 aPosition;\n"
+
+      "uniform mat4 uMvpMatrix;\n"
+      "uniform mat4 uModelView;\n"
+      "uniform mat4 uViewMatrix;\n"
+      "uniform mat4 uProjection;\n"
+      "uniform vec3 uSize;\n"
+
       "uniform mat4 uModelLastFrame;\n"
-      "uniform float uTimeDelta;\n"
+      "float timeDelta = 0.0167;\n"
 
       "uniform float uGeometryStretchFactor;\n"
       "uniform float uSpeedScalingFactor;\n"
@@ -111,20 +115,23 @@ inline ShaderEffect CreateMotionBlurEffect( unsigned int numBlurSamples = 8 )
       "varying vec2 vModelSpaceCenterToPos;\n"
       "varying vec2 vScreenSpaceVelocityVector;\n"
       "varying float vSpeed;\n"
+      "varying vec2 vTexCoord;\n"
 
       "void main()\n"
       "{\n"
       // get view space position of vertex this frame and last frame
-      " vec4 vertex = vec4(aPosition, 1.0);\n"
-      " vec4 viewSpaceVertex = uModelView * vertex;\n"
-      " vec4 viewSpaceVertexLastFrame = (uViewMatrix * uModelLastFrame) * vertex;\n"
-      " float reciprocalTimeDelta = 1.0 / ((uTimeDelta > 0.0) ? uTimeDelta : 0.01);\n"
+      " vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n"
+      " vertexPosition.xyz *= uSize;\n"
+
+      " vec4 viewSpaceVertex = uModelView * vertexPosition;\n"
+      " vec4 viewSpaceVertexLastFrame = (uViewMatrix * uModelLastFrame) * vertexPosition;\n"
+      " float reciprocalTimeDelta = 1.0 / timeDelta;\n"
 
       // work out vertex's last movement in view space
       " vec3 viewSpacePosDelta = viewSpaceVertex.xyz - viewSpaceVertexLastFrame.xyz;\n"
 
       // get clip space position of vertex this frame and last frame
-      " vec4 clipSpaceVertex = uMvpMatrix * vertex;\n"
+      " vec4 clipSpaceVertex = uMvpMatrix * vertexPosition;\n"
       " vec4 clipSpaceVertexLastFrame = uProjection * viewSpaceVertexLastFrame;\n"
 
       // decide how much this vertex is 'trailing', i.e. at the back of the object relative to its direction of motion. We do this
@@ -133,7 +140,7 @@ inline ShaderEffect CreateMotionBlurEffect( unsigned int numBlurSamples = 8 )
       " float posDeltaLength = length(viewSpacePosDelta);\n"
       " if(posDeltaLength > 0.001)\n" // avoid div by 0 if object has barely moved
       " {\n"
-      "   vec4 viewSpaceCenterToPos = uModelView * vec4(aPosition, 0.0);\n"
+      "   vec4 viewSpaceCenterToPos = uModelView * vec4(vertexPosition.xy, 0.0, 0.0);\n"
       "   float centerToVertexDist = length(viewSpaceCenterToPos);\n"
       "   if(centerToVertexDist > 0.001)\n" // avoid div by 0 if object has vertex at model space origin
       "   {\n"
@@ -158,21 +165,20 @@ inline ShaderEffect CreateMotionBlurEffect( unsigned int numBlurSamples = 8 )
       " vSpeed = clamp(vSpeed, 0.0, 1.0);\n"
 
       // provide fragment shader with vector from center of object to pixel (assumes the objects model space origin is at its center and verts have same z)
-      " vModelSpaceCenterToPos = aPosition.xy;\n"
+      " vModelSpaceCenterToPos = viewSpaceVertex.xy;\n"
 
-      " vTexCoord = aTexCoord;\n"
+      " vec2 texCoord = aPosition + vec2(0.5);"
+      " vTexCoord = texCoord;\n"
       "}\n";
 
 
-  // Dali fragmentSource prefix for reference:
-  // precision highp     float;
-  // uniform   sampler2D sTexture;
-  // uniform   sampler2D sEffect;
-  // uniform   vec4      uColor;
-  // varying   vec2      vTexCoord;
   std::string fragmentSource;
   fragmentSource =
       "precision mediump float;\n"
+
+      "uniform sampler2D sTexture;\n"
+      "uniform vec4 uColor;\n"
+
       "uniform vec2 uObjectFadeStart;\n"
       "uniform vec2 uObjectFadeEnd;\n"
       "uniform float uAlphaScale;\n"
@@ -184,6 +190,7 @@ inline ShaderEffect CreateMotionBlurEffect( unsigned int numBlurSamples = 8 )
       "varying vec2 vModelSpaceCenterToPos;\n"
       "varying vec2 vScreenSpaceVelocityVector;\n"
       "varying float vSpeed;\n"
+      "varying vec2 vTexCoord;\n"
 
       "void main()\n"
       "{\n"
@@ -208,30 +215,25 @@ inline ShaderEffect CreateMotionBlurEffect( unsigned int numBlurSamples = 8 )
       "   col += texture2D(sTexture, vTexCoord + (velocity * t)) * uRecipNumSamples;\n"
       " }\n"
       " gl_FragColor = mix(colActor, col, vSpeed);\n" // lerp blurred and non-blurred actor based on speed of motion
-      " gl_FragColor.a = colActor.a * fadeToEdgesScale;\n" // fade blurred actor to its edges based on speed of motion
+      " gl_FragColor.a = fadeToEdgesScale;//colActor.a * fadeToEdgesScale;\n" // fade blurred actor to its edges based on speed of motion
       " gl_FragColor *= uColor;\n"
       "}\n";
 
+
+  Property::Map map;
+
+  Property::Map customShader;
+  customShader[ "vertex-shader" ] = vertexSource;
+  customShader[ "fragment-shader" ] = fragmentSource;
+
+  customShader[ "subdivide-grid-x" ] = 10;
+  customShader[ "subdivide-grid-y" ] = 10;
+
   // NOTE: we must turn on alpha blending for the actor (HINT_BLENDING)
-  ShaderEffect shader = ShaderEffect::New( vertexSource, fragmentSource,
-                                           ShaderEffect::GeometryHints( ShaderEffect::HINT_BLENDING | ShaderEffect::HINT_GRID) );
-
-  //////////////////////////////////////
-  // Register uniform properties
-  //
-  //
-  shader.SetUniform( "uBlurTexCoordScale", 0.125f );
-  shader.SetUniform( "uGeometryStretchFactor", 0.05f );
-  shader.SetUniform( "uSpeedScalingFactor", 0.5f );
-  shader.SetUniform( "uObjectFadeStart", Vector2( 0.25f, 0.25f ) );
-  shader.SetUniform( "uObjectFadeEnd", Vector2( 0.5f, 0.5f ) );
-  shader.SetUniform( "uAlphaScale", 0.75f );
-  shader.SetUniform( "uNumSamples", static_cast<float>( numBlurSamples ) );
-  shader.SetUniform( "uRecipNumSamples", 1.0f / static_cast<float>( numBlurSamples ) );
-  shader.SetUniform( "uRecipNumSamplesMinusOne", 1.0f / static_cast<float>( numBlurSamples - 1.0f ) );
-  shader.SetUniform( "uModelLastFrame", Matrix::IDENTITY );
-
-  return shader;
+  customShader[ "hints" ] = "output-is-transparent";
+
+  map[ "shader" ] = customShader;
+  return map;
 }
 
 }
index e16e2ef..5e43953 100644 (file)
@@ -29,25 +29,26 @@ namespace Toolkit
 {
 
 /**
+ * @brief Set the properties for the motion stretch
+ */
+inline void SetMotionStretchProperties( Actor& actor )
+{
+  actor.RegisterProperty( "uGeometryStretchFactor", 0.5f );
+  actor.RegisterProperty( "uSpeedScalingFactor", 0.5f );
+  actor.RegisterProperty( "uObjectFadeStart", Vector2( 0.25f, 0.25f ) );
+  actor.RegisterProperty( "uObjectFadeEnd", Vector2( 0.5f, 0.5f ) );
+  actor.RegisterProperty( "uAlphaScale", 0.75f );
+  Property::Index uModelProperty = actor.RegisterProperty( "uModelLastFrame", Matrix::IDENTITY );
+
+  Constraint constraint = Constraint::New<Matrix>( actor, uModelProperty, EqualToConstraint() );
+  constraint.AddSource( Source( actor , Actor::Property::WORLD_MATRIX ) );
+  constraint.Apply();
+}
+
+/**
  * @brief Creates a new MotionStretchEffect
  *
- * Motion stretch shader works on a per object basis. Objects will stretch in the direction of motion when they move, or if the camera moves. Can be applied
- * to ImageActor or TextActor only.
- *
- * Usage example:-
- *
- * // Create shader used for doing motion stretch\n
- * ShaderEffect MotionStretchEffect = CreateMotionStretchEffect();
- *
- * // set actor shader to the stretch one\n
- * Actor actor = Actor::New( ... );\n
- * actor.SetShaderEffect( MotionStretchEffect );
- *
- * // Constrain "uModelLastFrame" to be the same as the actor's world matrix\n
- * Dali::Property::Index uModelProperty = MotionBlurEffect.GetPropertyIndex( "uModelLastFrame" );
- * Constraint constraint = Constraint::New<Matrix>( MotionBlurEffect, uModelProperty, EqualToConstraint() );\n
- * constraint.AddSource( Source( actor , Actor::Property::WORLD_MATRIX ) );\n
- * constraint.Apply();\n
+ * Motion stretch shader works on a per object basis. Objects will stretch in the direction of motion when they move, or if the camera moves.
  *
  * Animatable/Constrainable uniforms:
  *  "uGeometryStretchFactor"  - This scales the amount the geometry stretches along the motion velocity vector.
@@ -68,25 +69,24 @@ namespace Toolkit
  *                              applied. Default 0.75.
  *  "uModelLastFrame"         - The model to world space transformation matrix of the actor in the previous frame.
  *
- * @return A handle to a newly allocated ShaderEffect
+ * @return The newly created Property::Map with the motion stretch effect
  */
-inline ShaderEffect CreateMotionStretchEffect()
+inline Property::Map CreateMotionStretchEffect()
 {
-  // Dali vertexSource prefix for reference:
-  // precision highp float;
-  // attribute vec3  aPosition;
-  // attribute vec2  aTexCoord;
-  // uniform   mat4  uMvpMatrix;
-  // uniform   mat4  uModelView;
-  // uniform   mat3  uNormalMatrix;
-  // uniform   mat4  uProjection;
-  // uniform   vec4  uColor;
-  // varying   vec2  vTexCoord;
   std::string vertexSource;
   vertexSource =
       "precision mediump float;\n"
+
+      "attribute vec2 aPosition;\n"
+
+      "uniform mat4 uMvpMatrix;\n"
+      "uniform mat4 uModelView;\n"
+      "uniform mat4 uViewMatrix;\n"
+      "uniform mat4 uProjection;\n"
+      "uniform vec3 uSize;\n"
+
       "uniform mat4  uModelLastFrame;\n"
-      "uniform float uTimeDelta;\n"
+      "float timeDelta = 0.0167;\n"
 
       "uniform float uGeometryStretchFactor;\n"
       "uniform float uSpeedScalingFactor;\n"
@@ -95,20 +95,23 @@ inline ShaderEffect CreateMotionStretchEffect()
       "varying vec2 vModelSpaceCenterToPos;\n"
       "varying vec2 vScreenSpaceVelocityVector;\n"
       "varying float vSpeed;\n"
+      "varying vec2 vTexCoord;\n"
 
       "void main()\n"
       "{\n"
       // get view space position of vertex this frame and last frame
-      " vec4 vertex = vec4(aPosition, 1.0);\n"
-      " vec4 viewSpaceVertex = uModelView * vertex;\n"
-      " vec4 viewSpaceVertexLastFrame = uViewMatrix * uModelLastFrame * vertex;\n"
+      " vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n"
+      " vertexPosition.xyz *= uSize;\n"
+
+      " vec4 viewSpaceVertex = uModelView * vertexPosition;\n"
+      " vec4 viewSpaceVertexLastFrame = uViewMatrix * uModelLastFrame * vertexPosition;\n"
 
       // work out vertex's last movement in view space
       " vec3 viewSpacePosDelta = viewSpaceVertex.xyz - viewSpaceVertexLastFrame.xyz;\n"
-      " float reciprocalTimeDelta = 1.0 / ((uTimeDelta > 0.0) ? uTimeDelta : 0.01);\n"
+      " float reciprocalTimeDelta = 1.0 / timeDelta;\n"
 
       // get clip space position of vertex this frame and last frame
-      " vec4 clipSpaceVertex = uMvpMatrix * vertex;\n"
+      " vec4 clipSpaceVertex = uMvpMatrix * vertexPosition;\n"
       " vec4 clipSpaceVertexLastFrame = uProjection * viewSpaceVertexLastFrame;\n"
 
       // decide how much this vertex is 'trailing', i.e. at the back of the object relative to its direction of motion. We do this
@@ -117,7 +120,7 @@ inline ShaderEffect CreateMotionStretchEffect()
       " float posDeltaLength = length(viewSpacePosDelta);\n"
       " if(posDeltaLength > 0.001)\n" // avoid div by 0 if object has barely moved
       " {\n"
-      "   vec4 viewSpaceCenterToPos = uModelView * vec4(aPosition, 0.0);\n"
+      "   vec4 viewSpaceCenterToPos = uModelView * vec4(aPosition, 0.0, 0.0);\n"
       "   float centerToVertexDist = length(viewSpaceCenterToPos);\n"
       "   if(centerToVertexDist > 0.001)\n" // avoid div by 0 if object has vertex at model space origin
       "   {\n"
@@ -143,22 +146,19 @@ inline ShaderEffect CreateMotionStretchEffect()
       " vSpeed = clamp(vSpeed, 0.0, 1.0);\n"
 
       // provide fragment shader with vector from center of object to pixel (assumes the objects model space origin is at its center and verts have same z)
-      " vModelSpaceCenterToPos = aPosition.xy;\n"
+      " vModelSpaceCenterToPos = viewSpaceVertex.xy;\n"
 
-      " vTexCoord = aTexCoord;\n"
+      " vec2 texCoord = aPosition + vec2(0.5);"
+      " vTexCoord = texCoord;\n"
       "}\n";
 
-
-  // Dali fragmentSource prefix for reference:
-  // precision highp     float;
-  // uniform   sampler2D sTexture;
-  // uniform   sampler2D sEffect;
-  // uniform   vec4      uColor;
-  // varying   vec2      vTexCoord;
   std::string fragmentSource;
   fragmentSource =
       "precision mediump float;\n"
 
+      "uniform sampler2D sTexture;\n"
+      "uniform vec4 uColor;\n"
+
       "uniform vec2 uObjectFadeStart;\n"
       "uniform vec2 uObjectFadeEnd;\n"
       "uniform float uAlphaScale;\n"
@@ -167,6 +167,7 @@ inline ShaderEffect CreateMotionStretchEffect()
       "varying vec2 vModelSpaceCenterToPos;\n"
       "varying vec2 vScreenSpaceVelocityVector;\n"
       "varying float vSpeed;\n"
+      "varying vec2 vTexCoord;\n"
 
       "void main()\n"
       "{\n"
@@ -184,24 +185,20 @@ inline ShaderEffect CreateMotionStretchEffect()
       " gl_FragColor *= uColor;\n"
       "}";
 
+  Property::Map map;
+
+  Property::Map customShader;
+  customShader[ "vertex-shader" ] = vertexSource;
+  customShader[ "fragment-shader" ] = fragmentSource;
+
+  customShader[ "subdivide-grid-x" ] = 10;
+  customShader[ "subdivide-grid-y" ] = 10;
+
   // NOTE: we must turn on alpha blending for the actor (HINT_BLENDING)
-  ShaderEffect shaderEffect = ShaderEffect::New(
-      vertexSource, fragmentSource,
-      ShaderEffect::GeometryHints( ShaderEffect::HINT_BLENDING | ShaderEffect::HINT_GRID ) );
-
-
-  //////////////////////////////////////
-  // Register uniform properties
-  //
-  //
-  shaderEffect.SetUniform( "uGeometryStretchFactor",  0.5f );
-  shaderEffect.SetUniform( "uSpeedScalingFactor",     0.5f );
-  shaderEffect.SetUniform( "uObjectFadeStart",        Vector2( 0.25f, 0.25f ) );
-  shaderEffect.SetUniform( "uObjectFadeEnd",          Vector2( 0.5f, 0.5f ) );
-  shaderEffect.SetUniform( "uAlphaScale",             0.75f );
-  shaderEffect.SetUniform( "uModelLastFrame",         Matrix::IDENTITY );
-
-  return shaderEffect;
+  customShader[ "hints" ] = "output-is-transparent";
+
+  map[ "shader" ] = customShader;
+  return map;
 }
 
 }
index c78e19c..c2d77a7 100644 (file)
@@ -102,7 +102,7 @@ Vector4 HexStringToVector4( const char* s )
 /**
  * A property value type can be forced when its unknown by a disambiguation convention in the json
  * ie  "myarray": [1,2,3,4] ; would be a vector but
- *     "myarray": {'type-cast':'array', 'value':[1,2,3,4]} would be an array
+ *     "myarray": {"type-cast":"array", "value":[1,2,3,4]} would be an array
  * @param child The node whos string to search for a disambiguated type
  * @param value The value to set
  * @param overrideMap The user overriding constant map
index 9fed7cc..aeb1de2 100644 (file)
@@ -132,16 +132,14 @@ void BubbleEmitter::OnInitialize()
   // Prepare the frame buffer to store the color adjusted background image
   mEffectImage = FrameBufferImage::New( mMovementArea.width/4.f, mMovementArea.height/4.f, Pixel::RGBA8888, Dali::Image::UNUSED );
 
-  // Generate the samplers and geometry, which is used by all bubbleActors
-  mSamplerBackground = Sampler::New( mEffectImage, "sBackground" );
-  mSamplerBubbleShape = Sampler::New( mShapeImage, "sBubbleShape" );
+  // Generate the geometry, which is used by all bubbleActors
   mMeshGeometry =  CreateGeometry( mNumBubblePerActor*mDensity );
 
   Shader bubbleShader = CreateBubbleShader (mNumBubblePerActor );
 
   mMaterial = Material::New( bubbleShader );
-  mMaterial.AddSampler( mSamplerBackground );
-  mMaterial.AddSampler( mSamplerBubbleShape );
+  mMaterial.AddTexture( mEffectImage, "sBackground" );
+  mMaterial.AddTexture( mShapeImage,  "sBubbleShape" );
 
   mBubbleActors.resize( mNumActor );
 
@@ -195,7 +193,7 @@ void BubbleEmitter::SetBackground( Image bgImage, const Vector3& hsvDelta )
 
 void BubbleEmitter::SetShapeImage( Image shapeImage )
 {
-  mSamplerBubbleShape.SetImage( shapeImage );
+  mMaterial.SetTextureImage( 1, shapeImage );
 }
 
 void BubbleEmitter::SetBubbleScale( float scale )
index 40b4b74..08185a0 100644 (file)
@@ -163,8 +163,6 @@ private:
   FrameBufferImage            mEffectImage;         ///< The image stores the adjusted color of the background image.The bubbles pick color from this image.
   CameraActor                 mCameraActor;         ///< The render task views the scene from the perspective of this actor.
 
-  Sampler                     mSamplerBackground;    ///< The sampler which provides the background image to material
-  Sampler                     mSamplerBubbleShape;   ///< The sampler which provides the bubble shape image to material
   Geometry                    mMeshGeometry;         ///< The mesh geometry which contains the vertices and indices data
   Material                    mMaterial;             ///< The material which controls the bubble display
   std::vector<BubbleActorPtr> mBubbleActors;         ///< The meshActor vector, its size is mNumShader.
index 5da6110..ddbb242 100644 (file)
@@ -326,32 +326,6 @@ void GaussianBlurView::OnInitialize()
 }
 
 
-/**
- * ZrelativeToYconstraint
- *
- * f(current, property, scale) = Vector3(current.x, current.y, property.y * scale)
- */
-struct ZrelativeToYconstraint
-{
-  ZrelativeToYconstraint( float scale )
-    : mScale( scale )
-  {}
-
-  Vector3 operator()(const Vector3&    current,
-                     const PropertyInput& property)
-  {
-    Vector3 v;
-
-    v.x = current.x;
-    v.y = current.y;
-    v.z = property.GetVector3().y * mScale;
-
-    return v;
-  }
-
-  float mScale;
-};
-
 void GaussianBlurView::OnSizeSet(const Vector3& targetSize)
 {
   mTargetSize = Vector2(targetSize);
index 9f7294b..691f932 100644 (file)
@@ -215,6 +215,8 @@ float ImageView::GetWidthForHeight( float height )
 
 void ImageView::OnStageConnection( int depth )
 {
+  Control::OnStageConnection( depth );
+
   if( mRenderer )
   {
     CustomActor self = Self();
@@ -229,6 +231,8 @@ void ImageView::OnStageDisconnection()
     CustomActor self = Self();
     mRenderer.SetOffStage( self );
   }
+
+  Control::OnStageDisconnection();
 }
 
 
index 84780be..9405ec0 100644 (file)
@@ -447,6 +447,8 @@ Property::Value Model3dView::GetProperty( BaseObject* object, Property::Index in
 
 void Model3dView::OnStageConnection( int depth )
 {
+  Control::OnStageConnection( depth );
+
   CustomActor self = Self();
   self.AddRenderer( mRenderer );
 
@@ -627,11 +629,8 @@ void Model3dView::LoadTextures()
     Image tex0 = ResourceImage::New( imgUrl );
     if( tex0 )
     {
-      Sampler sampler = Sampler::New( tex0, "sDiffuse" );
-      sampler.SetWrapMode(Sampler::REPEAT,Sampler::REPEAT);
-      sampler.SetAffectsTransparency(false);
-
-      mMaterial.AddSampler( sampler );
+      size_t index = mMaterial.AddTexture( tex0, "sDiffuse" );
+      mMaterial.SetTextureAffectsTransparency(index, false );
     }
   }
 
@@ -643,12 +642,8 @@ void Model3dView::LoadTextures()
     Image tex1 = ResourceImage::New( imgUrl );
     if (tex1)
     {
-      Sampler sampler = Sampler::New( tex1, "sNormal" );
-      sampler.SetWrapMode(Sampler::REPEAT,Sampler::REPEAT);
-      sampler.SetAffectsTransparency(false);
-      sampler.SetFilterMode(Sampler::LINEAR,Sampler::LINEAR);
-
-      mMaterial.AddSampler( sampler );
+      size_t index = mMaterial.AddTexture( tex1, "sNormal" );
+      mMaterial.SetTextureAffectsTransparency(index, false );
     }
   }
 
@@ -660,12 +655,8 @@ void Model3dView::LoadTextures()
     Image tex2 = ResourceImage::New( imgUrl );
     if( tex2 )
     {
-      Sampler sampler = Sampler::New( tex2, "sGloss" );
-      sampler.SetWrapMode(Sampler::REPEAT,Sampler::REPEAT);
-      sampler.SetAffectsTransparency(false);
-      sampler.SetFilterMode(Sampler::LINEAR,Sampler::LINEAR);
-
-      mMaterial.AddSampler( sampler );
+      size_t index = mMaterial.AddTexture( tex2, "sGloss" );
+      mMaterial.SetTextureAffectsTransparency(index, false );
     }
   }
 }
index 9edfc95..7210e9e 100644 (file)
@@ -359,6 +359,8 @@ void PageTurnView::SetupShadowView()
 
 void PageTurnView::OnStageConnection( int depth )
 {
+  Control::OnStageConnection( depth );
+
   SetupShadowView();
   mTurningPageLayer.Raise();
 }
@@ -385,6 +387,8 @@ void PageTurnView::OnStageDisconnection()
 
     SetSpineEffect( mPanActor, mIsTurnBack[mPanActor] );
   }
+
+  Control::OnStageDisconnection();
 }
 
 void PageTurnView::SetPageSize( const Vector2& pageSize )
index c080be2..c616669 100644 (file)
@@ -48,7 +48,6 @@ struct Internal::ControlRenderer::Impl
   };
 
   std::string mCachedRendererKey;  ///< The key to use for caching of the renderer. If it is empty then no caching will occur
-  RendererFactoryCache::CachedRendererPtr mCachedRenderer; ///< The current cached renderer from the Factory Cache. mCachedRenderer == null whilst this control render is offstage
   Renderer mRenderer;
 
   CustomShader* mCustomShader;
index 18374e1..990182c 100644 (file)
@@ -133,19 +133,15 @@ void ControlRenderer::SetCachedRendererKey( const std::string& cachedRendererKey
   }
   else
   {
-    //remove the cached renderer from the cache if we and the cache are the only things that hold a reference to it
-    if( mImpl->mCachedRenderer && mImpl->mCachedRenderer->ReferenceCount() == 2 )
-    {
-      mFactoryCache.RemoveRenderer( mImpl->mCachedRenderer->mKey );
-    }
-    mImpl->mCachedRenderer.Reset();
+    //clean the renderer from the cache since it may no longer be in use
+    mFactoryCache.CleanRendererCache( mImpl->mCachedRendererKey );
 
     //add the new renderer
     mImpl->mCachedRendererKey = cachedRendererKey;
     if( !mImpl->mCachedRendererKey.empty() && !mImpl->mCustomShader )
     {
       DALI_ASSERT_DEBUG( mImpl->mRenderer && "The control render is on stage but it doesn't have a valid renderer.");
-      mImpl->mCachedRenderer = mFactoryCache.SaveRenderer( mImpl->mCachedRendererKey, mImpl->mRenderer );
+      mFactoryCache.SaveRenderer( mImpl->mCachedRendererKey, mImpl->mRenderer );
     }
   }
 }
@@ -154,16 +150,11 @@ void ControlRenderer::SetOnStage( Actor& actor )
 {
   if( !mImpl->mCachedRendererKey.empty() && !mImpl->mCustomShader )
   {
-    mImpl->mCachedRenderer = mFactoryCache.GetRenderer( mImpl->mCachedRendererKey );
-    if( !mImpl->mCachedRenderer || !mImpl->mCachedRenderer->mRenderer )
+    mImpl->mRenderer = mFactoryCache.GetRenderer( mImpl->mCachedRendererKey );
+    if( !mImpl->mRenderer )
     {
       InitializeRenderer( mImpl->mRenderer );
-      mImpl->mCachedRenderer = mFactoryCache.SaveRenderer( mImpl->mCachedRendererKey, mImpl->mRenderer );
-    }
-
-    if( mImpl->mCachedRenderer && mImpl->mCachedRenderer->mRenderer )
-    {
-      mImpl->mRenderer = mImpl->mCachedRenderer->mRenderer;
+      mFactoryCache.SaveRenderer( mImpl->mCachedRendererKey, mImpl->mRenderer );
     }
   }
 
@@ -184,17 +175,12 @@ void ControlRenderer::SetOffStage( Actor& actor )
   if( mImpl->mIsOnStage )
   {
     DoSetOffStage( actor );
-
-    //remove the cached renderer from the cache if we and the cache are the only things that hold a reference to it
-    if( mImpl->mCachedRenderer && mImpl->mCachedRenderer->ReferenceCount() == 2 )
-    {
-      mFactoryCache.RemoveRenderer( mImpl->mCachedRenderer->mKey );
-    }
-    mImpl->mCachedRenderer.Reset();
-
     actor.RemoveRenderer( mImpl->mRenderer );
     mImpl->mRenderer.Reset();
 
+    //clean the renderer from the cache since it may no longer be in use
+    mFactoryCache.CleanRendererCache( mImpl->mCachedRendererKey );
+
     mImpl->mIsOnStage = false;
   }
 }
index 30a587f..6dc25ca 100644 (file)
@@ -155,22 +155,22 @@ DALI_COMPOSE_SHADER(
 )
 };
 
-Sampler::WrapMode GetWrapMode( Gradient::SpreadMethod spread )
+Dali::WrapMode::Type GetWrapMode( Gradient::SpreadMethod spread )
 {
   switch(spread)
   {
     case Gradient::REPEAT:
     {
-      return Sampler::REPEAT;
+      return Dali::WrapMode::REPEAT;
     }
     case Gradient::REFLECT:
     {
-      return Sampler::MIRRORED_REPEAT;
+      return Dali::WrapMode::MIRRORED_REPEAT;
     }
     case Gradient::PAD:
     default:
     {
-      return Sampler::CLAMP_TO_EDGE;
+      return Dali::WrapMode::CLAMP_TO_EDGE;
     }
   }
 }
@@ -324,11 +324,11 @@ void GradientRenderer::InitializeRenderer( Dali::Renderer& renderer )
   }
 
   Dali::BufferImage lookupTexture = mGradient->GenerateLookupTexture();
-  Sampler sampler = Sampler::New( lookupTexture, UNIFORM_TEXTULRE_NAME );
-  Sampler::WrapMode wrap = GetWrapMode( mGradient->GetSpreadMethod() );
+  Sampler sampler = Sampler::New();
+  Dali::WrapMode::Type wrap = GetWrapMode( mGradient->GetSpreadMethod() );
   sampler.SetWrapMode(  wrap, wrap  );
 
-  material.AddSampler( sampler );
+  material.AddTexture( lookupTexture, UNIFORM_TEXTULRE_NAME, sampler );
 
   renderer.RegisterProperty( UNIFORM_ALIGNMENT_MATRIX_NAME, mGradientTransform );
 }
index b595a48..8f02d85 100644 (file)
@@ -401,7 +401,10 @@ void ImageRenderer::DoSetOnStage( Actor& actor )
 {
   if( !mImageUrl.empty() && !mImage )
   {
-    mImage = Dali::ResourceImage::New( mImageUrl, mDesiredSize, mFittingMode, mSamplingMode );
+    Dali::ResourceImage resourceImage = Dali::ResourceImage::New( mImageUrl, mDesiredSize, mFittingMode, mSamplingMode );
+    resourceImage.LoadingFinishedSignal().Connect( this, &ImageRenderer::OnImageLoaded );
+
+    mImage = resourceImage;
   }
 
   ApplyImageToSampler();
@@ -529,7 +532,10 @@ void ImageRenderer::SetImage( const std::string& imageUrl, int desiredWidth, int
 
     if( !mImageUrl.empty() && mImpl->mIsOnStage )
     {
-      mImage = Dali::ResourceImage::New( mImageUrl, mDesiredSize, mFittingMode, mSamplingMode );
+      Dali::ResourceImage resourceImage = Dali::ResourceImage::New( mImageUrl, mDesiredSize, mFittingMode, mSamplingMode );
+      resourceImage.LoadingFinishedSignal().Connect( this, &ImageRenderer::OnImageLoaded );
+      mImage = resourceImage;
+
       ApplyImageToSampler();
     }
     else
@@ -568,18 +574,26 @@ void ImageRenderer::ApplyImageToSampler()
     Material material = mImpl->mRenderer.GetMaterial();
     if( material )
     {
-      for( std::size_t i = 0; i < material.GetNumberOfSamplers(); ++i )
+      int index = material.GetTextureIndex(TEXTURE_UNIFORM_NAME);
+      if( index != -1 )
       {
-        Sampler sampler = material.GetSamplerAt( i );
-        if( sampler.GetUniformName() == TEXTURE_UNIFORM_NAME )
-        {
-          sampler.SetImage( mImage );
-          return;
-        }
+        material.SetTextureImage( index, mImage );
+        return;
       }
 
-      Sampler sampler = Sampler::New( mImage, TEXTURE_UNIFORM_NAME );
-      material.AddSampler( sampler );
+      material.AddTexture( mImage,TEXTURE_UNIFORM_NAME );
+    }
+  }
+}
+
+void ImageRenderer::OnImageLoaded( ResourceImage image )
+{
+  if( image.GetLoadingState() == Dali::ResourceLoadingFailed )
+  {
+    mImage = RendererFactory::GetBrokenRendererImage();
+    if( mImpl->mIsOnStage )
+    {
+      ApplyImageToSampler();
     }
   }
 }
index f408fb2..efcbf53 100644 (file)
@@ -24,6 +24,7 @@
 // EXTERNAL INCLUDES
 #include <dali/public-api/images/image.h>
 #include <dali/public-api/images/image-operations.h>
+#include <dali/public-api/images/resource-image.h>
 
 namespace Dali
 {
@@ -68,7 +69,7 @@ typedef IntrusivePtr< ImageRenderer > ImageRendererPtr;
  *   "default"
  *
  */
-class ImageRenderer: public ControlRenderer
+class ImageRenderer: public ControlRenderer, public ConnectionTracker
 {
 public:
 
@@ -175,6 +176,12 @@ private:
    */
   void ApplyImageToSampler();
 
+  /**
+   * Callback function of image resource loading succeed
+   * @param[in] image The Image content that we attempted to load from mImageUrl
+   */
+  void OnImageLoaded( ResourceImage image );
+
 private:
   Image mImage;
 
index 63e2f5d..8e509a9 100644 (file)
@@ -49,6 +49,32 @@ const char * const BORDER_ONLY("border-only");
 
 std::string TEXTURE_UNIFORM_NAME = "sTexture";
 
+const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
+  attribute mediump vec2 aPosition;\n
+  varying mediump vec2 vTexCoord;\n
+  uniform mediump mat4 uMvpMatrix;\n
+  uniform mediump vec3 uSize;\n
+  uniform mediump vec2 uNinePatchFactorsX[ FACTOR_SIZE_X ];\n
+  uniform mediump vec2 uNinePatchFactorsY[ FACTOR_SIZE_Y ];\n
+  \n
+  void main()\n
+  {\n
+    mediump vec2 fixedFactor  = vec2( uNinePatchFactorsX[ int( ( aPosition.x + 1.0 ) * 0.5 ) ].x, uNinePatchFactorsY[ int( ( aPosition.y + 1.0 ) * 0.5 ) ].x );\n
+    mediump vec2 stretch      = vec2( uNinePatchFactorsX[ int( ( aPosition.x       ) * 0.5 ) ].y, uNinePatchFactorsY[ int( ( aPosition.y       ) * 0.5 ) ].y );\n
+    \n
+    mediump vec2 fixedTotal   = vec2( uNinePatchFactorsX[ FACTOR_SIZE_X - 1 ].x, uNinePatchFactorsY[ FACTOR_SIZE_Y - 1 ].x );\n
+    mediump vec2 stretchTotal = vec2( uNinePatchFactorsX[ FACTOR_SIZE_X - 1 ].y, uNinePatchFactorsY[ FACTOR_SIZE_Y - 1 ].y );\n
+    \n
+    mediump vec4 vertexPosition = vec4( ( fixedFactor + ( uSize.xy - fixedTotal ) * stretch / stretchTotal ), 0.0, 1.0 );\n
+    vertexPosition.xy -= uSize.xy * vec2( 0.5, 0.5 );\n
+    vertexPosition = uMvpMatrix * vertexPosition;\n
+    \n
+    vTexCoord = ( fixedFactor + stretch ) / ( fixedTotal + stretchTotal );\n
+    \n
+    gl_Position = vertexPosition;\n
+  }\n
+);
+
 const char* VERTEX_SHADER_3X3 = DALI_COMPOSE_SHADER(
     attribute mediump vec2 aPosition;\n
     varying mediump vec2 vTexCoord;\n
@@ -146,6 +172,37 @@ void AddVertex( Vector< Vector2 >& vertices, unsigned int x, unsigned int y )
   vertices.PushBack( Vector2( x, y ) );
 }
 
+void RegisterStretchProperties( Material& material, const char * uniformName, const NinePatchImage::StretchRanges& stretchPixels, uint16_t imageExtent)
+{
+  uint16_t prevEnd = 0;
+  uint16_t prevFix = 0;
+  uint16_t prevStretch = 0;
+  unsigned int i = 1;
+  for( NinePatchImage::StretchRanges::ConstIterator it = stretchPixels.Begin(); it != stretchPixels.End(); ++it, ++i )
+  {
+    uint16_t start = it->GetX();
+    uint16_t end = it->GetY();
+
+    uint16_t fix = prevFix + start - prevEnd;
+    uint16_t stretch = prevStretch + end - start;
+
+    std::stringstream uniform;
+    uniform << uniformName << "[" << i << "]";
+    material.RegisterProperty( uniform.str(), Vector2( fix, stretch ) );
+
+    prevEnd = end;
+    prevFix = fix;
+    prevStretch = stretch;
+  }
+
+  {
+    prevFix += imageExtent - prevEnd;
+    std::stringstream uniform;
+    uniform << uniformName << "[" << i << "]";
+    material.RegisterProperty( uniform.str(), Vector2( prevFix, prevStretch ) );
+  }
+}
+
 } //unnamed namespace
 
 /////////////////NPatchRenderer////////////////
@@ -175,11 +232,11 @@ void NPatchRenderer::DoInitialize( const Property::Map& propertyMap )
     if( imageURLValue->Get( mImageUrl ) )
     {
       NinePatchImage nPatch = NinePatchImage::New( mImageUrl );
-      InitialiseFromImage( nPatch );
+      InitializeFromImage( nPatch );
     }
     else
     {
-      CreateErrorImage();
+      InitializeFromBrokenImage();
       DALI_LOG_ERROR( "The property '%s' is not a string\n", IMAGE_URL_NAME );
     }
   }
@@ -191,17 +248,17 @@ void NPatchRenderer::GetNaturalSize( Vector2& naturalSize ) const
   {
     naturalSize.x = mImage.GetWidth();
     naturalSize.y = mImage.GetHeight();
-    return;
   }
   else if( !mImageUrl.empty() )
   {
     ImageDimensions dimentions = ResourceImage::GetImageSize( mImageUrl );
     naturalSize.x = dimentions.GetWidth();
     naturalSize.y = dimentions.GetHeight();
-    return;
   }
-
-  naturalSize = Vector2::ZERO;
+  else
+  {
+    naturalSize = Vector2::ZERO;
+  }
 }
 
 void NPatchRenderer::SetClipRect( const Rect<int>& clipRect )
@@ -218,30 +275,51 @@ void NPatchRenderer::SetOffset( const Vector2& offset )
 void NPatchRenderer::InitializeRenderer( Renderer& renderer )
 {
   Geometry geometry;
-  if( !mBorderOnly )
+  Shader shader;
+  if( mStretchPixelsX.Size() == 1 && mStretchPixelsY.Size() == 1 )
   {
-    geometry = mFactoryCache.GetGeometry( RendererFactoryCache::NINE_PATCH_GEOMETRY );
-    if( !geometry )
+    if( !mBorderOnly )
     {
-      geometry = CreateGeometry( Uint16Pair( 3, 3 ) );
-      mFactoryCache.SaveGeometry( RendererFactoryCache::NINE_PATCH_GEOMETRY, geometry );
+      geometry = mFactoryCache.GetGeometry( RendererFactoryCache::NINE_PATCH_GEOMETRY );
+      if( !geometry )
+      {
+        geometry = CreateGeometry( Uint16Pair( 3, 3 ) );
+        mFactoryCache.SaveGeometry( RendererFactoryCache::NINE_PATCH_GEOMETRY, geometry );
+      }
     }
-  }
-  else
-  {
-    geometry = mFactoryCache.GetGeometry( RendererFactoryCache::NINE_PATCH_BORDER_GEOMETRY );
-    if( !geometry )
+    else
+    {
+      geometry = mFactoryCache.GetGeometry( RendererFactoryCache::NINE_PATCH_BORDER_GEOMETRY );
+      if( !geometry )
+      {
+        geometry = CreateGeometryBorder( Uint16Pair( 3, 3 ) );
+        mFactoryCache.SaveGeometry( RendererFactoryCache::NINE_PATCH_BORDER_GEOMETRY, geometry );
+      }
+    }
+
+    shader = mFactoryCache.GetShader( RendererFactoryCache::NINE_PATCH_SHADER );
+    if( !shader )
     {
-      geometry = CreateGeometryBorder( Uint16Pair( 3, 3 ) );
-      mFactoryCache.SaveGeometry( RendererFactoryCache::NINE_PATCH_BORDER_GEOMETRY, geometry );
+      shader = Shader::New( VERTEX_SHADER_3X3, FRAGMENT_SHADER );
+      mFactoryCache.SaveShader( RendererFactoryCache::NINE_PATCH_SHADER, shader );
     }
   }
+  else if( mStretchPixelsX.Size() > 0 || mStretchPixelsY.Size() > 0)
+  {
+    Uint16Pair gridSize( 2 * mStretchPixelsX.Size() + 1,  2 * mStretchPixelsY.Size() + 1 );
+    geometry = !mBorderOnly ? CreateGeometry( gridSize ) : CreateGeometryBorder( gridSize );
+
+    std::stringstream vertexShader;
+    vertexShader << "#define FACTOR_SIZE_X " << mStretchPixelsX.Size() + 2 << "\n"
+                 << "#define FACTOR_SIZE_Y " << mStretchPixelsY.Size() + 2 << "\n"
+                 << VERTEX_SHADER;
 
-  Shader shader = mFactoryCache.GetShader( RendererFactoryCache::NINE_PATCH_SHADER );
-  if( !shader )
+    shader = Shader::New( vertexShader.str(), FRAGMENT_SHADER );
+  }
+  else
   {
-    shader = Shader::New( VERTEX_SHADER_3X3, FRAGMENT_SHADER );
-    mFactoryCache.SaveShader( RendererFactoryCache::NINE_PATCH_SHADER, shader );
+    DALI_LOG_ERROR("The 9 patch image '%s' doesn't have any valid stretch borders and so is not a valid 9 patch image\n", mImageUrl.c_str() );
+    InitializeFromBrokenImage();
   }
 
   if( !renderer )
@@ -267,12 +345,14 @@ void NPatchRenderer::DoSetOnStage( Actor& actor )
     if( !mImageUrl.empty() )
     {
       NinePatchImage nPatch = NinePatchImage::New( mImageUrl );
-      InitialiseFromImage( nPatch );
+      InitializeFromImage( nPatch );
     }
     else if( mImage )
     {
-      InitialiseFromImage( mImage );
+      InitializeFromImage( mImage );
     }
+
+    InitializeRenderer( mImpl->mRenderer );
   }
 
   if( mCroppedImage )
@@ -312,7 +392,7 @@ void NPatchRenderer::SetImage( const std::string& imageUrl, bool borderOnly )
 
   mImageUrl = imageUrl;
   NinePatchImage nPatch = NinePatchImage::New( mImageUrl );
-  InitialiseFromImage( nPatch );
+  InitializeFromImage( nPatch );
 
   if( mCroppedImage && mImpl->mIsOnStage )
   {
@@ -330,7 +410,7 @@ void NPatchRenderer::SetImage( NinePatchImage image, bool borderOnly )
   }
 
   mImage = image;
-  InitialiseFromImage( mImage );
+  InitializeFromImage( mImage );
 
   if( mCroppedImage && mImpl->mIsOnStage )
   {
@@ -338,13 +418,13 @@ void NPatchRenderer::SetImage( NinePatchImage image, bool borderOnly )
   }
 }
 
-void NPatchRenderer::InitialiseFromImage( NinePatchImage nPatch )
+void NPatchRenderer::InitializeFromImage( NinePatchImage nPatch )
 {
   mCroppedImage = nPatch.CreateCroppedBufferImage();
   if( !mCroppedImage )
   {
     DALI_LOG_ERROR("'%s' specify a valid 9 patch image\n", mImageUrl.c_str() );
-    CreateErrorImage();
+    InitializeFromBrokenImage();
     return;
   }
 
@@ -354,21 +434,10 @@ void NPatchRenderer::InitialiseFromImage( NinePatchImage nPatch )
   mStretchPixelsY = nPatch.GetStretchPixelsY();
 }
 
-void NPatchRenderer::CreateErrorImage()
+void NPatchRenderer::InitializeFromBrokenImage()
 {
-  mImageSize = ImageDimensions( 1, 1 );
-
-  BufferImage bufferImage = BufferImage::New( mImageSize.GetWidth(), mImageSize.GetHeight(), Pixel::RGBA8888 );
-  mCroppedImage = bufferImage;
-  PixelBuffer* pixbuf = bufferImage.GetBuffer();
-
-  for( size_t i = 0; i < mImageSize.GetWidth() * mImageSize.GetHeight() * 4u; )
-  {
-    pixbuf[ i++ ] = 0;
-    pixbuf[ i++ ] = 0;
-    pixbuf[ i++ ] = 0;
-    pixbuf[ i++ ] = 255;
-  }
+  mCroppedImage = RendererFactory::GetBrokenRendererImage();
+  mImageSize = ImageDimensions( mCroppedImage.GetWidth(), mCroppedImage.GetHeight() );
 
   mStretchPixelsX.Clear();
   mStretchPixelsX.PushBack( Uint16Pair( 0, mImageSize.GetWidth() ) );
@@ -381,35 +450,37 @@ void NPatchRenderer::ApplyImageToSampler()
   Material material = mImpl->mRenderer.GetMaterial();
   if( material )
   {
-    Sampler sampler;
-    for( std::size_t i = 0; i < material.GetNumberOfSamplers(); ++i )
+    int index = material.GetTextureIndex( TEXTURE_UNIFORM_NAME );
+    if( index > -1 )
     {
-      sampler = material.GetSamplerAt( i );
-      if( sampler.GetUniformName() == TEXTURE_UNIFORM_NAME )
-      {
-        sampler.SetImage( mCroppedImage );
-        break;
-      }
+      material.SetTextureImage( index, mCroppedImage );
     }
-    if( !sampler )
+    else
     {
-      sampler = Sampler::New( mCroppedImage, TEXTURE_UNIFORM_NAME );
-      material.AddSampler( sampler );
+      material.AddTexture(  mCroppedImage, TEXTURE_UNIFORM_NAME );
     }
 
-    if( mStretchPixelsX.Size() > 0 && mStretchPixelsY.Size() > 0 )
+    if( mStretchPixelsX.Size() == 1 && mStretchPixelsY.Size() == 1 )
     {
-      //only 9 patch supported for now
+      //special case for 9 patch
       Uint16Pair stretchX = mStretchPixelsX[ 0 ];
       Uint16Pair stretchY = mStretchPixelsY[ 0 ];
 
       uint16_t stretchWidth = stretchX.GetY() - stretchX.GetX();
       uint16_t stretchHeight = stretchY.GetY() - stretchY.GetX();
 
-      sampler.RegisterProperty( "uFixed[0]", Vector2::ZERO );
-      sampler.RegisterProperty( "uFixed[1]", Vector2( stretchX.GetX(), stretchY.GetX()) );
-      sampler.RegisterProperty( "uFixed[2]", Vector2( mImageSize.GetWidth() - stretchWidth, mImageSize.GetHeight() - stretchHeight ) );
-      sampler.RegisterProperty( "uStretchTotal", Vector2( stretchWidth, stretchHeight ) );
+      material.RegisterProperty( "uFixed[0]", Vector2::ZERO );
+      material.RegisterProperty( "uFixed[1]", Vector2( stretchX.GetX(), stretchY.GetX()) );
+      material.RegisterProperty( "uFixed[2]", Vector2( mImageSize.GetWidth() - stretchWidth, mImageSize.GetHeight() - stretchHeight ) );
+      material.RegisterProperty( "uStretchTotal", Vector2( stretchWidth, stretchHeight ) );
+    }
+    else
+    {
+      material.RegisterProperty( "uNinePatchFactorsX[0]", Vector2::ZERO );
+      material.RegisterProperty( "uNinePatchFactorsY[0]", Vector2::ZERO );
+
+      RegisterStretchProperties( material, "uNinePatchFactorsX", mStretchPixelsX, mImageSize.GetWidth() );
+      RegisterStretchProperties( material, "uNinePatchFactorsY", mStretchPixelsY, mImageSize.GetHeight() );
     }
   }
 }
index 77ba2a4..c17b167 100644 (file)
@@ -166,13 +166,13 @@ private:
    *
    * @param nPatchImage The NinePatchImage to base our cropped images and stretch borders from
    */
-  void InitialiseFromImage( NinePatchImage nPatchImage );
+  void InitializeFromImage( NinePatchImage nPatchImage );
 
   /**
-   * @brief Creates a black Image to indicate that there was an error in either the image url or the parsing of the image
+   * @brief Creates an error Image to indicate that there was an error in either the image url or the parsing of the image
    *
    */
-  void CreateErrorImage();
+  void InitializeFromBrokenImage();
 
   /**
    * @brief Applies this renderer's image to the sampler to the material used for this renderer
@@ -183,8 +183,6 @@ private:
 
   NinePatchImage mImage; ///< The image to render if the renderer was set from an NinePatchImage, empty otherwise
   Image mCroppedImage;
-  Geometry mNinePatchGeometry;
-  Geometry mNinePatchBorderGeometry;
 
   std::string mImageUrl; ///< The url to the image resource to render if the renderer was set from an image resource url, empty otherwise
   NinePatchImage::StretchRanges mStretchPixelsX;
index a22f541..c7b53b6 100644 (file)
@@ -73,7 +73,7 @@ int RendererFactoryCache::FindRenderer( const std::string& key ) const
     if( it != mRendererHashes.End() )
     {
       int index = it - mRendererHashes.Begin();
-      const CachedRendererPtr& cachedRenderer = mRenderers[ index ];
+      const CachedRenderer* cachedRenderer = mRenderers[ index ];
 
       if( cachedRenderer && cachedRenderer->mKey == key )
       {
@@ -90,47 +90,51 @@ int RendererFactoryCache::FindRenderer( const std::string& key ) const
   return -1;
 }
 
-RendererFactoryCache::CachedRendererPtr RendererFactoryCache::GetRenderer( const std::string& key ) const
+Renderer RendererFactoryCache::GetRenderer( const std::string& key ) const
 {
   int index = FindRenderer( key );
   if( index != -1 )
   {
-    return mRenderers[ index ];
+    return mRenderers[ index ]->mRenderer.GetHandle();
   }
   else
   {
-    return CachedRendererPtr();
+    return Renderer();
   }
 }
 
-RendererFactoryCache::CachedRendererPtr RendererFactoryCache::SaveRenderer( const std::string& key, Renderer& renderer )
+void RendererFactoryCache::SaveRenderer( const std::string& key, Renderer& renderer )
 {
   int hash = Dali::CalculateHash( key );
-  CachedRendererPtr newCachedRenderer = new CachedRenderer( key, renderer );
+  const CachedRenderer* cachedRenderer = new CachedRenderer( key, renderer );
 
-  CachedRenderers::iterator it = std::find(mRenderers.begin(), mRenderers.end(), CachedRendererPtr() );
-  if( it != mRenderers.end() )
+  CachedRenderers::Iterator it = std::find( mRenderers.Begin(), mRenderers.End(), static_cast< CachedRenderer* >( NULL ) );
+  if( it != mRenderers.End() )
   {
-    *it = newCachedRenderer;
-    int index = it - mRenderers.begin();
+    *it = cachedRenderer;
+    int index = it - mRenderers.Begin();
     mRendererHashes[ index ] = hash;
   }
   else
   {
     mRendererHashes.PushBack( hash );
-    mRenderers.push_back( newCachedRenderer );
+    mRenderers.PushBack( cachedRenderer );
   }
-
-  return newCachedRenderer;
 }
 
-void RendererFactoryCache::RemoveRenderer( const std::string& key )
+void RendererFactoryCache::CleanRendererCache( const std::string& key )
 {
   int index = FindRenderer( key );
   if( index != -1 )
   {
-    mRendererHashes[ index ] = Dali::CalculateHash( "" );
-    mRenderers[ index ].Reset();
+    const CachedRenderer*& cachedRenderer = mRenderers[ index ];
+    if( !cachedRenderer->mRenderer.GetHandle() )
+    {
+      mRendererHashes[ index ] = Dali::INITIAL_HASH_VALUE;
+
+      delete cachedRenderer;
+      cachedRenderer = NULL;
+    }
   }
 }
 
index f546c85..947fd47 100644 (file)
@@ -24,6 +24,9 @@
 #include <dali/devel-api/rendering/geometry.h>
 #include <dali/devel-api/rendering/shader.h>
 #include <dali/devel-api/rendering/renderer.h>
+#include <dali/devel-api/common/owner-container.h>
+#include <dali/devel-api/object/weak-handle.h>
+
 
 namespace Dali
 {
@@ -110,25 +113,13 @@ public:
   static Geometry CreateQuadGeometry();
 
 public:
-  struct CachedRenderer : RefObject
-  {
-    std::string mKey;
-    Renderer mRenderer;
-
-    CachedRenderer( const std::string& key, const Renderer& renderer )
-    : mKey( key ),
-      mRenderer( renderer )
-    {}
-  };
-
-  typedef IntrusivePtr< CachedRenderer > CachedRendererPtr;
 
   /**
    * @brief Request renderer from the url
    *
-   * @return The cached renderer if exist in the cache. Otherwise null is returned.
+   * @return The cached renderer if exist in the cache. Otherwise an empty handle is returned.
    */
-  CachedRendererPtr GetRenderer( const std::string& key ) const;
+  Renderer GetRenderer( const std::string& key ) const;
 
   /**
    * @brief Cache the renderer based on the given key.
@@ -138,17 +129,15 @@ public:
    *
    * @param[in] key The key to use for caching
    * @param[in] renderer The Renderer to be cached
-   *
-   * @return The cached renderer stored in the cache
    */
-  CachedRendererPtr SaveRenderer( const std::string& key, Renderer& renderer );
+  void SaveRenderer( const std::string& key, Renderer& renderer );
 
   /**
-   * @brief Removes the renderer from the cache based on the given key
+   * @brief Cleans the renderer cache by removing the renderer from the cache based on the given key if there are no longer any references to it
    *
    * @param[in] key The key used for caching
    */
-  void RemoveRenderer( const std::string& key );
+  void CleanRendererCache( const std::string& key );
 
 protected:
 
@@ -168,8 +157,19 @@ protected:
   RendererFactoryCache& operator=(const RendererFactoryCache& rhs);
 
 private:
+  struct CachedRenderer
+  {
+    std::string mKey;
+    WeakHandle< Renderer > mRenderer;
+
+    CachedRenderer( const std::string& key, Renderer& renderer )
+    : mKey( key ),
+      mRenderer( renderer)
+    {}
+  };
+
   typedef Dali::Vector< std::size_t > HashVector;
-  typedef std::vector< CachedRendererPtr > CachedRenderers;
+  typedef Dali::OwnerContainer< const CachedRenderer* > CachedRenderers;
 
   /**
    * @brief Finds the first index into the cached renderers from the url
index b9d1d40..ddac18e 100644 (file)
@@ -41,6 +41,8 @@ const char * const BORDER_RENDERER("border-renderer");
 const char * const GRADIENT_RENDERER("gradient-renderer");
 const char * const IMAGE_RENDERER("image-renderer");
 const char * const N_PATCH_RENDERER("n-patch-renderer");
+
+const char * const BROKEN_RENDERER_IMAGE_URL( DALI_IMAGE_DIR "broken.png");
 }
 
 namespace Dali
@@ -307,6 +309,11 @@ bool RendererFactory::ResetRenderer( Toolkit::ControlRenderer& renderer, const P
   return false;
 }
 
+Image RendererFactory::GetBrokenRendererImage()
+{
+  return ResourceImage::New( BROKEN_RENDERER_IMAGE_URL );
+}
+
 } // namespace Internal
 
 } // namespace Toolkit
index 99ef2b8..a76c572 100644 (file)
@@ -94,6 +94,12 @@ public:
    */
   bool ResetRenderer( Toolkit::ControlRenderer& renderer, const std::string& image );
 
+public:
+  /**
+   * @brief Returns an image to be used when a renderer has failed to correctly render
+   */
+  static Image GetBrokenRendererImage();
+
 protected:
 
   /**
index d2b699b..f92f721 100755 (executable)
@@ -152,6 +152,7 @@ const char* INDICATOR_HEIGHT_POLICY_NAME[] = {"Variable", "Fixed"};
 
 ScrollBar::ScrollBar(Toolkit::ScrollBar::Direction direction)
 : Control( ControlBehaviour( REQUIRES_TOUCH_EVENTS | REQUIRES_STYLE_CHANGE_SIGNALS ) ),
+  mIndicatorShowAlpha(1.0f),
   mDirection(direction),
   mScrollableObject(WeakHandleBase()),
   mPropertyScrollPosition(Property::INVALID_INDEX),
@@ -161,10 +162,11 @@ ScrollBar::ScrollBar(Toolkit::ScrollBar::Direction direction)
   mIndicatorShowDuration(DEFAULT_INDICATOR_SHOW_DURATION),
   mIndicatorHideDuration(DEFAULT_INDICATOR_HIDE_DURATION),
   mScrollStart(0.0f),
-  mIsPanning(false),
   mCurrentScrollPosition(0.0f),
   mIndicatorHeightPolicy(Toolkit::ScrollBar::Variable),
-  mIndicatorFixedHeight(DEFAULT_INDICATOR_FIXED_HEIGHT)
+  mIndicatorFixedHeight(DEFAULT_INDICATOR_FIXED_HEIGHT),
+  mIsPanning(false),
+  mIndicatorFirstShow(true)
 {
 }
 
@@ -218,6 +220,7 @@ void ScrollBar::SetScrollIndicator( Actor indicator )
   if( indicator )
   {
     mIndicator = indicator;
+    mIndicatorFirstShow = true;
     Self().Add(mIndicator);
 
     EnableGestureDetection(Gesture::Type(Gesture::Pan));
@@ -328,15 +331,22 @@ void ScrollBar::ShowIndicator()
     mAnimation.Reset();
   }
 
+  if( mIndicatorFirstShow )
+  {
+    // Preserve the alpha value from the stylesheet
+    mIndicatorShowAlpha = Self().GetCurrentColor().a;
+    mIndicatorFirstShow = false;
+  }
+
   if(mIndicatorShowDuration > 0.0f)
   {
     mAnimation = Animation::New( mIndicatorShowDuration );
-    mAnimation.AnimateTo( Property( mIndicator, Actor::Property::COLOR_ALPHA ), 1.0f, AlphaFunction::EASE_IN );
+    mAnimation.AnimateTo( Property( mIndicator, Actor::Property::COLOR_ALPHA ), mIndicatorShowAlpha, AlphaFunction::EASE_IN );
     mAnimation.Play();
   }
   else
   {
-    mIndicator.SetOpacity(1.0f);
+    mIndicator.SetOpacity(mIndicatorShowAlpha);
   }
 }
 
index 23d3fa7..1f9691d 100755 (executable)
@@ -265,6 +265,7 @@ private:
 private:
 
   Actor mIndicator;                                                  ///< Image of scroll indicator.
+  float mIndicatorShowAlpha;                                         ///< The alpha value when the indicator is fully shown
   Animation mAnimation;                                              ///< Scroll indicator Show/Hide Animation.
 
   Toolkit::ScrollBar::Direction mDirection;                          ///< The direction of scroll bar (vertical or horizontal)
@@ -282,7 +283,6 @@ private:
   float mScrollStart;                                                ///< Scroll Start position (start of drag)
   Vector3 mGestureDisplacement;                                      ///< Gesture Displacement.
 
-  bool mIsPanning;                                                  ///< Whether the scroll bar is being panned.
   float mCurrentScrollPosition;                                     ///< The current scroll position updated by the pan gesture
 
   Toolkit::ScrollBar::IndicatorHeightPolicy mIndicatorHeightPolicy;  ///< The height policy of scroll indicator (variable or fixed)
@@ -300,6 +300,9 @@ private:
   Constraint mIndicatorPositionConstraint;
   Constraint mIndicatorSizeConstraint;
   Constraint mScrollPositionInCurrentAxisConstraint;
+
+  bool mIsPanning          : 1;                                      ///< Whether the scroll bar is being panned.
+  bool mIndicatorFirstShow : 1;                                      ///< True if the indicator has never been shown
 };
 
 } // namespace Internal
index 89eb96e..9969f77 100644 (file)
@@ -39,7 +39,14 @@ namespace Internal
 namespace
 {
 // Bouncing effect is presented by stacked three layers with same color and opacity
-const Vector3 LAYER_HEIGHTS( 1.f, 27.f/42.f, 13.f/42.f);
+const float LAYER_HEIGHTS[5] =
+{
+  1.f,
+  26.f * 4.f/ 130.f,
+  26.f * 3.f / 130.f,
+  26.f * 2.f / 130.f,
+  26.f / 130.f
+};
 
 #define MAKE_SHADER(A)#A
 
@@ -77,33 +84,43 @@ Actor CreateBouncingEffectActor( Property::Index& bouncePropertyIndex )
     Vector3 position2;
   };
   // 4 vertices 2 triangles per layer. The depth interval between each layer is 0.01
-  VertexPosition vertexData[12] = {
-    //bottom layer
+  VertexPosition vertexData[20] = {
+    // bottom layer
     { Vector3( -0.5f, -0.5f, 0.f ),  Vector3( -0.5f, -0.5f, 0.f )  },
     { Vector3( 0.5f, -0.5f, 0.f ),   Vector3( 0.5f, -0.5f, 0.f )   },
     { Vector3( -0.5f, -0.5f, 0.f ),  Vector3( -0.5f, -0.5f + LAYER_HEIGHTS[0], 0.f ) },
     { Vector3( 0.5f, -0.5f, 0.f ),   Vector3( 0.5f, -0.5f+ LAYER_HEIGHTS[0], 0.f )   },
-    // middle layer
+    // mid-bottom layer
     { Vector3( -0.5f, -0.5f, 0.01f ),  Vector3( -0.5f, -0.5f, 0.01f )  },
     { Vector3( 0.5f, -0.5f, 0.01f ),   Vector3( 0.5f, -0.5f, 0.01f )   },
     { Vector3( -0.5f, -0.5f, 0.01f ),  Vector3( -0.5f, -0.5f + LAYER_HEIGHTS[1], 0.01f ) },
     { Vector3( 0.5f, -0.5f, 0.01f ),   Vector3( 0.5f, -0.5f+ LAYER_HEIGHTS[1], 0.01f )   },
-    // top layer
+    // middle layer
     { Vector3( -0.5f, -0.5f, 0.02f ),  Vector3( -0.5f, -0.5f, 0.02f )  },
     { Vector3( 0.5f, -0.5f, 0.02f ),   Vector3( 0.5f, -0.5f, 0.02f )   },
     { Vector3( -0.5f, -0.5f, 0.02f ),  Vector3( -0.5f, -0.5f + LAYER_HEIGHTS[2], 0.02f ) },
-    { Vector3( 0.5f, -0.5f, 0.02f ),   Vector3( 0.5f, -0.5f+ LAYER_HEIGHTS[2], 0.02f )   }
+    { Vector3( 0.5f, -0.5f, 0.02f ),   Vector3( 0.5f, -0.5f+ LAYER_HEIGHTS[2], 0.02f )   },
+    // mid-top layer
+    { Vector3( -0.5f, -0.5f, 0.03f ),  Vector3( -0.5f, -0.5f, 0.03f )  },
+    { Vector3( 0.5f, -0.5f, 0.03f ),   Vector3( 0.5f, -0.5f, 0.03f )   },
+    { Vector3( -0.5f, -0.5f, 0.03f ),  Vector3( -0.5f, -0.5f + LAYER_HEIGHTS[3], 0.03f ) },
+    { Vector3( 0.5f, -0.5f, 0.03f ),   Vector3( 0.5f, -0.5f+ LAYER_HEIGHTS[3], 0.03f )   },
+    // top layer
+    { Vector3( -0.5f, -0.5f, 0.04f ),  Vector3( -0.5f, -0.5f, 0.04f )  },
+    { Vector3( 0.5f, -0.5f, 0.04f ),   Vector3( 0.5f, -0.5f, 0.04f )   },
+    { Vector3( -0.5f, -0.5f, 0.04f ),  Vector3( -0.5f, -0.5f + LAYER_HEIGHTS[4], 0.04f ) },
+    { Vector3( 0.5f, -0.5f, 0.04f ),   Vector3( 0.5f, -0.5f+ LAYER_HEIGHTS[4], 0.04f )   }
   };
   Property::Map vertexFormat;
   vertexFormat["aPosition1"] = Property::VECTOR3;
   vertexFormat["aPosition2"] = Property::VECTOR3;
-  PropertyBuffer vertices = PropertyBuffer::New( vertexFormat, 12u );
+  PropertyBuffer vertices = PropertyBuffer::New( vertexFormat, 20u );
   vertices.SetData( vertexData );
 
-  unsigned int indexData[18] = { 0,3,1,0,2,3,4,7,5,4,6,7,8,11,9,8,10,11 };
+  unsigned int indexData[30] = { 0,3,1,0,2,3,4,7,5,4,6,7,8,11,9,8,10,11,12,15,13,12,14,15,16,19,17,16,18,19};
   Property::Map indexFormat;
   indexFormat["indices"] = Property::INTEGER;
-  PropertyBuffer indices = PropertyBuffer::New( indexFormat, 18u );
+  PropertyBuffer indices = PropertyBuffer::New( indexFormat, 30u );
   indices.SetData( indexData );
 
   Geometry meshGeometry = Geometry::New();
index 9cb8aff..27054bd 100644 (file)
@@ -71,7 +71,6 @@ const float DEFAULT_ANCHORING_DURATION = 1.0f;  // 1 second
 
 const float MILLISECONDS_PER_SECONDS = 1000.0f;
 
-const Vector2 OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE( 720.0f, 42.0f );
 const float OVERSHOOT_BOUNCE_ACTOR_RESIZE_THRESHOLD = 180.0f;
 const Vector4 OVERSHOOT_OVERLAY_NINE_PATCH_BORDER(0.0f, 0.0f, 1.0f, 12.0f);
 const float DEFAULT_KEYBOARD_FOCUS_SCROLL_DURATION = 0.2f;
@@ -90,23 +89,33 @@ float CalculateScrollDistance(Vector2 panDistance, Toolkit::ItemLayout& layout)
 }
 
 // Overshoot overlay constraints
-void OvershootOverlaySizeConstraint( Vector3& current, const PropertyInputContainer& inputs )
+struct OvershootOverlaySizeConstraint
 {
-  const Vector2& parentScrollDirection = inputs[0]->GetVector2();
-  const Toolkit::ControlOrientation::Type& layoutOrientation = static_cast<Toolkit::ControlOrientation::Type>(inputs[1]->GetInteger());
-  const Vector3& parentSize = inputs[2]->GetVector3();
-
-  if(Toolkit::IsVertical(layoutOrientation))
+  OvershootOverlaySizeConstraint( float height )
+  : mOvershootHeight( height )
   {
-    current.width = fabsf(parentScrollDirection.y) > Math::MACHINE_EPSILON_1 ? parentSize.x : parentSize.y;
   }
-  else
+
+  void operator()( Vector3& current, const PropertyInputContainer& inputs )
   {
-    current.width = fabsf(parentScrollDirection.x) > Math::MACHINE_EPSILON_1 ? parentSize.y : parentSize.x;
+    const Vector2& parentScrollDirection = inputs[0]->GetVector2();
+    const Toolkit::ControlOrientation::Type& layoutOrientation = static_cast<Toolkit::ControlOrientation::Type>(inputs[1]->GetInteger());
+    const Vector3& parentSize = inputs[2]->GetVector3();
+
+    if(Toolkit::IsVertical(layoutOrientation))
+    {
+      current.width = fabsf(parentScrollDirection.y) > Math::MACHINE_EPSILON_1 ? parentSize.x : parentSize.y;
+    }
+    else
+    {
+      current.width = fabsf(parentScrollDirection.x) > Math::MACHINE_EPSILON_1 ? parentSize.y : parentSize.x;
+    }
+
+    current.height = ( current.width > OVERSHOOT_BOUNCE_ACTOR_RESIZE_THRESHOLD ) ? mOvershootHeight : mOvershootHeight*0.5f;
   }
 
-  current.height = ( current.width > OVERSHOOT_BOUNCE_ACTOR_RESIZE_THRESHOLD ) ? OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.height : OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.height*0.5f;
-}
+  float mOvershootHeight;
+};
 
 void OvershootOverlayRotationConstraint( Quaternion& current, const PropertyInputContainer& inputs )
 {
@@ -307,8 +316,6 @@ void ItemView::OnInitialize()
 {
   Actor self = Self();
 
-  SetOvershootEnabled(true);
-
   Vector2 stageSize = Stage::GetCurrent().GetSize();
   mWheelScrollDistanceStep = stageSize.y * DEFAULT_WHEEL_SCROLL_DISTANCE_STEP_PROPORTION;
 
@@ -1177,7 +1184,10 @@ void ItemView::OnPan( const PanGesture& gesture )
 
       self.SetProperty(Toolkit::ItemView::Property::LAYOUT_POSITION, firstItemScrollPosition );
 
-      if( (firstItemScrollPosition >= 0.0f && currentOvershoot < 1.0f) || (firstItemScrollPosition >= mActiveLayout->GetMinimumLayoutPosition(mItemFactory.GetNumberOfItems(), layoutSize) && currentOvershoot > -1.0f) )
+      if( ( firstItemScrollPosition >= 0.0f &&
+            currentOvershoot < 1.0f ) ||
+          ( firstItemScrollPosition <= mActiveLayout->GetMinimumLayoutPosition(mItemFactory.GetNumberOfItems(), layoutSize) &&
+            currentOvershoot > -1.0f ) )
       {
         mTotalPanDisplacement += gesture.displacement;
       }
@@ -1483,13 +1493,13 @@ void ItemView::EnableScrollOvershoot( bool enable )
     mOvershootOverlay.SetDrawMode( DrawMode::OVERLAY_2D );
     self.Add(mOvershootOverlay);
 
-    Constraint constraint = Constraint::New<Vector3>( mOvershootOverlay, Actor::Property::SIZE, OvershootOverlaySizeConstraint );
+    Constraint constraint = Constraint::New<Vector3>( mOvershootOverlay, Actor::Property::SIZE, OvershootOverlaySizeConstraint(mOvershootSize.height) );
     constraint.AddSource( ParentSource( Toolkit::ItemView::Property::SCROLL_DIRECTION ) );
     constraint.AddSource( ParentSource( Toolkit::ItemView::Property::LAYOUT_ORIENTATION ) );
     constraint.AddSource( ParentSource( Actor::Property::SIZE ) );
     constraint.Apply();
 
-    mOvershootOverlay.SetSize(OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.width, OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.height);
+    mOvershootOverlay.SetSize(mOvershootSize.width, mOvershootSize.height);
 
     constraint = Constraint::New<Quaternion>( mOvershootOverlay, Actor::Property::ORIENTATION, OvershootOverlayRotationConstraint );
     constraint.AddSource( ParentSource( Toolkit::ItemView::Property::SCROLL_DIRECTION ) );
index 0420830..bfc49c0 100644 (file)
@@ -27,13 +27,13 @@ using namespace Dali;
 
 namespace
 {
-const Vector2 OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE( 720.0f, 42.0f );
+
 const float OVERSHOOT_BOUNCE_ACTOR_RESIZE_THRESHOLD = 180.0f;
 
 // local helper function to resize the height of the bounce actor
-float GetBounceActorHeight( float width )
+float GetBounceActorHeight( float width, float defaultHeight )
 {
-  return (width > OVERSHOOT_BOUNCE_ACTOR_RESIZE_THRESHOLD) ? OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.height : OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.height * 0.5f;
+  return (width > OVERSHOOT_BOUNCE_ACTOR_RESIZE_THRESHOLD) ? defaultHeight : defaultHeight * 0.5f;
 }
 
 const float MAX_OVERSHOOT_NOTIFY_AMOUNT = 0.99f;                     // maximum amount to set notification for increased overshoot, beyond this we just wait for it to reduce again
@@ -129,6 +129,7 @@ ScrollOvershootEffectRipple::ScrollOvershootEffectRipple( bool vertical, Scrolla
     mOvershootProperty(Property::INVALID_INDEX),
     mEffectOvershootProperty(Property::INVALID_INDEX),
     mOvershoot(0.0f),
+    mOvershootSize( scrollable.GetOvershootSize() ),
     mAnimationStateFlags(0)
 {
   mOvershootOverlay = CreateBouncingEffectActor(mEffectOvershootProperty);
@@ -145,7 +146,7 @@ void ScrollOvershootEffectRipple::Apply()
   mOvershootProperty = IsVertical() ? Toolkit::ScrollView::Property::OVERSHOOT_Y : Toolkit::ScrollView::Property::OVERSHOOT_X;
 
   // make sure height is set, since we only create a constraint for image width
-  mOvershootOverlay.SetSize(OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.width, OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.height);
+  mOvershootOverlay.SetSize( mOvershootSize );
 
   mAttachedScrollView.AddOverlay(mOvershootOverlay);
 
@@ -242,12 +243,12 @@ void ScrollOvershootEffectRipple::UpdateVisibility( bool visible )
       if(IsVertical())
       {
         mOvershootOverlay.SetOrientation( Quaternion( Radian( 0.0f ), Vector3::ZAXIS ) );
-        mOvershootOverlay.SetSize(parentSize.width, GetBounceActorHeight(parentSize.width), size.depth);
+        mOvershootOverlay.SetSize(parentSize.width, GetBounceActorHeight(parentSize.width, mOvershootSize.height), size.depth);
       }
       else
       {
         mOvershootOverlay.SetOrientation( Quaternion( Radian( 1.5f * Math::PI ), Vector3::ZAXIS ) );
-        mOvershootOverlay.SetSize(parentSize.height, GetBounceActorHeight(parentSize.height), size.depth);
+        mOvershootOverlay.SetSize(parentSize.height, GetBounceActorHeight(parentSize.height, mOvershootSize.height), size.depth);
         relativeOffset = Vector3(0.0f, 1.0f, 0.0f);
       }
       mOvershootOverlay.SetPosition(relativeOffset * parentSize);
@@ -261,13 +262,13 @@ void ScrollOvershootEffectRipple::UpdateVisibility( bool visible )
       if(IsVertical())
       {
         mOvershootOverlay.SetOrientation( Quaternion( Radian( Math::PI ), Vector3::ZAXIS ) );
-        mOvershootOverlay.SetSize(parentSize.width, GetBounceActorHeight(parentSize.width), size.depth);
+        mOvershootOverlay.SetSize(parentSize.width, GetBounceActorHeight(parentSize.width, mOvershootSize.height), size.depth);
         relativeOffset = Vector3(1.0f, 1.0f, 0.0f);
       }
       else
       {
         mOvershootOverlay.SetOrientation( Quaternion( Radian( 0.5f * Math::PI ), Vector3::ZAXIS ) );
-        mOvershootOverlay.SetSize(parentSize.height, GetBounceActorHeight(parentSize.height), size.depth);
+        mOvershootOverlay.SetSize(parentSize.height, GetBounceActorHeight(parentSize.height, mOvershootSize.height), size.depth);
         relativeOffset = Vector3(1.0f, 0.0f, 0.0f);
       }
       mOvershootOverlay.SetPosition(relativeOffset * parentSize);
index 7eebe4b..1dadcfc 100644 (file)
@@ -251,8 +251,9 @@ private:
   PropertyNotification  mOvershootDecreaseNotification;///< notification used to inform as overshoot decreases
   Property::Index       mOvershootProperty;            ///< index of the overshoot property in the scrollable actor
   Property::Index       mEffectOvershootProperty;      ///< index of the effect's overshoot property
-  float                mOvershoot;                    ///< last overshoot value as detected by notifications
-  unsigned short      mAnimationStateFlags;          ///< contains flags indicating the current state of the overshoot animation
+  float                 mOvershoot;                    ///< last overshoot value as detected by notifications
+  Vector2               mOvershootSize;                ///< The size of the overshoot effect
+  unsigned short        mAnimationStateFlags;          ///< contains flags indicating the current state of the overshoot animation
 };
 
 } // namespace Internal
index a8bd61e..929cab2 100644 (file)
@@ -313,93 +313,132 @@ ScrollView::LockAxis GetLockAxis(const Vector2& panDelta, ScrollView::LockAxis c
  */
 struct InternalPrePositionConstraint
 {
-  InternalPrePositionConstraint(const Vector2& initialPanPosition,
-                                const Vector2& initialPanMask,
-                                bool axisAutoLock,
-                                float axisAutoLockGradient,
-                                ScrollView::LockAxis initialLockAxis,
-                                const Vector2& maxOvershoot,
-                                const RulerDomain& domainX, const RulerDomain& domainY)
-  : mLocalStart(initialPanPosition),
-    mInitialPanMask(initialPanMask),
-    mDomainMin( -domainX.min, -domainY.min ),
-    mDomainMax( -domainX.max, -domainY.max ),
-    mMaxOvershoot(maxOvershoot),
-    mAxisAutoLockGradient(axisAutoLockGradient),
-    mLockAxis(initialLockAxis),
-    mAxisAutoLock(axisAutoLock),
-    mWasPanning(false),
-    mClampX( domainX.enabled ),
-    mClampY( domainY.enabled )
-  {
+  InternalPrePositionConstraint( const Vector2& initialPanPosition,
+                                 const Vector2& initialPanMask,
+                                 bool axisAutoLock,
+                                 float axisAutoLockGradient,
+                                 ScrollView::LockAxis initialLockAxis,
+                                 const Vector2& maxOvershoot,
+                                 const RulerPtr& rulerX, const RulerPtr& rulerY )
+  : mLocalStart( initialPanPosition ),
+    mInitialPanMask( initialPanMask ),
+    mMaxOvershoot( maxOvershoot ),
+    mAxisAutoLockGradient( axisAutoLockGradient ),
+    mLockAxis( initialLockAxis ),
+    mAxisAutoLock( axisAutoLock ),
+    mWasPanning( false )
+  {
+    const RulerDomain& rulerDomainX = rulerX->GetDomain();
+    const RulerDomain& rulerDomainY = rulerY->GetDomain();
+    mDomainMin = Vector2( rulerDomainX.min, -rulerDomainY.min );
+    mDomainMax = Vector2( -rulerDomainX.max, -rulerDomainY.max );
+    mClampX = rulerDomainX.enabled;
+    mClampY = rulerDomainY.enabled;
+    mFixedRulerX = rulerX->GetType() == Ruler::Fixed;
+    mFixedRulerY = rulerY->GetType() == Ruler::Fixed;
   }
 
   void operator()( Vector2& scrollPostPosition, const PropertyInputContainer& inputs )
   {
     const Vector2& panPosition = inputs[0]->GetVector2();
+    const bool& inGesture = inputs[1]->GetBoolean();
 
-    if(!mWasPanning)
+    // First check if we are within a gesture.
+    // The ScrollView may have received a start gesture from ::OnPan()
+    // while the finish gesture is received now in this constraint.
+    // This gesture must then be rejected as the value will be "old".
+    // Typically the last value from the end of the last gesture.
+    // If we are rejecting the gesture, we simply don't modify the constraint target.
+    if( inGesture )
     {
-      mPrePosition = scrollPostPosition;
-      mCurrentPanMask = mInitialPanMask;
-      mWasPanning = true;
-    }
-
-    // Calculate Deltas...
-    const Vector2& currentPosition = panPosition;
-    Vector2 panDelta( currentPosition - mLocalStart );
-
-    // Axis Auto Lock - locks the panning to the horizontal or vertical axis if the pan
-    // appears mostly horizontal or mostly vertical respectively...
-    if( mAxisAutoLock )
-    {
-      mLockAxis = GetLockAxis(panDelta, mLockAxis, mAxisAutoLockGradient);
-      if( mLockAxis == ScrollView::LockVertical )
+      if( !mWasPanning )
       {
-        mCurrentPanMask.y = 0.0f;
+        mPrePosition = scrollPostPosition;
+        mStartPosition = mPrePosition;
+        mCurrentPanMask = mInitialPanMask;
+        mWasPanning = true;
       }
-      else if( mLockAxis == ScrollView::LockHorizontal )
+
+      // Calculate Deltas...
+      const Vector2& currentPosition = panPosition;
+      Vector2 panDelta( currentPosition - mLocalStart );
+
+      // Axis Auto Lock - locks the panning to the horizontal or vertical axis if the pan
+      // appears mostly horizontal or mostly vertical respectively...
+      if( mAxisAutoLock )
       {
-        mCurrentPanMask.x = 0.0f;
+        mLockAxis = GetLockAxis( panDelta, mLockAxis, mAxisAutoLockGradient );
+        if( mLockAxis == ScrollView::LockVertical )
+        {
+          mCurrentPanMask.y = 0.0f;
+        }
+        else if( mLockAxis == ScrollView::LockHorizontal )
+        {
+          mCurrentPanMask.x = 0.0f;
+        }
       }
-    }
 
-    // Restrict deltas based on ruler enable/disable and axis-lock state...
-    panDelta *= mCurrentPanMask;
+      // Restrict deltas based on ruler enable/disable and axis-lock state...
+      panDelta *= mCurrentPanMask;
 
-    // Perform Position transform based on input deltas...
-    scrollPostPosition = mPrePosition;
-    scrollPostPosition += panDelta;
+      // Perform Position transform based on input deltas...
+      scrollPostPosition = mPrePosition;
+      scrollPostPosition += panDelta;
 
-    // if no wrapping then clamp preposition to maximum overshoot amount
-    const Vector3& size = inputs[1]->GetVector3();
-    if( mClampX )
-    {
-      float newXPosition = Clamp(scrollPostPosition.x, (mDomainMax.x + size.x) - mMaxOvershoot.x, mDomainMin.x + mMaxOvershoot.x );
-      if( (newXPosition < scrollPostPosition.x - Math::MACHINE_EPSILON_1)
-              || (newXPosition > scrollPostPosition.x + Math::MACHINE_EPSILON_1) )
+      // if no wrapping then clamp preposition to maximum overshoot amount
+      const Vector3& size = inputs[2]->GetVector3();
+      if( mClampX )
       {
-        mPrePosition.x = newXPosition;
-        mLocalStart.x = panPosition.x;
+        float newXPosition = Clamp( scrollPostPosition.x, ( mDomainMax.x + size.x ) - mMaxOvershoot.x, mDomainMin.x + mMaxOvershoot.x );
+        if( (newXPosition < scrollPostPosition.x - Math::MACHINE_EPSILON_1)
+          || (newXPosition > scrollPostPosition.x + Math::MACHINE_EPSILON_1) )
+        {
+          mPrePosition.x = newXPosition;
+          mLocalStart.x = panPosition.x;
+        }
+        scrollPostPosition.x = newXPosition;
       }
-      scrollPostPosition.x = newXPosition;
-    }
-    if( mClampY )
-    {
-      float newYPosition = Clamp(scrollPostPosition.y, (mDomainMax.y + size.y) - mMaxOvershoot.y, mDomainMin.y + mMaxOvershoot.y );
-      if( (newYPosition < scrollPostPosition.y - Math::MACHINE_EPSILON_1)
-              || (newYPosition > scrollPostPosition.y + Math::MACHINE_EPSILON_1) )
+      if( mClampY )
       {
-        mPrePosition.y = newYPosition;
-        mLocalStart.y = panPosition.y;
+        float newYPosition = Clamp( scrollPostPosition.y, ( mDomainMax.y + size.y ) - mMaxOvershoot.y, mDomainMin.y + mMaxOvershoot.y );
+        if( ( newYPosition < scrollPostPosition.y - Math::MACHINE_EPSILON_1 )
+          || ( newYPosition > scrollPostPosition.y + Math::MACHINE_EPSILON_1 ) )
+        {
+          mPrePosition.y = newYPosition;
+          mLocalStart.y = panPosition.y;
+        }
+        scrollPostPosition.y = newYPosition;
+      }
+
+      // If we are using a fixed ruler in a particular axis, limit the maximum pages scrolled on that axis.
+      if( mFixedRulerX || mFixedRulerY )
+      {
+        // Here we limit the maximum amount that can be moved from the starting position of the gesture to one page.
+        // We do this only if we have a fixed ruler (on that axis) and the mode is enabled.
+        // Note: 1.0f is subtracted to keep the value within one page size (otherwise we stray on to the page after).
+        // Note: A further 1.0f is subtracted to handle a compensation that happens later within the flick handling code in SnapWithVelocity().
+        //       When a flick is completed, an adjustment of 1.0f is sometimes made to allow for the scenario where:
+        //       A flick finishes before the update thread has advanced the scroll position past the previous snap point.
+        Vector2 pageSizeLimit( size.x - ( 1.0f + 1.0f ), size.y - ( 1.0f - 1.0f ) );
+        Vector2 minPosition( mStartPosition.x - pageSizeLimit.x, mStartPosition.y - pageSizeLimit.y );
+        Vector2 maxPosition( mStartPosition.x + pageSizeLimit.x, mStartPosition.y + pageSizeLimit.y );
+
+        if( mFixedRulerX )
+        {
+          scrollPostPosition.x = Clamp( scrollPostPosition.x, minPosition.x, maxPosition.x );
+        }
+        if( mFixedRulerY )
+        {
+          scrollPostPosition.y = Clamp( scrollPostPosition.y, minPosition.y, maxPosition.y );
+        }
       }
-      scrollPostPosition.y = newYPosition;
     }
   }
 
   Vector2 mPrePosition;
   Vector2 mLocalStart;
-  Vector2 mInitialPanMask;              ///< Initial pan mask (based on ruler settings)
+  Vector2 mStartPosition;               ///< The start position of the gesture - used to limit scroll amount (not modified by clamping).
+  Vector2 mInitialPanMask;              ///< Initial pan mask (based on ruler settings).
   Vector2 mCurrentPanMask;              ///< Current pan mask that can be altered by axis lock mode.
   Vector2 mDomainMin;
   Vector2 mDomainMax;
@@ -408,10 +447,12 @@ struct InternalPrePositionConstraint
   float mAxisAutoLockGradient;          ///< Set by ScrollView
   ScrollView::LockAxis mLockAxis;
 
-  bool mAxisAutoLock:1;                   ///< Set by ScrollView
+  bool mAxisAutoLock:1;                 ///< Set by ScrollView
   bool mWasPanning:1;
   bool mClampX:1;
   bool mClampY:1;
+  bool mFixedRulerX:1;
+  bool mFixedRulerY:1;
 };
 
 /**
@@ -600,7 +641,6 @@ ScrollView::ScrollView()
   mMaxFlickSpeed(DEFAULT_MAX_FLICK_SPEED),
   mWheelScrollDistanceStep(Vector2::ZERO),
   mInAccessibilityPan(false),
-  mInitialized(false),
   mScrolling(false),
   mScrollInterrupted(false),
   mPanning(false),
@@ -636,8 +676,6 @@ void ScrollView::OnInitialize()
 
   mWheelScrollDistanceStep = Stage::GetCurrent().GetSize() * DEFAULT_WHEEL_SCROLL_DISTANCE_STEP_PROPORTION;
 
-  mInitialized = true;
-
   mGestureStackDepth = 0;
 
   EnableGestureDetection( Gesture::Type( Gesture::Pan ) );
@@ -648,8 +686,6 @@ void ScrollView::OnInitialize()
   mRulerX = ruler;
   mRulerY = ruler;
 
-  SetOvershootEnabled(true);
-
   self.SetProperty(Toolkit::Scrollable::Property::CAN_SCROLL_VERTICAL, mCanScrollVertical);
   self.SetProperty(Toolkit::Scrollable::Property::CAN_SCROLL_HORIZONTAL, mCanScrollHorizontal);
 
@@ -659,6 +695,8 @@ void ScrollView::OnInitialize()
 
 void ScrollView::OnStageConnection( int depth )
 {
+  ScrollBase::OnStageConnection( depth );
+
   DALI_LOG_SCROLL_STATE("[0x%X]", this);
 
   if ( mSensitive )
@@ -678,6 +716,8 @@ void ScrollView::OnStageDisconnection()
   DALI_LOG_SCROLL_STATE("[0x%X]", this);
 
   StopAnimation();
+
+  ScrollBase::OnStageDisconnection();
 }
 
 ScrollView::~ScrollView()
@@ -1698,19 +1738,25 @@ bool ScrollView::AnimateTo(const Vector2& position, const Vector2& positionDurat
 
 void ScrollView::EnableScrollOvershoot(bool enable)
 {
-  if(enable && !mOvershootIndicator)
-  {
-    mOvershootIndicator = ScrollOvershootIndicator::New();
-  }
-  if( enable )
+  if (enable)
   {
+    if (!mOvershootIndicator)
+    {
+      mOvershootIndicator = ScrollOvershootIndicator::New();
+    }
+
     mOvershootIndicator->AttachToScrollable(*this);
   }
   else
   {
     mMaxOvershoot = mUserMaxOvershoot;
-    mOvershootIndicator->DetachFromScrollable(*this);
+
+    if (mOvershootIndicator)
+    {
+      mOvershootIndicator->DetachFromScrollable(*this);
+    }
   }
+
   UpdateMainInternalConstraint();
 }
 
@@ -2657,9 +2703,10 @@ void ScrollView::UpdateMainInternalConstraint()
                                                                                                         mAxisAutoLockGradient,
                                                                                                         mLockAxis,
                                                                                                         mMaxOvershoot,
-                                                                                                        mRulerX->GetDomain(),
-                                                                                                        mRulerY->GetDomain() ) );
+                                                                                                        mRulerX,
+                                                                                                        mRulerY ) );
     mScrollMainInternalPrePositionConstraint.AddSource( Source( detector, PanGestureDetector::Property::LOCAL_POSITION ) );
+    mScrollMainInternalPrePositionConstraint.AddSource( Source( detector, PanGestureDetector::Property::PANNING ) );
     mScrollMainInternalPrePositionConstraint.AddSource( Source( self, Actor::Property::SIZE ) );
     mScrollMainInternalPrePositionConstraint.Apply();
   }
index bbd87bc..c2b62bf 100644 (file)
@@ -900,8 +900,7 @@ private:
 
   Toolkit::ScrollView::SnapStartedSignalType mSnapStartedSignal;
 
-  bool mInAccessibilityPan : 1;           ///< With AccessibilityPan its easier to move between snap positions
-  bool mInitialized:1;
+  bool mInAccessibilityPan:1;             ///< With AccessibilityPan its easier to move between snap positions
   bool mScrolling:1;                      ///< Flag indicating whether the scroll view is being scrolled (by user or animation)
   bool mScrollInterrupted:1;              ///< Flag set for when a down event interrupts a scroll
   bool mPanning:1;                        ///< Whether scroll view is currently panning or not
index b3a2152..79b463f 100644 (file)
@@ -48,6 +48,8 @@ DALI_TYPE_REGISTRATION_BEGIN( Toolkit::Scrollable, Toolkit::Control, Create );
 
 DALI_PROPERTY_REGISTRATION( Toolkit, Scrollable, "overshoot-effect-color",    VECTOR4, OVERSHOOT_EFFECT_COLOR    )
 DALI_PROPERTY_REGISTRATION( Toolkit, Scrollable, "overshoot-animation-speed", FLOAT,   OVERSHOOT_ANIMATION_SPEED )
+const int OVERSHOOT_SIZE = Dali::Toolkit::Scrollable::Property::OVERSHOOT_ANIMATION_SPEED + 1; // OVERSHOOT_SIZE is not public yet
+Dali::PropertyRegistration p1( typeRegistration, "overshoot-size", OVERSHOOT_SIZE, Property::VECTOR2, Dali::Toolkit::Internal::Scrollable::SetProperty, Dali::Toolkit::Internal::Scrollable::GetProperty );
 
 DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, Scrollable, "scroll-relative-position", VECTOR2, SCROLL_RELATIVE_POSITION)
 DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, Scrollable, "scroll-position-min",      VECTOR2, SCROLL_POSITION_MIN)
@@ -67,6 +69,7 @@ DALI_TYPE_REGISTRATION_END()
 
 const Vector4 DEFAULT_OVERSHOOT_COLOUR(0.0f, 0.64f, 0.85f, 0.25f);
 const float DEFAULT_OVERSHOOT_ANIMATION_SPEED(120.0f); // 120 pixels per second
+const Vector2 OVERSHOOT_DEFAULT_SIZE( 720.0f, 42.0f );
 
 }
 
@@ -80,7 +83,8 @@ Scrollable::Scrollable()
 : Control( ControlBehaviour( REQUIRES_TOUCH_EVENTS | REQUIRES_STYLE_CHANGE_SIGNALS | DISABLE_SIZE_NEGOTIATION ) ),
   mOvershootEffectColor(  DEFAULT_OVERSHOOT_COLOUR ),
   mOvershootAnimationSpeed ( DEFAULT_OVERSHOOT_ANIMATION_SPEED ),
-  mOvershootEnabled(false)
+  mOvershootSize( OVERSHOOT_DEFAULT_SIZE ),
+  mOvershootEnabled(true)
 {
 }
 
@@ -88,7 +92,8 @@ Scrollable::Scrollable( ControlBehaviour behaviourFlags )
 : Control( ControlBehaviour( REQUIRES_TOUCH_EVENTS | REQUIRES_STYLE_CHANGE_SIGNALS | behaviourFlags ) ),
   mOvershootEffectColor(  DEFAULT_OVERSHOOT_COLOUR ),
   mOvershootAnimationSpeed ( DEFAULT_OVERSHOOT_ANIMATION_SPEED ),
-  mOvershootEnabled(false)
+  mOvershootSize( OVERSHOOT_DEFAULT_SIZE ),
+  mOvershootEnabled(true)
 {
 }
 
@@ -122,6 +127,11 @@ float Scrollable::GetOvershootAnimationSpeed() const
   return mOvershootAnimationSpeed;
 };
 
+const Vector2& Scrollable::GetOvershootSize() const
+{
+  return mOvershootSize;
+}
+
 Toolkit::Scrollable::ScrollStartedSignalType& Scrollable::ScrollStartedSignal()
 {
   return mScrollStartedSignal;
@@ -184,6 +194,16 @@ void Scrollable::SetProperty( BaseObject* object, Property::Index index, const P
         scrollableImpl.SetOvershootAnimationSpeed( value.Get<float>() );
         break;
       }
+      case OVERSHOOT_SIZE: // OVERSHOOT_SIZE is not public yet
+      {
+        Vector2 input;
+        if( value.Get( input ) )
+        {
+          scrollableImpl.mOvershootSize = input;
+        }
+        scrollableImpl.EnableScrollOvershoot( scrollableImpl.IsOvershootEnabled() );
+        break;
+      }
     }
   }
 }
@@ -209,6 +229,11 @@ Property::Value Scrollable::GetProperty( BaseObject* object, Property::Index ind
         value = scrollableImpl.GetOvershootAnimationSpeed();
         break;
       }
+      case OVERSHOOT_SIZE: // OVERSHOOT_SIZE is not public yet
+      {
+        value = scrollableImpl.mOvershootSize;
+        break;
+      }
     }
   }
 
index 0b349f5..97b3107 100644 (file)
@@ -110,6 +110,11 @@ public:
    */
   float GetOvershootAnimationSpeed() const;
 
+  /**
+   * @copydoc Dali::Toolkit::Scrollable::GetOvershootSize()
+   */
+  const Vector2& GetOvershootSize() const;
+
 private:
 
   /**
@@ -205,6 +210,7 @@ protected:
 
   Vector4         mOvershootEffectColor;    ///<The color of the overshoot bouncing effect
   float           mOvershootAnimationSpeed; ///<The speed of the overshoot animation (pixels per second)
+  Vector2         mOvershootSize;           ///<The size of the overshoot effect
 
   Toolkit::Scrollable::ScrollStartedSignalType mScrollStartedSignal;
   Toolkit::Scrollable::ScrollUpdatedSignalType mScrollUpdatedSignal;
index 9ecd378..34d10cc 100644 (file)
@@ -1,8 +1,6 @@
 # Add local source files here
 
 toolkit_src_files = \
-   $(toolkit_src_dir)/atlas-manager/atlas-manager.cpp \
-   $(toolkit_src_dir)/atlas-manager/atlas-manager-impl.cpp \
    $(toolkit_src_dir)/builder/builder-actor.cpp \
    $(toolkit_src_dir)/builder/builder-animations.cpp \
    $(toolkit_src_dir)/builder/builder-impl.cpp \
@@ -99,6 +97,9 @@ toolkit_src_files = \
    $(toolkit_src_dir)/text/rendering/atlas/text-atlas-renderer.cpp \
    $(toolkit_src_dir)/text/rendering/atlas/atlas-glyph-manager.cpp \
    $(toolkit_src_dir)/text/rendering/atlas/atlas-glyph-manager-impl.cpp \
+   $(toolkit_src_dir)/text/rendering/atlas/atlas-manager.cpp \
+   $(toolkit_src_dir)/text/rendering/atlas/atlas-manager-impl.cpp \
+   $(toolkit_src_dir)/text/rendering/atlas/atlas-mesh-factory.cpp \
    $(toolkit_src_dir)/text/rendering/text-backend-impl.cpp \
    $(toolkit_src_dir)/transition-effects/cube-transition-effect-impl.cpp \
    $(toolkit_src_dir)/transition-effects/cube-transition-cross-effect-impl.cpp \
index 1af079c..5d3976c 100644 (file)
@@ -85,8 +85,6 @@ Integration::Log::Filter* gLogFilter( Integration::Log::Filter::New(Debug::NoLog
 // Local Data
 namespace
 {
-const int DEFAULT_POPUP_OFFSET( -100.0f ); // Vertical offset of Popup from cursor or handles position.
-
 const Dali::Vector3 DEFAULT_GRAB_HANDLE_RELATIVE_SIZE( 1.25f, 1.5f, 1.0f );
 const Dali::Vector3 DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE( 1.25f, 1.5f, 1.0f );
 
@@ -242,14 +240,12 @@ struct Decorator::Impl : public ConnectionTracker
   struct PopupImpl
   {
     PopupImpl()
-    : position(),
-      offset( DEFAULT_POPUP_OFFSET )
+    : position()
     {
     }
 
     TextSelectionPopup actor;
     Vector3 position;
-    int offset;
   };
 
   Impl( ControllerInterface& controller,
@@ -298,6 +294,8 @@ struct Decorator::Impl : public ConnectionTracker
    */
   void Relayout( const Vector2& size )
   {
+    mControlSize = size;
+
     // TODO - Remove this if nothing is active
     CreateActiveLayer();
 
@@ -307,7 +305,7 @@ struct Decorator::Impl : public ConnectionTracker
     if( mPrimaryCursor )
     {
       const CursorImpl& cursor = mCursor[PRIMARY_CURSOR];
-      mPrimaryCursorVisible = ( cursor.position.x + mCursorWidth <= size.width ) && ( cursor.position.x >= 0.f );
+      mPrimaryCursorVisible = ( cursor.position.x + mCursorWidth <= mControlSize.width ) && ( cursor.position.x >= 0.f );
       if( mPrimaryCursorVisible )
       {
         mPrimaryCursor.SetPosition( cursor.position.x,
@@ -319,7 +317,7 @@ struct Decorator::Impl : public ConnectionTracker
     if( mSecondaryCursor )
     {
       const CursorImpl& cursor = mCursor[SECONDARY_CURSOR];
-      mSecondaryCursorVisible = ( cursor.position.x + mCursorWidth <= size.width ) && ( cursor.position.x >= 0.f );
+      mSecondaryCursorVisible = ( cursor.position.x + mCursorWidth <= mControlSize.width ) && ( cursor.position.x >= 0.f );
       if( mSecondaryCursorVisible )
       {
         mSecondaryCursor.SetPosition( cursor.position.x,
@@ -331,9 +329,10 @@ struct Decorator::Impl : public ConnectionTracker
 
     // Show or hide the grab handle
     HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
+    bool newGrabHandlePosition = false;
     if( grabHandle.active )
     {
-      const bool isVisible = ( grabHandle.position.x + floor( 0.5f * mCursorWidth ) <= size.width ) && ( grabHandle.position.x >= 0.f );
+      const bool isVisible = ( grabHandle.position.x + floor( 0.5f * mCursorWidth ) <= mControlSize.width ) && ( grabHandle.position.x >= 0.f );
 
       if( isVisible )
       {
@@ -344,6 +343,8 @@ struct Decorator::Impl : public ConnectionTracker
 
         // Sets the grab handle image according if it's pressed, flipped, etc.
         SetHandleImage( GRAB_HANDLE );
+
+        newGrabHandlePosition = true;
       }
 
       if( grabHandle.actor )
@@ -359,10 +360,12 @@ struct Decorator::Impl : public ConnectionTracker
     // Show or hide the selection handles/highlight
     HandleImpl& primary = mHandle[ LEFT_SELECTION_HANDLE ];
     HandleImpl& secondary = mHandle[ RIGHT_SELECTION_HANDLE ];
+    bool newPrimaryHandlePosition = false;
+    bool newSecondaryHandlePosition = false;
     if( primary.active || secondary.active )
     {
-      const bool isPrimaryVisible = ( primary.position.x <= size.width ) && ( primary.position.x >= 0.f );
-      const bool isSecondaryVisible = ( secondary.position.x <= size.width ) && ( secondary.position.x >= 0.f );
+      const bool isPrimaryVisible = ( primary.position.x <= mControlSize.width ) && ( primary.position.x >= 0.f );
+      const bool isSecondaryVisible = ( secondary.position.x <= mControlSize.width ) && ( secondary.position.x >= 0.f );
 
       if( isPrimaryVisible || isSecondaryVisible )
       {
@@ -376,6 +379,8 @@ struct Decorator::Impl : public ConnectionTracker
           SetHandleImage( LEFT_SELECTION_HANDLE );
 
           SetSelectionHandleMarkerSize( primary );
+
+          newPrimaryHandlePosition = true;
         }
 
         if( isSecondaryVisible )
@@ -386,6 +391,8 @@ struct Decorator::Impl : public ConnectionTracker
           SetHandleImage( RIGHT_SELECTION_HANDLE );
 
           SetSelectionHandleMarkerSize( secondary );
+
+          newSecondaryHandlePosition = true;
         }
       }
 
@@ -417,6 +424,14 @@ struct Decorator::Impl : public ConnectionTracker
       }
     }
 
+    if( newGrabHandlePosition    ||
+        newPrimaryHandlePosition ||
+        newSecondaryHandlePosition )
+    {
+      // Setup property notifications to find whether the handles leave the boundaries of the current display.
+      SetupActiveLayerPropertyNotifications();
+    }
+
     if( mActiveCopyPastePopup )
     {
       ShowPopup();
@@ -459,32 +474,40 @@ struct Decorator::Impl : public ConnectionTracker
 
   void DeterminePositionPopup()
   {
-    if ( !mActiveCopyPastePopup )
+    if( !mActiveCopyPastePopup )
     {
       return;
     }
 
+    // Retrieves the popup's size after relayout.
+    const Vector3 popupSize = Vector3( mCopyPastePopup.actor.GetRelayoutSize( Dimension::WIDTH ), mCopyPastePopup.actor.GetRelayoutSize( Dimension::HEIGHT ), 0.0f );
+
     if( mPopupSetNewPosition )
     {
-      if ( mHandle[LEFT_SELECTION_HANDLE].active || mHandle[RIGHT_SELECTION_HANDLE].active )
-      {
-        float minHandleXPosition = std::min (  mHandle[LEFT_SELECTION_HANDLE].position.x, mHandle[RIGHT_SELECTION_HANDLE].position.x );
-        float maxHandleXPosition = std::max (  mHandle[LEFT_SELECTION_HANDLE].position.x, mHandle[RIGHT_SELECTION_HANDLE].position.x );
+      const HandleImpl& primaryHandle = mHandle[LEFT_SELECTION_HANDLE];
+      const HandleImpl& secondaryHandle = mHandle[RIGHT_SELECTION_HANDLE];
+      const HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
+      const CursorImpl& cursor = mCursor[PRIMARY_CURSOR];
 
-        float minHandleYPosition = std::min (  mHandle[LEFT_SELECTION_HANDLE].position.y, mHandle[RIGHT_SELECTION_HANDLE].position.y );
+      if( primaryHandle.active || secondaryHandle.active )
+      {
+        // Calculates the popup's position if selection handles are active.
+        const float minHandleXPosition = std::min( primaryHandle.position.x, secondaryHandle.position.x );
+        const float maxHandleXPosition = std::max( primaryHandle.position.x, secondaryHandle.position.x );
+        const float maxHandleHeight = std::max( primaryHandle.size.height, secondaryHandle.size.height );
 
-        mCopyPastePopup.position.x = minHandleXPosition + ( ( maxHandleXPosition - minHandleXPosition ) *0.5f );
-        mCopyPastePopup.position.y = minHandleYPosition + mCopyPastePopup.offset;
+        mCopyPastePopup.position.x = minHandleXPosition + ( ( maxHandleXPosition - minHandleXPosition ) * 0.5f );
+        mCopyPastePopup.position.y = -0.5f * popupSize.height - maxHandleHeight + std::min( primaryHandle.position.y, secondaryHandle.position.y );
       }
       else
       {
-        mCopyPastePopup.position = Vector3( mCursor[PRIMARY_CURSOR].position.x, mCursor[PRIMARY_CURSOR].position.y -100.0f , 0.0f ); //todo 100 to be an offset Property
+        // Calculates the popup's position if the grab handle is active.
+        mCopyPastePopup.position = Vector3( cursor.position.x, -0.5f * popupSize.height - grabHandle.size.height + cursor.position.y, 0.0f );
       }
     }
 
-    Vector3 popupSize = Vector3( mCopyPastePopup.actor.GetRelayoutSize( Dimension::WIDTH ), mCopyPastePopup.actor.GetRelayoutSize( Dimension::HEIGHT ), 0.0f );
-
-    GetConstrainedPopupPosition( mCopyPastePopup.position, popupSize, AnchorPoint::CENTER, mActiveLayer, mBoundingBox );
+    // Checks if there is enough space above the text control. If not it places the popup under it.
+    GetConstrainedPopupPosition( mCopyPastePopup.position, popupSize * AnchorPoint::CENTER, mActiveLayer, mBoundingBox );
 
     SetUpPopupPositionNotifications();
 
@@ -769,16 +792,14 @@ struct Decorator::Impl : public ConnectionTracker
 
   void CalculateHandleWorldCoordinates( HandleImpl& handle, Vector2& position )
   {
-    // Get the world position of the active layer
+    // Gets the world position of the active layer. The active layer is where the handles are added.
     const Vector3 parentWorldPosition = mActiveLayer.GetCurrentWorldPosition();
 
-    // Get the size of the UI control.
-    Vector2 targetSize;
-    mController.GetTargetSize( targetSize );
-
     // The grab handle position in world coords.
-    position.x = parentWorldPosition.x - 0.5f * targetSize.width + handle.position.x;
-    position.y = parentWorldPosition.y - 0.5f * targetSize.height + handle.position.y + handle.lineHeight;
+    // The active layer's world position is the center of the active layer. The origin of the
+    // coord system of the handles is the top left of the active layer.
+    position.x = parentWorldPosition.x - 0.5f * mControlSize.width + handle.position.x;
+    position.y = parentWorldPosition.y - 0.5f * mControlSize.height + handle.position.y;
   }
 
   void SetGrabHandlePosition()
@@ -786,7 +807,12 @@ struct Decorator::Impl : public ConnectionTracker
     // Reference to the grab handle.
     HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
 
-    // The grab handle position in world coords.
+    // Transforms the handle position into world coordinates.
+    // @note This is not the same value as grabHandle.actor.GetCurrentWorldPosition()
+    // as it's transforming the handle's position set by the text-controller and not
+    // the final position set to the actor. Another difference is the GetCurrentWorldPosition()
+    // retrieves the position of the center of the actor but the handle's position set
+    // by the text controller is not the center of the actor.
     Vector2 grabHandleWorldPosition;
     CalculateHandleWorldCoordinates( grabHandle, grabHandleWorldPosition );
 
@@ -794,8 +820,8 @@ struct Decorator::Impl : public ConnectionTracker
     // At the moment only the height is checked for the grab handle.
 
     grabHandle.verticallyFlipped = ( grabHandle.verticallyFlippedPreferred &&
-                                     ( ( grabHandleWorldPosition.y - grabHandle.lineHeight - grabHandle.size.height ) > mBoundingBox.y ) ) ||
-                                   ( grabHandleWorldPosition.y + grabHandle.size.height > mBoundingBox.w );
+                                     ( ( grabHandleWorldPosition.y - grabHandle.size.height ) > mBoundingBox.y ) ) ||
+                                   ( grabHandleWorldPosition.y + grabHandle.lineHeight + grabHandle.size.height > mBoundingBox.w );
 
     // The grab handle 'y' position in local coords.
     // If the grab handle exceeds the bottom of the decoration box,
@@ -814,7 +840,12 @@ struct Decorator::Impl : public ConnectionTracker
     // Reference to the selection handle.
     HandleImpl& handle = mHandle[type];
 
-    // Get the world coordinates of the handle position.
+    // Transforms the handle position into world coordinates.
+    // @note This is not the same value as handle.actor.GetCurrentWorldPosition()
+    // as it's transforming the handle's position set by the text-controller and not
+    // the final position set to the actor. Another difference is the GetCurrentWorldPosition()
+    // retrieves the position of the center of the actor but the handle's position set
+    // by the text controller is not the center of the actor.
     Vector2 handleWorldPosition;
     CalculateHandleWorldCoordinates( handle, handleWorldPosition );
 
@@ -848,7 +879,6 @@ struct Decorator::Impl : public ConnectionTracker
 
     // Check if the selection handle exceeds the boundaries of the decoration box.
     const bool exceedsLeftEdge = ( isPrimaryHandle ? !flipHandle : flipHandle ) && ( handleWorldPosition.x - handle.size.width < mBoundingBox.x );
-
     const bool exceedsRightEdge = ( isPrimaryHandle ? flipHandle : !flipHandle ) && ( handleWorldPosition.x + handle.size.width > mBoundingBox.z );
 
     // Does not flip if both conditions are true (double flip)
@@ -877,8 +907,8 @@ struct Decorator::Impl : public ConnectionTracker
 
     // Whether to flip the handle vertically.
     handle.verticallyFlipped = ( verticallyFlippedPreferred &&
-                                 ( ( handleWorldPosition.y - handle.lineHeight - handle.size.height ) > mBoundingBox.y ) ) ||
-                               ( handleWorldPosition.y + handle.size.height > mBoundingBox.w );
+                                 ( ( handleWorldPosition.y - handle.size.height ) > mBoundingBox.y ) ) ||
+                               ( handleWorldPosition.y + handle.lineHeight + handle.size.height > mBoundingBox.w );
 
     // The primary selection handle 'y' position in local coords.
     // If the handle exceeds the bottom of the decoration box,
@@ -1215,38 +1245,234 @@ struct Decorator::Impl : public ConnectionTracker
     return true;
   }
 
-  // Popup
+  void HandleResetPosition( PropertyNotification& source )
+  {
+    const HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
 
-  float AlternatePopUpPositionRelativeToCursor()
+    if( grabHandle.active )
+    {
+      // Sets the grab handle position and calculates if it needs to be vertically flipped if it exceeds the boundary box.
+      SetGrabHandlePosition();
+
+      // Sets the grab handle image according if it's pressed, flipped, etc.
+      SetHandleImage( GRAB_HANDLE );
+    }
+    else
+    {
+      // Sets the primary selection handle position and calculates if it needs to be vertically flipped if it exceeds the boundary box.
+      SetSelectionHandlePosition( LEFT_SELECTION_HANDLE );
+
+      // Sets the primary handle image according if it's pressed, flipped, etc.
+      SetHandleImage( LEFT_SELECTION_HANDLE );
+
+      // Sets the secondary selection handle position and calculates if it needs to be vertically flipped if it exceeds the boundary box.
+      SetSelectionHandlePosition( RIGHT_SELECTION_HANDLE );
+
+      // Sets the secondary handle image according if it's pressed, flipped, etc.
+      SetHandleImage( RIGHT_SELECTION_HANDLE );
+    }
+  }
+
+  void SetupActiveLayerPropertyNotifications()
   {
-    const float popupHeight = 120.0f; // todo Set as a MaxSize Property in Control or retrieve from CopyPastePopup class.
-    const float BOTTOM_HANDLE_BOTTOM_OFFSET = 1.5; //todo Should be a property
+    if( !mActiveLayer )
+    {
+      return;
+    }
 
-    float alternativePosition=0.0f;;
+    // Vertical notifications.
 
-    if( mPrimaryCursor ) // Secondary cursor not used for paste
+    // Disconnect any previous connected callback.
+    if( mVerticalLessThanNotification )
     {
-      alternativePosition = mCursor[PRIMARY_CURSOR].position.y + popupHeight;
+      mVerticalLessThanNotification.NotifySignal().Disconnect( this, &Decorator::Impl::HandleResetPosition );
+      mActiveLayer.RemovePropertyNotification( mVerticalLessThanNotification );
+    }
+
+    if( mVerticalGreaterThanNotification )
+    {
+      mVerticalGreaterThanNotification.NotifySignal().Disconnect( this, &Decorator::Impl::HandleResetPosition );
+      mActiveLayer.RemovePropertyNotification( mVerticalGreaterThanNotification );
     }
 
     const HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
-    const HandleImpl& selectionPrimaryHandle = mHandle[LEFT_SELECTION_HANDLE];
-    const HandleImpl& selectionSecondaryHandle = mHandle[RIGHT_SELECTION_HANDLE];
+    const HandleImpl& primaryHandle = mHandle[LEFT_SELECTION_HANDLE];
+    const HandleImpl& secondaryHandle = mHandle[RIGHT_SELECTION_HANDLE];
 
     if( grabHandle.active )
     {
-      // If grab handle enabled then position pop-up below the grab handle.
-      alternativePosition = grabHandle.position.y + grabHandle.size.height + popupHeight + BOTTOM_HANDLE_BOTTOM_OFFSET;
+      if( grabHandle.verticallyFlipped )
+      {
+        // The grab handle is vertically flipped. Never is going to exceed the bottom edje of the display.
+        mVerticalGreaterThanNotification.Reset();
+
+        // The vertical distance from the center of the active layer to the top edje of the display.
+        const float topHeight = 0.5f * mControlSize.height - grabHandle.position.y + grabHandle.size.height;
+
+        mVerticalLessThanNotification = mActiveLayer.AddPropertyNotification( Actor::Property::WORLD_POSITION_Y,
+                                                                              LessThanCondition( mBoundingBox.y + topHeight ) );
 
+        // Notifies the change from false to true and from true to false.
+        mVerticalLessThanNotification.SetNotifyMode( PropertyNotification::NotifyOnChanged );
+
+        // Connects the signals with the callbacks.
+        mVerticalLessThanNotification.NotifySignal().Connect( this, &Decorator::Impl::HandleResetPosition );
+      }
+      else
+      {
+        // The grab handle is not vertically flipped. Never is going to exceed the top edje of the display.
+        mVerticalLessThanNotification.Reset();
+
+        // The vertical distance from the center of the active layer to the bottom edje of the display.
+        const float bottomHeight = -0.5f * mControlSize.height + grabHandle.position.y + grabHandle.lineHeight + grabHandle.size.height;
+
+        mVerticalGreaterThanNotification = mActiveLayer.AddPropertyNotification( Actor::Property::WORLD_POSITION_Y,
+                                                                                 GreaterThanCondition( mBoundingBox.w - bottomHeight ) );
+
+        // Notifies the change from false to true and from true to false.
+        mVerticalGreaterThanNotification.SetNotifyMode( PropertyNotification::NotifyOnChanged );
+
+        // Connects the signals with the callbacks.
+        mVerticalGreaterThanNotification.NotifySignal().Connect( this, &Decorator::Impl::HandleResetPosition );
+      }
     }
-    else if( selectionPrimaryHandle.active || selectionSecondaryHandle.active )
+    else // The selection handles are active
     {
-      const float maxHeight = std::max( selectionPrimaryHandle.size.height,
-                                        selectionSecondaryHandle.size.height );
-      const float maxY = std::max( selectionPrimaryHandle.position.y,
-                                   selectionSecondaryHandle.position.y );
+      if( primaryHandle.verticallyFlipped && secondaryHandle.verticallyFlipped )
+      {
+        // Both selection handles are vertically flipped. Never are going to exceed the bottom edje of the display.
+        mVerticalGreaterThanNotification.Reset();
+
+        // The vertical distance from the center of the active layer to the top edje of the display.
+        const float topHeight = 0.5f * mControlSize.height + std::max( -primaryHandle.position.y + primaryHandle.size.height, -secondaryHandle.position.y + secondaryHandle.size.height );
+
+        mVerticalLessThanNotification = mActiveLayer.AddPropertyNotification( Actor::Property::WORLD_POSITION_Y,
+                                                                              LessThanCondition( mBoundingBox.y + topHeight ) );
+
+        // Notifies the change from false to true and from true to false.
+        mVerticalLessThanNotification.SetNotifyMode( PropertyNotification::NotifyOnChanged );
+
+        // Connects the signals with the callbacks.
+        mVerticalLessThanNotification.NotifySignal().Connect( this, &Decorator::Impl::HandleResetPosition );
+      }
+      else if( !primaryHandle.verticallyFlipped && !secondaryHandle.verticallyFlipped )
+      {
+        // Both selection handles aren't vertically flipped. Never are going to exceed the top edje of the display.
+        mVerticalLessThanNotification.Reset();
+
+        // The vertical distance from the center of the active layer to the bottom edje of the display.
+        const float bottomHeight = -0.5f * mControlSize.height + std::max( primaryHandle.position.y + primaryHandle.lineHeight + primaryHandle.size.height,
+                                                                           secondaryHandle.position.y + secondaryHandle.lineHeight + secondaryHandle.size.height );
+
+        mVerticalGreaterThanNotification = mActiveLayer.AddPropertyNotification( Actor::Property::WORLD_POSITION_Y,
+                                                                                 GreaterThanCondition( mBoundingBox.w - bottomHeight ) );
+
+        // Notifies the change from false to true and from true to false.
+        mVerticalGreaterThanNotification.SetNotifyMode( PropertyNotification::NotifyOnChanged );
+
+        // Connects the signals with the callbacks.
+        mVerticalGreaterThanNotification.NotifySignal().Connect( this, &Decorator::Impl::HandleResetPosition );
+      }
+      else
+      {
+        // Only one of the selection handles is vertically flipped. Both vertical notifications are needed.
+
+        // The vertical distance from the center of the active layer to the top edje of the display.
+        const float topHeight = 0.5f * mControlSize.height + ( primaryHandle.verticallyFlipped                              ?
+                                                               -primaryHandle.position.y + primaryHandle.size.height        :
+                                                               -secondaryHandle.position.y + secondaryHandle.size.height );
+
+        mVerticalLessThanNotification = mActiveLayer.AddPropertyNotification( Actor::Property::WORLD_POSITION_Y,
+                                                                              LessThanCondition( mBoundingBox.y + topHeight ) );
+
+        // Notifies the change from false to true and from true to false.
+        mVerticalLessThanNotification.SetNotifyMode( PropertyNotification::NotifyOnChanged );
+
+        // Connects the signals with the callbacks.
+        mVerticalLessThanNotification.NotifySignal().Connect( this, &Decorator::Impl::HandleResetPosition );
+
+        // The vertical distance from the center of the active layer to the bottom edje of the display.
+        const float bottomHeight = -0.5f * mControlSize.height + ( primaryHandle.verticallyFlipped                                                       ?
+                                                                   secondaryHandle.position.y + secondaryHandle.lineHeight + secondaryHandle.size.height :
+                                                                   primaryHandle.position.y + primaryHandle.lineHeight + primaryHandle.size.height );
+
+        mVerticalGreaterThanNotification = mActiveLayer.AddPropertyNotification( Actor::Property::WORLD_POSITION_Y,
+                                                                                 GreaterThanCondition( mBoundingBox.w - bottomHeight ) );
+
+        // Notifies the change from false to true and from true to false.
+        mVerticalGreaterThanNotification.SetNotifyMode( PropertyNotification::NotifyOnChanged );
+
+        // Connects the signals with the callbacks.
+        mVerticalGreaterThanNotification.NotifySignal().Connect( this, &Decorator::Impl::HandleResetPosition );
+      }
+    }
+
+    // Horizontal notifications.
+
+    // Disconnect any previous connected callback.
+    if( mHorizontalLessThanNotification )
+    {
+      mHorizontalLessThanNotification.NotifySignal().Disconnect( this, &Decorator::Impl::HandleResetPosition );
+      mActiveLayer.RemovePropertyNotification( mHorizontalLessThanNotification );
+    }
+
+    if( mHorizontalGreaterThanNotification )
+    {
+      mHorizontalGreaterThanNotification.NotifySignal().Disconnect( this, &Decorator::Impl::HandleResetPosition );
+      mActiveLayer.RemovePropertyNotification( mHorizontalGreaterThanNotification );
+    }
+
+    if( primaryHandle.active || secondaryHandle.active )
+    {
+      // The horizontal distance from the center of the active layer to the left edje of the display.
+      const float leftWidth = 0.5f * mControlSize.width + std::max( -primaryHandle.position.x + primaryHandle.size.width,
+                                                                    -secondaryHandle.position.x + secondaryHandle.size.width );
+
+      mHorizontalLessThanNotification = mActiveLayer.AddPropertyNotification( Actor::Property::WORLD_POSITION_X,
+                                                                              LessThanCondition( mBoundingBox.x + leftWidth ) );
 
-      alternativePosition = maxY + maxHeight + popupHeight + BOTTOM_HANDLE_BOTTOM_OFFSET;
+      // Notifies the change from false to true and from true to false.
+      mHorizontalLessThanNotification.SetNotifyMode( PropertyNotification::NotifyOnChanged );
+
+      // Connects the signals with the callbacks.
+      mHorizontalLessThanNotification.NotifySignal().Connect( this, &Decorator::Impl::HandleResetPosition );
+
+      // The horizontal distance from the center of the active layer to the right edje of the display.
+      const float rightWidth = -0.5f * mControlSize.width + std::max( primaryHandle.position.x + primaryHandle.size.width,
+                                                                      secondaryHandle.position.x + secondaryHandle.size.width );
+
+      mHorizontalGreaterThanNotification = mActiveLayer.AddPropertyNotification( Actor::Property::WORLD_POSITION_X,
+                                                                                 GreaterThanCondition( mBoundingBox.z - rightWidth ) );
+
+      // Notifies the change from false to true and from true to false.
+      mHorizontalGreaterThanNotification.SetNotifyMode( PropertyNotification::NotifyOnChanged );
+
+      // Connects the signals with the callbacks.
+      mHorizontalGreaterThanNotification.NotifySignal().Connect( this, &Decorator::Impl::HandleResetPosition );
+    }
+  }
+
+  // Popup
+
+  float AlternatePopUpPositionRelativeToCursor()
+  {
+    float alternativePosition = 0.0f;
+
+    const float popupHeight = mCopyPastePopup.actor.GetRelayoutSize( Dimension::HEIGHT );
+
+    const HandleImpl& primaryHandle = mHandle[LEFT_SELECTION_HANDLE];
+    const HandleImpl& secondaryHandle = mHandle[RIGHT_SELECTION_HANDLE];
+    const HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
+    const CursorImpl& cursor = mCursor[PRIMARY_CURSOR];
+
+    if( primaryHandle.active || secondaryHandle.active )
+    {
+      const float maxHandleHeight = std::max( primaryHandle.size.height, secondaryHandle.size.height );
+      alternativePosition = 0.5f * popupHeight + cursor.lineHeight + maxHandleHeight + std::min( primaryHandle.position.y, secondaryHandle.position.y );
+    }
+    else
+    {
+      alternativePosition = 0.5f * popupHeight + cursor.lineHeight + grabHandle.size.height + cursor.position.y;
     }
 
     return alternativePosition;
@@ -1254,7 +1480,7 @@ struct Decorator::Impl : public ConnectionTracker
 
   void PopUpLeavesVerticalBoundary( PropertyNotification& source )
   {
-    float alternativeYPosition=0.0f;
+    float alternativeYPosition = 0.0f;
     // todo use AlternatePopUpPositionRelativeToSelectionHandles() if text is highlighted
     // if can't be positioned above, then position below row.
     alternativeYPosition = AlternatePopUpPositionRelativeToCursor();
@@ -1262,30 +1488,28 @@ struct Decorator::Impl : public ConnectionTracker
     mCopyPastePopup.actor.SetY( alternativeYPosition );
   }
 
-  void SetUpPopupPositionNotifications( )
+  void SetUpPopupPositionNotifications()
   {
     // Note Property notifications ignore any set anchor point so conditions must allow for this.  Default is Top Left.
 
     // Exceeding vertical boundary
 
-    float popupHeight = mCopyPastePopup.actor.GetRelayoutSize( Dimension::HEIGHT);
+    const float popupHeight = mCopyPastePopup.actor.GetRelayoutSize( Dimension::HEIGHT );
 
     PropertyNotification verticalExceedNotification = mCopyPastePopup.actor.AddPropertyNotification( Actor::Property::WORLD_POSITION_Y,
-                                                      OutsideCondition( mBoundingBox.y + popupHeight * 0.5f,
-                                                                        mBoundingBox.w - popupHeight * 0.5f ) );
+                                                                                                     OutsideCondition( mBoundingBox.y + popupHeight * 0.5f,
+                                                                                                                       mBoundingBox.w - popupHeight * 0.5f ) );
 
     verticalExceedNotification.NotifySignal().Connect( this, &Decorator::Impl::PopUpLeavesVerticalBoundary );
   }
 
-  void GetConstrainedPopupPosition( Vector3& requiredPopupPosition, Vector3& popupSize, Vector3 anchorPoint, Actor& parent, const Vector4& boundingRectangleWorld )
+  void GetConstrainedPopupPosition( Vector3& requiredPopupPosition, const Vector3& popupDistanceFromAnchorPoint, Actor parent, const Vector4& boundingRectangleWorld )
   {
     DALI_ASSERT_DEBUG ( "Popup parent not on stage" && parent.OnStage() )
 
     // Parent must already by added to Stage for these Get calls to work
-    Vector3 parentAnchorPoint = parent.GetCurrentAnchorPoint();
-    Vector3 parentWorldPositionLeftAnchor = parent.GetCurrentWorldPosition() - parent.GetCurrentSize()*parentAnchorPoint;
-    Vector3 popupWorldPosition = parentWorldPositionLeftAnchor + requiredPopupPosition;  // Parent World position plus popup local position gives World Position
-    Vector3 popupDistanceFromAnchorPoint = popupSize*anchorPoint;
+    const Vector3 parentWorldPositionLeftAnchor = parent.GetCurrentWorldPosition() - parent.GetCurrentSize() * parent.GetCurrentAnchorPoint();
+    const Vector3 popupWorldPosition = parentWorldPositionLeftAnchor + requiredPopupPosition;  // Parent World position plus popup local position gives World Position
 
     // Calculate distance to move popup (in local space) so fits within the boundary
     float xOffSetToKeepWithinBounds = 0.0f;
@@ -1293,13 +1517,13 @@ struct Decorator::Impl : public ConnectionTracker
     {
       xOffSetToKeepWithinBounds = boundingRectangleWorld.x - ( popupWorldPosition.x - popupDistanceFromAnchorPoint.x );
     }
-    else if ( popupWorldPosition.x +  popupDistanceFromAnchorPoint.x > boundingRectangleWorld.z )
+    else if( popupWorldPosition.x +  popupDistanceFromAnchorPoint.x > boundingRectangleWorld.z )
     {
       xOffSetToKeepWithinBounds = boundingRectangleWorld.z - ( popupWorldPosition.x +  popupDistanceFromAnchorPoint.x );
     }
 
     // Ensure initial display of Popup is in alternative position if can not fit above. As Property notification will be a frame behind.
-    if ( popupWorldPosition.y - popupDistanceFromAnchorPoint.y < boundingRectangleWorld.y )
+    if( popupWorldPosition.y - popupDistanceFromAnchorPoint.y < boundingRectangleWorld.y )
     {
       requiredPopupPosition.y = AlternatePopUpPositionRelativeToCursor();
     }
@@ -1307,8 +1531,8 @@ struct Decorator::Impl : public ConnectionTracker
     requiredPopupPosition.x = requiredPopupPosition.x + xOffSetToKeepWithinBounds;
 
     // Prevent pixel mis-alignment by rounding down.
-    requiredPopupPosition.x = static_cast<int>( requiredPopupPosition.x );
-    requiredPopupPosition.y = static_cast<int>( requiredPopupPosition.y );
+    requiredPopupPosition.x = floor( requiredPopupPosition.x );
+    requiredPopupPosition.y = floor( requiredPopupPosition.y );
   }
 
   void SetHandleImage( HandleType handleType, HandleImageType handleImageType, Dali::Image image )
@@ -1405,11 +1629,15 @@ struct Decorator::Impl : public ConnectionTracker
   Timer               mCursorBlinkTimer;          ///< Timer to signal cursor to blink
   Timer               mScrollTimer;               ///< Timer used to scroll the text when the grab handle is moved close to the edges.
 
-  Layer               mActiveLayer;               ///< Layer for active handles and alike that ensures they are above all else.
-  ImageActor          mPrimaryCursor;
-  ImageActor          mSecondaryCursor;
+  Layer                mActiveLayer;                       ///< Layer for active handles and alike that ensures they are above all else.
+  PropertyNotification mVerticalLessThanNotification;      ///< Notifies when the 'y' coord of the active layer is less than a given value.
+  PropertyNotification mVerticalGreaterThanNotification;   ///< Notifies when the 'y' coord of the active layer is grater than a given value.
+  PropertyNotification mHorizontalLessThanNotification;    ///< Notifies when the 'x' coord of the active layer is less than a given value.
+  PropertyNotification mHorizontalGreaterThanNotification; ///< Notifies when the 'x' coord of the active layer is grater than a given value.
+  ImageActor           mPrimaryCursor;
+  ImageActor           mSecondaryCursor;
 
-  Actor               mHighlightActor;        ///< Actor to display highlight
+  Actor               mHighlightActor;            ///< Actor to display highlight
   Renderer            mHighlightRenderer;
   Material            mHighlightMaterial;         ///< Material used for highlight
   Property::Map       mQuadVertexFormat;
@@ -1432,6 +1660,7 @@ struct Decorator::Impl : public ConnectionTracker
   Vector4             mBoundingBox;               ///< The bounding box in world coords.
   Vector4             mHighlightColor;            ///< Color of the highlight
   Vector2             mHighlightPosition;         ///< The position of the highlight actor.
+  Vector2             mControlSize;               ///< The control's size. Set by the Relayout.
 
   unsigned int        mActiveCursor;
   unsigned int        mCursorBlinkInterval;
index 3841229..f2c328e 100644 (file)
@@ -20,8 +20,6 @@
 // EXTERNAL INCLUDES
 #include <dali/integration-api/debug.h>
 
-#define MAKE_SHADER(A)#A
-
 namespace
 {
 
@@ -29,52 +27,42 @@ namespace
   Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_RENDERING");
 #endif
 
+#define MAKE_SHADER(A)#A
+
 const char* VERTEX_SHADER = MAKE_SHADER(
 attribute mediump vec2    aPosition;
 attribute mediump vec2    aTexCoord;
+uniform   mediump vec2    uOffset;
 uniform   mediump mat4    uMvpMatrix;
 varying   mediump vec2    vTexCoord;
 
 void main()
 {
-  mediump vec4 position = vec4( aPosition, 0.0, 1.0 );
+  mediump vec4 position = vec4( aPosition.xy + uOffset, 0.0, 1.0 );
   gl_Position = uMvpMatrix * position;
   vTexCoord = aTexCoord;
 }
 );
 
-const char* FRAGMENT_SHADER = MAKE_SHADER(
+const char* FRAGMENT_SHADER_L8 = MAKE_SHADER(
+uniform lowp    vec4      uColor;
 uniform         sampler2D sTexture;
 varying mediump vec2      vTexCoord;
 
 void main()
 {
-  gl_FragColor = texture2D( sTexture, vTexCoord );
-}
-);
-
-const char* VERTEX_SHADER_SHADOW = MAKE_SHADER(
-attribute mediump vec2    aPosition;
-attribute mediump vec2    aTexCoord;
-varying   mediump vec2    vTexCoord;
-
-void main()
-{
-  mediump vec4 position = vec4( aPosition, 0.0, 1.0 );
-  gl_Position = position;
-  vTexCoord = aTexCoord;
+  mediump vec4 color = texture2D( sTexture, vTexCoord );
+  gl_FragColor = vec4( uColor.rgb, uColor.a * color.r );
 }
 );
 
-const char* FRAGMENT_SHADER_SHADOW = MAKE_SHADER(
+const char* FRAGMENT_SHADER_RGBA = MAKE_SHADER(
 uniform         sampler2D sTexture;
-uniform lowp    vec4      uColor;
 varying mediump vec2      vTexCoord;
 
 void main()
 {
-  mediump vec4 color = texture2D( sTexture, vTexCoord );
-  gl_FragColor = vec4(uColor.rgb, uColor.a*color.r);
+  gl_FragColor = texture2D( sTexture, vTexCoord );
 }
 );
 
@@ -91,9 +79,9 @@ namespace Internal
 
 AtlasGlyphManager::AtlasGlyphManager()
 {
+  mShaderL8 = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_L8 );
+  mShaderRgba = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_RGBA );
   mAtlasManager = Dali::Toolkit::AtlasManager::New();
-  mEffectBufferShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
-  mShadowShader = Shader::New( VERTEX_SHADER_SHADOW, FRAGMENT_SHADER_SHADOW, Dali::Shader::HINT_MODIFIES_GEOMETRY );
 }
 
 void AtlasGlyphManager::Add( const Text::GlyphInfo& glyph,
@@ -102,7 +90,16 @@ void AtlasGlyphManager::Add( const Text::GlyphInfo& glyph,
 {
   DALI_LOG_INFO( gLogFilter, Debug::General, "Added glyph, font: %d index: %d\n", glyph.fontId, glyph.index );
 
-  mAtlasManager.Add( bitmap, slot );
+  if ( mAtlasManager.Add( bitmap, slot ) )
+  {
+    // A new atlas was created so set the material details for the atlas
+    Dali::Atlas atlas = mAtlasManager.GetAtlasContainer( slot.mAtlasId );
+    Pixel::Format pixelFormat = mAtlasManager.GetPixelFormat( slot.mAtlasId );
+    Material material = Material::New( pixelFormat == Pixel::L8 ? mShaderL8 : mShaderRgba );
+    material.AddTexture( atlas, "sTexture" );
+    material.SetBlendMode( BlendingMode::ON );
+    mAtlasManager.SetMaterial( slot.mAtlasId, material );
+  }
 
   GlyphRecordEntry record;
   record.mIndex = glyph.index;
@@ -140,13 +137,7 @@ void AtlasGlyphManager::GenerateMeshData( uint32_t imageId,
   mAtlasManager.GenerateMeshData( imageId, position, mesh, false );
 }
 
-void AtlasGlyphManager::StitchMesh( Toolkit::AtlasManager::Mesh2D& first,
-                                    const Toolkit::AtlasManager::Mesh2D& second )
-{
-  mAtlasManager.StitchMesh( first, second );
-}
-
-bool AtlasGlyphManager::Cached( Text::FontId fontId,
+bool AtlasGlyphManager::IsCached( Text::FontId fontId,
                                 Text::GlyphIndex index,
                                 Dali::Toolkit::AtlasManager::AtlasSlot& slot )
 {
@@ -263,11 +254,6 @@ Material AtlasGlyphManager::GetMaterial( uint32_t atlasId ) const
   return mAtlasManager.GetMaterial( atlasId );
 }
 
-Sampler AtlasGlyphManager::GetSampler( uint32_t atlasId ) const
-{
-  return mAtlasManager.GetSampler( atlasId );
-}
-
 AtlasGlyphManager::~AtlasGlyphManager()
 {
   // mAtlasManager handle is automatically released here
index 5ba6740..0c67501 100644 (file)
@@ -81,17 +81,11 @@ public:
                          Toolkit::AtlasManager::Mesh2D& mesh );
 
   /**
-   * @copydoc Toolkit::AtlasGlyphManager::StitchMesh
+   * @copydoc Toolkit::AtlasGlyphManager::IsCached
    */
-  void StitchMesh( Toolkit::AtlasManager::Mesh2D& first,
-                   const Toolkit::AtlasManager::Mesh2D& second );
-
-  /**
-   * @copydoc Toolkit::AtlasGlyphManager::Cached
-   */
-  bool Cached( Text::FontId fontId,
-               Text::GlyphIndex index,
-               Dali::Toolkit::AtlasManager::AtlasSlot& slot );
+  bool IsCached( Text::FontId fontId,
+                 Text::GlyphIndex index,
+                 Dali::Toolkit::AtlasManager::AtlasSlot& slot );
 
   /**
    * @copydoc Toolkit::AtlasGlyphManager::GetAtlasSize
@@ -119,31 +113,10 @@ public:
   Material GetMaterial( uint32_t atlasId ) const;
 
   /**
-   * @copydoc Toolkit::AtlasGlyphManager::GetMaterial
-   */
-  Sampler GetSampler( uint32_t atlasId ) const;
-
-  /**
    * @copydoc Toolkit::AtlasGlyphManager::GetMetrics
    */
   const Toolkit::AtlasGlyphManager::Metrics& GetMetrics();
 
-  /**
-   * @copydoc Toolkit::AtlasGlyphManager::GetEffectBufferShader
-   */
-  Shader GetEffectBufferShader() const
-  {
-    return mEffectBufferShader;
-  }
-
-  /**
-   * @copydoc Toolkit::AtlasGlyphManager::GetGlyphShadowShader
-   */
-  Shader GetGlyphShadowShader() const
-  {
-    return mShadowShader;
-  }
-
 protected:
 
   /**
@@ -156,8 +129,9 @@ private:
   Dali::Toolkit::AtlasManager mAtlasManager;          ///> Atlas Manager created by GlyphManager
   std::vector< FontGlyphRecord > mFontGlyphRecords;
   Toolkit::AtlasGlyphManager::Metrics mMetrics;       ///> Metrics to pass back on GlyphManager status
-  Shader mEffectBufferShader;                         ///> Shader used to render drop shadow buffer textures
-  Shader mShadowShader;                               ///> Shader used to render drop shadow into buffer
+
+  Shader mShaderL8;
+  Shader mShaderRgba;
 };
 
 } // namespace Internal
index 463a3e8..5a46ef5 100644 (file)
@@ -84,17 +84,11 @@ void AtlasGlyphManager::GenerateMeshData( uint32_t imageId,
                                              mesh );
 }
 
-void AtlasGlyphManager::StitchMesh( Toolkit::AtlasManager::Mesh2D& first,
-                                    const Toolkit::AtlasManager::Mesh2D& second )
+bool AtlasGlyphManager::IsCached( Text::FontId fontId,
+                                  Text::GlyphIndex index,
+                                  AtlasManager::AtlasSlot& slot )
 {
-  GetImplementation(*this).StitchMesh( first, second );
-}
-
-bool AtlasGlyphManager::Cached( Text::FontId fontId,
-                                Text::GlyphIndex index,
-                                AtlasManager::AtlasSlot& slot )
-{
-  return GetImplementation(*this).Cached( fontId, index, slot );
+  return GetImplementation(*this).IsCached( fontId, index, slot );
 }
 
 void AtlasGlyphManager::SetNewAtlasSize( uint32_t width, uint32_t height, uint32_t blockWidth, uint32_t blockHeight )
@@ -117,11 +111,6 @@ Material AtlasGlyphManager::GetMaterial( uint32_t atlasId ) const
   return GetImplementation(*this).GetMaterial( atlasId );
 }
 
-Sampler AtlasGlyphManager::GetSampler( uint32_t atlasId ) const
-{
-  return GetImplementation(*this).GetSampler( atlasId );
-}
-
 const Toolkit::AtlasGlyphManager::Metrics& AtlasGlyphManager::GetMetrics()
 {
   return GetImplementation(*this).GetMetrics();
@@ -132,16 +121,6 @@ void AtlasGlyphManager::AdjustReferenceCount( Text::FontId fontId, Text::GlyphIn
   GetImplementation(*this).AdjustReferenceCount( fontId, index, delta );
 }
 
-Shader AtlasGlyphManager::GetEffectBufferShader() const
-{
-  return GetImplementation(*this).GetEffectBufferShader();
-}
-
-Shader AtlasGlyphManager::GetGlyphShadowShader() const
-{
-  return GetImplementation(*this).GetGlyphShadowShader();
-}
-
 } // namespace Toolkit
 
 } // namespace Dali
index a74ce28..1870bd5 100644 (file)
@@ -19,7 +19,7 @@
  */
 
 // INTERNAL INCLUDES
-#include <dali-toolkit/internal/atlas-manager/atlas-manager.h>
+#include <dali-toolkit/internal/text/rendering/atlas/atlas-manager.h>
 #include <dali-toolkit/internal/text/text-definitions.h>
 
 namespace Dali
@@ -99,15 +99,6 @@ public:
                          Toolkit::AtlasManager::Mesh2D& mesh );
 
   /**
-   * @brief Stitch Two Meshes together
-   *
-   * @param[in] first first mesh
-   * @param[in] second second mesh
-   */
-  void StitchMesh( Toolkit::AtlasManager::Mesh2D& first,
-                   const Toolkit::AtlasManager::Mesh2D& second );
-
-  /**
    * @brief Check to see if a glyph is being cached
    *
    * @param[in] fontId The font that this glyph comes from
@@ -116,9 +107,9 @@ public:
    *
    * @return Whether glyph is cached or not ?
    */
-  bool Cached( Text::FontId fontId,
-               Text::GlyphIndex index,
-               AtlasManager::AtlasSlot& slot );
+  bool IsCached( Text::FontId fontId,
+                 Text::GlyphIndex index,
+                 AtlasManager::AtlasSlot& slot );
 
   /**
    * @brief Retrieve the size of an atlas
@@ -158,15 +149,6 @@ public:
   Material GetMaterial( uint32_t atlasId ) const;
 
   /**
-   * @brief Get the sampler used by an atlas
-   *
-   * @param[in] atlasId Id of an atlas
-   *
-   * @return The sampler used by the atlas
-   */
-  Sampler GetSampler( uint32_t atlasId ) const;
-
-  /**
    * @brief Get Glyph Manager metrics
    *
    * @return const reference to glyph manager metrics
@@ -182,20 +164,6 @@ public:
    */
   void AdjustReferenceCount( Text::FontId fontId, Text::GlyphIndex index, int32_t delta );
 
-  /**
-   * @brief Get Shader used for rendering glyph effect buffers
-   *
-   * @return Handle of shader needed
-   */
-  Shader GetEffectBufferShader() const;
-
-  /**
-   * @brief Get Shader used rendering Glyph Shadows
-   *
-   * @return Handle of shader needed
-   */
-  Shader GetGlyphShadowShader() const;
-
 private:
 
   explicit DALI_INTERNAL AtlasGlyphManager(Internal::AtlasGlyphManager *impl);
  */
 
 // CLASS HEADER
-#include <dali-toolkit/internal/atlas-manager/atlas-manager-impl.h>
+#include <dali-toolkit/internal/text/rendering/atlas/atlas-manager-impl.h>
 
-// EXTERNAL INCLUDE
-#include <iostream>
+// EXTERNAL INCLUDES
 #include <string.h>
-#include <dali/devel-api/rendering/sampler.h>
-#include <dali/devel-api/rendering/shader.h>
 #include <dali/integration-api/debug.h>
 
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/rendering/atlas/atlas-mesh-factory.h>
+
 namespace Dali
 {
 
@@ -43,45 +43,6 @@ namespace
   const uint32_t DOUBLE_PIXEL_PADDING( SINGLE_PIXEL_PADDING << 1 );
   const uint32_t FILLED_PIXEL( -1 );
   Toolkit::AtlasManager::AtlasSize EMPTY_SIZE;
-
-  #define MAKE_SHADER(A)#A
-
-  const char* VERTEX_SHADER = MAKE_SHADER(
-  attribute mediump vec2    aPosition;
-  attribute mediump vec2    aTexCoord;
-  uniform   mediump mat4    uMvpMatrix;
-  varying   mediump vec2    vTexCoord;
-
-  void main()
-  {
-    mediump vec4 position = vec4( aPosition, 0.0, 1.0 );
-    gl_Position = uMvpMatrix * position;
-    vTexCoord = aTexCoord;
-  }
-  );
-
-  const char* FRAGMENT_SHADER_L8 = MAKE_SHADER(
-  uniform lowp    vec4      uColor;
-  uniform         sampler2D sTexture;
-  varying mediump vec2      vTexCoord;
-
-  void main()
-  {
-    mediump vec4 color = texture2D( sTexture, vTexCoord );
-    gl_FragColor = vec4( uColor.rgb, uColor.a * color.r );
-  }
-  );
-
-  const char* FRAGMENT_SHADER_RGBA = MAKE_SHADER(
-  uniform         sampler2D sTexture;
-  varying mediump vec2      vTexCoord;
-
-  void main()
-  {
-    gl_FragColor = texture2D( sTexture, vTexCoord );
-  }
-  );
-
 }
 
 AtlasManager::AtlasManager()
@@ -91,8 +52,6 @@ AtlasManager::AtlasManager()
   mNewAtlasSize.mHeight = DEFAULT_ATLAS_HEIGHT;
   mNewAtlasSize.mBlockWidth = DEFAULT_BLOCK_WIDTH;
   mNewAtlasSize.mBlockHeight = DEFAULT_BLOCK_HEIGHT;
-  mShaderL8 = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_L8 );
-  mShaderRgba = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_RGBA );
 }
 
 AtlasManagerPtr AtlasManager::New()
@@ -158,13 +117,6 @@ Toolkit::AtlasManager::AtlasId AtlasManager::CreateAtlas( const Toolkit::AtlasMa
 
   memset( buffer, 0xFF, filledPixelImage.GetBufferSize() );
   atlas.Upload( filledPixelImage, 0, 0 );
-
-  Sampler sampler = Sampler::New( atlas, "sTexture" );
-  sampler.SetProperty( Sampler::Property::AFFECTS_TRANSPARENCY, true );
-  atlasDescriptor.mMaterial = Material::New( pixelformat == Pixel::L8 ? mShaderL8 : mShaderRgba );
-  atlasDescriptor.mMaterial.AddSampler( sampler );
-  atlasDescriptor.mSampler = sampler;
-  atlasDescriptor.mMaterial.SetBlendMode( BlendingMode::ON );
   mAtlasList.push_back( atlasDescriptor );
   return mAtlasList.size();
 }
@@ -174,16 +126,14 @@ void AtlasManager::SetAddPolicy( Toolkit::AtlasManager::AddFailPolicy policy )
   mAddFailPolicy = policy;
 }
 
-void AtlasManager::Add( const BufferImage& image,
+bool AtlasManager::Add( const BufferImage& image,
                         Toolkit::AtlasManager::AtlasSlot& slot,
                         Toolkit::AtlasManager::AtlasId atlas )
 {
-  // See if there's a slot in an atlas that matches the requirements of this image
-  // A bitmap must be sliceable into a single atlas
+  bool created = false;
   Pixel::Format pixelFormat = image.GetPixelFormat();
   SizeType width = image.GetWidth();
   SizeType height = image.GetHeight();
-  SizeType blockArea = 0;
   SizeType foundAtlas = 0;
   SizeType index = 0;
   slot.mImageId = 0;
@@ -193,13 +143,13 @@ void AtlasManager::Add( const BufferImage& image,
   // If there is a preferred atlas then check for room in that first
   if ( atlas-- )
   {
-    foundAtlas = CheckAtlas( atlas, width, height, pixelFormat, blockArea );
+    foundAtlas = CheckAtlas( atlas, width, height, pixelFormat );
   }
 
   // Search current atlases to see if there is a good match
   while( !foundAtlas && index < mAtlasList.size() )
   {
-    foundAtlas = CheckAtlas( index, width, height, pixelFormat, blockArea );
+    foundAtlas = CheckAtlas( index, width, height, pixelFormat );
     ++index;
   }
 
@@ -216,35 +166,32 @@ void AtlasManager::Add( const BufferImage& image,
                        mNewAtlasSize.mHeight,
                        mNewAtlasSize.mBlockWidth,
                        mNewAtlasSize.mBlockHeight );
-        return;
+        return created;
       }
-
-      foundAtlas = CheckAtlas( foundAtlas, width, height, pixelFormat, blockArea );
+      created = true;
+      foundAtlas = CheckAtlas( foundAtlas, width, height, pixelFormat );
     }
 
     if ( !foundAtlas-- || Toolkit::AtlasManager::FAIL_ON_ADD_FAILS == mAddFailPolicy )
     {
       // Haven't found an atlas for this image!!!!!!
       DALI_LOG_ERROR("Failed to create an atlas under current policy.\n");
-      return;
+      return created;
     }
   }
 
-  // Work out where the blocks are we're going to use
-  for ( SizeType i = 0; i < blockArea; ++i )
+  // Work out which the block we're going to use
+  // Is there currently a next free block available ?
+  if ( mAtlasList[ foundAtlas ].mAvailableBlocks )
   {
-    // Is there currently a next free block available ?
-    if ( mAtlasList[ foundAtlas ].mAvailableBlocks )
-    {
-      // Yes, so select our next block
-      desc.mBlocksList.PushBack( mAtlasList[ foundAtlas ].mTotalBlocks - mAtlasList[ foundAtlas ].mAvailableBlocks-- );
-    }
-    else
-    {
-      // Our next block must be from the free list, fetch from the start of the list
-      desc.mBlocksList.PushBack( mAtlasList[ foundAtlas ].mFreeBlocksList[ 0 ] );
-      mAtlasList[ foundAtlas ].mFreeBlocksList.Remove( mAtlasList[ foundAtlas ].mFreeBlocksList.Begin() );
-    }
+    // Yes, so select our next block
+    desc.mBlock = mAtlasList[ foundAtlas ].mTotalBlocks - mAtlasList[ foundAtlas ].mAvailableBlocks--;
+  }
+  else
+  {
+    // Our next block must be from the free list, fetch from the start of the list
+    desc.mBlock = mAtlasList[ foundAtlas ].mFreeBlocksList[ 0 ];
+    mAtlasList[ foundAtlas ].mFreeBlocksList.Remove( mAtlasList[ foundAtlas ].mFreeBlocksList.Begin() );
   }
 
   desc.mImageWidth = width;
@@ -254,7 +201,7 @@ void AtlasManager::Add( const BufferImage& image,
 
   // See if there's a previously freed image ID that we can assign to this new image
   uint32_t imageId = 0u;
-  for ( uint32_t i = 0u; i < mImageList.size(); ++i )
+  for ( uint32_t i = 0u; i < mImageList.Size(); ++i )
   {
     if ( !mImageList[ i ].mCount )
     {
@@ -264,8 +211,8 @@ void AtlasManager::Add( const BufferImage& image,
   }
   if ( !imageId )
   {
-    mImageList.push_back( desc );
-    slot.mImageId = mImageList.size();
+    mImageList.PushBack( desc );
+    slot.mImageId = mImageList.Size();
   }
   else
   {
@@ -273,15 +220,18 @@ void AtlasManager::Add( const BufferImage& image,
     slot.mImageId = imageId;
   }
   slot.mAtlasId = foundAtlas + 1u;
+
+  // Upload the buffer image into the atlas
   UploadImage( image, desc );
+  return created;
 }
 
 AtlasManager::SizeType AtlasManager::CheckAtlas( SizeType atlas,
                                                  SizeType width,
                                                  SizeType height,
-                                                 Pixel::Format pixelFormat,
-                                                 SizeType& blockArea )
+                                                 Pixel::Format pixelFormat )
 {
+  AtlasManager::SizeType result = 0u;
   if ( pixelFormat == mAtlasList[ atlas ].mPixelFormat )
   {
     // Check to see if the image will fit in these blocks, if not we'll need to create a new atlas
@@ -289,254 +239,10 @@ AtlasManager::SizeType AtlasManager::CheckAtlas( SizeType atlas,
            && width + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mBlockWidth
            && height + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mBlockHeight )
     {
-      blockArea = 1u;
-      return ( atlas + 1u );
+      result = atlas + 1u;
     }
   }
-  return 0u;
-}
-
-void AtlasManager::CreateMesh( SizeType atlas,
-                               SizeType imageWidth,
-                               SizeType imageHeight,
-                               const Vector2& position,
-                               SizeType widthInBlocks,
-                               SizeType heightInBlocks,
-                               Toolkit::AtlasManager::Mesh2D& mesh,
-                               AtlasSlotDescriptor& desc )
-{
-  Toolkit::AtlasManager::Vertex2D vertex;
-  uint32_t faceIndex = 0;       // TODO change to unsigned short when property type is available
-
-  SizeType blockWidth = mAtlasList[ atlas ].mSize.mBlockWidth;
-  SizeType blockHeight = mAtlasList[ atlas ].mSize.mBlockHeight;
-
-  float vertexBlockWidth = static_cast< float >( blockWidth );
-  float vertexBlockHeight = static_cast< float >( blockHeight );
-
-  SizeType width = mAtlasList[ atlas ].mSize.mWidth;
-  SizeType height = mAtlasList[ atlas ].mSize.mHeight;
-
-  SizeType atlasWidthInBlocks = ( width - 1u ) / blockWidth;
-
-  // Get the normalized size of a texel in both directions
-  // TODO when texture resizing and passing texture size via uniforms is available,
-  //      we will encode pixel positions into the vertex data rather than normalized
-  //      meaning that geometry needn't be changed on an atlas resize
-  float texelX = 1.0f / static_cast< float >( width );
-  float texelY = 1.0f / static_cast< float >( height );
-
-  float oneAndAHalfTexelX = texelX + ( texelX * 0.5f );
-  float oneAndAHalfTexelY = texelY + ( texelY * 0.5f );
-
-  // Get the normalized size of a block in texels
-  float texelBlockWidth = texelX * vertexBlockWidth;
-  float texelBlockHeight = texelY * vertexBlockHeight;
-
-  // Get partial block space
-  float vertexEdgeWidth = static_cast< float >( imageWidth % blockWidth );
-  float vertexEdgeHeight = static_cast< float >( imageHeight % blockHeight );
-
-  // And in texels
-  float texelEdgeWidth = texelX * vertexEdgeWidth;
-  float texelEdgeHeight = texelY * vertexEdgeHeight;
-
-  // We're going to 'blit' half a pixel more on each edge
-  vertexBlockWidth++;
-  vertexEdgeWidth++;
-  vertexBlockHeight++;
-  vertexEdgeHeight++;
-
-   // Block by block create the two triangles for the quad
-  SizeType blockIndex = 0;
-  float ndcWidth;
-  float ndcHeight;
-  float ndcVWidth;
-  float ndcVHeight;
-
-  // Move back half a pixel
-  Vector2 topLeft = Vector2( position.x - 0.5f, position.y - 0.5f );
-
-  for ( SizeType y = 0; y < heightInBlocks; ++y )
-  {
-
-    float currentX = position.x;
-
-    if ( ( heightInBlocks - 1u ) == y && vertexEdgeHeight > 0.0f )
-    {
-      ndcHeight = texelEdgeHeight + texelY;
-      ndcVHeight = vertexEdgeHeight;
-    }
-    else
-    {
-      ndcHeight = texelBlockHeight + texelY;
-      ndcVHeight = vertexBlockHeight;
-    }
-
-    for ( SizeType x = 0; x < widthInBlocks; ++x )
-    {
-      SizeType block = desc.mBlocksList[ blockIndex++ ];
-
-      float fBlockX = texelBlockWidth * static_cast< float >( block % atlasWidthInBlocks );
-      float fBlockY = texelBlockHeight * static_cast< float >( block / atlasWidthInBlocks );
-
-      // Add on texture filtering compensation ( half a texel plus compensation for filled pixel in top left corner )
-      fBlockX += oneAndAHalfTexelX;
-      fBlockY += oneAndAHalfTexelY;
-
-      if (  ( widthInBlocks - 1u ) == x && vertexEdgeWidth > 0.0f )
-      {
-        ndcWidth = texelEdgeWidth + texelX;
-        ndcVWidth = vertexEdgeWidth;
-      }
-      else
-      {
-        ndcWidth = texelBlockWidth + texelX;
-        ndcVWidth = vertexBlockWidth;
-      }
-
-      // Top left
-      vertex.mPosition.x = topLeft.x;
-      vertex.mPosition.y = topLeft.y;
-      vertex.mTexCoords.x = fBlockX;
-      vertex.mTexCoords.y = fBlockY;
-
-      mesh.mVertices.PushBack( vertex );
-
-      // Top Right
-      vertex.mPosition.x = topLeft.x + ndcVWidth;
-      vertex.mPosition.y = topLeft.y;
-      vertex.mTexCoords.x = fBlockX + ndcWidth;
-      vertex.mTexCoords.y = fBlockY;
-
-      mesh.mVertices.PushBack( vertex );
-
-      // Bottom Left
-      vertex.mPosition.x = topLeft.x;
-      vertex.mPosition.y = topLeft.y + ndcVHeight;
-      vertex.mTexCoords.x = fBlockX;
-      vertex.mTexCoords.y = fBlockY + ndcHeight;
-
-      mesh.mVertices.PushBack( vertex );
-
-      // Bottom Right
-      topLeft.x += ndcVWidth;
-      vertex.mPosition.x = topLeft.x;
-      vertex.mPosition.y = topLeft.y + ndcVHeight;
-      vertex.mTexCoords.x = fBlockX + ndcWidth;
-      vertex.mTexCoords.y = fBlockY + ndcHeight;
-
-      mesh.mVertices.PushBack( vertex );
-
-      // Six indices in counter clockwise winding
-      mesh.mIndices.PushBack( faceIndex + 1u );
-      mesh.mIndices.PushBack( faceIndex );
-      mesh.mIndices.PushBack( faceIndex + 2u );
-      mesh.mIndices.PushBack( faceIndex + 2u );
-      mesh.mIndices.PushBack( faceIndex + 3u );
-      mesh.mIndices.PushBack( faceIndex + 1u );
-      faceIndex += 4;
-    }
-
-    // Move down a row
-    topLeft.x = currentX;
-    topLeft.y += vertexBlockHeight;
-  }
-
-  // If there's only one block then skip this next vertex optimisation
-  if ( widthInBlocks * heightInBlocks > 1 )
-  {
-    Toolkit::AtlasManager::Mesh2D optimizedMesh;
-    OptimizeMesh( mesh, optimizedMesh );
-  }
-}
-
-void AtlasManager::PrintMeshData( const Toolkit::AtlasManager::Mesh2D& mesh )
-{
-  uint32_t vertexCount = mesh.mVertices.Size();
-  uint32_t indexCount = mesh.mIndices.Size();
-  std::cout << "\nMesh Data for Image: VertexCount = " << vertexCount;
-  std::cout << ", Triangles = " << indexCount / 3 << std::endl;
-
-  for ( SizeType v = 0; v < vertexCount; ++v )
-  {
-    std::cout << " Vertex(" << v << ") x = " << mesh.mVertices[v].mPosition.x << ", ";
-    std::cout << "y = " << mesh.mVertices[v].mPosition.y << ", ";
-    std::cout << "u = " << mesh.mVertices[v].mTexCoords.x << ", ";
-    std::cout << "v = " << mesh.mVertices[v].mTexCoords.y << std::endl;
-  }
-
-  std::cout << "\n Indices: ";
-  for ( SizeType i = 0; i < indexCount; ++i )
-  {
-    std::cout << " " << mesh.mIndices[ i ];
-  }
-  std::cout << std::endl;
-}
-
-void AtlasManager::OptimizeMesh( const Toolkit::AtlasManager::Mesh2D& in,
-                                 Toolkit::AtlasManager::Mesh2D& out )
-{
-  unsigned short vertexIndex = 0;
-
-  // We could check to see if blocks are next to each other, but it's probably just as quick to compare verts
-  for ( SizeType i = 0; i < in.mIndices.Size(); ++i )
-  {
-    // Fetch a vertex, has it already been assigned?
-    bool foundVertex = false;
-    Toolkit::AtlasManager::Vertex2D v = in.mVertices[ in.mIndices[ i ] ];
-    for ( SizeType j = 0; j < out.mVertices.Size(); ++j )
-    {
-      if ( ( fabsf( v.mPosition.x - out.mVertices[ j ].mPosition.x ) < Math::MACHINE_EPSILON_1000 ) &&
-           ( fabsf( v.mPosition.y - out.mVertices[ j ].mPosition.y ) < Math::MACHINE_EPSILON_1000 ) &&
-           ( fabsf( v.mTexCoords.x - out.mVertices[ j ].mTexCoords.x ) < Math::MACHINE_EPSILON_1000 ) &&
-           ( fabsf( v.mTexCoords.y - out.mVertices[ j ].mTexCoords.y ) < Math::MACHINE_EPSILON_1000 ) )
-      {
-        // Yes, so store this down as the vertex to use
-        out.mIndices.PushBack( j );
-        foundVertex = true;
-        break;
-      }
-    }
-
-    // Did we find a vertex ?
-    if ( !foundVertex )
-    {
-      // No so add a new one
-      out.mVertices.PushBack( v );
-      vertexIndex++;
-    }
-  }
-}
-
-void AtlasManager::StitchMesh( Toolkit::AtlasManager::Mesh2D& first,
-                               const Toolkit::AtlasManager::Mesh2D& second,
-                               bool optimize )
-{
-  const uint32_t verticesCount = first.mVertices.Size();
-  first.mVertices.Insert( first.mVertices.End(),
-                          second.mVertices.Begin(),
-                          second.mVertices.End() );
-
-  const uint32_t indicesCount = first.mIndices.Size();
-  first.mIndices.Insert( first.mIndices.End(),
-                         second.mIndices.Begin(),
-                         second.mIndices.End() );
-
-  for( Vector<unsigned int>::Iterator it = first.mIndices.Begin() + indicesCount,
-         endIt = first.mIndices.End();
-       it != endIt;
-       ++it )
-  {
-    *it += verticesCount;
-  }
-
-  if ( optimize )
-  {
-    Toolkit::AtlasManager::Mesh2D optimizedMesh;
-    OptimizeMesh( first, optimizedMesh );
-    first = optimizedMesh;
-  }
+  return result;
 }
 
 void AtlasManager::UploadImage( const BufferImage& image,
@@ -556,9 +262,8 @@ void AtlasManager::UploadImage( const BufferImage& image,
   SizeType atlasBlockHeight = mAtlasList[ atlas ].mSize.mBlockHeight;
   SizeType atlasWidthInBlocks = ( mAtlasList[ atlas ].mSize.mWidth - 1u ) / mAtlasList[ atlas ].mSize.mBlockWidth;
 
-  SizeType block = desc.mBlocksList[ 0 ];
-  SizeType blockX = block % atlasWidthInBlocks;
-  SizeType blockY = block / atlasWidthInBlocks;
+  SizeType blockX = desc.mBlock % atlasWidthInBlocks;
+  SizeType blockY = desc.mBlock / atlasWidthInBlocks;
   SizeType blockOffsetX = ( blockX * atlasBlockWidth ) + 1u;
   SizeType blockOffsetY = ( blockY * atlasBlockHeight) + 1u;
 
@@ -625,18 +330,12 @@ void AtlasManager::GenerateMeshData( ImageId id,
     SizeType width = mImageList[ imageId ].mImageWidth;
     SizeType height = mImageList[ imageId ].mImageHeight;
 
-    SizeType widthInBlocks = width / mAtlasList[ atlas ].mSize.mBlockWidth;
-    if ( width % mAtlasList[ atlas ].mSize.mBlockWidth )
-    {
-      widthInBlocks++;
-    }
-    SizeType heightInBlocks = height / mAtlasList[ atlas ].mSize.mBlockHeight;
-    if ( height % mAtlasList[ atlas ].mSize.mBlockHeight )
-    {
-      heightInBlocks++;
-    }
-
-    CreateMesh( atlas, width, height, position, widthInBlocks, heightInBlocks, meshData, mImageList[ imageId ] );
+    AtlasMeshFactory::CreateQuad( width,
+                                  height,
+                                  mImageList[ imageId ].mBlock,
+                                  mAtlasList[ atlas ].mSize,
+                                  position,
+                                  meshData );
 
     // Mesh created so increase the reference count, if we're asked to
     if ( addReference )
@@ -652,14 +351,13 @@ void AtlasManager::GenerateMeshData( ImageId id,
 
 Dali::Atlas AtlasManager::GetAtlasContainer( AtlasId atlas ) const
 {
-  Dali::Atlas null;
-  if ( !atlas || atlas > mAtlasList.size( ) )
+  DALI_ASSERT_DEBUG( atlas && atlas <= mAtlasList.size() );
+  Dali::Atlas atlasContainer;
+  if ( atlas && atlas-- <= mAtlasList.size() )
   {
-
-    DALI_LOG_ERROR("Cannot get Atlas from AtlasID ( doesn't exist ).\n");
-    return null;
+    atlasContainer = mAtlasList[ atlas ].mAtlas;
   }
-  return mAtlasList[ atlas -1u ].mAtlas;
+  return atlasContainer;
 }
 
 bool AtlasManager::Remove( ImageId id )
@@ -668,7 +366,7 @@ bool AtlasManager::Remove( ImageId id )
   SizeType imageId = id - 1u;
   bool removed = false;
 
-  if ( id > mImageList.size() )
+  if ( id > mImageList.Size() )
      {
     DALI_LOG_ERROR("Atlas was asked to free an invalid imageID: %i\n", id );
     return false;
@@ -687,24 +385,20 @@ bool AtlasManager::Remove( ImageId id )
     removed = true;
     mImageList[ imageId ].mCount = 0;
     SizeType atlas = mImageList[ imageId ].mAtlasId - 1u;
-    for ( uint32_t i = 0; i < mImageList[ imageId ].mBlocksList.Size(); ++i )
-    {
-      mAtlasList[ atlas ].mFreeBlocksList.PushBack( mImageList[ imageId ].mBlocksList[ i ] );
-    }
+    mAtlasList[ atlas ].mFreeBlocksList.PushBack( mImageList[ imageId ].mBlock );
   }
   return removed;
 }
 
 AtlasManager::AtlasId AtlasManager::GetAtlas( ImageId id ) const
 {
-  if ( id && id <= mImageList.size() )
-  {
-    return mImageList[ id - 1u ].mAtlasId;
-  }
-  else
+  DALI_ASSERT_DEBUG( id && id <= mImageList.Size() );
+  AtlasManager::AtlasId atlasId = 0u;
+  if ( id && id-- <= mImageList.Size() )
   {
-    return 0;
+    atlasId = mImageList[ id ].mAtlasId;
   }
+  return atlasId;
 }
 
 void AtlasManager::SetNewAtlasSize( const Toolkit::AtlasManager::AtlasSize& size )
@@ -718,6 +412,7 @@ void AtlasManager::SetNewAtlasSize( const Toolkit::AtlasManager::AtlasSize& size
 
 const Toolkit::AtlasManager::AtlasSize& AtlasManager::GetAtlasSize( AtlasId atlas )
 {
+  DALI_ASSERT_DEBUG( atlas && atlas <= mAtlasList.size() );
   if ( atlas && atlas-- <= mAtlasList.size() )
   {
     return mAtlasList[ atlas ].mSize;
@@ -727,14 +422,13 @@ const Toolkit::AtlasManager::AtlasSize& AtlasManager::GetAtlasSize( AtlasId atla
 
 AtlasManager::SizeType AtlasManager::GetFreeBlocks( AtlasId atlas ) const
 {
+  DALI_ASSERT_DEBUG( atlas && atlas <= mAtlasList.size() );
+  AtlasManager::SizeType freeBlocks = 0u;
   if ( atlas && atlas-- <= mAtlasList.size() )
   {
-    return ( mAtlasList[ atlas ].mAvailableBlocks + mAtlasList[ atlas ].mFreeBlocksList.Size() );
-  }
-  else
-  {
-    return 0;
+    freeBlocks = mAtlasList[ atlas ].mAvailableBlocks + mAtlasList[ atlas ].mFreeBlocksList.Size();
   }
+  return freeBlocks;
 }
 
 AtlasManager::SizeType AtlasManager::GetAtlasCount() const
@@ -744,13 +438,13 @@ AtlasManager::SizeType AtlasManager::GetAtlasCount() const
 
 Pixel::Format AtlasManager::GetPixelFormat( AtlasId atlas )
 {
-  if ( !atlas || atlas > mAtlasList.size( ) )
+  DALI_ASSERT_DEBUG( atlas && atlas <= mAtlasList.size() );
+  Pixel::Format pixelFormat = Pixel::RGBA8888;
+  if ( atlas && atlas-- <= mAtlasList.size() )
   {
-
-    DALI_LOG_ERROR("Cannot get Atlas from AtlasID ( doesn't exist ).\n");
-    return Pixel::L8;
+    pixelFormat = mAtlasList[ atlas ].mPixelFormat;
   }
-  return mAtlasList[ --atlas].mPixelFormat;
+  return pixelFormat;
 }
 
 void AtlasManager::GetMetrics( Toolkit::AtlasManager::Metrics& metrics )
@@ -784,22 +478,22 @@ void AtlasManager::GetMetrics( Toolkit::AtlasManager::Metrics& metrics )
 
 Material AtlasManager::GetMaterial( AtlasId atlas ) const
 {
+  DALI_ASSERT_DEBUG( atlas && atlas <= mAtlasList.size() );
+  Material material;
   if ( atlas && atlas-- <= mAtlasList.size() )
   {
-    return mAtlasList[ atlas ].mMaterial;
+    material = mAtlasList[ atlas ].mMaterial;
   }
-  Material null;
-  return null;
+  return material;
 }
 
-Sampler AtlasManager::GetSampler( AtlasId atlas ) const
+void AtlasManager::SetMaterial( AtlasId atlas, Material& material )
 {
+  DALI_ASSERT_DEBUG( atlas && atlas <= mAtlasList.size() );
   if ( atlas && atlas-- <= mAtlasList.size() )
   {
-    return mAtlasList[ atlas ].mSampler;
+    mAtlasList[ atlas ].mMaterial = material;
   }
-  Sampler null;
-  return null;
 }
 
 } // namespace Internal
@@ -23,7 +23,7 @@
 #include <dali/public-api/object/base-object.h>
 
 // INTERNAL INCLUDES
-#include <dali-toolkit/internal/atlas-manager/atlas-manager.h>
+#include <dali-toolkit/internal/text/rendering/atlas/atlas-manager.h>
 
 namespace Dali
 {
@@ -65,7 +65,6 @@ public:
     BufferImage mHorizontalStrip;                                       // Image used to pad upload
     BufferImage mVerticalStrip;                                         // Image used to pad upload
     Material mMaterial;                                                 // material used for atlas texture
-    Sampler mSampler;                                                   // sampler used for atlas texture
     SizeType mTotalBlocks;                                              // total number of blocks in atlas
     SizeType mAvailableBlocks;                                          // number of blocks available in atlas
     Dali::Vector< SizeType > mFreeBlocksList;                           // unless there are any previously freed blocks
@@ -77,7 +76,7 @@ public:
     SizeType mImageWidth;                                               // Width of image stored
     SizeType mImageHeight;                                              // Height of image stored
     AtlasId mAtlasId;                                                   // Image is stored in this Atlas
-    Dali::Vector< SizeType > mBlocksList;                               // List of blocks within atlas used for image
+    SizeType mBlock;                                                    // Block within atlas used for image
   };
 
   AtlasManager();
@@ -102,7 +101,7 @@ public:
   /**
    * @copydoc Toolkit::AtlasManager::Add
    */
-  void Add( const BufferImage& image,
+  bool Add( const BufferImage& image,
             Toolkit::AtlasManager::AtlasSlot& slot,
             Toolkit::AtlasManager::AtlasId atlas );
 
@@ -115,13 +114,6 @@ public:
                          bool addReference );
 
   /**
-   * @copydoc Toolkit::AtlasManager::StitchMesh
-   */
-  void StitchMesh( Toolkit::AtlasManager::Mesh2D& first,
-                   const Toolkit::AtlasManager::Mesh2D& second,
-                   bool optimize );
-
-  /**
    * @copydoc Toolkit::AtlasManager::Remove
    */
   bool Remove( ImageId id );
@@ -176,44 +168,26 @@ public:
    */
   Material GetMaterial( AtlasId atlas ) const;
 
-/**
-   * @copydoc Toolkit::AtlasManager::GetSampler
+  /**
+   * @copydoc Toolkit::AtlasManager::SetMaterial
    */
-  Sampler GetSampler( AtlasId atlas ) const;
+  void SetMaterial( AtlasId atlas, Material& material );
 
 private:
 
   std::vector< AtlasDescriptor > mAtlasList;            // List of atlases created
-  std::vector< AtlasSlotDescriptor > mImageList;        // List of bitmaps store in atlases
+  Vector< AtlasSlotDescriptor > mImageList;             // List of bitmaps stored in atlases
   Toolkit::AtlasManager::AtlasSize mNewAtlasSize;       // Atlas size to use in next creation
   Toolkit::AtlasManager::AddFailPolicy mAddFailPolicy;  // Policy for faling to add an Image
 
   SizeType CheckAtlas( SizeType atlas,
                        SizeType width,
                        SizeType height,
-                       Pixel::Format pixelFormat,
-                       SizeType& blockArea );
-
-  void CreateMesh( SizeType atlas,
-                   SizeType imageWidth,
-                   SizeType imageHeight,
-                   const Vector2& position,
-                   SizeType widthInBlocks,
-                   SizeType heightInBlocks,
-                   Toolkit::AtlasManager::Mesh2D& mesh,
-                   AtlasSlotDescriptor& desc );
-
-  void OptimizeMesh( const Toolkit::AtlasManager::Mesh2D& in,
-                     Toolkit::AtlasManager::Mesh2D& out );
+                       Pixel::Format pixelFormat );
 
   void UploadImage( const BufferImage& image,
                     const AtlasSlotDescriptor& desc );
 
-  void PrintMeshData( const Toolkit::AtlasManager::Mesh2D& mesh );
-
-  Shader mShaderL8;
-  Shader mShaderRgba;
-
 };
 
 } // namespace Internal
  */
 
 // CLASS HEADER
-#include <dali-toolkit/internal/atlas-manager/atlas-manager.h>
+#include <dali-toolkit/internal/text/rendering/atlas/atlas-manager.h>
 
- // INTERNAL INCLUDES
-#include <dali-toolkit/internal/atlas-manager/atlas-manager-impl.h>
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/rendering/atlas/atlas-manager-impl.h>
 
 namespace Dali
 {
@@ -55,11 +55,11 @@ void AtlasManager::SetAddPolicy( AddFailPolicy policy )
   GetImplementation(*this).SetAddPolicy( policy );
 }
 
-void AtlasManager::Add( const BufferImage& image,
+bool AtlasManager::Add( const BufferImage& image,
                         AtlasManager::AtlasSlot& slot,
                         AtlasManager::AtlasId atlas )
 {
-  GetImplementation(*this).Add( image, slot, atlas );
+  return GetImplementation(*this).Add( image, slot, atlas );
 }
 
 bool AtlasManager::Remove( ImageId id )
@@ -78,13 +78,6 @@ void AtlasManager::GenerateMeshData( ImageId id,
                                              addReference );
 }
 
-void AtlasManager::StitchMesh( Mesh2D& first,
-                               const Mesh2D& second,
-                               bool optimize )
-{
-  GetImplementation(*this).StitchMesh( first, second, optimize );
-}
-
 Dali::Atlas AtlasManager::GetAtlasContainer( AtlasId atlas ) const
 {
   return GetImplementation(*this).GetAtlasContainer( atlas );
@@ -130,9 +123,9 @@ Material AtlasManager::GetMaterial( AtlasId atlas ) const
   return GetImplementation(*this).GetMaterial( atlas );
 }
 
-Sampler AtlasManager::GetSampler( AtlasId atlas ) const
+void AtlasManager::SetMaterial( AtlasId atlas, Material& material )
 {
-  return GetImplementation(*this).GetSampler( atlas );
+  GetImplementation(*this).SetMaterial( atlas, material );
 }
 
 } // namespace Toolkit
@@ -37,120 +37,6 @@ class AtlasManager;
 
 } // namespace Internal
 
-/**
- * AtlasManager
- * ------------
- *
- * Creates and manages additions and removals of images from Texture Atlases
- *
- * The AtlasManager will match pixeltype and optimal block use to determine
- * the appropriate atlas to upload an image to.
- *
- * A policy can be specified to determine the action the AtlasManager will carry
- * out, should it not be able to add an image. This can return an error, or create
- * a new atlas of pre-determined dimensions to accomodate the new image.
- *
- * Images are referenced by an ImageId once they have been successfully uploaded.
- *
- * Once an image has been successfully uploaded, Geometry can be generated by passing
- * the ImageId to the GenerateMeshData method and geometry can be consolidated via
- * the StitchMesh method.
- *
- * Images are reference counted once mesh data has been generated. An image is removed
- * from the Atlas via the Remove( ImageId ) method. This unreferences the image and only
- * physically removes it from the atlas once all references have been freed.
- *
- * If the AddPolicy is set to generate and error if an image can't be uploaded, then it
- * is the applications responsibility to deal with the situation. An error will be indicated
- * with an ImageId of 0.
- *
- * Examples using the AtlasManager
- *
- * Create or obtain the AtlasManager
- * @code
- *
- * AtlasManager manager = AtlasManager::Get();
- *
- * @endcode
- *
- * Set the AtlasManager AddPolicy
- *
- * @code
- *
- * // Tell the atlas manager to create a new atlas, if it needs to
- * manager.SetAddPolicy( FAIL_ON_ADD_CREATES );
- *
- * // Tell the atlas manager to return an error, if it can't add an image
- * manager.SetAddPolicy( FAIL_ON_ADD_FAILS );
- *
- * @endcode
- *
- * Simple add and removal of BufferImage to and from an atlas
- *
- * @code
- *
- * // Structure returned by AtlasManager operations
- * AtlasSlot slot;
- *
- * // Add image to an atlas ( will be created if none suitable exists )
- * manager.Add( bitmapImage, slot );
- *
- * // slot.mImage returns the imageId for the bitmap, slot.mAtlas indicates the atlasId
- * // that the image was added to. The imageId is used to communicate with the AtlasManager
- * uint32_t imageId = slot.mImage;
- * if ( !imageId )
- * {
- *  // Addition has failed.....
- * }
- * ...
- * ...
- * // Done with image, so remove from atlas, if not being used elsewhere
- * manager.Remove( imageId );
- *
- * @endcode
- *
- * Create a Specific Atlas for adding BufferImages to
- *
- * @code
- *
- * // Create an RGB888 atlas of 2048x2848, with a blocksize of 128x128
- * uint32_t atlas = manager.CreateAtlas( 2048u, 2048u, 128u, 128u, Pixel::RGB888 );
- *
- * // Add an image to a preferred atlas ( note not specifying atlas may still result
- * // in the bitmap being added to the atlas above )
- * manager.Add( bitmapImage, slot, atlas );
- *
- * @endcode
- *
- * Create Geometry for a previously added image
- *
- * @code
- *
- * // Top left corner of geometry to be generated
- * Vector2 position( 1.0f, 1.0f );
- *
- * // Geometry will end up here!
- * MeshData meshData;
- * manager.GenerateMeshData( imageId, position, meshData );
- *
- * @endcode
- *
- * Generating Geometry from multiple images in the same atlas
- *
- * @code
- *
- * MeshData firstMesh;
- * MeshData secondMesh;
- * manager.GenerateMeshData( imageid_1, position_1, firstMesh );
- * manager.GenerateMeshData( imageid_2, position_2, secondMesh );
- *
- * // Combine the two meshes. Passing MESH_OPTIMIZE as an optional third parameter will remove duplicate vertices
- * manager.StitchMesh( first, second );
- *
- * @endcode
- *
- */
-
 class AtlasManager : public BaseHandle
 {
 public:
@@ -158,7 +44,6 @@ public:
   typedef uint32_t SizeType;
   typedef SizeType AtlasId;
   typedef SizeType ImageId;
-  static const bool MESH_OPTIMIZE = true;
 
   struct AtlasSize
   {
@@ -197,14 +82,14 @@ public:
 
   struct Vertex2D
   {
-    Vector2 mPosition;
-    Vector2 mTexCoords;
+    Vector2 mPosition;        ///< Vertex posiiton
+    Vector2 mTexCoords;       ///< Vertex texture co-ordinates
   };
 
   struct Mesh2D
   {
-    Vector< Vertex2D > mVertices;
-    Vector< unsigned int> mIndices;
+    Vector< Vertex2D > mVertices;       ///< container of vertices
+    Vector< SizeType > mIndices;        ///< container of indices
   };
 
   /**
@@ -274,8 +159,10 @@ public:
    * @param[in] image reference to a bitmapimage
    * @param[out] slot result of add operation
    * @param[in] atlas optional preferred atlas
+   *
+   * @return true if a new atlas was created
    */
-  void Add( const BufferImage& image,
+  bool Add( const BufferImage& image,
             AtlasSlot& slot,
             AtlasId atlas = 0 );
 
@@ -302,17 +189,6 @@ public:
                          bool addReference = true );
 
   /**
-   * @brief Append second mesh to the first mesh
-   *
-   * @param[in] first First mesh
-   * @param[in] second Second mesh
-   * @param[in] optimize should we optimize vertex data
-   */
-  void StitchMesh( Mesh2D& first,
-                   const Mesh2D& second,
-                   bool optimize = false );
-
-  /**
    * @brief Get the BufferImage containing an atlas
    *
    * @param[in] atlas AtlasId returned when atlas was created
@@ -382,20 +258,20 @@ public:
   /**
    * @brief Get Material used by atlas
    *
-   * @param atlas[in] atlas AtlasId
+   * @param[in] atlas AtlasId
    *
    * @return Material used by atlas
    */
   Material GetMaterial( AtlasId atlas ) const;
 
- /**
-   * @brief Get Sampler used by atlas
-   *
-   * @param atlas[in] atlas AtlasId
+  /**
+   * @brief Set the material used by an atlas
    *
-   * @return Sampler used by atlas
+   * @param[in] atlas AtlasId
+   * @param[in] material The Material to assign
    */
-  Sampler GetSampler( AtlasId atlas ) const;
+  void SetMaterial( AtlasId atlas, Material& material );
+
 private:
 
   explicit DALI_INTERNAL AtlasManager(Internal::AtlasManager *impl);
diff --git a/dali-toolkit/internal/text/rendering/atlas/atlas-mesh-factory.cpp b/dali-toolkit/internal/text/rendering/atlas/atlas-mesh-factory.cpp
new file mode 100644 (file)
index 0000000..3a64c96
--- /dev/null
@@ -0,0 +1,166 @@
+ /*
+ * Copyright (c) 2015 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 <dali-toolkit/internal/text/rendering/atlas/atlas-mesh-factory.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace AtlasMeshFactory
+{
+
+void CreateQuad( SizeType imageWidth,
+                 SizeType imageHeight,
+                 SizeType block,
+                 const Toolkit::AtlasManager::AtlasSize& atlasSize,
+                 const Vector2& position,
+                 Toolkit::AtlasManager::Mesh2D& mesh )
+{
+  Toolkit::AtlasManager::Vertex2D vertex;
+
+  SizeType blockWidth = atlasSize.mBlockWidth;
+  SizeType blockHeight = atlasSize.mBlockHeight;
+
+  float vertexBlockWidth = static_cast< float >( blockWidth );
+  float vertexBlockHeight = static_cast< float >( blockHeight );
+
+  SizeType atlasWidth = atlasSize.mWidth;
+  SizeType atlasHeight = atlasSize.mHeight;
+
+  SizeType atlasWidthInBlocks = ( atlasWidth - 1u ) / blockWidth;
+
+  // Get the normalized size of a texel in both directions
+  float texelX = 1.0f / static_cast< float >( atlasWidth );
+  float texelY = 1.0f / static_cast< float >( atlasHeight );
+
+  float oneAndAHalfTexelX = texelX + ( texelX * 0.5f );
+  float oneAndAHalfTexelY = texelY + ( texelY * 0.5f );
+
+  float texelBlockWidth = texelX * vertexBlockWidth;
+  float texelBlockHeight = texelY * vertexBlockHeight;
+
+  uint32_t pixelsX = imageWidth % blockWidth;
+  uint32_t pixelsY = imageHeight % blockHeight;
+
+  if ( !pixelsX )
+  {
+    pixelsX = blockWidth;
+  }
+  if ( !pixelsY )
+  {
+    pixelsY = blockHeight;
+  }
+  float vertexWidth = static_cast< float >( pixelsX );
+  float vertexHeight = static_cast< float >( pixelsY );
+  float texelWidth = texelX * vertexWidth;
+  float texelHeight = texelY * vertexHeight;
+
+  // We're going to 'blit' half a pixel more on each edge
+  vertexWidth++;
+  vertexHeight++;
+
+  // Move back half a pixel
+  Vector2 topLeft = Vector2( position.x - 0.5f, position.y - 0.5f );
+
+  float fBlockX = texelBlockWidth * static_cast< float >( block % atlasWidthInBlocks );
+  float fBlockY = texelBlockHeight * static_cast< float >( block / atlasWidthInBlocks );
+
+  // Add on texture filtering compensation ( half a texel plus compensation for filled pixel in top left corner )
+  fBlockX += oneAndAHalfTexelX;
+  fBlockY += oneAndAHalfTexelY;
+
+  float texelWidthOffset = texelWidth + texelX;
+  float texelHeightOffset = texelHeight + texelY;
+
+  // Top left
+  vertex.mPosition.x = topLeft.x;
+  vertex.mPosition.y = topLeft.y;
+  vertex.mTexCoords.x = fBlockX;
+  vertex.mTexCoords.y = fBlockY;
+
+  mesh.mVertices.Reserve( 4u );
+  mesh.mVertices.PushBack( vertex );
+
+  // Top Right
+  vertex.mPosition.x = topLeft.x + vertexWidth;
+  vertex.mPosition.y = topLeft.y;
+  vertex.mTexCoords.x = fBlockX + texelWidthOffset;
+  vertex.mTexCoords.y = fBlockY;
+
+  mesh.mVertices.PushBack( vertex );
+
+  // Bottom Left
+  vertex.mPosition.x = topLeft.x;
+  vertex.mPosition.y = topLeft.y + vertexHeight;
+  vertex.mTexCoords.x = fBlockX;
+  vertex.mTexCoords.y = fBlockY + texelHeightOffset;
+
+  mesh.mVertices.PushBack( vertex );
+
+  // Bottom Right
+  vertex.mPosition.x = topLeft.x + vertexWidth;
+  vertex.mPosition.y = topLeft.y + vertexHeight;
+  vertex.mTexCoords.x = fBlockX + texelWidthOffset;
+  vertex.mTexCoords.y = fBlockY + texelHeightOffset;
+
+  mesh.mVertices.PushBack( vertex );
+
+  // Six indices in counter clockwise winding
+  mesh.mIndices.Reserve( 6u );
+  mesh.mIndices.PushBack( 1u );
+  mesh.mIndices.PushBack( 0u );
+  mesh.mIndices.PushBack( 2u );
+  mesh.mIndices.PushBack( 2u );
+  mesh.mIndices.PushBack( 3u );
+  mesh.mIndices.PushBack( 1u );
+}
+
+void AppendMesh( Toolkit::AtlasManager::Mesh2D& first,
+                 const Toolkit::AtlasManager::Mesh2D& second )
+{
+  const uint32_t verticesCount = first.mVertices.Size();
+  first.mVertices.Insert( first.mVertices.End(),
+                          second.mVertices.Begin(),
+                          second.mVertices.End() );
+
+  const uint32_t indicesCount = first.mIndices.Size();
+  first.mIndices.Insert( first.mIndices.End(),
+                         second.mIndices.Begin(),
+                         second.mIndices.End() );
+
+  for( Vector<unsigned int>::Iterator it = first.mIndices.Begin() + indicesCount,
+         endIt = first.mIndices.End();
+       it != endIt;
+       ++it )
+  {
+    *it += verticesCount;
+  }
+}
+
+} // namespace AtlasMeshFactory
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/rendering/atlas/atlas-mesh-factory.h b/dali-toolkit/internal/text/rendering/atlas/atlas-mesh-factory.h
new file mode 100644 (file)
index 0000000..f3a953c
--- /dev/null
@@ -0,0 +1,70 @@
+#ifndef __DALI_TOOLKIT_ATLAS_MESH_FACTORY_H__
+#define __DALI_TOOLKIT_ATLAS_MESH_FACTORY_H__
+
+/*
+ * Copyright (c) 2015 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.
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/rendering/atlas/atlas-manager.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace AtlasMeshFactory
+{
+  typedef uint32_t SizeType;
+
+  /**
+   * @brief Create a Quad that describes an area in an atlas and a position.
+   *
+   * @param[in]  width Width of area in pixels.
+   * @param[in]  height Height of area in pixels.
+   * @param[in]  block Block position in atlas.
+   * @param[in]  atlasSize Atlas and block dimensions.
+   * @param[in]  position Position to place area in space.
+   * @param[out] mesh Mesh object to hold created quad.
+   */
+  void CreateQuad( SizeType width,
+                   SizeType height,
+                   SizeType block,
+                   const Toolkit::AtlasManager::AtlasSize& atlasSize,
+                   const Vector2& position,
+                   Toolkit::AtlasManager::Mesh2D& mesh );
+
+  /**
+   * @brief Append one mesh to another.
+   *
+   * @param[in,out] first Mesh to append to.
+   * @param[in]     second Mesh to append.
+   */
+  void AppendMesh( Toolkit::AtlasManager::Mesh2D& first,
+                   const Toolkit::AtlasManager::Mesh2D& second );
+
+} // namespace AtlasMeshFactory
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // __DALI_TOOLKIT_ATLAS_MESH_FACTORY_H__
index 7c629fd..8653b43 100644 (file)
 
 // EXTERNAL INCLUDES
 #include <dali/integration-api/debug.h>
-#include <dali/public-api/common/stage.h>
-#include <dali/public-api/images/frame-buffer-image.h>
-#include <dali/public-api/render-tasks/render-task.h>
-#include <dali/public-api/render-tasks/render-task-list.h>
 #include <dali/devel-api/rendering/renderer.h>
 #include <dali/devel-api/rendering/geometry.h>
 #include <dali/devel-api/text-abstraction/font-client.h>
@@ -32,6 +28,7 @@
 #include <dali-toolkit/public-api/controls/control-depth-index-ranges.h>
 #include <dali-toolkit/internal/text/glyph-run.h>
 #include <dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h>
+#include <dali-toolkit/internal/text/rendering/atlas/atlas-mesh-factory.h>
 #include <dali-toolkit/internal/text/text-view.h>
 
 using namespace Dali;
@@ -47,11 +44,11 @@ namespace
 const float ZERO( 0.0f );
 const float HALF( 0.5f );
 const float ONE( 1.0f );
-const float TWO( 2.0f );
 const uint32_t DEFAULT_ATLAS_WIDTH = 512u;
 const uint32_t DEFAULT_ATLAS_HEIGHT = 512u;
 }
-struct AtlasRenderer::Impl : public ConnectionTracker
+
+struct AtlasRenderer::Impl
 {
   enum Style
   {
@@ -151,9 +148,6 @@ struct AtlasRenderer::Impl : public ConnectionTracker
   bool IsGlyphUnderlined( GlyphIndex index,
                           const Vector<GlyphRun>& underlineRuns )
   {
-    // TODO: At the moment it works because we always traverse the glyphs starting from the beginning
-    //       and there is only one glyph run! If there are more they should be ordered.
-
     for( Vector<GlyphRun>::ConstIterator it = underlineRuns.Begin(),
            endIt = underlineRuns.End();
            it != endIt;
@@ -267,7 +261,7 @@ struct AtlasRenderer::Impl : public ConnectionTracker
           lastUnderlinedFontId = glyph.fontId;
         } // underline
 
-        if ( !mGlyphManager.Cached( glyph.fontId, glyph.index, slot ) )
+        if ( !mGlyphManager.IsCached( glyph.fontId, glyph.index, slot ) )
         {
           // Select correct size for new atlas if needed....?
           if ( lastFontId != glyph.fontId )
@@ -358,7 +352,6 @@ struct AtlasRenderer::Impl : public ConnectionTracker
     // Now remove references for the old text
     RemoveText();
     mTextCache.Swap( newTextCache );
-    RemoveAllShadowRenderTasks();
 
     if( thereAreUnderlinedGlyphs )
     {
@@ -376,9 +369,33 @@ struct AtlasRenderer::Impl : public ConnectionTracker
         // Create an effect if necessary
         if ( style == STYLE_DROP_SHADOW )
         {
-          Actor shadowActor = GenerateShadow( *mIt, actorSize, shadowOffset, shadowColor );
-          shadowActor.Add( actor );
-          actor = shadowActor;
+          // Create a container actor to act as a common parent for text and shadow, to avoid color inheritence issues.
+          Actor containerActor = Actor::New();
+          containerActor.SetParentOrigin( ParentOrigin::CENTER );
+          containerActor.SetSize( actorSize );
+
+          Actor shadowActor = Actor::New();
+#if defined(DEBUG_ENABLED)
+          shadowActor.SetName( "Text Shadow renderable actor" );
+#endif
+          // Offset shadow in x and y
+          shadowActor.RegisterProperty("uOffset", shadowOffset );
+          if ( actor.GetRendererCount() )
+          {
+            Dali::Renderer renderer( actor.GetRendererAt( 0 ) );
+            Geometry geometry = renderer.GetGeometry();
+            Material material = renderer.GetMaterial();
+
+            Dali::Renderer shadowRenderer = Dali::Renderer::New( geometry, material );
+            shadowRenderer.SetDepthIndex( renderer.GetDepthIndex() - 1 );
+            shadowActor.AddRenderer( shadowRenderer );
+            shadowActor.SetParentOrigin( ParentOrigin::CENTER );
+            shadowActor.SetSize( actorSize );
+            shadowActor.SetColor( shadowColor );
+            containerActor.Add( shadowActor );
+            containerActor.Add( actor );
+            actor = containerActor;
+          }
         }
 
         if( mActor )
@@ -446,6 +463,7 @@ struct AtlasRenderer::Impl : public ConnectionTracker
     actor.SetParentOrigin( ParentOrigin::CENTER ); // Keep all of the origins aligned
     actor.SetSize( actorSize );
     actor.SetColor( meshRecord.mColor );
+    actor.RegisterProperty("uOffset", Vector2::ZERO );
     return actor;
   }
 
@@ -473,8 +491,8 @@ struct AtlasRenderer::Impl : public ConnectionTracker
       {
         if ( slot.mAtlasId == mIt->mAtlasId && color == mIt->mColor )
         {
-          // Stitch the mesh to the existing mesh and adjust any extents
-          mGlyphManager.StitchMesh( mIt->mMesh, newMesh );
+          // Append the mesh to the existing mesh and adjust any extents
+          Toolkit::Internal::AtlasMeshFactory::AppendMesh( mIt->mMesh, newMesh );
 
           if( underlineGlyph )
           {
@@ -647,7 +665,7 @@ struct AtlasRenderer::Impl : public ConnectionTracker
 
       if ( underlineColor == textColor )
       {
-        mGlyphManager.StitchMesh( meshRecords[ index ].mMesh, newMesh );
+        Toolkit::Internal::AtlasMeshFactory::AppendMesh( meshRecords[ index ].mMesh, newMesh );
       }
       else
       {
@@ -660,171 +678,14 @@ struct AtlasRenderer::Impl : public ConnectionTracker
     }
   }
 
-  Actor GenerateShadow( MeshRecord& meshRecord,
-                        const Vector2& actorSize,
-                        const Vector2& shadowOffset,
-                        const Vector4& shadowColor )
-  {
-    // Scan vertex buffer to determine width and height of effect buffer needed
-    const Vector< AtlasManager::Vertex2D >& verts = meshRecord.mMesh.mVertices;
-    float tlx = verts[ 0 ].mPosition.x;
-    float tly = verts[ 0 ].mPosition.y;
-    float brx = ZERO;
-    float bry = ZERO;
-
-    for ( uint32_t i = 0; i < verts.Size(); ++i )
-    {
-      if ( verts[ i ].mPosition.x < tlx )
-      {
-        tlx = verts[ i ].mPosition.x;
-      }
-      if ( verts[ i ].mPosition.y < tly )
-      {
-        tly = verts[ i ].mPosition.y;
-      }
-      if ( verts[ i ].mPosition.x > brx )
-      {
-        brx = verts[ i ].mPosition.x;
-      }
-      if ( verts[ i ].mPosition.y > bry )
-      {
-        bry = verts[ i ].mPosition.y;
-      }
-    }
-
-    float width = brx - tlx;
-    float height = bry - tly;
-    float divWidth = TWO / width;
-    float divHeight = TWO / height;
-
-    // Create a buffer to render to
-    meshRecord.mBuffer = FrameBufferImage::New( width, height );
-
-    // We will render a quad into this buffer
-    unsigned int indices[ 6 ] = { 1, 0, 2, 2, 3, 1 };
-    PropertyBuffer quadVertices = PropertyBuffer::New( mQuadVertexFormat, 4u );
-    PropertyBuffer quadIndices = PropertyBuffer::New( mQuadIndexFormat, sizeof(indices)/sizeof(indices[0]) );
-
-    AtlasManager::Vertex2D vertices[ 4 ] = {
-    { Vector2( tlx + shadowOffset.x, tly + shadowOffset.y ), Vector2( ZERO, ZERO ) },
-    { Vector2( brx + shadowOffset.x, tly + shadowOffset.y ), Vector2( ONE, ZERO ) },
-    { Vector2( tlx + shadowOffset.x, bry + shadowOffset.y ), Vector2( ZERO, ONE ) },
-    { Vector2( brx + shadowOffset.x, bry + shadowOffset.y ), Vector2( ONE, ONE ) } };
-
-    quadVertices.SetData( vertices );
-    quadIndices.SetData( indices );
-
-    Geometry quadGeometry = Geometry::New();
-    quadGeometry.AddVertexBuffer( quadVertices );
-    quadGeometry.SetIndexBuffer( quadIndices );
-
-    Sampler sampler = Sampler::New( meshRecord.mBuffer, "sTexture" );
-    Material material = Material::New( mGlyphManager.GetEffectBufferShader() );
-    material.AddSampler( sampler );
-
-    Dali::Renderer renderer = Dali::Renderer::New( quadGeometry, material );
-
-    // Set depth index to -1.0 to make sure shadow is rendered first in 3D layers
-    renderer.SetDepthIndex( -1.0f );
-    Actor actor = Actor::New();
-    actor.AddRenderer( renderer );
-    actor.SetParentOrigin( ParentOrigin::CENTER ); // Keep all of the origins aligned
-    actor.SetSize( actorSize );
-
-    // Create a sub actor to render the source with normalized vertex positions
-    Vector< AtlasManager::Vertex2D > normVertexList;
-    for ( uint32_t i = 0; i < verts.Size(); ++i )
-    {
-      AtlasManager::Vertex2D vertex = verts[ i ];
-      vertex.mPosition.x = ( ( vertex.mPosition.x - tlx ) * divWidth ) - ONE;
-      vertex.mPosition.y = ( ( vertex.mPosition.y - tly ) * divHeight ) - ONE;
-      normVertexList.PushBack( vertex );
-    }
-
-    PropertyBuffer normVertices = PropertyBuffer::New( mQuadVertexFormat, normVertexList.Size() );
-    PropertyBuffer normIndices = PropertyBuffer::New( mQuadIndexFormat, meshRecord.mMesh.mIndices.Size() );
-    normVertices.SetData( const_cast< AtlasManager::Vertex2D* >( &normVertexList[ 0 ] ) );
-    normIndices.SetData( const_cast< unsigned int* >( &meshRecord.mMesh.mIndices[ 0 ] ) );
-
-    Geometry normGeometry = Geometry::New();
-    normGeometry.AddVertexBuffer( normVertices );
-    normGeometry.SetIndexBuffer( normIndices );
-
-    Material normMaterial = Material::New( mGlyphManager.GetGlyphShadowShader() );
-    Sampler normSampler =  mGlyphManager.GetSampler( meshRecord.mAtlasId );
-    normMaterial.AddSampler( normSampler );
-    Dali::Renderer normRenderer = Dali::Renderer::New( normGeometry, normMaterial );
-    Actor subActor = Actor::New();
-    subActor.AddRenderer( normRenderer );
-    subActor.SetParentOrigin( ParentOrigin::CENTER ); // Keep all of the origins aligned
-    subActor.SetSize( actorSize );
-    subActor.SetColor( shadowColor );
-
-    // Create a render task to render the effect
-    RenderTask shadowTask = Stage::GetCurrent().GetRenderTaskList().CreateTask();
-    shadowTask.SetTargetFrameBuffer( meshRecord.mBuffer );
-    shadowTask.SetSourceActor( subActor );
-    shadowTask.SetClearEnabled( true );
-    shadowTask.SetClearColor( Vector4::ZERO );
-    shadowTask.SetExclusive( true );
-    shadowTask.SetRefreshRate( RenderTask::REFRESH_ONCE );
-    shadowTask.FinishedSignal().Connect( this, &AtlasRenderer::Impl::RenderComplete );
-    mShadowTasks.push_back( shadowTask );
-    actor.Add( subActor );
-
-    return actor;
-  }
-
-  void RemoveShadowRenderTask( RenderTask renderTask )
-  {
-    if( renderTask )
-    {
-      renderTask.FinishedSignal().Disconnect( this, &AtlasRenderer::Impl::RenderComplete );
-
-      // Guard to prevent accessing Stage after dali-core destruction
-      if( Stage::IsInstalled() )
-      {
-        Stage::GetCurrent().GetRenderTaskList().RemoveTask( renderTask );
-      }
-      renderTask.Reset();
-    }
-  }
-
-  void RenderComplete( RenderTask& renderTask )
-  {
-    // Get the actor used for render to buffer and remove it from the parent
-    Actor renderActor = renderTask.GetSourceActor();
-    if ( renderActor )
-    {
-      Actor parent = renderActor.GetParent();
-      if ( parent )
-      {
-        parent.Remove( renderActor );
-      }
-    }
-
-    RemoveShadowRenderTask( renderTask );
-  }
-
-  void RemoveAllShadowRenderTasks()
-  {
-    for ( std::vector< RenderTask >::iterator shadowIterator = mShadowTasks.begin();
-          shadowIterator != mShadowTasks.end(); ++shadowIterator )
-    {
-      RemoveShadowRenderTask( *shadowIterator );
-    }
-  }
-
   Actor mActor;                                       ///< The actor parent which renders the text
   AtlasGlyphManager mGlyphManager;                    ///< Glyph Manager to handle upload and caching
-  std::vector< RenderTask > mShadowTasks;             ///< Used to render shadows
   TextAbstraction::FontClient mFontClient;            ///> The font client used to supply glyph information
   std::vector< MaxBlockSize > mBlockSizes;            ///> Maximum size needed to contain a glyph in a block within a new atlas
-  std::vector< uint32_t > mFace;                      ///> Face indices for a quad
-  Vector< TextCacheEntry > mTextCache;
-  Property::Map mQuadVertexFormat;
-  Property::Map mQuadIndexFormat;
-  int mDepth;
+  Vector< TextCacheEntry > mTextCache;                ///> Caches data from previous render
+  Property::Map mQuadVertexFormat;                    ///> Describes the vertex format for text
+  Property::Map mQuadIndexFormat;                     ///> Describes the index format for text
+  int mDepth;                                         ///> DepthIndex passed by control when connect to stage
 };
 
 Text::RendererPtr AtlasRenderer::New()
@@ -872,8 +733,6 @@ AtlasRenderer::AtlasRenderer()
 
 AtlasRenderer::~AtlasRenderer()
 {
-  mImpl->RemoveAllShadowRenderTasks();
-
   mImpl->RemoveText();
   delete mImpl;
 }
index e6a8b18..b1c0b14 100644 (file)
@@ -1438,7 +1438,6 @@ CharacterIndex Controller::Impl::GetClosestCursorIndex( float visualX,
 
   // Get the glyphs per character table.
   const Length* const glyphsPerCharacterBuffer = mVisualModel->mGlyphsPerCharacter.Begin();
-  const Length* const charactersPerGlyphBuffer = mVisualModel->mCharactersPerGlyph.Begin();
 
   // If the vector is void, there is no right to left characters.
   const bool hasRightToLeftCharacters = NULL != visualToLogicalBuffer;
@@ -1452,6 +1451,7 @@ CharacterIndex Controller::Impl::GetClosestCursorIndex( float visualX,
 
   // Traverses glyphs in visual order. To do that use the visual to logical conversion table.
   CharacterIndex visualIndex = startCharacter;
+  Length numberOfCharacters = 0u;
   for( ; !matched && ( visualIndex < endCharacter ); ++visualIndex )
   {
     // The character in logical order.
@@ -1460,44 +1460,59 @@ CharacterIndex Controller::Impl::GetClosestCursorIndex( float visualX,
     // Get the script of the character.
     const Script script = mLogicalModel->GetScript( characterLogicalOrderIndex );
 
-    // The first glyph for that character in logical order.
-    const GlyphIndex glyphLogicalOrderIndex = *( charactersToGlyphBuffer + characterLogicalOrderIndex );
     // The number of glyphs for that character
     const Length numberOfGlyphs = *( glyphsPerCharacterBuffer + characterLogicalOrderIndex );
+    ++numberOfCharacters;
 
-    // Get the metrics for the group of glyphs.
-    GlyphMetrics glyphMetrics;
-    GetGlyphsMetrics( glyphLogicalOrderIndex,
-                      numberOfGlyphs,
-                      glyphMetrics,
-                      mVisualModel,
-                      mMetrics );
 
-    const Vector2& position = *( positionsBuffer + glyphLogicalOrderIndex );
+    if( 0u != numberOfGlyphs )
+    {
+      // Get the first character/glyph of the group of glyphs.
+      const CharacterIndex firstVisualCharacterIndex = 1u + visualIndex - numberOfCharacters;
+      const CharacterIndex firstLogicalCharacterIndex = hasRightToLeftCharacters ? *( visualToLogicalBuffer + firstVisualCharacterIndex ) : firstVisualCharacterIndex;
+      const GlyphIndex firstLogicalGlyphIndex = *( charactersToGlyphBuffer + firstLogicalCharacterIndex );
 
-    // Prevents to jump the whole Latin ligatures like fi, ff, or Arabic ï»»...
-    const Length numberOfCharactersInLigature = HasLigatureMustBreak( script ) ? *( charactersPerGlyphBuffer + glyphLogicalOrderIndex ) : 1u;
-    const float glyphAdvance = glyphMetrics.advance / static_cast<float>( numberOfCharactersInLigature );
+      // Get the metrics for the group of glyphs.
+      GlyphMetrics glyphMetrics;
+      GetGlyphsMetrics( firstLogicalGlyphIndex,
+                        numberOfGlyphs,
+                        glyphMetrics,
+                        mVisualModel,
+                        mMetrics );
 
-    for( GlyphIndex index = 0u; !matched && ( index < numberOfCharactersInLigature ); ++index )
-    {
-      // Find the mid-point of the area containing the glyph
-      const float glyphCenter = -glyphMetrics.xBearing + position.x + ( static_cast<float>( index ) + 0.5f ) * glyphAdvance;
+      // Get the position of the first glyph.
+      const Vector2& position = *( positionsBuffer + firstLogicalGlyphIndex );
+
+      // Whether the glyph can be split, like Latin ligatures fi, ff or Arabic ï»». 
+      const bool isInterglyphIndex = ( numberOfCharacters > numberOfGlyphs ) && HasLigatureMustBreak( script );
+      const Length numberOfBlocks = isInterglyphIndex ? numberOfCharacters : 1u;
+      const float glyphAdvance = glyphMetrics.advance / static_cast<float>( numberOfBlocks );
+
+      GlyphIndex index = 0u;
+      for( ; !matched && ( index < numberOfBlocks ); ++index )
+      {
+        // Find the mid-point of the area containing the glyph
+        const float glyphCenter = -glyphMetrics.xBearing + position.x + ( static_cast<float>( index ) + 0.5f ) * glyphAdvance;
 
-      if( visualX < glyphCenter )
+        if( visualX < glyphCenter )
+        {
+          matched = true;
+          break;
+        }
+      }
+
+      if( matched )
       {
-        visualIndex += index;
-        matched = true;
+        visualIndex = firstVisualCharacterIndex + index;
         break;
       }
-    }
 
-    if( matched )
-    {
-      break;
+      numberOfCharacters = 0u;
     }
+
   }
 
+
   // Return the logical position of the cursor in characters.
 
   if( !matched )
index 07cb7fe..e990d42 100644 (file)
@@ -1709,12 +1709,21 @@ void Controller::PasteText( const std::string& stringToPaste )
   InsertText( stringToPaste, Text::Controller::COMMIT );
   mImpl->ChangeState( EventData::EDITING );
   mImpl->RequestRelayout();
+
+  // Do this last since it provides callbacks into application code
+  mImpl->mControlInterface.TextChanged();
 }
 
 void Controller::PasteClipboardItemEvent()
 {
+  // Retrieve the clipboard contents first
   ClipboardEventNotifier notifier( ClipboardEventNotifier::Get() );
   std::string stringToPaste( notifier.GetContent() );
+
+  // Commit the current pre-edit text; the contents of the clipboard should be appended
+  mImpl->ResetImfManager();
+
+  // Paste
   PasteText( stringToPaste );
 }
 
index 795e9cf..b3b265f 100644 (file)
@@ -31,7 +31,7 @@ namespace Toolkit
 
 const unsigned int TOOLKIT_MAJOR_VERSION = 1;
 const unsigned int TOOLKIT_MINOR_VERSION = 1;
-const unsigned int TOOLKIT_MICRO_VERSION = 6;
+const unsigned int TOOLKIT_MICRO_VERSION = 7;
 const char * const TOOLKIT_BUILD_DATE    = __DATE__ " " __TIME__;
 
 #ifdef DEBUG_ENABLED
index dc32fbd..3484c8c 100644 (file)
@@ -117,7 +117,15 @@ distributing this software or its derivatives.
     },
     "scrollview":
     {
-      "overshoot-effect-color":"B018"
+      "overshoot-effect-color":"B018",
+      "overshoot-animation-speed":120.0,
+      "overshoot-size":[480.0,42.0]
+    },
+    "itemview":
+    {
+      "overshoot-effect-color":"B018",
+      "overshoot-animation-speed":120.0,
+      "overshoot-size":[480.0,42.0]
     }
   }
 }
index 7501b72..0c20938 100644 (file)
@@ -117,7 +117,15 @@ distributing this software or its derivatives.
     },
     "scrollview":
     {
-      "overshoot-effect-color":"B018"
+      "overshoot-effect-color":"B018",
+      "overshoot-animation-speed":360.0,
+      "overshoot-size":[720.0,130.0]
+    },
+    "itemview":
+    {
+      "overshoot-effect-color":"B018",
+      "overshoot-animation-speed":360.0,
+      "overshoot-size":[720.0,130.0]
     }
   }
 }
diff --git a/dali-toolkit/styles/images-common/broken.png b/dali-toolkit/styles/images-common/broken.png
new file mode 100644 (file)
index 0000000..2d1c272
Binary files /dev/null and b/dali-toolkit/styles/images-common/broken.png differ
index f1949ca..d6c197f 100644 (file)
@@ -57,6 +57,6 @@ Each style selector can have resource folders associated with it.
 
 Images for that style should be in their own folder named images.
 
-Common images not specific for a particular style will be in the dali-toolkit common images folder.
+Common images not specific for a particular style will be in the images-common folder located in the style folder.
 *
 */
index 9939f2c..8e5b5c9 100644 (file)
@@ -1,6 +1,6 @@
 Name:       dali-toolkit
 Summary:    The OpenGLES Canvas Core Library Toolkit
-Version:    1.1.6
+Version:    1.1.7
 Release:    1
 Group:      System/Libraries
 License:    Apache-2.0, BSD-2.0, MIT