Skip to content

WinForms - Viewport(?) does not take up size of control after container resize and leaves black space #5174

@BenceBordas

Description

@BenceBordas

Is there an existing issue for this?

  • I have searched both open/closed issues, no issue already exists.

CefSharp Version

139.0.280

Operating System

Windows 11

Architecture

x64

.Net Version

.NET Framework 4.7.2

Implementation

WinForms

Reproduction Steps

Form1.Designer.cs:

partial class Form1
{
    /// <summary>
    /// Required designer variable.
    /// </summary>
    private System.ComponentModel.IContainer components = null;

    /// <summary>
    /// Clean up any resources being used.
    /// </summary>
    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }

    #region Windows Form Designer generated code

    /// <summary>
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    /// </summary>
    private void InitializeComponent()
    {
        this._scrollPanel = new System.Windows.Forms.Panel();
        this._browserContainer = new System.Windows.Forms.Panel();
        this._browser = new CefSharp.WinForms.ChromiumWebBrowser();
        this._buttonContainer = new System.Windows.Forms.Panel();
        this._resizeButton = new System.Windows.Forms.Button();
        this._loadButton = new System.Windows.Forms.Button();
        this._scrollPanel.SuspendLayout();
        this._browserContainer.SuspendLayout();
        this._buttonContainer.SuspendLayout();
        this.SuspendLayout();
        // 
        // _scrollPanel
        // 
        this._scrollPanel.AutoScroll = true;
        this._scrollPanel.BackColor = System.Drawing.Color.DarkMagenta;
        this._scrollPanel.Controls.Add(this._browserContainer);
        this._scrollPanel.Controls.Add(this._buttonContainer);
        this._scrollPanel.Dock = System.Windows.Forms.DockStyle.Fill;
        this._scrollPanel.Location = new System.Drawing.Point(0, 0);
        this._scrollPanel.Name = "_scrollPanel";
        this._scrollPanel.Size = new System.Drawing.Size(800, 450);
        this._scrollPanel.TabIndex = 0;
        // 
        // _browserContainer
        // 
        this._browserContainer.BackColor = System.Drawing.Color.Plum;
        this._browserContainer.Controls.Add(this._browser);
        this._browserContainer.Dock = System.Windows.Forms.DockStyle.Top;
        this._browserContainer.Location = new System.Drawing.Point(0, 80);
        this._browserContainer.MinimumSize = new System.Drawing.Size(100, 100);
        this._browserContainer.Name = "_browserContainer";
        this._browserContainer.Padding = new System.Windows.Forms.Padding(10, 0, 10, 0);
        this._browserContainer.Size = new System.Drawing.Size(800, 100);
        this._browserContainer.TabIndex = 1;
        // 
        // _browser
        // 
        this._browser.ActivateBrowserOnCreation = false;
        this._browser.Dock = System.Windows.Forms.DockStyle.Fill;
        this._browser.Location = new System.Drawing.Point(10, 0);
        this._browser.MinimumSize = new System.Drawing.Size(100, 100);
        this._browser.Name = "_browser";
        this._browser.Size = new System.Drawing.Size(780, 100);
        this._browser.TabIndex = 0;
        // 
        // _buttonContainer
        // 
        this._buttonContainer.BackColor = System.Drawing.Color.DarkSlateBlue;
        this._buttonContainer.Controls.Add(this._resizeButton);
        this._buttonContainer.Controls.Add(this._loadButton);
        this._buttonContainer.Dock = System.Windows.Forms.DockStyle.Top;
        this._buttonContainer.Location = new System.Drawing.Point(0, 0);
        this._buttonContainer.Name = "_buttonContainer";
        this._buttonContainer.Padding = new System.Windows.Forms.Padding(10);
        this._buttonContainer.Size = new System.Drawing.Size(800, 80);
        this._buttonContainer.TabIndex = 0;
        // 
        // _resizeButton
        // 
        this._resizeButton.Dock = System.Windows.Forms.DockStyle.Fill;
        this._resizeButton.Location = new System.Drawing.Point(10, 40);
        this._resizeButton.Name = "_resizeButton";
        this._resizeButton.Size = new System.Drawing.Size(780, 30);
        this._resizeButton.TabIndex = 0;
        this._resizeButton.Text = "Resize";
        this._resizeButton.UseVisualStyleBackColor = true;
        this._resizeButton.Click += new System.EventHandler(this.ResizeButton_Click);
        // 
        // _loadButton
        // 
        this._loadButton.Dock = System.Windows.Forms.DockStyle.Top;
        this._loadButton.Location = new System.Drawing.Point(10, 10);
        this._loadButton.MinimumSize = new System.Drawing.Size(30, 30);
        this._loadButton.Name = "_loadButton";
        this._loadButton.Size = new System.Drawing.Size(780, 30);
        this._loadButton.TabIndex = 1;
        this._loadButton.Text = "Load Page";
        this._loadButton.UseVisualStyleBackColor = true;
        this._loadButton.Click += new System.EventHandler(this.LoadButton_Click);
        // 
        // Form1
        // 
        this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
        this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
        this.ClientSize = new System.Drawing.Size(800, 450);
        this.Controls.Add(this._scrollPanel);
        this.Name = "Form1";
        this.Text = "Form1";
        this._scrollPanel.ResumeLayout(false);
        this._browserContainer.ResumeLayout(false);
        this._buttonContainer.ResumeLayout(false);
        this.ResumeLayout(false);

    }

    #endregion

    private System.Windows.Forms.Panel _scrollPanel;
    private System.Windows.Forms.Panel _buttonContainer;
    private System.Windows.Forms.Button _resizeButton;
    private System.Windows.Forms.Panel _browserContainer;
    private CefSharp.WinForms.ChromiumWebBrowser _browser;
    private System.Windows.Forms.Button _loadButton;
}

Form1.cs:

    public partial class Form1 : Form
    {

        private static readonly string _html = @"
<!DOCTYPE html>
<html>

<head>
  <meta charset=""utf-8"">
  <title>NewCefTest</title>
  <base href=""/"">
  <meta name=""viewport"" content=""width=device-width, initial-scale=1"">
</head>

<body>
  <div style=""display: flex; flex-direction: column; gap: 10px;"">
    <div
      style=""border: 1px solid black; box-sizing: border-box; display: flex; align-items: center; justify-content: center; height: 100px;"">
      <span>1</span>
    </div>
    <div
      style=""border: 1px solid black; box-sizing: border-box; display: flex; align-items: center; justify-content: center; height: 100px;"">
      <span>2</span>
    </div>
    <div
      style=""border: 1px solid black; box-sizing: border-box; display: flex; align-items: center; justify-content: center; height: 100px;"">
      <span>3</span>
    </div>
    <div
      style=""border: 1px solid black; box-sizing: border-box; display: flex; align-items: center; justify-content: center; height: 100px;"">
      <span>4</span>
    </div>
    <div
      style=""border: 1px solid black; box-sizing: border-box; display: flex; align-items: center; justify-content: center; height: 100px;"">
      <span>5</span>
    </div>
    <div
      style=""border: 1px solid black; box-sizing: border-box; display: flex; align-items: center; justify-content: center; height: 100px;"">
      <span>6</span>
    </div>
    <div
      style=""border: 1px solid black; box-sizing: border-box; display: flex; align-items: center; justify-content: center; height: 100px;"">
      <span>7</span>
    </div>
    <div
      style=""border: 1px solid black; box-sizing: border-box; display: flex; align-items: center; justify-content: center; height: 100px;"">
      <span>8</span>
    </div>
    <div
      style=""border: 1px solid black; box-sizing: border-box; display: flex; align-items: center; justify-content: center; height: 100px;"">
      <span>9</span>
    </div>
    <div
      style=""border: 1px solid black; box-sizing: border-box; display: flex; align-items: center; justify-content: center; height: 100px;"">
      <span>10</span>
    </div>
    <div
      style=""border: 1px solid black; box-sizing: border-box; display: flex; align-items: center; justify-content: center; height: 100px;"">
      <span>11</span>
    </div>
    <div
      style=""border: 1px solid black; box-sizing: border-box; display: flex; align-items: center; justify-content: center; height: 100px;"">
      <span>12</span>
    </div>
    <div
      style=""border: 1px solid black; box-sizing: border-box; display: flex; align-items: center; justify-content: center; height: 100px;"">
      <span>13</span>
    </div>
    <div
      style=""border: 1px solid black; box-sizing: border-box; display: flex; align-items: center; justify-content: center; height: 100px;"">
      <span>14</span>
    </div>
    <div
      style=""border: 1px solid black; box-sizing: border-box; display: flex; align-items: center; justify-content: center; height: 100px;"">
      <span>15</span>
    </div>
    <div
      style=""border: 1px solid black; box-sizing: border-box; display: flex; align-items: center; justify-content: center; height: 100px;"">
      <span>16</span>
    </div>
    <div
      style=""border: 1px solid black; box-sizing: border-box; display: flex; align-items: center; justify-content: center; height: 100px;"">
      <span>17</span>
    </div>
    <div
      style=""border: 1px solid black; box-sizing: border-box; display: flex; align-items: center; justify-content: center; height: 100px;"">
      <span>18</span>
    </div>
    <div
      style=""border: 1px solid black; box-sizing: border-box; display: flex; align-items: center; justify-content: center; height: 100px;"">
      <span>19</span>
    </div>
    <div
      style=""border: 1px solid black; box-sizing: border-box; display: flex; align-items: center; justify-content: center; height: 100px;"">
      <span>20</span>
    </div>
  </div>


</body>

</html>";

        public Form1()
        {
            InitializeComponent();

            _browser.IsBrowserInitializedChanged += (s, e) =>
            {
                _browser.ShowDevTools();
            };
        }

        private void ResizeButton_Click(object sender, EventArgs e)
        {
            if (!_browser.IsBrowserInitialized)
            {
                return;
            }

            IFrame mainFrame = _browser.GetMainFrame();
            if (mainFrame == null)
            {
                _browserContainer.Height = _browser.MinimumSize.Height;
                return;
            }

            // An example that gets the Document Height
            var task = mainFrame.EvaluateScriptAsync("(function() { var body = document.body, html = document.documentElement; return  Math.max( body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight ); })();");

            //Continue execution on the UI Thread
            task.ContinueWith(t =>
            {
                if (!t.IsFaulted)
                {
                    var response = t.Result;
                    var result = response.Success ? (response.Result ?? "null") : response.Message;

                    if (result is int height)
                    {
                        _browserContainer.Height = height;
                    }
                }
            }, TaskScheduler.FromCurrentSynchronizationContext());
        }

        private void LoadButton_Click(object sender, EventArgs e)
        {
            _browser.LoadHtml(_html);
        }
    }

Expected behavior

Based on the structure in Form1.Designer.cs, we first load the page with the _loadButton. Then, by clicking the _resizeButton, we should get the document height. We use that height to set the height of the _browserContainer, which causes the _scrollPanel to resize and add a scroll bar. This gives us the ability to scroll down to the bottom and view the 20th div in the document.
This allows us to eliminate the scroll inside the _browser, leaving us to be able to scroll only the panel.

Actual behavior

Sadly, we don't get the expected behavior. Instead, we get a weird combination of "correct sizing of the control but no sizing of the viewport."
It seems like the _browser control gets resized since it's docked to fill in the _browserContainer, which we set.
However, the "Viewport" does not size after it. It's sort of "cut in half."

Image

Strangely, when I first resize using the button or resize the entire form horizontally, we receive a "size feedback" (I don't know the specific name for it) of the "viewport." This is definitely not the document itself, since the _browser control received the correct size from the script.

Image

The scroll for the document appears inside the _browser control, with which I can scroll all the way down and see the actual bottom of the document, which is the 20th div.

Regression?

We are updating from version 98.x because we are experiencing DPI issues. After updating to the latest version (currently 139.0.280), we solved the DPI issue but encountered other problems. I've been switching between versions to see where this issue starts to appear.
I got to version 130.1.90, up to which the "black wall" did not appear. After that, I could not test from 131.3.50 to 137.0.100 for some reason. My debug started, but shortly after, before any form appeared, it stopped without any errors. For the life of me, I could not figure out why.
Starting with version 138.0.340, I could debug again and I experienced the "black wall."
In conclusion, based on my limited testing, the problem appears to start somewhere between versions 131.3.50 and 137.0.100.

Known Workarounds

I've been looking through forums and GitHub issues, and I even dared to ask Copilot about the issue. I haven't seen anything related to this issue nor found a solution.

Copilot suggested adding the following to app.manifest:

<application xmlns="urn:schemas-microsoft-com:asm.v3">
    <windowsSettings>
        <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
        <dpiAware>true/PM</dpiAware>
    </windowsSettings>
</application>

I am not sure if its even relevant to the issue, but it did not help.

From what I've read here and there, as well as from Copilot, I should add arguments to CefSettings. I've ended up with the following, some of which we actually use in our current version 98.x implementation:

internal static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static int Main()
    {
        var settings = new CefSettings()
        {
            LogFile = "C:\\Debug.log", //You can customise this path
            LogSeverity = LogSeverity.Info, // You can change the log level
        };

        settings.CefCommandLineArgs.Add("allow-access-from-files");
        settings.CefCommandLineArgs.Add("allow-universal-access-from-files");
        settings.CefCommandLineArgs.Add("disable-web-security");

        settings.CefCommandLineArgs.Add("disable-gpu-vsync", "1");
        settings.CefCommandLineArgs.Add("disable-gpu", "1");
        settings.CefCommandLineArgs.Add("disable-gpu-compositing");


        //Perform dependency check to make sure all relevant resources are in our output directory.
        var initialized = Cef.Initialize(settings, performDependencyCheck: true, browserProcessHandler: null);

        if (!initialized)
        {
            var exitCode = Cef.GetExitCode();

            if (exitCode == ResultCode.NormalExitProcessNotified)
            {
                MessageBox.Show($"Cef.Initialize failed with {exitCode}, another process is already using cache path {string.Empty}");
            }
            else
            {
                MessageBox.Show($"Cef.Initialize failed with {exitCode}, check the log file for more details.");
            }

            return 0;
        }

        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());

        return 0;
    }
}

Once again, sadly it did not change anything.

Does this problem also occur in the CEF Sample Application

No, can't reproduce the issue, because of functional differences.

Other information

Sadly I do not get any exception, since cef seems to be working correctly(?).
Inside Debug.log this is all I get:

[23116:21508:0919/114036.887:WARNING:chrome\browser\signin\account_consistency_mode_manager.cc:74] Desktop Identity Consistency cannot be enabled as no OAuth client ID and client secret have been configured.
[23116:13632:0919/114040.790:ERROR:google_apis\gcm\engine\registration_request.cc:291] Registration response error message: DEPRECATED_ENDPOINT
[23116:13632:0919/114101.693:ERROR:google_apis\gcm\engine\connection_factory_impl.cc:434] Failed to connect to MCS endpoint with error -118

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions