Merge "(Vector) Support EncodedImageBuffer can use for vector image" into devel/master
authorEunki Hong <eunkiki.hong@samsung.com>
Wed, 8 Nov 2023 04:56:41 +0000 (04:56 +0000)
committerGerrit Code Review <gerrit@review>
Wed, 8 Nov 2023 04:56:41 +0000 (04:56 +0000)
1  2 
automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp
dali-toolkit/internal/image-loader/loading-task.cpp
dali-toolkit/internal/visuals/animated-vector-image/animated-vector-image-visual.cpp
dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.cpp
dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.h
dali-toolkit/internal/visuals/svg/svg-task.cpp

@@@ -879,6 -879,86 +879,86 @@@ int UtcDaliImageViewSyncLoadingEncodedB
    END_TEST;
  }
  
+ int UtcDaliImageViewEncodedBufferWithSvg(void)
+ {
+   ToolkitTestApplication     application;
+   TestGlAbstraction&         gl          = application.GetGlAbstraction();
+   const std::vector<GLuint>& textures    = gl.GetBoundTextures();
+   size_t                     numTextures = textures.size();
+   // Get encoded raw-buffer svg image and generate url
+   EncodedImageBuffer buffer = ConvertFileToEncodedImageBuffer(TEST_SVG_FILE_NAME, EncodedImageBuffer::ImageType::VECTOR_IMAGE);
+   ImageUrl           url    = Toolkit::Image::GenerateUrl(buffer);
+   // Async loading, no atlasing for big size image
+   ImageView imageView = ImageView::New(url.GetUrl());
+   // By default, Aysnc loading is used
+   application.GetScene().Add(imageView);
+   imageView.SetProperty(Actor::Property::SIZE, Vector2(100, 100));
+   imageView.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+   application.SendNotification();
+   application.Render(16);
+   // Load svg image + rasterize.
+   DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
+   application.SendNotification();
+   application.Render(16);
+   application.SendNotification();
+   const std::vector<GLuint>& textures2 = gl.GetBoundTextures();
+   DALI_TEST_GREATER(textures2.size(), numTextures, TEST_LOCATION);
+   // Remove visual, for line coverage.
+   imageView.Unparent();
+   application.SendNotification();
+   application.Render(16);
+   END_TEST;
+ }
+ int UtcDaliImageViewEncodedBufferWithAnimatedVectorImage(void)
+ {
+   ToolkitTestApplication     application;
+   TestGlAbstraction&         gl          = application.GetGlAbstraction();
+   const std::vector<GLuint>& textures    = gl.GetBoundTextures();
+   size_t                     numTextures = textures.size();
+   // Get encoded raw-buffer lottie image and generate url
+   EncodedImageBuffer buffer = ConvertFileToEncodedImageBuffer(TEST_ANIMATED_VECTOR_IMAGE_FILE_NAME, EncodedImageBuffer::ImageType::ANIMATED_VECTOR_IMAGE);
+   ImageUrl           url    = Toolkit::Image::GenerateUrl(buffer);
+   // Async loading, no atlasing for big size image
+   ImageView imageView = ImageView::New(url.GetUrl());
+   // By default, Aysnc loading is used
+   application.GetScene().Add(imageView);
+   imageView.SetProperty(Actor::Property::SIZE, Vector2(100, 100));
+   imageView.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+   application.SendNotification();
+   application.Render(16);
+   // Load lottie image is sync. Only wait rasterize.
+   DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+   application.SendNotification();
+   application.Render(16);
+   application.SendNotification();
+   const std::vector<GLuint>& textures2 = gl.GetBoundTextures();
+   DALI_TEST_GREATER(textures2.size(), numTextures, TEST_LOCATION);
+   // Remove visual, for line coverage.
+   imageView.Unparent();
+   application.SendNotification();
+   application.Render(16);
+   END_TEST;
+ }
  int UtcDaliImageViewAddedTexture(void)
  {
    ToolkitTestApplication application;
@@@ -2789,6 -2869,34 +2869,34 @@@ int UtcDaliImageViewLoadRemoteSVG(void
    END_TEST;
  }
  
+ int UtcDaliImageViewLoadRemoteLottie(void)
+ {
+   tet_infoline("Test load from a remote server. (Note we don't support real download now. Just for line coverage)");
+   ToolkitTestApplication application;
+   {
+     Toolkit::ImageView imageView;
+     imageView = Toolkit::ImageView::New();
+     imageView.SetImage("https://lottie.json");
+     imageView.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+     imageView.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+     imageView.SetProperty(Actor::Property::SIZE, Vector2(300, 300));
+     imageView.SetProperty(Actor::Property::POSITION, Vector3(150.0f, 150.0f, 0.0f));
+     application.GetScene().Add(imageView);
+     DALI_TEST_CHECK(imageView);
+     application.SendNotification();
+     application.Render();
+     // Do not check anything for here.
+   }
+   END_TEST;
+ }
  int UtcDaliImageViewSyncSVGLoading(void)
  {
    ToolkitTestApplication application;
@@@ -3773,34 -3881,6 +3881,34 @@@ void OnResourceReadySignal10(Control co
    }
  }
  
 +void OnResourceReadySignal11(Control control)
 +{
 +  gResourceReadySignalCounter++;
 +
 +  if(!gImageView2)
 +  {
 +    auto scene = gImageView1.GetParent();
 +
 +    // Try to load animated image visual here which is already cached, and then ignore forcely.
 +
 +    Property::Map map1;
 +    map1[Toolkit::ImageVisual::Property::URL] = TEST_GIF_FILE_NAME;
 +
 +    gImageView2 = ImageView::New();
 +    gImageView2.SetProperty(Toolkit::ImageView::Property::IMAGE, map1);
 +
 +    gImageView3 = ImageView::New();
 +    gImageView3.SetProperty(Toolkit::ImageView::Property::IMAGE, map1);
 +
 +    scene.Add(gImageView2);
 +    gImageView2.Unparent();
 +
 +    scene.Add(gImageView3);
 +    gImageView3.Unparent();
 +    gImageView3.Reset(); // Destroy visual
 +  }
 +}
 +
  } // namespace
  
  int UtcDaliImageViewSetImageOnResourceReadySignal01(void)
@@@ -4645,82 -4725,6 +4753,82 @@@ int UtcDaliImageViewSetImageOnResourceR
    END_TEST;
  }
  
 +int UtcDaliImageViewSetImageOnResourceReadySignal11(void)
 +{
 +  tet_infoline("Test ResourceReady Add AnimatedImageVisual and then Remove immediately.");
 +
 +  ToolkitTestApplication application;
 +
 +  gResourceReadySignalCounter = 0;
 +
 +  // Clear image view for clear test
 +
 +  if(gImageView1)
 +  {
 +    gImageView1.Reset();
 +  }
 +  if(gImageView2)
 +  {
 +    gImageView2.Reset();
 +  }
 +  if(gImageView3)
 +  {
 +    gImageView3.Reset();
 +  }
 +
 +  try
 +  {
 +    gImageView1 = ImageView::New();
 +    gImageView1.SetProperty(Toolkit::ImageView::Property::IMAGE, TEST_GIF_FILE_NAME);
 +    gImageView1.ResourceReadySignal().Connect(&OnResourceReadySignal11);
 +    application.GetScene().Add(gImageView1); // It will call resourceReady signal 1 time.
 +
 +    tet_printf("ResourceReady called %d times\n", gResourceReadySignalCounter);
 +
 +    DALI_TEST_EQUALS(gResourceReadySignalCounter, 0, TEST_LOCATION);
 +
 +    application.SendNotification();
 +    application.Render();
 +
 +    // Load gImageView1
 +    DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
 +
 +    tet_printf("ResourceReady called %d times\n", gResourceReadySignalCounter);
 +
 +    DALI_TEST_EQUALS(gResourceReadySignalCounter, 1, TEST_LOCATION);
 +
 +    DALI_TEST_CHECK(true);
 +  }
 +  catch(...)
 +  {
 +    // Exception should not happened
 +    DALI_TEST_CHECK(false);
 +  }
 +
 +  // Clear cache.
 +  application.SendNotification();
 +  application.Render();
 +
 +  gResourceReadySignalCounter = 0;
 +
 +  // Clear image view for clear test
 +
 +  if(gImageView1)
 +  {
 +    gImageView1.Reset();
 +  }
 +  if(gImageView2)
 +  {
 +    gImageView2.Reset();
 +  }
 +  if(gImageView3)
 +  {
 +    gImageView3.Reset();
 +  }
 +
 +  END_TEST;
 +}
 +
  int UtcDaliImageViewUseSameUrlWithAnimatedImageVisual(void)
  {
    tet_infoline("Test multiple views with same image in animated image visual");
@@@ -163,7 -163,7 +163,7 @@@ void LoadingTask::Process(
    {
      std::ostringstream oss;
      oss << "[url:" << (!!(animatedImageLoading) ? animatedImageLoading.GetUrl() : url.GetUrl()) << "]";
 -    DALI_TRACE_BEGIN(gTraceFilter, "DALI_IMAGE_LOADING_TASK");
 +    // DALI_TRACE_BEGIN(gTraceFilter, "DALI_IMAGE_LOADING_TASK"); ///< TODO : Open it if we can control trace log level
      DALI_LOG_RELEASE_INFO("BEGIN: DALI_IMAGE_LOADING_TASK %s", oss.str().c_str());
    }
  #endif
        oss << "premult:" << pixelBuffers[0].IsAlphaPreMultiplied() << " ";
      }
      oss << "url:" << (!!(animatedImageLoading) ? animatedImageLoading.GetUrl() : url.GetUrl()) << "]";
 -    DALI_TRACE_END(gTraceFilter, "DALI_IMAGE_LOADING_TASK");
 +    // DALI_TRACE_END(gTraceFilter, "DALI_IMAGE_LOADING_TASK"); ///< TODO : Open it if we can control trace log level
      DALI_LOG_RELEASE_INFO("END: DALI_IMAGE_LOADING_TASK %s", oss.str().c_str());
    }
  #endif
@@@ -215,6 -215,9 +215,9 @@@ void LoadingTask::Load(
    else if(encodedImageBuffer)
    {
      pixelBuffer = Dali::LoadImageFromBuffer(encodedImageBuffer.GetRawBuffer(), dimensions, fittingMode, samplingMode, orientationCorrection);
+     // We don't need to hold image buffer anymore.
+     encodedImageBuffer.Reset();
    }
    else if(url.IsValid() && url.IsLocalResource())
    {
@@@ -113,6 -113,12 +113,12 @@@ AnimatedVectorImageVisual::~AnimatedVec
  {
    if(!mCoreShutdown)
    {
+     if(mImageUrl.IsBufferResource())
+     {
+       TextureManager& textureManager = mFactoryCache.GetTextureManager();
+       textureManager.RemoveEncodedImageBuffer(mImageUrl.GetUrl());
+     }
      auto& vectorAnimationManager = mFactoryCache.GetVectorAnimationManager();
      vectorAnimationManager.RemoveObserver(*this);
  
@@@ -204,10 -210,6 +210,10 @@@ void AnimatedVectorImageVisual::DoCreat
    mVectorAnimationTask->GetLayerInfo(layerInfo);
    map.Insert(Toolkit::DevelImageVisual::Property::CONTENT_INFO, layerInfo);
  
 +  Property::Map markerInfo;
 +  mVectorAnimationTask->GetMarkerInfo(markerInfo);
 +  map.Insert(Toolkit::DevelImageVisual::Property::MARKER_INFO, markerInfo);
 +
    map.Insert(Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, IsSynchronousLoadingRequired());
    map.Insert(Toolkit::ImageVisual::Property::DESIRED_WIDTH, mDesiredSize.GetWidth());
    map.Insert(Toolkit::ImageVisual::Property::DESIRED_HEIGHT, mDesiredSize.GetHeight());
@@@ -384,7 -386,20 +390,20 @@@ void AnimatedVectorImageVisual::OnIniti
    mVectorAnimationTask->ResourceReadySignal().Connect(this, &AnimatedVectorImageVisual::OnResourceReady);
    mVectorAnimationTask->SetAnimationFinishedCallback(MakeCallback(this, &AnimatedVectorImageVisual::OnAnimationFinished));
  
-   mVectorAnimationTask->RequestLoad(mImageUrl, IsSynchronousLoadingRequired());
+   EncodedImageBuffer encodedImageBuffer;
+   if(mImageUrl.IsBufferResource())
+   {
+     // Increase reference count of External Resources :
+     // EncodedImageBuffer.
+     // Reference count will be decreased at destructor of the visual.
+     TextureManager& textureManager = mFactoryCache.GetTextureManager();
+     textureManager.UseExternalResource(mImageUrl.GetUrl());
+     encodedImageBuffer = textureManager.GetEncodedImageBuffer(mImageUrl.GetUrl());
+   }
+   mVectorAnimationTask->RequestLoad(mImageUrl, encodedImageBuffer, IsSynchronousLoadingRequired());
  
    auto& vectorAnimationManager = mFactoryCache.GetVectorAnimationManager();
    vectorAnimationManager.AddObserver(*this);
@@@ -19,6 -19,7 +19,7 @@@
  #include <dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.h>
  
  // EXTERNAL INCLUDES
+ #include <dali/devel-api/adaptor-framework/file-loader.h>
  #include <dali/integration-api/debug.h>
  #include <dali/integration-api/trace.h>
  #include <dali/public-api/math/math-utils.h>
@@@ -55,6 -56,7 +56,7 @@@ DALI_INIT_TRACE_FILTER(gTraceFilter, DA
  VectorAnimationTask::VectorAnimationTask(VisualFactoryCache& factoryCache)
  : AsyncTask(MakeCallback(this, &VectorAnimationTask::TaskCompleted), AsyncTask::PriorityType::HIGH, AsyncTask::ThreadType::WORKER_THREAD),
    mImageUrl(),
+   mEncodedImageBuffer(),
    mVectorRenderer(VectorAnimationRenderer::New()),
    mAnimationData(),
    mVectorAnimationThread(factoryCache.GetVectorAnimationManager().GetVectorAnimationThread()),
@@@ -148,19 -150,41 +150,41 @@@ bool VectorAnimationTask::Load(bool syn
    {
      std::ostringstream oss;
      oss << "[url:" << mImageUrl.GetUrl() << "]";
 -    DALI_TRACE_BEGIN(gTraceFilter, "DALI_LOTTIE_LOADING_TASK");
 +    // DALI_TRACE_BEGIN(gTraceFilter, "DALI_LOTTIE_LOADING_TASK"); ///< TODO : Open it if we can control trace log level
      DALI_LOG_RELEASE_INFO("BEGIN: DALI_LOTTIE_LOADING_TASK %s", oss.str().c_str());
    }
  #endif
  
-   if(!mVectorRenderer.Load(mImageUrl.GetUrl()))
+   if(mEncodedImageBuffer)
    {
-     DALI_LOG_ERROR("VectorAnimationTask::Load: Load failed [%s]\n", mImageUrl.GetUrl().c_str());
-     mLoadFailed = true;
+     if(!mVectorRenderer.Load(mEncodedImageBuffer.GetRawBuffer()))
+     {
+       mLoadFailed = true;
+     }
+     // We don't need to hold image buffer anymore.
+     mEncodedImageBuffer.Reset();
+   }
+   else if(mImageUrl.IsLocalResource())
+   {
+     if(!mVectorRenderer.Load(mImageUrl.GetUrl()))
+     {
+       mLoadFailed = true;
+     }
+   }
+   else
+   {
+     Dali::Vector<uint8_t> remoteData;
+     if(!Dali::FileLoader::DownloadFileSynchronously(mImageUrl.GetUrl(), remoteData) || // Failed if we fail to download json file,
+        !mVectorRenderer.Load(remoteData))                                              // or download data is not valid vector animation file.
+     {
+       mLoadFailed = true;
+     }
    }
  
    if(mLoadFailed)
    {
+     DALI_LOG_ERROR("VectorAnimationTask::Load: Load failed [%s]\n", mImageUrl.GetUrl().c_str());
      mLoadRequest = false;
      if(!synchronousLoading && mLoadCompletedCallback)
      {
      {
        std::ostringstream oss;
        oss << "[url:" << mImageUrl.GetUrl() << "]";
 -      DALI_TRACE_END(gTraceFilter, "DALI_LOTTIE_LOADING_TASK");
 +      // DALI_TRACE_END(gTraceFilter, "DALI_LOTTIE_LOADING_TASK"); ///< TODO : Open it if we can control trace log level
        DALI_LOG_RELEASE_INFO("END: DALI_LOTTIE_LOADING_TASK %s", oss.str().c_str());
      }
  #endif
    {
      std::ostringstream oss;
      oss << "[url:" << mImageUrl.GetUrl() << "]";
 -    DALI_TRACE_END(gTraceFilter, "DALI_LOTTIE_LOADING_TASK");
 +    // DALI_TRACE_END(gTraceFilter, "DALI_LOTTIE_LOADING_TASK"); ///< TODO : Open it if we can control trace log level
      DALI_LOG_RELEASE_INFO("END: DALI_LOTTIE_LOADING_TASK %s", oss.str().c_str());
    }
  #endif
@@@ -215,9 -239,10 +239,10 @@@ void VectorAnimationTask::SetRenderer(R
    DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetRenderer [%p]\n", this);
  }
  
- void VectorAnimationTask::RequestLoad(const VisualUrl& url, bool synchronousLoading)
+ void VectorAnimationTask::RequestLoad(const VisualUrl& url, EncodedImageBuffer encodedImageBuffer, bool synchronousLoading)
  {
-   mImageUrl = url;
+   mImageUrl           = url;
+   mEncodedImageBuffer = encodedImageBuffer;
  
    if(!synchronousLoading)
    {
@@@ -462,11 -487,6 +487,11 @@@ void VectorAnimationTask::GetLayerInfo(
    mVectorRenderer.GetLayerInfo(map);
  }
  
 +void VectorAnimationTask::GetMarkerInfo(Property::Map& map) const
 +{
 +  mVectorRenderer.GetMarkerInfo(map);
 +}
 +
  VectorAnimationTask::ResourceReadySignalType& VectorAnimationTask::ResourceReadySignal()
  {
    return mResourceReadySignal;
@@@ -22,6 -22,7 +22,7 @@@
  #include <dali/devel-api/adaptor-framework/vector-animation-renderer.h>
  #include <dali/devel-api/threading/conditional-wait.h>
  #include <dali/public-api/adaptor-framework/async-task-manager.h>
+ #include <dali/public-api/adaptor-framework/encoded-image-buffer.h>
  #include <dali/public-api/common/vector-wrapper.h>
  #include <dali/public-api/object/property-array.h>
  #include <chrono>
@@@ -162,9 -163,10 +163,10 @@@ public
     * @brief Requests to load the animation file.
     *
     * @param[in] url The url of the vector animation file
+    * @param[in] encodedImageBuffer The resource buffer if required.
     * @param[in] synchronousLoading True if the url should be loaded synchronously
     */
-   void RequestLoad(const VisualUrl& url, bool synchronousLoading);
+   void RequestLoad(const VisualUrl& url, EncodedImageBuffer encodedImageBuffer, bool synchronousLoading);
  
    /**
     * @brief Queries whether loading is requested.
    void GetLayerInfo(Property::Map& map) const;
  
    /**
 +   * @brief Gets the all marker information.
 +   * @param[out] map The marker information
 +   */
 +  void GetMarkerInfo(Property::Map& map) const;
 +
 +  /**
     * @brief Connect to this signal to be notified when the resource is ready.
     * @return The signal to connect to.
     */
@@@ -363,6 -359,7 +365,7 @@@ private
    };
  
    VisualUrl                            mImageUrl;
+   EncodedImageBuffer                   mEncodedImageBuffer;
    VectorAnimationRenderer              mVectorRenderer;
    std::vector<AnimationData>           mAnimationData[2];
    VectorAnimationThread&               mVectorAnimationThread;
@@@ -16,7 -16,7 +16,7 @@@
   */
  
  // CLASS HEADER
- #include "svg-task.h"
+ #include <dali-toolkit/internal/visuals/svg/svg-task.h>
  
  // EXTERNAL INCLUDES
  #include <dali/devel-api/adaptor-framework/file-loader.h>
@@@ -64,9 -64,10 +64,10 @@@ VectorImageRenderer SvgTask::GetRendere
    return mVectorRenderer;
  }
  
- SvgLoadingTask::SvgLoadingTask(VectorImageRenderer vectorRenderer, const VisualUrl& url, float dpi, CallbackBase* callback)
+ SvgLoadingTask::SvgLoadingTask(VectorImageRenderer vectorRenderer, const VisualUrl& url, EncodedImageBuffer encodedImageBuffer, float dpi, CallbackBase* callback)
  : SvgTask(vectorRenderer, callback, url.GetProtocolType() == VisualUrl::ProtocolType::REMOTE ? AsyncTask::PriorityType::LOW : AsyncTask::PriorityType::HIGH),
    mImageUrl(url),
+   mEncodedImageBuffer(encodedImageBuffer),
    mDpi(dpi)
  {
  }
@@@ -89,7 -90,7 +90,7 @@@ void SvgLoadingTask::Process(
    {
      std::ostringstream oss;
      oss << "[url:" << mImageUrl.GetUrl() << "]";
 -    DALI_TRACE_BEGIN(gTraceFilter, "DALI_SVG_LOADING_TASK");
 +    // DALI_TRACE_BEGIN(gTraceFilter, "DALI_SVG_LOADING_TASK"); ///< TODO : Open it if we can control trace log level
      DALI_LOG_RELEASE_INFO("BEGIN: DALI_SVG_LOADING_TASK %s", oss.str().c_str());
    }
  #endif
  
    Dali::Vector<uint8_t> buffer;
  
-   if(!mImageUrl.IsLocalResource())
+   if(mEncodedImageBuffer)
    {
-     if(!Dali::FileLoader::DownloadFileSynchronously(mImageUrl.GetUrl(), buffer))
+     // Copy raw buffer.
+     // TODO : Can't we load svg without copy buffer in future?
+     buffer = mEncodedImageBuffer.GetRawBuffer();
+     // We don't need to hold image buffer anymore.
+     mEncodedImageBuffer.Reset();
+   }
+   else if(mImageUrl.IsLocalResource())
+   {
+     if(!Dali::FileLoader::ReadFile(mImageUrl.GetUrl(), buffer))
      {
-       DALI_LOG_ERROR("Failed to download file! [%s]\n", mImageUrl.GetUrl().c_str());
+       DALI_LOG_ERROR("Failed to read file! [%s]\n", mImageUrl.GetUrl().c_str());
        loadFailed = true;
      }
    }
    else
    {
-     if(!Dali::FileLoader::ReadFile(mImageUrl.GetUrl(), buffer))
+     if(!Dali::FileLoader::DownloadFileSynchronously(mImageUrl.GetUrl(), buffer))
      {
-       DALI_LOG_ERROR("Failed to read file! [%s]\n", mImageUrl.GetUrl().c_str());
+       DALI_LOG_ERROR("Failed to download file! [%s]\n", mImageUrl.GetUrl().c_str());
        loadFailed = true;
      }
    }
  
    if(!loadFailed)
    {
+     buffer.Reserve(buffer.Count() + 1u);
      buffer.PushBack('\0');
  
      if(!mVectorRenderer.Load(buffer, mDpi))
      std::ostringstream oss;
      oss << "[success:" << mHasSucceeded << " ";
      oss << "url:" << mImageUrl.GetUrl() << "]";
 -    DALI_TRACE_END(gTraceFilter, "DALI_SVG_LOADING_TASK");
 +    // DALI_TRACE_END(gTraceFilter, "DALI_SVG_LOADING_TASK"); ///< TODO : Open it if we can control trace log level
      DALI_LOG_RELEASE_INFO("END: DALI_SVG_LOADING_TASK %s", oss.str().c_str());
    }
  #endif