(WebView) Set display area and Change Visual when WebView relayout 07/299107/5
authorEunki, Hong <eunkiki.hong@samsung.com>
Wed, 20 Sep 2023 02:05:43 +0000 (11:05 +0900)
committerEunki Hong <eunkiki.hong@samsung.com>
Tue, 26 Sep 2023 00:26:55 +0000 (09:26 +0900)
Previously, we change display area after only at PropertyNotification time.
It will wait until 1 frame rendered.

If we change web view size by event side, the display area applied lately.

This patch make we change update area when OnRelayout, so we can apply
changeness more faster timing.

--

And also, Let we change visual when the size of webview changed.
If so, it can be reduce some flickering effect while change the udpate area.

Change-Id: Ia7d6becc11160d88353f62bbdb43f75764550b67
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
dali-toolkit/internal/controls/web-view/web-view-impl.cpp [changed mode: 0755->0644]
dali-toolkit/internal/controls/web-view/web-view-impl.h

old mode 100755 (executable)
new mode 100644 (file)
index a92c4bb..987f297
  */
 
 // CLASS HEADER
-#include "web-view-impl.h"
+#include <dali-toolkit/internal/controls/web-view/web-view-impl.h>
 
 // EXTERNAL INCLUDES
-#include <cstring>
 #include <dali/devel-api/adaptor-framework/web-engine/web-engine-back-forward-list.h>
 #include <dali/devel-api/adaptor-framework/web-engine/web-engine-certificate.h>
 #include <dali/devel-api/adaptor-framework/web-engine/web-engine-console-message.h>
 #include <dali-toolkit/devel-api/controls/control-devel.h>
 #include <dali-toolkit/devel-api/controls/web-view/web-back-forward-list.h>
 #include <dali-toolkit/devel-api/controls/web-view/web-settings.h>
+#include <dali-toolkit/devel-api/visuals/visual-actions-devel.h>
+#include <dali-toolkit/internal/visuals/visual-base-impl.h>
 #include <dali-toolkit/internal/visuals/visual-factory-impl.h>
-#include <dali-toolkit/public-api/image-loader/image.h>
 #include <dali-toolkit/public-api/image-loader/image-url.h>
+#include <dali-toolkit/public-api/image-loader/image.h>
 #include <dali-toolkit/public-api/visuals/image-visual-properties.h>
 
 #include <functional>
@@ -95,6 +96,57 @@ std::unordered_map<Dali::WebEnginePlugin*, Dali::WeakHandle<Toolkit::WebView>>&
   static std::unordered_map<Dali::WebEnginePlugin*, Dali::WeakHandle<Toolkit::WebView>> pluginWebViewMap;
   return pluginWebViewMap;
 }
+
+enum class DisplayAreaCalculateOption
+{
+  PROPERTY         = 0, ///< Calculate display update area by property
+  CURRENT_PROPERTY = 1, ///< Calculate display update area by current property
+};
+
+/**
+ * @brief Helper function to calculate exact display area, offset and size.
+ * It will be useful when view size is not integer value, or view size is not matched with texture size.
+ *
+ * @param[in] self The view itself.
+ * @param[in] option Option of this calculation. Let we decide what kind of property will be used.
+ * @return DisplayArea for this view.
+ */
+Rect<int32_t> CalculateDisplayArea(Dali::Actor self, DisplayAreaCalculateOption option)
+{
+  bool    positionUsesAnchorPoint = self.GetProperty<bool>(Actor::Property::POSITION_USES_ANCHOR_POINT);
+  Vector3 actorSize               = (option == DisplayAreaCalculateOption::CURRENT_PROPERTY) ? self.GetCurrentProperty<Vector3>(Actor::Property::SIZE) * self.GetCurrentProperty<Vector3>(Actor::Property::SCALE)
+                                                                                             : self.GetProperty<Vector3>(Actor::Property::SIZE) * self.GetProperty<Vector3>(Actor::Property::SCALE);
+  Vector3 anchorPointOffSet       = actorSize * (positionUsesAnchorPoint ? self.GetCurrentProperty<Vector3>(Actor::Property::ANCHOR_POINT) : AnchorPoint::TOP_LEFT);
+  Vector2 screenPosition          = (option == DisplayAreaCalculateOption::CURRENT_PROPERTY) ? self.GetProperty<Vector2>(Actor::Property::SCREEN_POSITION)
+                                                                                             : Dali::DevelActor::CalculateScreenPosition(self);
+
+  Dali::Rect<int32_t> displayArea;
+  displayArea.x      = screenPosition.x - anchorPointOffSet.x;
+  displayArea.y      = screenPosition.y - anchorPointOffSet.y;
+  displayArea.width  = actorSize.x;
+  displayArea.height = actorSize.y;
+
+  return displayArea;
+}
+
+constexpr Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
+
+/**
+ * @brief Helper function to calculate exact pixel area value by view and texture size.
+ * It will be useful when view size is not integer value, or view size is not matched with texture size.
+ *
+ * @param[in] viewSize The size of view.
+ * @param[in] textureWidth The width of texture, that must be integer type.
+ * @param[in] textureHeight The height of texture, that must be integer type.
+ * @return PixelArea value that image visual can use.
+ */
+Vector4 CalculatePixelArea(const Size& viewSize, const uint32_t textureWidth, const uint32_t textureHeight)
+{
+  float widthRatio  = textureWidth == 0u ? 1.0f : viewSize.width / static_cast<float>(textureWidth);
+  float heightRatio = textureHeight == 0u ? 1.0f : viewSize.height / static_cast<float>(textureHeight);
+  return Vector4(0.0f, 0.0f, widthRatio, heightRatio);
+}
+
 } // namespace
 
 WebView::WebView(const std::string& locale, const std::string& timezoneId)
@@ -102,10 +154,13 @@ WebView::WebView(const std::string& locale, const std::string& timezoneId)
   mVisual(),
   mWebViewSize(Stage::GetCurrent().GetSize()),
   mWebEngine(),
+  mLastRenderedNativeImageWidth(0u),
+  mLastRenderedNativeImageHeight(0u),
   mWebViewArea(0, 0, mWebViewSize.width, mWebViewSize.height),
   mVideoHoleEnabled(false),
   mMouseEventsEnabled(true),
   mKeyEventsEnabled(true),
+  mVisualChangeRequired(false),
   mScreenshotCapturedCallback{nullptr},
   mFrameRenderedCallback{nullptr}
 {
@@ -123,10 +178,13 @@ WebView::WebView(uint32_t argc, char** argv)
   mVisual(),
   mWebViewSize(Stage::GetCurrent().GetSize()),
   mWebEngine(),
+  mLastRenderedNativeImageWidth(0u),
+  mLastRenderedNativeImageHeight(0u),
   mWebViewArea(0, 0, mWebViewSize.width, mWebViewSize.height),
   mVideoHoleEnabled(false),
   mMouseEventsEnabled(true),
   mKeyEventsEnabled(true),
+  mVisualChangeRequired(false),
   mScreenshotCapturedCallback{nullptr},
   mFrameRenderedCallback{nullptr}
 {
@@ -149,7 +207,7 @@ WebView::~WebView()
   if(mWebEngine)
   {
     auto iter = GetPluginWebViewTable().find(mWebEngine.GetPlugin());
-    if (iter != GetPluginWebViewTable().end())
+    if(iter != GetPluginWebViewTable().end())
     {
       GetPluginWebViewTable().erase(iter);
     }
@@ -161,7 +219,7 @@ Toolkit::WebView WebView::New()
 {
   WebView*         impl   = new WebView();
   Toolkit::WebView handle = Toolkit::WebView(*impl);
-  if (impl->GetPlugin())
+  if(impl->GetPlugin())
   {
     GetPluginWebViewTable()[impl->GetPlugin()] = handle;
   }
@@ -173,7 +231,7 @@ Toolkit::WebView WebView::New(const std::string& locale, const std::string& time
 {
   WebView*         impl   = new WebView(locale, timezoneId);
   Toolkit::WebView handle = Toolkit::WebView(*impl);
-  if (impl->GetPlugin())
+  if(impl->GetPlugin())
   {
     GetPluginWebViewTable()[impl->GetPlugin()] = handle;
   }
@@ -185,7 +243,7 @@ Toolkit::WebView WebView::New(uint32_t argc, char** argv)
 {
   WebView*         impl   = new WebView(argc, argv);
   Toolkit::WebView handle = Toolkit::WebView(*impl);
-  if (impl->GetPlugin())
+  if(impl->GetPlugin())
   {
     GetPluginWebViewTable()[impl->GetPlugin()] = handle;
   }
@@ -196,7 +254,7 @@ Toolkit::WebView WebView::New(uint32_t argc, char** argv)
 Toolkit::WebView WebView::FindWebView(Dali::WebEnginePlugin* plugin)
 {
   auto iter = GetPluginWebViewTable().find(plugin);
-  if (iter != GetPluginWebViewTable().end())
+  if(iter != GetPluginWebViewTable().end())
   {
     return iter->second.GetHandle();
   }
@@ -246,6 +304,18 @@ DevelControl::ControlAccessible* WebView::CreateAccessibleObject()
   return new WebViewAccessible(Self(), mWebEngine);
 }
 
+void WebView::OnRelayout(const Vector2& size, RelayoutContainer& container)
+{
+  if(!mWebEngine)
+  {
+    return;
+  }
+
+  auto displayArea = CalculateDisplayArea(Self(), DisplayAreaCalculateOption::PROPERTY);
+
+  SetDisplayArea(displayArea);
+}
+
 Dali::Toolkit::WebSettings* WebView::GetSettings() const
 {
   return mWebSettings.get();
@@ -772,48 +842,44 @@ void WebView::OnFrameRendered()
     mFrameRenderedCallback();
   }
 
-  // Make sure that mVisual is created only once.
-  if (mVisual)
-    return;
-
-  Dali::Toolkit::ImageUrl nativeImageUrl = Dali::Toolkit::Image::GenerateUrl(mWebEngine.GetNativeImageSource());
-  mVisual                                = Toolkit::VisualFactory::Get().CreateVisual({{Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE}, {Toolkit::ImageVisual::Property::URL, nativeImageUrl.GetUrl()}});
-  if(mVisual)
+  // Make sure that mVisual is created only if required.
+  if(mVisualChangeRequired || !mVisual)
   {
-    DevelControl::RegisterVisual(*this, Toolkit::WebView::Property::URL, mVisual);
-    EnableBlendMode(!mVideoHoleEnabled);
-  }
-}
+    // Reset flag
+    mVisualChangeRequired = false;
 
-void WebView::OnDisplayAreaUpdated(Dali::PropertyNotification& /*source*/)
-{
-  if(!mWebEngine)
-    return;
+    auto nativeImageSourcePtr = mWebEngine.GetNativeImageSource();
 
-  Actor self(Self());
+    mLastRenderedNativeImageWidth  = nativeImageSourcePtr->GetWidth();
+    mLastRenderedNativeImageHeight = nativeImageSourcePtr->GetHeight();
 
-  bool    positionUsesAnchorPoint = self.GetProperty<bool>(Actor::Property::POSITION_USES_ANCHOR_POINT);
-  Vector3 actorSize               = self.GetCurrentProperty<Vector3>(Actor::Property::SIZE) * self.GetCurrentProperty<Vector3>(Actor::Property::SCALE);
-  Vector3 anchorPointOffSet       = actorSize * (positionUsesAnchorPoint ? self.GetCurrentProperty<Vector3>(Actor::Property::ANCHOR_POINT) : AnchorPoint::TOP_LEFT);
-  Vector2 screenPosition          = self.GetProperty<Vector2>(Actor::Property::SCREEN_POSITION);
+    Dali::Toolkit::ImageUrl nativeImageUrl = Dali::Toolkit::Image::GenerateUrl(nativeImageSourcePtr);
 
-  Dali::Rect<int32_t> displayArea;
-  displayArea.x      = screenPosition.x - anchorPointOffSet.x;
-  displayArea.y      = screenPosition.y - anchorPointOffSet.y;
-  displayArea.width  = actorSize.x;
-  displayArea.height = actorSize.y;
+    mVisual = Toolkit::VisualFactory::Get().CreateVisual(
+      {{Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE},
+       {Toolkit::ImageVisual::Property::URL, nativeImageUrl.GetUrl()},
+       {Toolkit::ImageVisual::Property::PIXEL_AREA, FULL_TEXTURE_RECT},
+       {Toolkit::ImageVisual::Property::WRAP_MODE_U, Dali::WrapMode::CLAMP_TO_EDGE},
+       {Toolkit::ImageVisual::Property::WRAP_MODE_V, Dali::WrapMode::CLAMP_TO_EDGE}});
 
-  Size displaySize = Size(displayArea.width, displayArea.height);
-  if(mWebViewSize != displaySize)
-  {
-    mWebViewSize = displaySize;
+    if(mVisual)
+    {
+      DevelControl::RegisterVisual(*this, Toolkit::WebView::Property::URL, mVisual);
+      EnableBlendMode(!mVideoHoleEnabled);
+    }
   }
+}
 
-  if(mWebViewArea != displayArea)
+void WebView::OnDisplayAreaUpdated(Dali::PropertyNotification& /*source*/)
+{
+  if(!mWebEngine)
   {
-    mWebViewArea = displayArea;
-    mWebEngine.UpdateDisplayArea(mWebViewArea);
+    return;
   }
+
+  auto displayArea = CalculateDisplayArea(Self(), DisplayAreaCalculateOption::CURRENT_PROPERTY);
+
+  SetDisplayArea(displayArea);
 }
 
 void WebView::OnVisibilityChanged(Actor actor, bool isVisible, Dali::DevelActor::VisibilityChange::Type type)
@@ -833,6 +899,31 @@ void WebView::OnScreenshotCaptured(Dali::PixelData pixel)
   }
 }
 
+void WebView::SetDisplayArea(const Dali::Rect<int32_t>& displayArea)
+{
+  Size displaySize = Size(displayArea.width, displayArea.height);
+  if(mWebViewSize != displaySize)
+  {
+    mWebViewSize = displaySize;
+  }
+
+  if(mWebViewArea != displayArea)
+  {
+    // WebEngine visual size changed. we have to re-create visual.
+    mVisualChangeRequired = true;
+
+    // Change old visual's pixel area matched as changed web view size
+    if(mVisual)
+    {
+      auto pixelArea = CalculatePixelArea(mWebViewSize, mLastRenderedNativeImageWidth, mLastRenderedNativeImageHeight);
+      Toolkit::GetImplementation(mVisual).DoAction(Toolkit::DevelVisual::Action::UPDATE_PROPERTY, {{Toolkit::ImageVisual::Property::PIXEL_AREA, pixelArea}});
+    }
+
+    mWebViewArea = displayArea;
+    mWebEngine.UpdateDisplayArea(mWebViewArea);
+  }
+}
+
 void WebView::OnSceneConnection(int depth)
 {
   Control::OnSceneConnection(depth);
@@ -1258,7 +1349,9 @@ bool WebView::SetVisibility(bool visible)
 }
 
 WebView::WebViewAccessible::WebViewAccessible(Dali::Actor self, Dali::WebEngine& webEngine)
-: ControlAccessible(self), mRemoteChild{}, mWebEngine{webEngine}
+: ControlAccessible(self),
+  mRemoteChild{},
+  mWebEngine{webEngine}
 {
   mRemoteChild.SetParent(this);
 
index 0673f77..5cf24e5 100755 (executable)
@@ -443,6 +443,11 @@ private: // From Control
   DevelControl::ControlAccessible* CreateAccessibleObject() override;
 
   /**
+   * @copydoc Toolkit::Internal::Control::OnRelayout()
+   */
+  void OnRelayout(const Vector2& size, RelayoutContainer& container) override;
+
+  /**
    * @copydoc Toolkit::Control::GetNaturalSize
    */
   Vector3 GetNaturalSize() override;
@@ -678,6 +683,14 @@ private:
    */
   void OnScreenshotCaptured(Dali::PixelData pixel);
 
+  /**
+   * @brief Set DisplayArea by input value.
+   * It will send changes area infomations to webengine internally.
+   *
+   * @param[in] displayArea The display area for current webview want to show.
+   */
+  void SetDisplayArea(const Dali::Rect<int32_t>& displayArea);
+
 protected:
   class WebViewAccessible : public DevelControl::ControlAccessible
   {
@@ -711,6 +724,9 @@ private:
   Dali::Size                  mWebViewSize;
   Dali::WebEngine             mWebEngine;
 
+  uint32_t mLastRenderedNativeImageWidth;
+  uint32_t mLastRenderedNativeImageHeight;
+
   std::unique_ptr<Dali::Toolkit::WebSettings>        mWebSettings;
   std::unique_ptr<Dali::Toolkit::WebBackForwardList> mWebBackForwardList;
 
@@ -722,6 +738,8 @@ private:
   bool                       mMouseEventsEnabled;
   bool                       mKeyEventsEnabled;
 
+  bool mVisualChangeRequired;
+
   Dali::Toolkit::WebView::WebViewScreenshotCapturedCallback mScreenshotCapturedCallback;
   Dali::WebEnginePlugin::WebEngineFrameRenderedCallback     mFrameRenderedCallback;
 };