RaUI/Source/ryControls/HtmlRenderer/Core/HtmlRendererUtils.cs
zilinsoft 3262955f2f ### 2023-11-07更新
------
#### RaUIV4    V4.0.2311.0701
- *.[全新]整合了MyDb、ryControls、MyDb_MySQL等dll文件到RaUI一个项目。
- *.[新增]新增ApkOp类,可以轻松获取APK信息。
- *.[新增]新增JsonExt扩展类,让Json操作更简单。
- *.[新增]新增WebP类,可以支持webp格式的图片。
- *.[改进]ryQuickSQL中的AddField方法改为自动替换已存在的同名值。
- *.[修复]ryQuickSQL中的AddFieldCalc方法无法正常计算的BUG。
2023-11-07 16:37:53 +08:00

123 lines
6.0 KiB
C#

// "Therefore those skilled at the unorthodox
// are infinite as heaven and earth,
// inexhaustible as the great rivers.
// When they come to an end,
// they begin again,
// like the days and months;
// they die and are reborn,
// like the four seasons."
//
// - Sun Tsu,
// "The Art of War"
using System;
using TheArtOfDev.HtmlRenderer.Adapters;
using TheArtOfDev.HtmlRenderer.Adapters.Entities;
namespace TheArtOfDev.HtmlRenderer.Core
{
/// <summary>
/// General utilities.
/// </summary>
public static class HtmlRendererUtils
{
/// <summary>
/// Measure the size of the html by performing layout under the given restrictions.
/// </summary>
/// <param name="g">the graphics to use</param>
/// <param name="htmlContainer">the html to calculate the layout for</param>
/// <param name="minSize">the minimal size of the rendered html (zero - not limit the width/height)</param>
/// <param name="maxSize">the maximum size of the rendered html, if not zero and html cannot be layout within the limit it will be clipped (zero - not limit the width/height)</param>
/// <returns>return: the size of the html to be rendered within the min/max limits</returns>
public static RSize MeasureHtmlByRestrictions(RGraphics g, HtmlContainerInt htmlContainer, RSize minSize, RSize maxSize)
{
// first layout without size restriction to know html actual size
htmlContainer.PerformLayout(g);
if (maxSize.Width > 0 && maxSize.Width < htmlContainer.ActualSize.Width)
{
// to allow the actual size be smaller than max we need to set max size only if it is really larger
htmlContainer.MaxSize = new RSize(maxSize.Width, 0);
htmlContainer.PerformLayout(g);
}
// restrict the final size by min/max
var finalWidth = Math.Max(maxSize.Width > 0 ? Math.Min(maxSize.Width, (int)htmlContainer.ActualSize.Width) : (int)htmlContainer.ActualSize.Width, minSize.Width);
// if the final width is larger than the actual we need to re-layout so the html can take the full given width.
if (finalWidth > htmlContainer.ActualSize.Width)
{
htmlContainer.MaxSize = new RSize(finalWidth, 0);
htmlContainer.PerformLayout(g);
}
var finalHeight = Math.Max(maxSize.Height > 0 ? Math.Min(maxSize.Height, (int)htmlContainer.ActualSize.Height) : (int)htmlContainer.ActualSize.Height, minSize.Height);
return new RSize(finalWidth, finalHeight);
}
/// <summary>
/// Perform the layout of the html container by given size restrictions returning the final size.<br/>
/// The layout can be effected by the HTML content in the <paramref name="htmlContainer"/> if <paramref name="autoSize"/> or
/// <paramref name="autoSizeHeightOnly"/> is set to true.<br/>
/// Handle minimum and maximum size restrictions.<br/>
/// Handle auto size and auto size for height only. if <paramref name="autoSize"/> is true <paramref name="autoSizeHeightOnly"/>
/// is ignored.<br/>
/// </summary>
/// <param name="g">the graphics used for layout</param>
/// <param name="htmlContainer">the html container to layout</param>
/// <param name="size">the current size</param>
/// <param name="minSize">the min size restriction - can be empty for no restriction</param>
/// <param name="maxSize">the max size restriction - can be empty for no restriction</param>
/// <param name="autoSize">if to modify the size (width and height) by html content layout</param>
/// <param name="autoSizeHeightOnly">if to modify the height by html content layout</param>
public static RSize Layout(RGraphics g, HtmlContainerInt htmlContainer, RSize size, RSize minSize, RSize maxSize, bool autoSize, bool autoSizeHeightOnly)
{
if (autoSize)
htmlContainer.MaxSize = new RSize(0, 0);
else if (autoSizeHeightOnly)
htmlContainer.MaxSize = new RSize(size.Width, 0);
else
htmlContainer.MaxSize = size;
htmlContainer.PerformLayout(g);
RSize newSize = size;
if (autoSize || autoSizeHeightOnly)
{
if (autoSize)
{
if (maxSize.Width > 0 && maxSize.Width < htmlContainer.ActualSize.Width)
{
// to allow the actual size be smaller than max we need to set max size only if it is really larger
htmlContainer.MaxSize = maxSize;
htmlContainer.PerformLayout(g);
}
else if (minSize.Width > 0 && minSize.Width > htmlContainer.ActualSize.Width)
{
// if min size is larger than the actual we need to re-layout so all 100% layouts will be correct
htmlContainer.MaxSize = new RSize(minSize.Width, 0);
htmlContainer.PerformLayout(g);
}
newSize = htmlContainer.ActualSize;
}
else if (Math.Abs(size.Height - htmlContainer.ActualSize.Height) > 0.01)
{
var prevWidth = size.Width;
// make sure the height is not lower than min if given
newSize.Height = minSize.Height > 0 && minSize.Height > htmlContainer.ActualSize.Height
? minSize.Height
: htmlContainer.ActualSize.Height;
// handle if changing the height of the label affects the desired width and those require re-layout
if (Math.Abs(prevWidth - size.Width) > 0.01)
return Layout(g, htmlContainer, size, minSize, maxSize, false, true);
}
}
return newSize;
}
}
}