From 3f0b161cd0ef9a97d932325a7e17730293ff2e68 Mon Sep 17 00:00:00 2001
From: chylex <contact@chylex.com>
Date: Tue, 3 Apr 2018 18:26:33 +0200
Subject: [PATCH] Move screenshot height calculation to the screenshot window

---
 Core/Bridge/CallbackBridge.cs                 | 19 --------------
 Core/Bridge/TweetDeckBridge.cs                |  4 +--
 Core/FormBrowser.cs                           |  4 +--
 .../FormNotificationScreenshotable.cs         | 25 +++++++++++++-----
 .../Screenshot/ScreenshotBridge.cs            | 26 +++++++++++++++++++
 .../Screenshot/TweetScreenshotManager.cs      |  5 ++--
 Resources/Scripts/code.js                     | 15 +----------
 Resources/Scripts/screenshot.js               | 16 ++++++++++++
 TweetDuck.csproj                              |  2 +-
 9 files changed, 68 insertions(+), 48 deletions(-)
 delete mode 100644 Core/Bridge/CallbackBridge.cs
 create mode 100644 Core/Notification/Screenshot/ScreenshotBridge.cs
 create mode 100644 Resources/Scripts/screenshot.js

diff --git a/Core/Bridge/CallbackBridge.cs b/Core/Bridge/CallbackBridge.cs
deleted file mode 100644
index 804e11ff..00000000
--- a/Core/Bridge/CallbackBridge.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-using System;
-using System.Windows.Forms;
-using TweetDuck.Core.Controls;
-
-namespace TweetDuck.Core.Bridge{
-    sealed class CallbackBridge{
-        private readonly Control owner;
-        private readonly Action safeCallback;
-
-        public CallbackBridge(Control owner, Action safeCallback){
-            this.owner = owner;
-            this.safeCallback = safeCallback;
-        }
-
-        public void Trigger(){
-            owner.InvokeSafe(safeCallback);
-        }
-    }
-}
diff --git a/Core/Bridge/TweetDeckBridge.cs b/Core/Bridge/TweetDeckBridge.cs
index 4dd3115f..042e6461 100644
--- a/Core/Bridge/TweetDeckBridge.cs
+++ b/Core/Bridge/TweetDeckBridge.cs
@@ -117,8 +117,8 @@ public void OnTweetSound(){
             });
         }
 
-        public void ScreenshotTweet(string html, int width, int height){
-            form.InvokeAsyncSafe(() => form.OnTweetScreenshotReady(html, width, height));
+        public void ScreenshotTweet(string html, int width){
+            form.InvokeAsyncSafe(() => form.OnTweetScreenshotReady(html, width));
         }
 
         public void PlayVideo(string url, string username){
diff --git a/Core/FormBrowser.cs b/Core/FormBrowser.cs
index fb69aeeb..0e07c6d5 100644
--- a/Core/FormBrowser.cs
+++ b/Core/FormBrowser.cs
@@ -455,12 +455,12 @@ public void ShowTweetDetail(string columnId, string chirpId, string fallbackUrl)
             AnalyticsFile.TweetDetails.Trigger();
         }
 
-        public void OnTweetScreenshotReady(string html, int width, int height){
+        public void OnTweetScreenshotReady(string html, int width){
             if (notificationScreenshotManager == null){
                 notificationScreenshotManager = new TweetScreenshotManager(this, plugins);
             }
 
-            notificationScreenshotManager.Trigger(html, width, height);
+            notificationScreenshotManager.Trigger(html, width);
             AnalyticsFile.TweetScreenshots.Trigger();
         }
 
diff --git a/Core/Notification/Screenshot/FormNotificationScreenshotable.cs b/Core/Notification/Screenshot/FormNotificationScreenshotable.cs
index df508819..e1cc0b47 100644
--- a/Core/Notification/Screenshot/FormNotificationScreenshotable.cs
+++ b/Core/Notification/Screenshot/FormNotificationScreenshotable.cs
@@ -3,7 +3,7 @@
 using System.Drawing.Imaging;
 using System.Windows.Forms;
 using CefSharp;
-using TweetDuck.Core.Bridge;
+using TweetDuck.Core.Controls;
 using TweetDuck.Core.Other;
 using TweetDuck.Core.Utils;
 using TweetDuck.Data;
@@ -15,19 +15,26 @@ sealed class FormNotificationScreenshotable : FormNotificationBase{
         protected override bool CanDragWindow => false;
 
         private readonly PluginManager plugins;
+        private readonly int width;
 
-        public FormNotificationScreenshotable(Action callback, FormBrowser owner, PluginManager pluginManager) : base(owner, false){
+        public FormNotificationScreenshotable(Action callback, FormBrowser owner, PluginManager pluginManager, string html, int width) : base(owner, false){
             this.plugins = pluginManager;
+            this.width = width;
 
-            browser.RegisterAsyncJsObject("$TD_NotificationScreenshot", new CallbackBridge(this, callback));
+            browser.RegisterAsyncJsObject("$TD_NotificationScreenshot", new ScreenshotBridge(this, SetScreenshotHeight, callback));
 
             browser.LoadingStateChanged += (sender, args) => {
                 if (!args.IsLoading){
                     using(IFrame frame = args.Browser.MainFrame){
-                        ScriptLoader.ExecuteScript(frame, "window.setTimeout($TD_NotificationScreenshot.trigger, document.getElementsByTagName('iframe').length ? 267 : 67)", "gen:screenshot");
+                        if (!ScriptLoader.ExecuteFile(frame, "screenshot.js")){
+                            this.InvokeAsyncSafe(callback);
+                        }
                     }
                 }
             };
+            
+            LoadTweet(new TweetNotification(string.Empty, string.Empty, string.Empty, html, 0, string.Empty, string.Empty));
+            SetScreenshotHeight(0);
         }
         
         protected override string GetTweetHTML(TweetNotification tweet){
@@ -40,12 +47,16 @@ protected override string GetTweetHTML(TweetNotification tweet){
             return html;
         }
 
-        public void LoadNotificationForScreenshot(TweetNotification tweet, int width, int height){
-            LoadTweet(tweet);
-            SetNotificationSize(width, height);
+        private void SetScreenshotHeight(int height){
+            SetNotificationSize(width, height); // TODO test how it works on high DPI, probably not great?
         }
 
         public void TakeScreenshot(){
+            if (ClientSize.Height == 0){
+                FormMessage.Error("Screenshot Failed", "Could not detect screenshot size.", FormMessage.OK);
+                return;
+            }
+            
             IntPtr context = NativeMethods.GetDC(this.Handle);
 
             if (context == IntPtr.Zero){
diff --git a/Core/Notification/Screenshot/ScreenshotBridge.cs b/Core/Notification/Screenshot/ScreenshotBridge.cs
new file mode 100644
index 00000000..eeb841ff
--- /dev/null
+++ b/Core/Notification/Screenshot/ScreenshotBridge.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Windows.Forms;
+using TweetDuck.Core.Controls;
+
+namespace TweetDuck.Core.Notification.Screenshot{
+    sealed class ScreenshotBridge{
+        private readonly Control owner;
+
+        private readonly Action<int> safeSetHeight;
+        private readonly Action safeTriggerScreenshot;
+
+        public ScreenshotBridge(Control owner, Action<int> safeSetHeight, Action safeTriggerScreenshot){
+            this.owner = owner;
+            this.safeSetHeight = safeSetHeight;
+            this.safeTriggerScreenshot = safeTriggerScreenshot;
+        }
+
+        public void SetHeight(int tweetHeight){
+            owner.InvokeSafe(() => safeSetHeight(tweetHeight));
+        }
+
+        public void TriggerScreenshot(){
+            owner.InvokeSafe(safeTriggerScreenshot);
+        }
+    }
+}
diff --git a/Core/Notification/Screenshot/TweetScreenshotManager.cs b/Core/Notification/Screenshot/TweetScreenshotManager.cs
index b7341519..cf2500c0 100644
--- a/Core/Notification/Screenshot/TweetScreenshotManager.cs
+++ b/Core/Notification/Screenshot/TweetScreenshotManager.cs
@@ -37,13 +37,12 @@ private void disposer_Tick(object sender, EventArgs e){
             screenshot = null;
         }
 
-        public void Trigger(string html, int width, int height){
+        public void Trigger(string html, int width){
             if (screenshot != null){
                 return;
             }
 
-            screenshot = new FormNotificationScreenshotable(Callback, owner, plugins);
-            screenshot.LoadNotificationForScreenshot(new TweetNotification(string.Empty, string.Empty, string.Empty, html, 0, string.Empty, string.Empty), width, height);
+            screenshot = new FormNotificationScreenshotable(Callback, owner, plugins, html, width);
             screenshot.Show();
             timeout.Start();
 
diff --git a/Resources/Scripts/code.js b/Resources/Scripts/code.js
index 877b35eb..d60220e3 100644
--- a/Resources/Scripts/code.js
+++ b/Resources/Scripts/code.js
@@ -705,20 +705,7 @@
         html.addClass("td-notification-padded");
       }
       
-      let testTweet = html.clone().css({
-        position: "absolute",
-        left: "-999px",
-        width: columnWidth+"px"
-      }).appendTo(document.body);
-      
-      let testTweetAvatar = testTweet.find(".tweet-avatar").first();
-      let avatarBottom = testTweetAvatar.length === 1 ? testTweetAvatar.offset().top+testTweetAvatar.height() : 0;
-      
-      let realHeight = Math.floor(Math.max(testTweet.height(), avatarBottom+9));
-      testTweet.remove();
-      
-      html.find(".js-stream-item-content").first().css("height", "100vh");
-      $TD.screenshotTweet(html[0].outerHTML, columnWidth, realHeight);
+      $TD.screenshotTweet(html[0].outerHTML, columnWidth);
     };
   })();
   
diff --git a/Resources/Scripts/screenshot.js b/Resources/Scripts/screenshot.js
new file mode 100644
index 00000000..6ffb5f06
--- /dev/null
+++ b/Resources/Scripts/screenshot.js
@@ -0,0 +1,16 @@
+(function($TD){
+  document.getElementsByClassName("column")[0].style.height = "100%";
+  
+  let ele = document.getElementsByTagName("article")[0];
+  ele.style.width = window.outerWidth+"px";
+  
+  ele.style.position = "absolute";
+  let contentHeight = ele.offsetHeight;
+  ele.style.position = "static";
+  
+  let avatar = ele.querySelector(".tweet-avatar");
+  let avatarBottom = avatar ? avatar.getBoundingClientRect().bottom : 0;
+  
+  $TD.setHeight(Math.floor(Math.max(contentHeight, avatarBottom+9)));
+  setTimeout($TD.triggerScreenshot, document.getElementsByTagName("iframe").length ? 267 : 67);
+})($TD_NotificationScreenshot);
diff --git a/TweetDuck.csproj b/TweetDuck.csproj
index 26700592..82637d7b 100644
--- a/TweetDuck.csproj
+++ b/TweetDuck.csproj
@@ -245,7 +245,7 @@
     <Compile Include="Core\Other\Settings\TabSettingsNotifications.Designer.cs">
       <DependentUpon>TabSettingsNotifications.cs</DependentUpon>
     </Compile>
-    <Compile Include="Core\Bridge\CallbackBridge.cs" />
+    <Compile Include="Core\Notification\Screenshot\ScreenshotBridge.cs" />
     <Compile Include="Data\CommandLineArgs.cs" />
     <Compile Include="Core\Notification\Screenshot\FormNotificationScreenshotable.cs">
       <SubType>Form</SubType>