namespace XFESystem.Browser; internal static class BrowserCssImages { internal static IEnumerable 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); } }