Merge branch 'devel/master' into tizen 04/133604/1
authorSeoyeon Kim <seoyeon2.kim@samsung.com>
Tue, 13 Jun 2017 02:09:08 +0000 (11:09 +0900)
committerSeoyeon Kim <seoyeon2.kim@samsung.com>
Tue, 13 Jun 2017 02:09:17 +0000 (11:09 +0900)
Change-Id: I870581e0065ea9a692599dd899fa90dc48854a89

22 files changed:
automated-tests/resources/mask.png [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-compare-types.h
automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp
automated-tests/src/dali-toolkit/utc-Dali-ScrollBar.cpp
automated-tests/src/dali-toolkit/utc-Dali-TextEditor.cpp
automated-tests/src/dali-toolkit/utc-Dali-TextField.cpp
build/tizen/configure.ac
dali-toolkit/devel-api/controls/text-controls/text-editor-devel.cpp [new file with mode: 0644]
dali-toolkit/devel-api/controls/text-controls/text-editor-devel.h
dali-toolkit/devel-api/file.list
dali-toolkit/devel-api/visuals/image-visual-properties-devel.h
dali-toolkit/internal/controls/popup/popup-impl.cpp
dali-toolkit/internal/controls/scroll-bar/scroll-bar-impl.cpp
dali-toolkit/internal/controls/text-controls/text-editor-impl.cpp
dali-toolkit/internal/controls/text-controls/text-editor-impl.h
dali-toolkit/internal/controls/text-controls/text-field-impl.cpp
dali-toolkit/internal/visuals/image/image-visual.cpp
dali-toolkit/internal/visuals/image/image-visual.h
dali-toolkit/internal/visuals/texture-manager.cpp
dali-toolkit/internal/visuals/texture-manager.h
dali-toolkit/public-api/dali-toolkit-version.cpp
packaging/dali-toolkit.spec

diff --git a/automated-tests/resources/mask.png b/automated-tests/resources/mask.png
new file mode 100644 (file)
index 0000000..0032f29
Binary files /dev/null and b/automated-tests/resources/mask.png differ
index 248276e..dd6ba24 100644 (file)
@@ -173,9 +173,16 @@ inline bool CompareType<Property::Value>(Property::Value q1, Property::Value q2,
       result = CompareType<Quaternion>(a, b, epsilon);
       break;
     }
+    case Property::STRING:
+    {
+      std::string a, b;
+      q1.Get(a);
+      q2.Get(b);
+      result = (a.compare(b) == 0);
+      break;
+    }
     case Property::MATRIX:
     case Property::MATRIX3:
-    case Property::STRING:
     case Property::ARRAY:
     case Property::MAP:
     {
index a56df48..f6d34b9 100644 (file)
@@ -30,6 +30,7 @@
 #include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
 #include <dali-toolkit/devel-api/visual-factory/transition-data.h>
 #include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
 #include <dali-toolkit/dali-toolkit.h>
 #include "dummy-control.h"
 
@@ -48,12 +49,13 @@ void dali_image_visual_cleanup(void)
 
 namespace
 {
-const char* TEST_IMAGE_FILE_NAME =  TEST_RESOURCE_DIR  "/gallery_small-1.jpg";
+const char* TEST_IMAGE_FILE_NAME =  TEST_RESOURCE_DIR  "/gallery-small-1.jpg";
 const char* TEST_LARGE_IMAGE_FILE_NAME =  TEST_RESOURCE_DIR "/tbcol.png";
 const char* TEST_SMALL_IMAGE_FILE_NAME = TEST_RESOURCE_DIR "/icon-edit.png";
 const char* TEST_REMOTE_IMAGE_FILE_NAME = "https://www.tizen.org/sites/all/themes/tizen_theme/logo.png";
 const char* TEST_INVALID_FILE_NAME =  TEST_RESOURCE_DIR  "/invalid.jpg";
 const char* TEST_REMOTE_INVALID_FILE_NAME = "https://www.tizen.org/invalid.png";
+const char* TEST_MASK_IMAGE_FILE_NAME =  TEST_RESOURCE_DIR "/mask.png";
 }
 
 
@@ -343,7 +345,12 @@ int UtcDaliImageVisualTextureReuse2(void)
 
   DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
   DALI_TEST_EQUALS( drawTrace.CountMethod("DrawArrays"), 2, TEST_LOCATION );
-  DALI_TEST_EQUALS( textureTrace.CountMethod("BindTexture"), 2, TEST_LOCATION );
+  TraceCallStack::NamedParams tex1;
+  tex1["texture"] = "1";
+  TraceCallStack::NamedParams tex2;
+  tex1["texture"] = "2";
+  DALI_TEST_EQUALS( textureTrace.FindMethodAndParams("BindTexture", tex1), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethodAndParams("BindTexture", tex2), true, TEST_LOCATION );
 
   tet_infoline("Test that removing 1 actor deletes it's texture\n");
 
@@ -973,3 +980,107 @@ int UtcDaliImageVisualSetInvalidRemoteImage(void)
 
   END_TEST;
 }
+
+int UtcDaliImageVisualAlphaMask(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "Request image visual with a Property::Map containing an Alpha mask" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  Property::Map propertyMap;
+  propertyMap.Insert( Visual::Property::TYPE,  Visual::IMAGE );
+  propertyMap.Insert( ImageVisual::Property::URL,  TEST_LARGE_IMAGE_FILE_NAME );
+  propertyMap.Insert( DevelImageVisual::Property::ALPHA_MASK_URL, TEST_MASK_IMAGE_FILE_NAME );
+
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  Property::Map testMap;
+  visual.CreatePropertyMap(testMap);
+  DALI_TEST_EQUALS(*testMap.Find(DevelImageVisual::Property::ALPHA_MASK_URL),Property::Value(TEST_MASK_IMAGE_FILE_NAME), TEST_LOCATION );
+
+  // For tesing the LoadResourceFunc is called, a big image size should be set, so the atlasing is not applied.
+  // Image with a size smaller than 512*512 will be uploaded as a part of the atlas.
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  DummyControl actor = DummyControl::New();
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+
+  actor.SetSize( 200.f, 200.f );
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+  DALI_TEST_EQUALS( DevelControl::IsResourceReady( actor ), false, TEST_LOCATION );
+
+  Stage::GetCurrent().Add( actor );
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 2 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( DevelControl::IsResourceReady( actor ), true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageVisualRemoteAlphaMask(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "Request image visual with a Property::Map containing an Alpha mask" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  const std::string MASK_IMAGE = TEST_REMOTE_IMAGE_FILE_NAME;
+
+  Property::Map propertyMap;
+  propertyMap.Insert( Visual::Property::TYPE,  Visual::IMAGE );
+  propertyMap.Insert( ImageVisual::Property::URL,  TEST_IMAGE_FILE_NAME );
+  propertyMap.Insert( "alphaMaskUrl", MASK_IMAGE );
+
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  Property::Map testMap;
+  visual.CreatePropertyMap(testMap);
+  DALI_TEST_EQUALS(*testMap.Find(DevelImageVisual::Property::ALPHA_MASK_URL),Property::Value(MASK_IMAGE), TEST_LOCATION );
+
+  // For tesing the LoadResourceFunc is called, a big image size should be set, so the atlasing is not applied.
+  // Image with a size smaller than 512*512 will be uploaded as a part of the atlas.
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  DummyControl actor = DummyControl::New();
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+  DALI_TEST_EQUALS( DevelControl::IsResourceReady( actor ), false, TEST_LOCATION );
+
+  actor.SetSize( 200.f, 200.f );
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+
+  Stage::GetCurrent().Add( actor );
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 2 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( DevelControl::IsResourceReady( actor ), true, TEST_LOCATION );
+
+  END_TEST;
+}
index 95b784d..f3a377c 100644 (file)
@@ -698,6 +698,20 @@ int UtcDaliToolkitScrollBarGetScrollPositionIntervalsP(void)
   DALI_TEST_EQUALS( positionIntervals[8], results[8], TEST_LOCATION );
   DALI_TEST_EQUALS( positionIntervals[9], results[9], TEST_LOCATION );
 
+  Property::Array resultArray = scrollBar.GetProperty<Property::Array>(Toolkit::ScrollBar::Property::SCROLL_POSITION_INTERVALS);
+
+  DALI_TEST_EQUALS( positionIntervals.Count(), resultArray.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( positionIntervals[0], resultArray[0].Get<float>(), TEST_LOCATION );
+  DALI_TEST_EQUALS( positionIntervals[1], resultArray[1].Get<float>(), TEST_LOCATION );
+  DALI_TEST_EQUALS( positionIntervals[2], resultArray[2].Get<float>(), TEST_LOCATION );
+  DALI_TEST_EQUALS( positionIntervals[3], resultArray[3].Get<float>(), TEST_LOCATION );
+  DALI_TEST_EQUALS( positionIntervals[4], resultArray[4].Get<float>(), TEST_LOCATION );
+  DALI_TEST_EQUALS( positionIntervals[5], resultArray[5].Get<float>(), TEST_LOCATION );
+  DALI_TEST_EQUALS( positionIntervals[6], resultArray[6].Get<float>(), TEST_LOCATION );
+  DALI_TEST_EQUALS( positionIntervals[7], resultArray[7].Get<float>(), TEST_LOCATION );
+  DALI_TEST_EQUALS( positionIntervals[8], resultArray[8].Get<float>(), TEST_LOCATION );
+  DALI_TEST_EQUALS( positionIntervals[9], resultArray[9].Get<float>(), TEST_LOCATION );
+
   END_TEST;
 }
 
index 9fd6789..40e4ea1 100644 (file)
@@ -18,7 +18,6 @@
 #include <iostream>
 #include <stdlib.h>
 #include <unistd.h>
-
 #include <dali/public-api/rendering/renderer.h>
 #include <dali/devel-api/adaptor-framework/clipboard.h>
 #include <dali/integration-api/events/key-event-integ.h>
@@ -299,6 +298,31 @@ bool DaliTestCheckMaps( const Property::Map& fontStyleMapGet, const Property::Ma
   return true;
 }
 
+class ScrollStateChangeCallback : public Dali::ConnectionTracker
+{
+public:
+  ScrollStateChangeCallback(bool& startedCalled, bool& finishedCalled)
+  : mStartedCalled( startedCalled ),
+    mFinishedCalled( finishedCalled )
+  {
+  }
+
+  void Callback( TextEditor editor, DevelTextEditor::Scroll::Type type )
+  {
+    if( type == DevelTextEditor::Scroll::STARTED )
+    {
+      mStartedCalled = true;
+    }
+    else if( type == DevelTextEditor::Scroll::FINISHED )
+    {
+      mFinishedCalled = true;
+    }
+  }
+
+  bool& mStartedCalled;
+  bool& mFinishedCalled;
+};
+
 } // namespace
 
 int UtcDaliToolkitTextEditorConstructorP(void)
@@ -1571,17 +1595,18 @@ int utcDaliTextEditorEvent03(void)
   // The stencil actor should have two actors: the renderer and the highlight actor.
   Actor stencil = editor.GetChildAt( 0u );
 
+  // Highlight needs to be drawn before text, so should come first in child order
+  Renderer highlight = stencil.GetChildAt( 0u ).GetRendererAt( 0u );
+  DALI_TEST_CHECK( highlight );
+
   // The stencil actor has a container with all the actors which contain the text renderers.
-  Actor container = stencil.GetChildAt( 0u );
+  Actor container = stencil.GetChildAt( 1u );
   for( unsigned int index = 0; index < container.GetChildCount(); ++index )
   {
     Renderer renderer = container.GetChildAt( index ).GetRendererAt( 0u );
     DALI_TEST_CHECK( renderer );
   }
 
-  Renderer highlight = stencil.GetChildAt( 1u ).GetRendererAt( 0u );
-  DALI_TEST_CHECK( highlight );
-
   // Double tap out of bounds
   application.ProcessEvent( GenerateTap( Gesture::Possible, 2u, 1u, Vector2( 29.f, 25.0f ) ) );
   application.ProcessEvent( GenerateTap( Gesture::Started, 2u, 1u, Vector2( 29.f, 25.0f ) ) );
@@ -1957,6 +1982,7 @@ int utcDaliTextEditorFontStylePropertyStringP(void)
 
   END_TEST;
 }
+
 int utcDaliTextEditorGetPropertyLinecountP(void)
 {
   ToolkitTestApplication application;
@@ -1982,3 +2008,44 @@ int utcDaliTextEditorGetPropertyLinecountP(void)
 
   END_TEST;
 }
+
+int utcDaliTextEditorScrollStateChangedSignalTest(void)
+{
+
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextEditorScrollStateChangedSignalTest");
+
+  TextEditor editor = TextEditor::New();
+  DALI_TEST_CHECK( editor );
+
+  Stage::GetCurrent().Add( editor );
+
+  editor.SetProperty( TextEditor::Property::POINT_SIZE, 10.f );
+  editor.SetSize( 50.f, 50.f );
+  editor.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  editor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  editor.SetProperty( DevelTextEditor::Property::ENABLE_SCROLL_BAR, true );
+  editor.SetKeyboardFocusable(true);
+
+  bool startedCalled = false;
+  bool finishedCalled = false;
+
+  ScrollStateChangeCallback callback( startedCalled, finishedCalled );
+  DevelTextEditor::ScrollStateChangedSignal( editor ).Connect( &callback, &ScrollStateChangeCallback::Callback );
+
+  KeyboardFocusManager::Get().SetCurrentFocusActor( editor );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  editor.SetProperty( TextEditor::Property::TEXT, "Long enough message for TextEditor!");
+  application.SendNotification();
+  application.Render(6000);
+
+  application.SendNotification();
+  DALI_TEST_EQUALS( startedCalled, true, TEST_LOCATION );
+  DALI_TEST_EQUALS( finishedCalled, true, TEST_LOCATION );
+
+  END_TEST;
+}
index b05305b..2c1aa44 100644 (file)
@@ -1702,17 +1702,18 @@ int utcDaliTextFieldEvent03(void)
   // The offscreen root actor should have two actors: the renderer and the highlight actor.
   Actor stencil = field.GetChildAt( 0u );
 
+  // The highlight actor is drawn first, so is the first actor in the list
+  Renderer highlight = stencil.GetChildAt( 0u ).GetRendererAt( 0u );
+  DALI_TEST_CHECK( highlight );
+
   // The offscreen root actor has a container with all the actors which contain the text renderers.
-  Actor container = stencil.GetChildAt( 0u );
+  Actor container = stencil.GetChildAt( 1u );
   for( unsigned int index = 0; index < container.GetChildCount(); ++index )
   {
     Renderer renderer = container.GetChildAt( index ).GetRendererAt( 0u );
     DALI_TEST_CHECK( renderer );
   }
 
-  Renderer highlight = stencil.GetChildAt( 1u ).GetRendererAt( 0u );
-  DALI_TEST_CHECK( highlight );
-
   END_TEST;
 }
 
index f12ab89..80e4a8f 100755 (executable)
@@ -89,7 +89,7 @@ fi
 
 # Tizen Profile options
 AC_ARG_ENABLE([profile],
-              [AC_HELP_STRING([--enable-profile=UBUNTU,MOBILE,WEARABLE,TV],
+              [AC_HELP_STRING([--enable-profile=UBUNTU,TIZEN],
                             [Select the variant of tizen])],
               [dali_profile=$enableval],
               [dali_profile=UBUNTU])
@@ -102,7 +102,7 @@ AC_ARG_WITH(style,
               [dali_style=480x800])
 
 # Ensure valid profile selected
-if test "x$dali_profile" != "xUBUNTU" -a "x$dali_profile" != "xMOBILE" -a "x$dali_profile" != "xWEARABLE" -a "x$dali_profile" != "xTV" ; then
+if test "x$dali_profile" != "xUBUNTU" -a "x$dali_profile" != "xTIZEN"; then
   AC_MSG_ERROR([$enable_profile is an invalid profile])
 fi
 
diff --git a/dali-toolkit/devel-api/controls/text-controls/text-editor-devel.cpp b/dali-toolkit/devel-api/controls/text-controls/text-editor-devel.cpp
new file mode 100644 (file)
index 0000000..e9292bf
--- /dev/null
@@ -0,0 +1,43 @@
+
+/*
+ * Copyright (c) 2017 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/devel-api/controls/text-controls/text-editor-devel.h>
+
+// INTERNAL HEADER
+#include <dali-toolkit/internal/controls/text-controls/text-editor-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace DevelTextEditor
+{
+
+ScrollStateChangedSignalType& ScrollStateChangedSignal( TextEditor textEditor )
+{
+  return Dali::Toolkit::GetImpl( textEditor ).ScrollStateChangedSignal();
+}
+
+} // namespace DevelText
+
+} // namespace Toolkit
+
+} // namespace Dali
index 473adba..f95fc94 100644 (file)
@@ -132,7 +132,30 @@ namespace Property
   };
 } // namespace Property
 
-} // namespace DevelText
+namespace Scroll
+{
+  enum Type
+  {
+    STARTED,   ///< Scrolling is started.
+    FINISHED   ///< Scrolling is finished.
+  };
+} // namespace Scroll
+
+typedef Signal< void ( TextEditor, Scroll::Type ) > ScrollStateChangedSignalType;
+
+/**
+ * @brief This signal is emitted when TextEditor scrolling is started or finished.
+ *
+ * A callback of the following type may be connected:
+ * @code
+ *   void YourCallbackName( ScrollState::Type type );
+ * @endcode
+ * type: Whether the scrolling is started or finished.
+ * @return The signal to connect to
+ */
+DALI_IMPORT_API ScrollStateChangedSignalType& ScrollStateChangedSignal( TextEditor textEditor );
+
+} // namespace DevelTextEditor
 
 } // namespace Toolkit
 
index fa85816..fe8ef2b 100644 (file)
@@ -23,6 +23,7 @@ devel_api_src_files = \
   $(devel_api_src_dir)/controls/super-blur-view/super-blur-view.cpp \
   $(devel_api_src_dir)/controls/text-controls/text-selection-popup.cpp \
   $(devel_api_src_dir)/controls/text-controls/text-selection-toolbar.cpp \
+  $(devel_api_src_dir)/controls/text-controls/text-editor-devel.cpp \
   $(devel_api_src_dir)/controls/tool-bar/tool-bar.cpp \
   $(devel_api_src_dir)/focus-manager/keyinput-focus-manager.cpp \
   $(devel_api_src_dir)/focus-manager/keyboard-focus-manager-devel.cpp \
index d2622da..0471ae2 100644 (file)
@@ -64,6 +64,18 @@ enum Type
    */
 
   ATLASING = WRAP_MODE_V + 2,
+
+  /**
+   * @brief URL of a masking image
+   * @details Name "alphaMaskUrl", type Property::STRING, URL of image to apply as
+   * a mask after image loading. If set after the main URL has finished loading, this
+   * may necessitate a re-load of the main image. The alpha mask image will be scaled
+   * on load to match the size of the main image, then applied to the pixel data
+   * before uploading to GL.
+   * @note Optional.
+   */
+
+  ALPHA_MASK_URL = WRAP_MODE_V + 3,
 };
 
 } //namespace Property
index 9794921..7374138 100644 (file)
@@ -30,6 +30,7 @@
 #include <dali/public-api/events/touch-data.h>
 #include <dali/public-api/object/type-registry.h>
 #include <dali/devel-api/scripting/scripting.h>
+#include <dali/devel-api/actors/actor-devel.h>
 #include <dali/public-api/size-negotiation/relayout-container.h>
 
 // INTERNAL INCLUDES
@@ -592,6 +593,7 @@ void Popup::SetPopupBackgroundImage( Actor image )
   const bool prevAlter = mAlterAddedChild;
   mAlterAddedChild = false;
   mPopupContainer.Add( mPopupBackgroundImage );
+  DevelActor::LowerToBottom(mPopupBackgroundImage);
   mAlterAddedChild = prevAlter;
 
   if( mTailImage )
index dd55010..4360f1e 100755 (executable)
@@ -769,17 +769,20 @@ Property::Value ScrollBar::GetProperty( BaseObject* object, Property::Index inde
       }
       case Toolkit::ScrollBar::Property::SCROLL_POSITION_INTERVALS:
       {
-        Property::Value value( Property::ARRAY );
-        Property::Array* array = value.GetArray();
+        Property::Value tempValue( Property::ARRAY );
+        Property::Array* array = tempValue.GetArray();
 
         if( array )
         {
           Dali::Vector<float> positions = scrollBarImpl.GetScrollPositionIntervals();
-          size_t positionCount( array->Count() );
+          size_t positionCount( positions.Count() );
+
           for( size_t i( 0 ); i != positionCount; ++i )
           {
             array->PushBack( positions[i] );
           }
+
+          value = tempValue;
         }
         break;
       }
index ca78a26..eb2264b 100644 (file)
@@ -24,6 +24,7 @@
 #include <dali/public-api/adaptor-framework/key.h>
 #include <dali/public-api/common/stage.h>
 #include <dali/public-api/images/resource-image.h>
+#include <dali/devel-api/actors/actor-devel.h>
 #include <dali/devel-api/object/property-helper-devel.h>
 #include <dali/public-api/object/type-registry-helper.h>
 #include <dali/integration-api/adaptors/adaptor.h>
@@ -1091,6 +1092,11 @@ Toolkit::TextEditor::InputStyleChangedSignalType& TextEditor::InputStyleChangedS
   return mInputStyleChangedSignal;
 }
 
+Toolkit::DevelTextEditor::ScrollStateChangedSignalType& TextEditor::ScrollStateChangedSignal()
+{
+  return mScrollStateChangedSignal;
+}
+
 void TextEditor::OnInitialize()
 {
   Actor self = Self();
@@ -1285,6 +1291,7 @@ void TextEditor::RenderText( Text::Controller::UpdateTextType updateTextType )
          ++it )
     {
       self.Add( *it );
+      DevelActor::LowerToBottom( *it );
     }
     mClippingDecorationActors.clear();
 
@@ -1495,6 +1502,14 @@ void TextEditor::UpdateScrollBar()
     return;
   }
 
+  // If scrolling is not started, start scrolling and emit ScrollStateChangedSignal
+  if( !mScrollStarted )
+  {
+    mScrollStarted = true;
+    Dali::Toolkit::TextEditor handle( GetOwner() );
+    mScrollStateChangedSignal.Emit( handle, DevelTextEditor::Scroll::STARTED );
+  }
+
   CustomActor self = Self();
   if( !mScrollBar )
   {
@@ -1550,6 +1565,18 @@ void TextEditor::UpdateScrollBar()
   indicator.SetOpacity(1.0f);
   mAnimation.AnimateTo( Property( indicator, Actor::Property::COLOR_ALPHA ), 0.0f, AlphaFunction::EASE_IN, mAnimationPeriod );
   mAnimation.Play();
+  mAnimation.FinishedSignal().Connect( this, &TextEditor::OnScrollIndicatorAnimationFinished );
+}
+
+void TextEditor::OnScrollIndicatorAnimationFinished( Animation& animation )
+{
+  // If animation is successfully ended, then emit ScrollStateChangedSignal
+  if( animation.GetCurrentProgress() == 0.0f )
+  {
+    mScrollStarted = false;
+    Dali::Toolkit::TextEditor handle( GetOwner() );
+    mScrollStateChangedSignal.Emit( handle, DevelTextEditor::Scroll::FINISHED );
+  }
 }
 
 void TextEditor::OnStageConnect( Dali::Actor actor )
@@ -1667,7 +1694,8 @@ TextEditor::TextEditor()
   mRenderingBackend( DEFAULT_RENDERING_BACKEND ),
   mHasBeenStaged( false ),
   mScrollAnimationEnabled( false ),
-  mScrollBarEnabled( false )
+  mScrollBarEnabled( false ),
+  mScrollStarted( false )
 {
 }
 
index cc864f1..3c2cec4 100644 (file)
@@ -23,6 +23,7 @@
 #include <dali/public-api/animation/animation.h>
 
 // INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/text-controls/text-editor-devel.h>
 #include <dali-toolkit/public-api/controls/control-impl.h>
 #include <dali-toolkit/public-api/controls/scroll-bar/scroll-bar.h>
 #include <dali-toolkit/public-api/controls/text-controls/text-editor.h>
@@ -95,6 +96,11 @@ public:
    */
   Toolkit::TextEditor::InputStyleChangedSignalType& InputStyleChangedSignal();
 
+  /**
+   * @copydoc DevelTextEditor::ScrollStateChangedSignal()
+   */
+  Toolkit::DevelTextEditor::ScrollStateChangedSignalType& ScrollStateChangedSignal();
+
 private: // From Control
 
   /**
@@ -244,6 +250,13 @@ private: // Implementation
   void ApplyScrollPosition();
 
   /**
+   * @brief Callback function for ScrollBar indicator animation finished signal
+   *
+   * Emit ScrollBarStateChanged Signal and toggle mScrollStarted flag to false
+   */
+  void OnScrollIndicatorAnimationFinished( Animation& animation );
+
+  /**
    * Construct a new TextEditor.
    */
   TextEditor();
@@ -269,6 +282,7 @@ private: // Data
   // Signals
   Toolkit::TextEditor::TextChangedSignalType mTextChangedSignal;
   Toolkit::TextEditor::InputStyleChangedSignalType mInputStyleChangedSignal;
+  Toolkit::DevelTextEditor::ScrollStateChangedSignalType mScrollStateChangedSignal;
 
   ImfManager          mImfManager;
   Text::ControllerPtr mController;
@@ -290,6 +304,7 @@ private: // Data
   bool mHasBeenStaged:1;
   bool mScrollAnimationEnabled:1;
   bool mScrollBarEnabled:1;
+  bool mScrollStarted:1;
 };
 
 } // namespace Internal
index c7c9c4b..6083974 100644 (file)
@@ -24,6 +24,7 @@
 #include <dali/public-api/common/stage.h>
 #include <dali/public-api/images/resource-image.h>
 #include <dali/devel-api/object/property-helper-devel.h>
+#include <dali/devel-api/actors/actor-devel.h>
 #include <dali/public-api/object/type-registry-helper.h>
 #include <dali/integration-api/adaptors/adaptor.h>
 #include <dali/integration-api/debug.h>
@@ -1362,6 +1363,7 @@ void TextField::RenderText( Text::Controller::UpdateTextType updateTextType )
          ++it )
     {
       self.Add( *it );
+      DevelActor::LowerToBottom(*it);
     }
     mClippingDecorationActors.clear();
 
index d50cb91..dc16aac 100644 (file)
@@ -62,6 +62,7 @@ const char * const IMAGE_DESIRED_WIDTH( "desiredWidth" );
 const char * const IMAGE_DESIRED_HEIGHT( "desiredHeight" );
 const char * const SYNCHRONOUS_LOADING( "synchronousLoading" );
 const char * const IMAGE_ATLASING("atlasing");
+const char * const ALPHA_MASK_URL("alphaMaskUrl");
 
 // fitting modes
 DALI_ENUM_TO_STRING_TABLE_BEGIN( FITTING_MODE )
@@ -261,8 +262,10 @@ ImageVisual::ImageVisual( VisualFactoryCache& factoryCache,
   mPixelArea( FULL_TEXTURE_RECT ),
   mPlacementActor(),
   mImageUrl( imageUrl ),
+  mAlphaMaskUrl(),
   mDesiredSize( size ),
   mTextureId( TextureManager::INVALID_TEXTURE_ID ),
+  mAlphaMaskId( TextureManager::INVALID_TEXTURE_ID ),
   mFittingMode( fittingMode ),
   mSamplingMode( samplingMode ),
   mWrapModeU( WrapMode::DEFAULT ),
@@ -279,8 +282,10 @@ ImageVisual::ImageVisual( VisualFactoryCache& factoryCache, const Image& image )
   mPixelArea( FULL_TEXTURE_RECT ),
   mPlacementActor(),
   mImageUrl(),
+  mAlphaMaskUrl(),
   mDesiredSize(),
   mTextureId( TextureManager::INVALID_TEXTURE_ID ),
+  mAlphaMaskId( TextureManager::INVALID_TEXTURE_ID ),
   mFittingMode( FittingMode::DEFAULT ),
   mSamplingMode( SamplingMode::DEFAULT ),
   mWrapModeU( WrapMode::DEFAULT ),
@@ -292,6 +297,11 @@ ImageVisual::ImageVisual( VisualFactoryCache& factoryCache, const Image& image )
 
 ImageVisual::~ImageVisual()
 {
+  if( mAlphaMaskId != TextureManager::INVALID_TEXTURE_ID )
+  {
+    TextureManager& textureManager = mFactoryCache.GetTextureManager();
+    textureManager.Remove( mAlphaMaskId );
+  }
 }
 
 void ImageVisual::DoSetProperties( const Property::Map& propertyMap )
@@ -342,9 +352,20 @@ void ImageVisual::DoSetProperties( const Property::Map& propertyMap )
       {
         DoSetProperty( Toolkit::DevelImageVisual::Property::ATLASING, keyValue.second );
       }
+      else if ( keyValue.first == ALPHA_MASK_URL )
+      {
+        DoSetProperty( Toolkit::DevelImageVisual::Property::ALPHA_MASK_URL, keyValue.second );
+      }
     }
   }
 
+  if( mAlphaMaskUrl.IsValid() )
+  {
+    // Immediately trigger the alpha mask loading (it may just get a cached value)
+    TextureManager& textureManager = mFactoryCache.GetTextureManager();
+    mAlphaMaskId = textureManager.RequestMaskLoad( mAlphaMaskUrl );
+  }
+
   if( ( mImpl->mFlags & Impl::IS_SYNCHRONOUS_RESOURCE_LOADING ) && mImageUrl.IsValid() )
   {
     // if sync loading is required, the loading should start
@@ -451,6 +472,15 @@ void ImageVisual::DoSetProperty( Property::Index index, const Property::Value& v
       bool atlasing = false;
       mAttemptAtlasing = value.Get( atlasing );
     }
+
+    case Toolkit::DevelImageVisual::Property::ALPHA_MASK_URL:
+    {
+      std::string alphaUrl;
+      if( value.Get( alphaUrl ) )
+      {
+        mAlphaMaskUrl = VisualUrl( alphaUrl );
+      }
+    }
   }
 }
 
@@ -651,8 +681,17 @@ TextureSet ImageVisual::CreateTextureSet( Vector4& textureRect, bool synchronous
     {
       mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED;
       TextureManager& textureManager = mFactoryCache.GetTextureManager();
-      mTextureId = textureManager.RequestLoad( mImageUrl, mDesiredSize, mFittingMode,
-                                               mSamplingMode, TextureManager::NO_ATLAS, this );
+      if( mAlphaMaskId == TextureManager::INVALID_TEXTURE_ID )
+      {
+        mTextureId = textureManager.RequestLoad( mImageUrl, mDesiredSize, mFittingMode,
+                                                 mSamplingMode, TextureManager::NO_ATLAS, this );
+      }
+      else
+      {
+        mTextureId = textureManager.RequestLoad( mImageUrl, mAlphaMaskId, mDesiredSize,
+                                                 mFittingMode, mSamplingMode,
+                                                 TextureManager::NO_ATLAS, this );
+      }
 
       TextureManager::LoadState loadState = textureManager.GetTextureState( mTextureId );
 
@@ -819,6 +858,7 @@ void ImageVisual::DoCreatePropertyMap( Property::Map& map ) const
   map.Insert( Toolkit::ImageVisual::Property::WRAP_MODE_V, mWrapModeV );
 
   map.Insert( Toolkit::DevelImageVisual::Property::ATLASING, mAttemptAtlasing );
+  map.Insert( Toolkit::DevelImageVisual::Property::ALPHA_MASK_URL, mAlphaMaskUrl.GetUrl() );
 }
 
 void ImageVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
index 9113437..31dc79f 100644 (file)
@@ -46,13 +46,14 @@ class ImageVisual;
 typedef IntrusivePtr< ImageVisual > ImageVisualPtr;
 
 /**
- * The visual which renders an image to the control's quad
+ * The visual which renders an image to a quad geometry
  *
  * The following properties are optional
  *
  * | %Property Name     | Type              |
  * |--------------------|-------------------|
  * | url                | STRING            |
+ * | alphaMaskUrl       | STRING            |
  * | fittingMode        | INTEGER OR STRING |
  * | samplingMode       | INTEGER OR STRING |
  * | desiredWidth       | INTEGER           |
@@ -319,9 +320,11 @@ private:
   Vector4 mPixelArea;
   WeakHandle<Actor> mPlacementActor;
   VisualUrl mImageUrl;
+  VisualUrl mAlphaMaskUrl;
 
   Dali::ImageDimensions mDesiredSize;
   TextureManager::TextureId mTextureId;
+  TextureManager::TextureId mAlphaMaskId;
 
   Dali::FittingMode::Type mFittingMode:3;
   Dali::SamplingMode::Type mSamplingMode:4;
index 7c8098d..b113438 100644 (file)
@@ -20,6 +20,7 @@
 
 // EXTERNAL HEADERS
 #include <dali/devel-api/common/hash.h>
+#include <dali/devel-api/images/pixel-data-mask.h>
 #include <dali/devel-api/images/texture-set-image.h>
 #include <dali/integration-api/debug.h>
 
@@ -29,6 +30,7 @@
 #include <dali-toolkit/internal/image-loader/image-atlas-impl.h>
 #include <dali-toolkit/public-api/image-loader/sync-image-loader.h>
 
+
 namespace Dali
 {
 
@@ -71,13 +73,46 @@ TextureManager::TextureId TextureManager::RequestLoad(
   const UseAtlas           useAtlas,
   TextureUploadObserver*   observer )
 {
+  return RequestInternalLoad( url, INVALID_TEXTURE_ID, desiredSize, fittingMode, samplingMode, useAtlas, GPU_UPLOAD, observer );
+}
+
+TextureManager::TextureId TextureManager::RequestLoad(
+  const VisualUrl&         url,
+  TextureId                maskTextureId,
+  const ImageDimensions    desiredSize,
+  FittingMode::Type        fittingMode,
+  Dali::SamplingMode::Type samplingMode,
+  const UseAtlas           useAtlas,
+  TextureUploadObserver*   observer )
+{
+  return RequestInternalLoad( url, maskTextureId, desiredSize, fittingMode, samplingMode, useAtlas, GPU_UPLOAD, observer );
+}
+
+TextureManager::TextureId TextureManager::RequestMaskLoad( const VisualUrl& maskUrl )
+{
+  // Use the normal load procedure to get the alpha mask.
+  return RequestInternalLoad( maskUrl, INVALID_TEXTURE_ID, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, NO_ATLAS, CPU, NULL );
+}
+
+
+TextureManager::TextureId TextureManager::RequestInternalLoad(
+  const VisualUrl&         url,
+  TextureId                maskTextureId,
+  const ImageDimensions    desiredSize,
+  FittingMode::Type        fittingMode,
+  Dali::SamplingMode::Type samplingMode,
+  UseAtlas                 useAtlas,
+  StorageType              storageType,
+  TextureUploadObserver*   observer )
+{
   // First check if the requested Texture is cached.
-  const TextureHash textureHash = GenerateHash( url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas );
+  const TextureHash textureHash = GenerateHash( url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas, maskTextureId );
 
-  // Look up the texture by hash. Note: The extra parameters are used in case of a hash collision.
-  int cacheIndex = FindCachedTexture( textureHash, url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas );
   TextureManager::TextureId textureId = INVALID_TEXTURE_ID;
 
+  // Look up the texture by hash. Note: The extra parameters are used in case of a hash collision.
+  int cacheIndex = FindCachedTexture( textureHash, url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas, maskTextureId );
+
   // Check if the requested Texture exists in the cache.
   if( cacheIndex != INVALID_CACHE_INDEX )
   {
@@ -87,19 +122,25 @@ TextureManager::TextureId TextureManager::RequestLoad(
 
     DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "TextureManager::RequestLoad( url=%s observer=%p ) Using cached texture @%d, textureId=%d\n", url.GetUrl().c_str(), observer, cacheIndex, textureId );
   }
-  else
+
+  if( textureId == INVALID_TEXTURE_ID ) // There was no caching, or caching not required
   {
     // We need a new Texture.
     textureId = GenerateUniqueTextureId();
-    mTextureInfoContainer.push_back( TextureInfo( textureId, url.GetUrl(), desiredSize, fittingMode, samplingMode, false, useAtlas, textureHash ) );
+    mTextureInfoContainer.push_back( TextureInfo( textureId, maskTextureId, url.GetUrl(),
+                                                  desiredSize, fittingMode, samplingMode,
+                                                  false, useAtlas, textureHash ) );
     cacheIndex = mTextureInfoContainer.size() - 1u;
 
     DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "TextureManager::RequestLoad( url=%s observer=%p ) New texture, cacheIndex:%d, textureId=%d\n", url.GetUrl().c_str(), observer, cacheIndex, textureId );
   }
 
   // The below code path is common whether we are using the cache or not.
-  // The textureInfoIndex now refers to either a pre-existing cached TextureInfo, or a new TextureInfo just created.
+  // The textureInfoIndex now refers to either a pre-existing cached TextureInfo,
+  // or a new TextureInfo just created.
   TextureInfo& textureInfo( mTextureInfoContainer[ cacheIndex ] );
+  textureInfo.maskTextureId = maskTextureId;
+  textureInfo.storageType = storageType;
 
   DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "TextureInfo loadState:%s\n",
                  textureInfo.loadState == TextureManager::NOT_STARTED ? "NOT_STARTED" :
@@ -127,7 +168,7 @@ TextureManager::TextureId TextureManager::RequestLoad(
       {
         // The Texture has already loaded. The other observers have already been notified.
         // We need to send a "late" loaded notification for this observer.
-        observer->UploadComplete( textureInfo.loadingSucceeded,
+        observer->UploadComplete( true,
                                   textureInfo.textureSet, textureInfo.useAtlas,
                                   textureInfo.atlasRect );
       }
@@ -141,6 +182,11 @@ TextureManager::TextureId TextureManager::RequestLoad(
       ObserveTexture( textureInfo, observer );
       break;
     }
+    case TextureManager::LOAD_FINISHED:
+    case TextureManager::WAITING_FOR_MASK:
+    case TextureManager::LOAD_FAILED:
+      // Loading has already completed. Do nothing.
+      break;
   }
 
   // Return the TextureId for which this Texture can now be referenced by externally.
@@ -226,8 +272,6 @@ TextureSet TextureManager::GetTextureSet( TextureId textureId )
   return textureSet;
 }
 
-
-
 bool TextureManager::LoadTexture( TextureInfo& textureInfo )
 {
   bool success = true;
@@ -241,16 +285,18 @@ bool TextureManager::LoadTexture( TextureInfo& textureInfo )
       if( textureInfo.url.IsLocal() )
       {
         mAsyncLocalLoadingInfoContainer.push_back( AsyncLoadingInfo( textureInfo.textureId ) );
-        mAsyncLocalLoadingInfoContainer.back().loadId = GetImplementation(mAsyncLocalLoader).Load(
-          textureInfo.url, textureInfo.desiredSize,
-          textureInfo.fittingMode, textureInfo.samplingMode, true );
+        mAsyncLocalLoadingInfoContainer.back().loadId =
+          GetImplementation(mAsyncLocalLoader).Load( textureInfo.url, textureInfo.desiredSize,
+                                                     textureInfo.fittingMode,
+                                                     textureInfo.samplingMode, true );
       }
       else
       {
         mAsyncRemoteLoadingInfoContainer.push_back( AsyncLoadingInfo( textureInfo.textureId ) );
-        mAsyncRemoteLoadingInfoContainer.back().loadId = GetImplementation(mAsyncRemoteLoader).Load(
-          textureInfo.url, textureInfo.desiredSize,
-          textureInfo.fittingMode, textureInfo.samplingMode, true );
+        mAsyncRemoteLoadingInfoContainer.back().loadId =
+          GetImplementation(mAsyncRemoteLoader).Load( textureInfo.url, textureInfo.desiredSize,
+                                                      textureInfo.fittingMode,
+                                                      textureInfo.samplingMode, true );
       }
     }
   }
@@ -291,15 +337,12 @@ void TextureManager::AsyncLoadComplete( AsyncLoadingInfoContainerType& loadingCo
       int cacheIndex = GetCacheIndexFromId( loadingInfo.textureId );
       if( cacheIndex != INVALID_CACHE_INDEX )
       {
-        // Once we have found the TextureInfo data, we call a common function used to process loaded data for both sync and async loads.
         TextureInfo& textureInfo( mTextureInfoContainer[cacheIndex] );
 
         DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "  CacheIndex:%d LoadState: %d\n", cacheIndex, textureInfo.loadState );
 
-        // Only perform atlasing if the load has not been cancelled since the request.
         if( textureInfo.loadState != CANCELLED )
         {
-          // Perform atlasing and finalize the load.
           PostLoad( textureInfo, pixelData );
         }
         else
@@ -313,37 +356,108 @@ void TextureManager::AsyncLoadComplete( AsyncLoadingInfoContainerType& loadingCo
   }
 }
 
-
-bool TextureManager::PostLoad( TextureInfo& textureInfo, PixelData pixelData )
+void TextureManager::PostLoad( TextureInfo& textureInfo, PixelData pixelData )
 {
-  bool success = false;
-
   // Was the load successful?
   if( pixelData && ( pixelData.GetWidth() != 0 ) && ( pixelData.GetHeight() != 0 ) )
   {
-    // Regardless of whether the atlasing succeeds or not, we have a valid image, so we mark it as successful.
-    success = true;
-
-    bool usingAtlas = false;
-
     // No atlas support for now
     textureInfo.useAtlas = NO_ATLAS;
 
-    if( ! usingAtlas )
+    if( textureInfo.storageType == GPU_UPLOAD )
+    {
+      // If there is a mask texture ID associated with this texture, then apply the mask
+      // if it's already loaded. If it hasn't, and the mask is still loading,
+      // wait for the mask to finish loading.
+      if( textureInfo.maskTextureId != INVALID_TEXTURE_ID )
+      {
+        LoadState maskLoadState = GetTextureState( textureInfo.maskTextureId );
+        if( maskLoadState == LOADING )
+        {
+          textureInfo.pixelData = pixelData; // Store the pixel data temporarily
+          textureInfo.loadState = WAITING_FOR_MASK;
+        }
+        else if( maskLoadState == LOAD_FINISHED )
+        {
+          ApplyMask( pixelData, textureInfo.maskTextureId );
+          UploadTexture( pixelData, textureInfo );
+          NotifyObservers( textureInfo, true );
+        }
+      }
+      else
+      {
+        UploadTexture( pixelData, textureInfo );
+        NotifyObservers( textureInfo, true );
+      }
+    }
+    else // currently, CPU textures are local to texture manager
     {
-      DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "  TextureManager::PostLoad() textureId:%d\n", textureInfo.textureId );
+      textureInfo.pixelData = pixelData; // Store the pixel data
+      textureInfo.loadState = LOAD_FINISHED;
 
-      Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D, pixelData.GetPixelFormat(), pixelData.GetWidth(), pixelData.GetHeight() );
-      texture.Upload( pixelData );
-      textureInfo.textureSet = TextureSet::New();
-      textureInfo.textureSet.SetTexture( 0u, texture );
+      // Check if there was another texture waiting for this load to complete
+      // (e.g. if this was an image mask, and its load is on a different thread)
+      CheckForWaitingTexture( textureInfo );
     }
   }
-
-  if( ! success )
+  else
   {
     DALI_LOG_ERROR( "TextureManager::AsyncImageLoad(%s) failed\n", textureInfo.url.GetUrl().c_str() );
     // @todo If the load was unsuccessful, upload the broken image.
+    textureInfo.loadState = LOAD_FAILED;
+    CheckForWaitingTexture( textureInfo );
+    NotifyObservers( textureInfo, false );
+  }
+}
+
+void TextureManager::CheckForWaitingTexture( TextureInfo& maskTextureInfo )
+{
+  // Search the cache, checking if any texture has this texture id as a
+  // maskTextureId:
+  const unsigned int size = mTextureInfoContainer.size();
+
+  for( unsigned int cacheIndex = 0; cacheIndex < size; ++cacheIndex )
+  {
+    if( mTextureInfoContainer[cacheIndex].maskTextureId == maskTextureInfo.textureId &&
+        mTextureInfoContainer[cacheIndex].loadState == WAITING_FOR_MASK )
+    {
+      TextureInfo& textureInfo( mTextureInfoContainer[cacheIndex] );
+      PixelData pixelData = textureInfo.pixelData;
+      textureInfo.pixelData.Reset();
+
+      if( maskTextureInfo.loadState == LOAD_FINISHED )
+      {
+        ApplyMask( pixelData, maskTextureInfo.textureId );
+        UploadTexture( pixelData, textureInfo );
+        NotifyObservers( textureInfo, true );
+      }
+      else
+      {
+        DALI_LOG_ERROR( "TextureManager::ApplyMask to %s failed\n", textureInfo.url.GetUrl().c_str() );
+        textureInfo.loadState = LOAD_FAILED;
+        NotifyObservers( textureInfo, false );
+      }
+    }
+  }
+}
+
+void TextureManager::ApplyMask( PixelData pixelData, TextureId maskTextureId )
+{
+  int maskCacheIndex = GetCacheIndexFromId( maskTextureId );
+  PixelData maskPixelData = mTextureInfoContainer[maskCacheIndex].pixelData;
+  Dali::ApplyMask( pixelData, maskPixelData );
+}
+
+void TextureManager::UploadTexture( PixelData pixelData, TextureInfo& textureInfo )
+{
+  if( textureInfo.useAtlas != USE_ATLAS )
+  {
+    DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "  TextureManager::UploadTexture() New Texture for textureId:%d\n", textureInfo.textureId );
+
+    Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D, pixelData.GetPixelFormat(), pixelData.GetWidth(), pixelData.GetHeight() );
+    texture.Upload( pixelData );
+    textureInfo.textureSet = TextureSet::New();
+    textureInfo.textureSet.SetTexture( 0u, texture );
   }
 
   // Update the load state.
@@ -351,12 +465,11 @@ bool TextureManager::PostLoad( TextureInfo& textureInfo, PixelData pixelData )
   // load attempt is in progress or not.  If unsuccessful, a broken
   // image is still loaded.
   textureInfo.loadState = UPLOADED;
+}
 
-  // We need to store the load succeeded state as if a future request to load this texture comes in,
-  // we need to re-broadcast the UploadComplete notification to that observer.
-  textureInfo.loadingSucceeded = success;
-
-  // If there is an observer: Notify the load is complete, whether successful or not:
+void TextureManager::NotifyObservers( TextureInfo& textureInfo, bool success )
+{
+  // If there is an observer: Notify the upload is complete
   const unsigned int observerCount = textureInfo.observerList.Count();
   for( unsigned int i = 0; i < observerCount; ++i )
   {
@@ -369,10 +482,9 @@ bool TextureManager::PostLoad( TextureInfo& textureInfo, PixelData pixelData )
   }
 
   textureInfo.observerList.Clear();
-
-  return success;
 }
 
+
 TextureManager::TextureId TextureManager::GenerateUniqueTextureId()
 {
   return mCurrentTextureId++;
@@ -399,7 +511,8 @@ TextureManager::TextureHash TextureManager::GenerateHash(
   const ImageDimensions          size,
   const FittingMode::Type        fittingMode,
   const Dali::SamplingMode::Type samplingMode,
-  const UseAtlas                 useAtlas )
+  const UseAtlas                 useAtlas,
+  TextureId                      maskTextureId )
 {
   std::string hashTarget( url );
   const size_t urlLength = hashTarget.length();
@@ -431,6 +544,20 @@ TextureManager::TextureHash TextureManager::GenerateHash(
     hashTarget[ urlLength ] = useAtlas;
   }
 
+  if( maskTextureId != INVALID_TEXTURE_ID )
+  {
+    hashTarget.resize( urlLength + sizeof( TextureId ) );
+    TextureId* hashTargetPtr = reinterpret_cast<TextureId*>(&( hashTarget[ urlLength ] ));
+
+    // Append the hash target to the end of the URL byte by byte:
+    // (to avoid SIGBUS / alignment issues)
+    for( size_t byteIter = 0; byteIter < sizeof( TextureId ); ++byteIter )
+    {
+      *hashTargetPtr++ = maskTextureId & 0xff;
+      maskTextureId >>= 8u;
+    }
+  }
+
   return Dali::CalculateHash( hashTarget );
 }
 
@@ -440,7 +567,8 @@ int TextureManager::FindCachedTexture(
   const ImageDimensions             size,
   const FittingMode::Type           fittingMode,
   const Dali::SamplingMode::Type    samplingMode,
-  const bool                        useAtlas )
+  const bool                        useAtlas,
+  TextureId                         maskTextureId)
 {
   // Default to an invalid ID, in case we do not find a match.
   int cacheIndex = INVALID_CACHE_INDEX;
@@ -456,6 +584,7 @@ int TextureManager::FindCachedTexture(
 
       if( ( url == textureInfo.url.GetUrl() ) &&
           ( useAtlas == textureInfo.useAtlas ) &&
+          ( maskTextureId == textureInfo.maskTextureId ) &&
           ( size == textureInfo.desiredSize ) &&
           ( ( size.GetWidth() == 0 && size.GetHeight() == 0 ) ||
             ( fittingMode == textureInfo.fittingMode &&
index 312b12e..a650384 100644 (file)
@@ -41,6 +41,8 @@ namespace Toolkit
 namespace Internal
 {
 
+class MaskTextureObserver;
+
 /**
  * The TextureManager provides a common Image loading API for Visuals.
  *
@@ -55,12 +57,27 @@ public:
   typedef int32_t TextureId;       ///< The TextureId type. This is used as a handle to refer to a particular Texture.
   static const int INVALID_TEXTURE_ID = -1; ///< Used to represent a null TextureId or error
 
+  /**
+   * Whether the texture should be atlased or uploaded into it's own GPU texture
+   */
   enum UseAtlas
   {
     NO_ATLAS,
     USE_ATLAS
   };
 
+  /**
+   * Whether the texture should be stored in CPU memory, or uploaded to a GPU texture
+   */
+  enum StorageType
+  {
+    CPU,
+    GPU_UPLOAD
+  };
+
+  /**
+   * Whether the texture should be loaded synchronously or asynchronously.
+   */
   enum LoadType
   {
     LOAD_ASYNCHRONOUSLY,
@@ -68,14 +85,17 @@ public:
   };
 
   /**
-   * @brief The LoadState Enumeration represents the current state of a particular Textures life-cycle.
+   * @brief The LoadState Enumeration represents the current state of a particular Texture's life-cycle.
    */
   enum LoadState
   {
     NOT_STARTED,     ///< Default
     LOADING,         ///< Loading has been started, but not finished.
-    UPLOADED,        ///< Loaded (and ready).
+    LOAD_FINISHED,   ///< Loading has finished. (for CPU storage only)
+    WAITING_FOR_MASK,///< Loading has finished, but waiting for mask image
+    UPLOADED,        ///< Uploaded and ready. (For GPU upload only)
     CANCELLED,       ///< Removed before loading completed
+    LOAD_FAILED      ///< Async loading failed, e.g. connection problem
   };
 
 public:
@@ -91,7 +111,7 @@ public:
   ~TextureManager();
 
 
-// TextureManager Main API:
+  // TextureManager Main API:
 
   /**
    * @brief Requests an image load of the given URL.
@@ -119,6 +139,40 @@ public:
                          TextureUploadObserver*   observer );
 
   /**
+   * @brief Requests an image load of the given URL, when the texture has
+   * have loaded, it will perform a CPU blend with the image mask, and upload
+   * the blend texture.
+   *
+   * The parameters are used to specify how the image is loaded.
+   * The observer has the UploadComplete method called when the load is ready.
+   *
+   * When the client has finished with the Texture, Remove() should be called.
+   *
+   * @param[in] url               The URL of the image to load
+   * @param[in] desiredSize       The size the image is likely to appear at. This can be set to 0,0 for automatic
+   * @param[in] fittingMode       The FittingMode to use
+   * @param[in] samplingMode      The SamplingMode to use
+   * @param[in] useAtlasing       Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still be loaded, and marked successful,
+   *                              but "useAtlasing" will be set to false in the "UploadCompleted" callback from the TextureManagerUploadObserver.
+   * @param[in] observer          The client object should inherit from this and provide the "UploadCompleted" virtual.
+   *                              This is called when an image load completes (or fails).
+   * @return                      A TextureId to use as a handle to reference this Texture
+   */
+  TextureId RequestLoad( const VisualUrl&         url,
+                         TextureId                maskTextureId,
+                         const ImageDimensions    desiredSize,
+                         FittingMode::Type        fittingMode,
+                         Dali::SamplingMode::Type samplingMode,
+                         const UseAtlas           useAtlasing,
+                         TextureUploadObserver*   observer );
+
+  /**
+   * Requests a masking image to be loaded. This mask is not uploaded to GL,
+   * instead, it is stored in CPU memory, and can be used for CPU blending.
+   */
+  TextureId RequestMaskLoad( const VisualUrl& maskUrl );
+
+  /**
    * @brief Remove a Texture from the TextureManager.
    *
    * Textures are cached and therefore only the removal of the last
@@ -145,16 +199,48 @@ public:
 
 private:
 
+  /**
+   * @brief Requests an image load of the given URL, when the texture has
+   * have loaded, if there is a valid maskTextureId, it will perform a
+   * CPU blend with the mask, and upload the blend texture.
+   *
+   * The parameters are used to specify how the image is loaded.
+   * The observer has the UploadComplete method called when the load is ready.
+   *
+   * When the client has finished with the Texture, Remove() should be called.
+   *
+   * @param[in] url               The URL of the image to load
+   * @param[in] maskTextureId     The texture id of an image to use as a mask. If no mask is required, then set to INVALID_TEXTURE_ID
+   * @param[in] desiredSize       The size the image is likely to appear at. This can be set to 0,0 for automatic
+   * @param[in] fittingMode       The FittingMode to use
+   * @param[in] samplingMode      The SamplingMode to use
+   * @param[in] useAtlasing       Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still be loaded, and marked successful,
+   *                              but "useAtlasing" will be set to false in the "UploadCompleted" callback from the TextureManagerUploadObserver.
+   * @param[in] storageType,      Whether the pixel data is stored in the cache or uploaded to the GPU
+   * @param[in] observer          The client object should inherit from this and provide the "UploadCompleted" virtual.
+   *                              This is called when an image load completes (or fails).
+   * @return                      A TextureId to use as a handle to reference this Texture
+   */
+  TextureId RequestInternalLoad(
+    const VisualUrl&         url,
+    TextureId                maskTextureId,
+    const ImageDimensions    desiredSize,
+    FittingMode::Type        fittingMode,
+    Dali::SamplingMode::Type samplingMode,
+    UseAtlas                 useAtlas,
+    StorageType              storageType,
+    TextureUploadObserver*   observer );
+
 
   typedef size_t TextureHash; ///< The type used to store the hash used for Texture caching.
 
   /**
    * @brief This struct is used to manage the life-cycle of Texture loading and caching.
-   * TODO-TX: pimpl this
    */
   struct TextureInfo
   {
     TextureInfo( TextureId textureId,
+                 TextureId maskTextureId,
                  const VisualUrl& url,
                  ImageDimensions desiredSize,
                  FittingMode::Type fittingMode,
@@ -167,14 +253,15 @@ private:
       useSize( desiredSize ),
       atlasRect( 0.0f, 0.0f, 1.0f, 1.0f ), // Full atlas rectangle
       textureId( textureId ),
+      maskTextureId( maskTextureId ),
       hash( hash ),
       referenceCount( 1u ),
       loadState( NOT_STARTED ),
       fittingMode( fittingMode ),
       samplingMode( samplingMode ),
+      storageType( GPU_UPLOAD ),
       loadSynchronously( loadSynchronously ),
-      useAtlas( useAtlas ),
-      loadingSucceeded( false )
+      useAtlas( useAtlas )
     {
     }
 
@@ -185,21 +272,22 @@ private:
 
     ObserverListType observerList; ///< Container used to store all observer clients of this Texture
     Toolkit::ImageAtlas atlas;     ///< The atlas this Texture lays within (if any)
-    PixelData pixelData;           ///< The PixelData holding the image data (this is used if atlasing is deferred)
+    PixelData pixelData;           ///< The PixelData holding the image data (this is used if atlasing is deferred or CPU storage is required)
     TextureSet textureSet;         ///< The TextureSet holding the Texture
     VisualUrl url;                 ///< The URL of the image
     ImageDimensions desiredSize;   ///< The size requested
     ImageDimensions useSize;       ///< The size used
     Vector4 atlasRect;             ///< The atlas rect used if atlased
     TextureId textureId;           ///< The TextureId associated with this Texture
+    TextureId maskTextureId;       ///< The mask TextureId to be applied on load
     TextureManager::TextureHash hash; ///< The hash used to cache this Texture
     int16_t referenceCount;        ///< The reference count of clients using this Texture
     LoadState loadState:3;         ///< The load state showing the load progress of the Texture
     FittingMode::Type fittingMode:2; ///< The requested FittingMode
     Dali::SamplingMode::Type samplingMode:3; ///< The requested SamplingMode
-    bool loadSynchronously;        ///< True if synchronous loading was requested
-    UseAtlas useAtlas; ///< USE_ATLAS if an atlas was requested. This is updated to false if atlas is not used
-    bool loadingSucceeded;         ///< True if the image was loaded successfully
+    StorageType storageType:1;     ///< CPU storage / GPU upload;
+    bool loadSynchronously:1;      ///< True if synchronous loading was requested
+    UseAtlas useAtlas:1;           ///< USE_ATLAS if an atlas was requested. This is updated to false if atlas is not used
   };
 
   // Structs:
@@ -279,11 +367,47 @@ private:
 
   /**
    * @brief Performs Post-Load steps including atlasing.
-   * @param[in]           textureInfo The struct associated with this Texture
-   * @param[in]           pixelData   The image pixelData
-   * @return                          True if successful
+   * @param[in] textureInfo The struct associated with this Texture
+   * @param[in] pixelData   The image pixelData
+   * @return    True if successful
    */
-  bool PostLoad( TextureManager::TextureInfo& textureInfo, PixelData pixelData );
+  void PostLoad( TextureManager::TextureInfo& textureInfo, PixelData pixelData );
+
+  /**
+   * Check if there is a texture waiting to be masked. If there
+   * is then apply this mask and upload it.
+   * @param[in] maskTextureInfo The texture info of the mask that has just loaded.
+   */
+  void CheckForWaitingTexture( TextureInfo& maskTextureInfo );
+
+  /**
+   * Apply the mask texture to the image texture.
+   * @param[in] pixelData The image pixelData to apply the mask to
+   * @param[in] maskTextureId The texture id of the mask.
+   */
+  void ApplyMask( PixelData pixelData, TextureId maskTextureId );
+
+  /**
+   * Upload the texture specified in pixelData to the appropriate location
+   * @param[in] pixelData The image data to upload
+   * @param[in] textureInfo The texture info containing the location to
+   * store the data to.
+   */
+  void UploadTexture( PixelData pixelData, TextureInfo& textureInfo );
+
+  /**
+   * Mark the texture as complete, and inform observers
+   * @param[in] textureInfo The struct associated with this Texture
+   */
+  void UploadComplete( TextureInfo& textureInfo );
+
+  /**
+   * Notify the current observers that the texture upload is complete,
+   * then remove the observers from the list.
+   * @param[in] textureInfo The struct associated with this Texture
+   * @param[in] success If the pixel data was retrieved successfully and uploaded to GPU
+   */
+  void NotifyObservers( TextureInfo& textureInfo, bool success );
 
   /**
    * @brief Generates a new, unique TextureId
@@ -301,30 +425,42 @@ private:
 
   /**
    * @brief Generates a hash for caching based on the input parameters.
+   * Only applies size, fitting mode andsampling mode if the size is specified.
+   * Only applies maskTextureId if it isn't INVALID_TEXTURE_ID
+   * Always applies useAtlas.
    * @param[in] url          The URL of the image to load
    * @param[in] size         The image size
    * @param[in] fittingMode  The FittingMode to use
    * @param[in] samplingMode The SamplingMode to use
    * @param[in] useAtlas     True if atlased
+   * @param[in] maskTextureId The masking texture id (or INVALID_TEXTURE_ID)
    * @return                 A hash of the provided data for caching.
    */
   TextureHash GenerateHash( const std::string& url, const ImageDimensions size,
                             const FittingMode::Type fittingMode,
-                            const Dali::SamplingMode::Type samplingMode, const UseAtlas useAtlas );
+                            const Dali::SamplingMode::Type samplingMode, const UseAtlas useAtlas,
+                            TextureId maskTextureId );
 
   /**
    * @brief Looks up a cached texture by its hash.
    * If found, the given parameters are used to check there is no hash-collision.
-   * @param[in] hash The hash to look up
-   * @param[in] url          The URL of the image to load
-   * @param[in] size         The image size
-   * @param[in] fittingMode  The FittingMode to use
-   * @param[in] samplingMode The SamplingMode to use
-   * @param[in] useAtlas     True if atlased
-   * @return                 A TextureId of a cached Texture if found. Or INVALID_TEXTURE_ID if not found.
+   * @param[in] hash          The hash to look up
+   * @param[in] url           The URL of the image to load
+   * @param[in] size          The image size
+   * @param[in] fittingMode   The FittingMode to use
+   * @param[in] samplingMode  The SamplingMode to use
+   * @param[in] useAtlas      True if atlased
+   * @param[in] maskTextureId Optional texture ID to use to mask this image
+   * @return A TextureId of a cached Texture if found. Or INVALID_TEXTURE_ID if not found.
    */
-  TextureManager::TextureId FindCachedTexture( const TextureManager::TextureHash hash, const std::string& url, const ImageDimensions size,
-      const FittingMode::Type fittingMode, const Dali::SamplingMode::Type samplingMode, const bool useAtlas );
+  TextureManager::TextureId FindCachedTexture(
+    const TextureManager::TextureHash hash,
+    const std::string& url,
+    const ImageDimensions size,
+    const FittingMode::Type fittingMode,
+    const Dali::SamplingMode::Type samplingMode,
+    const bool useAtlas,
+    TextureId maskTextureId );
 
 
 private:
index a96fab6..d2ad3a6 100644 (file)
@@ -31,7 +31,7 @@ namespace Toolkit
 
 const unsigned int TOOLKIT_MAJOR_VERSION = 1;
 const unsigned int TOOLKIT_MINOR_VERSION = 2;
-const unsigned int TOOLKIT_MICRO_VERSION = 42;
+const unsigned int TOOLKIT_MICRO_VERSION = 43;
 const char * const TOOLKIT_BUILD_DATE    = __DATE__ " " __TIME__;
 
 #ifdef DEBUG_ENABLED
index c34d9aa..8db8b94 100644 (file)
@@ -1,6 +1,6 @@
 Name:       dali-toolkit
 Summary:    The OpenGLES Canvas Core Library Toolkit
-Version:    1.2.42
+Version:    1.2.43
 Release:    1
 Group:      System/Libraries
 License:    Apache-2.0 and BSD-3-Clause and MIT
@@ -34,21 +34,6 @@ BuildRequires:  pkgconfig(libtzplatform-config)
 %define profile %{tizen_profile_name}
 %endif
 
-%if "%{profile}" == "mobile"
-%define dali_toolkit_profile MOBILE
-%define dali_style_folder 720x1280
-# dali_style to be provided by build system as with dali_toolkit_profile or by passing --define 'dali_style 470x800' to the rpm build command
-%endif
-
-%if "%{profile}" == "tv"
-%define dali_toolkit_profile TV
-%define dali_style_folder 1920x1080
-%endif
-
-%if "%{?dali_style}"
-  %define dali_style_folder %{dali_style}
-%endif
-
 %description
 The OpenGLES Canvas Core Library Toolkit - a set of controls that provide
 user interface functionality.
@@ -144,8 +129,7 @@ autoreconf --install
 DALI_DATA_RW_DIR="%{dali_data_rw_dir}" ; export DALI_DATA_RW_DIR
 DALI_DATA_RO_DIR="%{dali_data_ro_dir}" ; export DALI_DATA_RO_DIR
 
-%configure --enable-profile=%{dali_toolkit_profile} \
-           --with-style=%{dali_style_folder} \
+%configure --enable-profile=TIZEN \
 %if 0%{?enable_debug}
            --enable-debug \
 %endif