[AT-SPI] Fix role setting
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / image-view / image-view-impl.cpp
old mode 100755 (executable)
new mode 100644 (file)
index f709559..0f893a3
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2020 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.
@@ -19,7 +19,6 @@
 #include "image-view-impl.h"
 
 // EXTERNAL INCLUDES
-#include <dali/public-api/images/resource-image.h>
 #include <dali/public-api/object/type-registry.h>
 #include <dali/public-api/object/type-registry-helper.h>
 #include <dali/devel-api/scripting/scripting.h>
@@ -32,6 +31,7 @@
 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
 #include <dali-toolkit/internal/visuals/visual-base-impl.h>
 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
+#include <dali-toolkit/internal/controls/control/control-data-impl.h>
 
 namespace Dali
 {
@@ -45,6 +45,8 @@ namespace Internal
 namespace
 {
 
+const Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
+
 BaseHandle Create()
 {
   return Toolkit::ImageView::New();
@@ -52,7 +54,6 @@ BaseHandle Create()
 
 // Setup properties, signals and actions using the type-registry.
 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::ImageView, Toolkit::Control, Create );
-DALI_PROPERTY_REGISTRATION( Toolkit, ImageView, "resourceUrl", STRING, RESOURCE_URL )
 DALI_PROPERTY_REGISTRATION( Toolkit, ImageView, "image", MAP, IMAGE )
 DALI_PROPERTY_REGISTRATION( Toolkit, ImageView, "preMultipliedAlpha", BOOLEAN, PRE_MULTIPLIED_ALPHA )
 
@@ -64,7 +65,10 @@ DALI_TYPE_REGISTRATION_END()
 using namespace Dali;
 
 ImageView::ImageView()
-: Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) )
+: Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
+  mImageSize(),
+  mImageVisualPaddingSetByTransform( false ),
+  mImageViewPixelAreaSetByFittingMode( false )
 {
 }
 
@@ -92,35 +96,11 @@ void ImageView::OnInitialize()
   // ImageView can relayout in the OnImageReady, alternative to a signal would be to have a upcall from the Control to ImageView
   Dali::Toolkit::Control handle( GetOwner() );
   handle.ResourceReadySignal().Connect( this, &ImageView::OnResourceReady );
-}
 
-void ImageView::SetImage( Image image )
-{
-  // Don't bother comparing if we had a visual previously, just drop old visual and create new one
-  mImage = image;
-  mUrl.clear();
-  mPropertyMap.Clear();
-
-  Toolkit::Visual::Base visual =  Toolkit::VisualFactory::Get().CreateVisual( image );
-  if( visual )
-  {
-    if( !mVisual )
-    {
-      mVisual = visual;
-    }
-
-    DevelControl::RegisterVisual( *this, Toolkit::ImageView::Property::IMAGE, visual  );
-  }
-  else
-  {
-    // Unregister the exsiting visual
-    DevelControl::UnregisterVisual( *this, Toolkit::ImageView::Property::IMAGE );
-
-    // Trigger a size negotiation request that may be needed when unregistering a visual.
-    RelayoutRequest();
-  }
-
-  Toolkit::DevelControl::RequestLayout( *this );
+  DevelControl::SetAccessibilityConstructor( Self(), []( Dali::Actor actor ) {
+    return std::unique_ptr< Dali::Accessibility::Accessible >(
+      new Control::Impl::AccessibleImpl( actor, Dali::Accessibility::Role::IMAGE ) );
+  } );
 }
 
 void ImageView::SetImage( const Property::Map& map )
@@ -128,7 +108,6 @@ void ImageView::SetImage( const Property::Map& map )
   // Comparing a property map is too expensive so just creating a new visual
   mPropertyMap = map;
   mUrl.clear();
-  mImage.Reset();
 
   Toolkit::Visual::Base visual =  Toolkit::VisualFactory::Get().CreateVisual( mPropertyMap );
   if( visual )
@@ -139,6 +118,12 @@ void ImageView::SetImage( const Property::Map& map )
       mVisual = visual;
     }
 
+    if( !mShaderMap.Empty() )
+    {
+      Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual );
+      visualImpl.SetCustomShader( mShaderMap );
+    }
+
     DevelControl::RegisterVisual( *this, Toolkit::ImageView::Property::IMAGE, visual  );
   }
   else
@@ -150,14 +135,14 @@ void ImageView::SetImage( const Property::Map& map )
     RelayoutRequest();
   }
 
-  Toolkit::DevelControl::RequestLayout( *this );
+  // Signal that a Relayout may be needed
 }
 
 void ImageView::SetImage( const std::string& url, ImageDimensions size )
 {
   // Don't bother comparing if we had a visual previously, just drop old visual and create new one
   mUrl = url;
-  mImage.Reset();
+  mImageSize = size;
   mPropertyMap.Clear();
 
   // Don't set mVisual until it is ready and shown. Getters will still use current visual.
@@ -169,6 +154,12 @@ void ImageView::SetImage( const std::string& url, ImageDimensions size )
       mVisual = visual;
     }
 
+    if( !mShaderMap.Empty() )
+    {
+      Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual );
+      visualImpl.SetCustomShader( mShaderMap );
+    }
+
     DevelControl::RegisterVisual( *this, Toolkit::ImageView::Property::IMAGE, visual );
   }
   else
@@ -180,12 +171,7 @@ void ImageView::SetImage( const std::string& url, ImageDimensions size )
     RelayoutRequest();
   }
 
-  Toolkit::DevelControl::RequestLayout( *this );
-}
-
-Image ImageView::GetImage() const
-{
-  return mImage;
+  // Signal that a Relayout may be needed
 }
 
 void ImageView::EnablePreMultipliedAlpha( bool preMultipled )
@@ -265,65 +251,174 @@ float ImageView::GetWidthForHeight( float height )
 void ImageView::OnRelayout( const Vector2& size, RelayoutContainer& container )
 {
   Control::OnRelayout( size, container );
-
   if( mVisual )
   {
     Property::Map transformMap = Property::Map();
 
     Extents padding = Self().GetProperty<Extents>( Toolkit::Control::Property::PADDING );
-    const Visual::FittingMode fittingMode = Toolkit::GetImplementation(mVisual).GetFittingMode();
 
-    if( ( padding != Extents() ) || // If padding is not zero
-        ( fittingMode == Visual::FittingMode::FIT_KEEP_ASPECT_RATIO ) )
+    bool zeroPadding = ( padding == Extents() );
+
+    Vector2 naturalSize;
+    mVisual.GetNaturalSize( naturalSize );
+
+    Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>(
+          Self().GetProperty( Dali::Actor::Property::LAYOUT_DIRECTION ).Get<int>() );
+    if( Dali::LayoutDirection::RIGHT_TO_LEFT == layoutDirection )
     {
-      Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>(
-            Self().GetProperty( Dali::Actor::Property::LAYOUT_DIRECTION ).Get<int>() );
+      std::swap( padding.start, padding.end );
+    }
 
-      if( Dali::LayoutDirection::RIGHT_TO_LEFT == layoutDirection )
-      {
-        std::swap( padding.start, padding.end );
-      }
+    // remove padding from the size to know how much is left for the visual
+    Vector2 finalSize = size - Vector2( padding.start + padding.end, padding.top + padding.bottom );
+    Vector2 finalOffset = Vector2( padding.start, padding.top );
 
-      auto finalOffset = Vector2( padding.start, padding.top );
+    ApplyFittingMode( finalSize, naturalSize, finalOffset, zeroPadding , transformMap );
 
-      // remove padding from the size to know how much is left for the visual
-      auto finalSize = size - Vector2( padding.start + padding.end, padding.top + padding.bottom );
+    mVisual.SetTransformAndSize( transformMap, size );
 
-      // Should provide a transform that handles aspect ratio according to image size
-      if( fittingMode == Visual::FittingMode::FIT_KEEP_ASPECT_RATIO )
-      {
-        auto availableVisualSize = finalSize;
+    // mVisual is not updated util the resource is ready in the case of visual replacement.
+    // in this case, the Property Map must be initialized so that the previous value is not reused.
+    // after mVisual is updated, the correct value will be reset.
+    Toolkit::Visual::Base visual = DevelControl::GetVisual( *this, Toolkit::ImageView::Property::IMAGE );
+    if( visual && visual != mVisual )
+    {
+      visual.SetTransformAndSize( Property::Map(), size );
+    }
+  }
+}
 
-        Vector2 naturalSize;
-        mVisual.GetNaturalSize( naturalSize );
+void ImageView::OnResourceReady( Toolkit::Control control )
+{
+  // Visual ready so update visual attached to this ImageView, following call to RelayoutRequest will use this visual.
+  mVisual = DevelControl::GetVisual( *this, Toolkit::ImageView::Property::IMAGE );
+  // Signal that a Relayout may be needed
+}
 
-        // scale to fit the padded area
-        finalSize = naturalSize * std::min( ( naturalSize.width  ? ( availableVisualSize.width  / naturalSize.width  ) : 0 ),
+void ImageView::SetTransformMapForFittingMode( Vector2 finalSize, Vector2 naturalSize, Vector2 finalOffset, Visual::FittingMode fittingMode, Property::Map& transformMap )
+{
+  switch(fittingMode)
+  {
+    case Visual::FittingMode::FIT_KEEP_ASPECT_RATIO:
+    {
+      auto availableVisualSize = finalSize;
+
+      // scale to fit the padded area
+      finalSize = naturalSize * std::min( ( naturalSize.width  ? ( availableVisualSize.width  / naturalSize.width  ) : 0 ),
                                             ( naturalSize.height ? ( availableVisualSize.height / naturalSize.height ) : 0 ) );
 
-        // calculate final offset within the padded area
-        finalOffset += ( availableVisualSize - finalSize ) * .5f;
-      }
+      // calculate final offset within the padded area
+      finalOffset += ( availableVisualSize - finalSize ) * .5f;
 
       // populate the transform map
       transformMap.Add( Toolkit::Visual::Transform::Property::OFFSET, finalOffset )
-                  .Add( Toolkit::Visual::Transform::Property::OFFSET_POLICY,
-                      Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
-                  .Add( Toolkit::Visual::Transform::Property::ORIGIN, Toolkit::Align::TOP_BEGIN )
-                  .Add( Toolkit::Visual::Transform::Property::ANCHOR_POINT, Toolkit::Align::TOP_BEGIN )
-                  .Add( Toolkit::Visual::Transform::Property::SIZE, finalSize )
-                  .Add( Toolkit::Visual::Transform::Property::SIZE_POLICY,
-                      Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) );
+                  .Add( Toolkit::Visual::Transform::Property::SIZE, finalSize );
+      break;
     }
+    case Visual::FittingMode::OVER_FIT_KEEP_ASPECT_RATIO:
+    {
+      mImageViewPixelAreaSetByFittingMode = true;
+      auto availableVisualSize = finalSize;
+      finalSize = naturalSize * std::max( ( naturalSize.width  ? ( availableVisualSize.width  / naturalSize.width  ) : 0 ),
+                                          ( naturalSize.height ? ( availableVisualSize.height / naturalSize.height ) : 0 ) );
 
-    mVisual.SetTransformAndSize( transformMap, size );
+      auto originalOffset = finalOffset;
+      finalOffset += ( availableVisualSize - finalSize ) * .5f;
+
+      float x = abs( (availableVisualSize.width - finalSize.width ) / finalSize.width )* .5f;
+      float y = abs( (availableVisualSize.height - finalSize.height ) / finalSize.height ) * .5f;
+      float widthRatio = 1.f - abs( (availableVisualSize.width - finalSize.width ) / finalSize.width );
+      float heightRatio = 1.f - abs( (availableVisualSize.height - finalSize.height ) / finalSize.height );
+      Vector4 pixelArea = Vector4( x, y, widthRatio, heightRatio);
+      Self().SetProperty( Toolkit::ImageView::Property::PIXEL_AREA, pixelArea );
+
+      // populate the transform map
+      transformMap.Add( Toolkit::Visual::Transform::Property::OFFSET, originalOffset )
+                  .Add( Toolkit::Visual::Transform::Property::SIZE, availableVisualSize );
+      break;
+    }
+    case Visual::FittingMode::CENTER:
+    {
+      auto availableVisualSize = finalSize;
+      if( availableVisualSize.width > naturalSize.width && availableVisualSize.height > naturalSize.height )
+      {
+        finalSize = naturalSize;
+      }
+      else
+      {
+        finalSize = naturalSize * std::min( ( naturalSize.width  ? ( availableVisualSize.width  / naturalSize.width  ) : 0 ),
+                                          ( naturalSize.height ? ( availableVisualSize.height / naturalSize.height ) : 0 ) );
+      }
+
+      finalOffset += ( availableVisualSize - finalSize ) * .5f;
+
+      // populate the transform map
+      transformMap.Add( Toolkit::Visual::Transform::Property::OFFSET, finalOffset )
+                  .Add( Toolkit::Visual::Transform::Property::SIZE, finalSize );
+      break;
+    }
+    case Visual::FittingMode::FILL:
+    {
+      transformMap.Add( Toolkit::Visual::Transform::Property::OFFSET, finalOffset )
+                  .Add( Toolkit::Visual::Transform::Property::SIZE, finalSize );
+      break;
+    }
+    case Visual::FittingMode::FIT_WIDTH:
+    case Visual::FittingMode::FIT_HEIGHT:
+    {
+      // This FittingMode already converted
+      break;
+    }
   }
 }
 
-void ImageView::OnResourceReady( Toolkit::Control control )
+void ImageView::ApplyFittingMode( Vector2 finalSize, Vector2 naturalSize, Vector2 finalOffset, bool zeroPadding , Property::Map& transformMap )
 {
-  // Visual ready so update visual attached to this ImageView, following call to RelayoutRequest will use this visual.
-  mVisual = DevelControl::GetVisual( *this, Toolkit::ImageView::Property::IMAGE );
+    Visual::FittingMode fittingMode = Toolkit::GetImplementation(mVisual).GetFittingMode();
+
+    // Reset PIXEL_AREA after using OVER_FIT_KEEP_ASPECT_RATIO
+    if( mImageViewPixelAreaSetByFittingMode )
+    {
+      Self().SetProperty( Toolkit::ImageView::Property::PIXEL_AREA, FULL_TEXTURE_RECT );
+      mImageViewPixelAreaSetByFittingMode = false;
+    }
+
+    if( ( !zeroPadding ) || // If padding is not zero
+        ( fittingMode != Visual::FittingMode::FILL ) )
+    {
+      mImageVisualPaddingSetByTransform = true;
+
+      // If FittingMode use FIT_WIDTH or FIT_HEIGTH, it need to change proper fittingMode
+      if( fittingMode == Visual::FittingMode::FIT_WIDTH )
+      {
+        fittingMode = ( finalSize.height  / naturalSize.height ) < ( finalSize.width / naturalSize.width ) ? Visual::FittingMode::OVER_FIT_KEEP_ASPECT_RATIO : Visual::FittingMode::FIT_KEEP_ASPECT_RATIO;
+      }
+      else if( fittingMode == Visual::FittingMode::FIT_HEIGHT )
+      {
+        fittingMode = ( finalSize.height  / naturalSize.height ) < ( finalSize.width / naturalSize.width ) ? Visual::FittingMode::FIT_KEEP_ASPECT_RATIO : Visual::FittingMode::OVER_FIT_KEEP_ASPECT_RATIO;
+      }
+
+      SetTransformMapForFittingMode( finalSize, naturalSize, finalOffset, fittingMode, transformMap );
+
+      // Set extra value for applying transformMap
+      transformMap.Add( Toolkit::Visual::Transform::Property::OFFSET_POLICY,
+                        Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
+                  .Add( Toolkit::Visual::Transform::Property::ORIGIN, Toolkit::Align::TOP_BEGIN )
+                  .Add( Toolkit::Visual::Transform::Property::ANCHOR_POINT, Toolkit::Align::TOP_BEGIN )
+                  .Add( Toolkit::Visual::Transform::Property::SIZE_POLICY,
+                        Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) );
+    }
+    else if ( mImageVisualPaddingSetByTransform && zeroPadding )  // Reset offset to zero only if padding applied previously
+    {
+      mImageVisualPaddingSetByTransform = false;
+      // Reset the transform map
+      transformMap.Add( Toolkit::Visual::Transform::Property::OFFSET, Vector2::ZERO )
+                  .Add( Toolkit::Visual::Transform::Property::OFFSET_POLICY,
+                        Vector2( Toolkit::Visual::Transform::Policy::RELATIVE, Toolkit::Visual::Transform::Policy::RELATIVE ) )
+                  .Add( Toolkit::Visual::Transform::Property::SIZE, Vector2::ONE )
+                  .Add( Toolkit::Visual::Transform::Property::SIZE_POLICY,
+                        Vector2( Toolkit::Visual::Transform::Policy::RELATIVE, Toolkit::Visual::Transform::Policy::RELATIVE ) );
+    }
 }
 
 ///////////////////////////////////////////////////////////
@@ -340,20 +435,10 @@ void ImageView::SetProperty( BaseObject* object, Property::Index index, const Pr
     ImageView& impl = GetImpl( imageView );
     switch ( index )
     {
-      case Toolkit::ImageView::Property::RESOURCE_URL:
-      {
-        std::string imageUrl;
-        if( value.Get( imageUrl ) )
-        {
-          impl.SetImage( imageUrl, ImageDimensions() );
-        }
-        break;
-      }
-
       case Toolkit::ImageView::Property::IMAGE:
       {
         std::string imageUrl;
-        Property::Map* map;
+        const Property::Map* map;
         if( value.Get( imageUrl ) )
         {
           impl.SetImage( imageUrl, ImageDimensions() );
@@ -371,18 +456,20 @@ void ImageView::SetProperty( BaseObject* object, Property::Index index, const Pr
               impl.SetImage( *map );
             }
             // the property map contains only the custom shader
-            else if( ( impl.mVisual )&&( map->Count() == 1u )&&( shaderValue ) )
+            else if( ( map->Count() == 1u )&&( shaderValue ) )
             {
               Property::Map* shaderMap = shaderValue->GetMap();
               if( shaderMap )
               {
-                Internal::Visual::Base& visual = Toolkit::GetImplementation( impl.mVisual );
-                visual.SetCustomShader( *shaderMap );
-                if( imageView.OnStage() )
+                impl.mShaderMap = *shaderMap;
+
+                if( !impl.mUrl.empty() )
+                {
+                  impl.SetImage( impl.mUrl, impl.mImageSize );
+                }
+                else if( !impl.mPropertyMap.Empty() )
                 {
-                  // force to create new core renderer to use the newly set shader
-                  visual.SetOffStage( imageView );
-                  visual.SetOnStage( imageView );
+                  impl.SetImage( impl.mPropertyMap );
                 }
               }
             }
@@ -415,31 +502,22 @@ Property::Value ImageView::GetProperty( BaseObject* object, Property::Index prop
     ImageView& impl = GetImpl( imageview );
     switch ( propertyIndex )
     {
-      case Toolkit::ImageView::Property::RESOURCE_URL:
-      {
-        if ( !impl.mUrl.empty() )
-        {
-          value = impl.mUrl;
-        }
-        break;
-      }
-
       case Toolkit::ImageView::Property::IMAGE:
       {
         if ( !impl.mUrl.empty() )
         {
           value = impl.mUrl;
         }
-        else if( impl.mImage )
+        else
         {
           Property::Map map;
-          Scripting::CreatePropertyMap( impl.mImage, map );
+          Toolkit::Visual::Base visual = DevelControl::GetVisual( impl, Toolkit::ImageView::Property::IMAGE );
+          if( visual )
+          {
+            visual.CreatePropertyMap( map );
+          }
           value = map;
         }
-        else if( !impl.mPropertyMap.Empty() )
-        {
-          value = impl.mPropertyMap;
-        }
         break;
       }