XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFESystem

【Rust】XFE系统,基于Rust和汇编

公开
关注 0 Fork 0 Star 0
UTF-8
namespace XFESystem.Browser;

internal static class BrowserCssImages
{
    internal static IEnumerable<string> Sources(string value)
    {
        for (int offset = 0; offset < value.Length;)
        {
            int begin = value.IndexOf("url(", offset, StringComparison.OrdinalIgnoreCase);
            if (begin < 0) yield break;
            int cursor = begin + 4;
            while (cursor < value.Length && char.IsWhiteSpace(value[cursor])) cursor++;
            char quote = cursor < value.Length && value[cursor] is '\'' or '"' ? value[cursor++] : '\0';
            var source = new System.Text.StringBuilder();
            while (cursor < value.Length && (quote == '\0' ? value[cursor] != ')' : value[cursor] != quote))
            {
                char character = value[cursor++];
                if (character == '\\' && cursor < value.Length) character = value[cursor++];
                source.Append(character);
            }
            if (quote != '\0' && cursor < value.Length) cursor++;
            while (cursor < value.Length && char.IsWhiteSpace(value[cursor])) cursor++;
            if (cursor >= value.Length || value[cursor] != ')') yield break;
            if (source.Length != 0) yield return source.ToString().Trim();
            offset = cursor + 1;
        }
    }

    internal static BrowserRect Size(BrowserRect area, BrowserCanvasSurface? image, CssComputedStyle style)
    {
        if (image is null) return area;
        double width = image.Width, height = image.Height;
        string size = style.Get("background-size", "auto").Split(',')[0].Trim();
        if (size is "cover" or "contain")
        {
            double scale = size == "cover" ? Math.Max(area.Width / width, area.Height / height) : Math.Min(area.Width / width, area.Height / height);
            width *= scale; height *= scale;
        }
        else
        {
            var tokens = size.Split(' ', StringSplitOptions.RemoveEmptyEntries);
            double? w = tokens.Length > 0 ? CssValue.Length(tokens[0], area.Width, style.Font.Size, style.Viewport, 16) : null;
            double? h = tokens.Length > 1 ? CssValue.Length(tokens[1], area.Height, style.Font.Size, style.Viewport, 16) : null;
            if (w is not null || h is not null)
            { double ratio = width / height; width = w ?? h!.Value * ratio; height = h ?? w!.Value / ratio; }
        }
        string[] positions = style.Get("background-position", "0% 0%").Split(' ', StringSplitOptions.RemoveEmptyEntries);
        string px = positions.ElementAtOrDefault(0) ?? "0%", py = positions.ElementAtOrDefault(1) ?? "center";
        double Position(string token, double spare, double basis) => token switch
        { "left" or "top" => 0, "center" => spare / 2, "right" or "bottom" => spare, _ => token.EndsWith('%') ? CssValue.Number(token[..^1], 0) * spare / 100 : CssValue.Length(token, basis, style.Font.Size, style.Viewport, 16) ?? 0 };
        return new(area.X + Position(px, area.Width - width, area.Width), area.Y + Position(py, area.Height - height, area.Height), width, height);
    }
}