e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
501 lines
17 KiB
C#
501 lines
17 KiB
C#
//------------------------------------------------------------------------------
|
|
// <copyright file="CssTextWriter.cs" company="Microsoft">
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// </copyright>
|
|
//------------------------------------------------------------------------------
|
|
|
|
namespace System.Web.UI {
|
|
using System;
|
|
using System.Collections;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Text;
|
|
using System.Web.Util;
|
|
|
|
|
|
/// <devdoc>
|
|
/// Derived TextWriter that provides CSS rendering API.
|
|
/// </devdoc>
|
|
internal sealed class CssTextWriter : TextWriter {
|
|
private TextWriter _writer;
|
|
|
|
private static Hashtable attrKeyLookupTable;
|
|
private static AttributeInformation[] attrNameLookupArray;
|
|
|
|
static CssTextWriter() {
|
|
// register known style attributes, HtmlTextWriterStyle.Length
|
|
attrKeyLookupTable = new Hashtable((int)HtmlTextWriterStyle.ZIndex + 1);
|
|
attrNameLookupArray = new AttributeInformation[(int)HtmlTextWriterStyle.ZIndex + 1];
|
|
|
|
RegisterAttribute("background-color", HtmlTextWriterStyle.BackgroundColor);
|
|
RegisterAttribute("background-image", HtmlTextWriterStyle.BackgroundImage, true, true);
|
|
RegisterAttribute("border-collapse", HtmlTextWriterStyle.BorderCollapse);
|
|
RegisterAttribute("border-color", HtmlTextWriterStyle.BorderColor);
|
|
RegisterAttribute("border-style", HtmlTextWriterStyle.BorderStyle);
|
|
RegisterAttribute("border-width", HtmlTextWriterStyle.BorderWidth);
|
|
RegisterAttribute("color", HtmlTextWriterStyle.Color);
|
|
RegisterAttribute("cursor", HtmlTextWriterStyle.Cursor);
|
|
RegisterAttribute("direction", HtmlTextWriterStyle.Direction);
|
|
RegisterAttribute("display", HtmlTextWriterStyle.Display);
|
|
RegisterAttribute("filter", HtmlTextWriterStyle.Filter);
|
|
RegisterAttribute("font-family", HtmlTextWriterStyle.FontFamily, true);
|
|
RegisterAttribute("font-size", HtmlTextWriterStyle.FontSize);
|
|
RegisterAttribute("font-style", HtmlTextWriterStyle.FontStyle);
|
|
RegisterAttribute("font-variant", HtmlTextWriterStyle.FontVariant);
|
|
RegisterAttribute("font-weight", HtmlTextWriterStyle.FontWeight);
|
|
RegisterAttribute("height", HtmlTextWriterStyle.Height);
|
|
RegisterAttribute("left", HtmlTextWriterStyle.Left);
|
|
RegisterAttribute("list-style-image", HtmlTextWriterStyle.ListStyleImage, true, true);
|
|
RegisterAttribute("list-style-type", HtmlTextWriterStyle.ListStyleType);
|
|
RegisterAttribute("margin", HtmlTextWriterStyle.Margin);
|
|
RegisterAttribute("margin-bottom", HtmlTextWriterStyle.MarginBottom);
|
|
RegisterAttribute("margin-left", HtmlTextWriterStyle.MarginLeft);
|
|
RegisterAttribute("margin-right", HtmlTextWriterStyle.MarginRight);
|
|
RegisterAttribute("margin-top", HtmlTextWriterStyle.MarginTop);
|
|
RegisterAttribute("overflow-x", HtmlTextWriterStyle.OverflowX);
|
|
RegisterAttribute("overflow-y", HtmlTextWriterStyle.OverflowY);
|
|
RegisterAttribute("overflow", HtmlTextWriterStyle.Overflow);
|
|
RegisterAttribute("padding", HtmlTextWriterStyle.Padding);
|
|
RegisterAttribute("padding-bottom", HtmlTextWriterStyle.PaddingBottom);
|
|
RegisterAttribute("padding-left", HtmlTextWriterStyle.PaddingLeft);
|
|
RegisterAttribute("padding-right", HtmlTextWriterStyle.PaddingRight);
|
|
RegisterAttribute("padding-top", HtmlTextWriterStyle.PaddingTop);
|
|
RegisterAttribute("position", HtmlTextWriterStyle.Position);
|
|
RegisterAttribute("text-align", HtmlTextWriterStyle.TextAlign);
|
|
RegisterAttribute("text-decoration", HtmlTextWriterStyle.TextDecoration);
|
|
RegisterAttribute("text-overflow", HtmlTextWriterStyle.TextOverflow);
|
|
RegisterAttribute("top", HtmlTextWriterStyle.Top);
|
|
RegisterAttribute("vertical-align", HtmlTextWriterStyle.VerticalAlign);
|
|
RegisterAttribute("visibility", HtmlTextWriterStyle.Visibility);
|
|
RegisterAttribute("width", HtmlTextWriterStyle.Width);
|
|
RegisterAttribute("white-space", HtmlTextWriterStyle.WhiteSpace);
|
|
RegisterAttribute("z-index", HtmlTextWriterStyle.ZIndex);
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// Initializes an instance of a CssTextWriter with its underlying TextWriter.
|
|
/// </devdoc>
|
|
public CssTextWriter(TextWriter writer) {
|
|
_writer = writer;
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
public override Encoding Encoding {
|
|
get {
|
|
return _writer.Encoding;
|
|
}
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
public override string NewLine {
|
|
get {
|
|
return _writer.NewLine;
|
|
}
|
|
set {
|
|
_writer.NewLine = value;
|
|
}
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
public override void Close() {
|
|
_writer.Close();
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
public override void Flush() {
|
|
_writer.Flush();
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// Returns the HtmlTextWriterStyle value for known style attributes.
|
|
/// </devdoc>
|
|
public static HtmlTextWriterStyle GetStyleKey(string styleName) {
|
|
if (!String.IsNullOrEmpty(styleName)) {
|
|
object key = attrKeyLookupTable[styleName.ToLower(CultureInfo.InvariantCulture)];
|
|
if (key != null) {
|
|
return (HtmlTextWriterStyle)key;
|
|
}
|
|
}
|
|
|
|
return (HtmlTextWriterStyle)(-1);
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// Returns the name of the attribute corresponding to the specified HtmlTextWriterStyle value.
|
|
/// </devdoc>
|
|
public static string GetStyleName(HtmlTextWriterStyle styleKey) {
|
|
if ((int)styleKey >= 0 && (int)styleKey < attrNameLookupArray.Length) {
|
|
return attrNameLookupArray[(int)styleKey].name;
|
|
}
|
|
|
|
return String.Empty;
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// Does the specified style key require attribute value encoding if the value is being
|
|
/// rendered in a style attribute.
|
|
/// </devdoc>
|
|
public static bool IsStyleEncoded(HtmlTextWriterStyle styleKey) {
|
|
if ((int)styleKey >= 0 && (int)styleKey < attrNameLookupArray.Length) {
|
|
return attrNameLookupArray[(int)styleKey].encode;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
/// <devdoc>
|
|
/// Registers the specified style attribute to create a mapping between a string representation
|
|
/// and the corresponding HtmlTextWriterStyle value.
|
|
/// </devdoc>
|
|
internal static void RegisterAttribute(string name, HtmlTextWriterStyle key) {
|
|
RegisterAttribute(name, key, false, false);
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
/// <devdoc>
|
|
/// Registers the specified style attribute to create a mapping between a string representation
|
|
/// and the corresponding HtmlTextWriterStyle value.
|
|
/// </devdoc>
|
|
internal static void RegisterAttribute(string name, HtmlTextWriterStyle key, bool encode) {
|
|
RegisterAttribute(name, key, encode, false);
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
/// <devdoc>
|
|
/// Registers the specified style attribute to create a mapping between a string representation
|
|
/// and the corresponding HtmlTextWriterStyle value.
|
|
/// In addition, the mapping can include additional information about the attribute type
|
|
/// such as whether it is a URL.
|
|
/// </devdoc>
|
|
internal static void RegisterAttribute(string name, HtmlTextWriterStyle key, bool encode, bool isUrl) {
|
|
string nameLCase = name.ToLower(CultureInfo.InvariantCulture);
|
|
|
|
attrKeyLookupTable.Add(nameLCase, key);
|
|
if ((int)key < attrNameLookupArray.Length) {
|
|
attrNameLookupArray[(int)key] = new AttributeInformation(name, encode, isUrl);
|
|
}
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
public override void Write(string s) {
|
|
_writer.Write(s);
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
public override void Write(bool value) {
|
|
_writer.Write(value);
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
public override void Write(char value) {
|
|
_writer.Write(value);
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
public override void Write(char[] buffer) {
|
|
_writer.Write(buffer);
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
public override void Write(char[] buffer, int index, int count) {
|
|
_writer.Write(buffer, index, count);
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
public override void Write(double value) {
|
|
_writer.Write(value);
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
public override void Write(float value) {
|
|
_writer.Write(value);
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
public override void Write(int value) {
|
|
_writer.Write(value);
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
public override void Write(long value) {
|
|
_writer.Write(value);
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
public override void Write(object value) {
|
|
_writer.Write(value);
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
public override void Write(string format, object arg0) {
|
|
_writer.Write(format, arg0);
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
public override void Write(string format, object arg0, object arg1) {
|
|
_writer.Write(format, arg0, arg1);
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
public override void Write(string format, params object[] arg) {
|
|
_writer.Write(format, arg);
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// Render out the specified style attribute and value.
|
|
/// </devdoc>
|
|
public void WriteAttribute(string name, string value) {
|
|
WriteAttribute(_writer, GetStyleKey(name), name, value);
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// Render out the specified style attribute and value.
|
|
/// </devdoc>
|
|
public void WriteAttribute(HtmlTextWriterStyle key, string value) {
|
|
WriteAttribute(_writer, key, GetStyleName(key), value);
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// Render the specified style attribute into the specified TextWriter.
|
|
/// This method contains all the logic for rendering a CSS name/value pair.
|
|
/// </devdoc>
|
|
private static void WriteAttribute(TextWriter writer, HtmlTextWriterStyle key, string name, string value) {
|
|
writer.Write(name);
|
|
writer.Write(':');
|
|
|
|
bool isUrl = false;
|
|
if (key != (HtmlTextWriterStyle)(-1)) {
|
|
isUrl = attrNameLookupArray[(int)key].isUrl;
|
|
}
|
|
|
|
if (isUrl == false) {
|
|
writer.Write(value);
|
|
}
|
|
else {
|
|
WriteUrlAttribute(writer, value);
|
|
}
|
|
|
|
writer.Write(';');
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// Render the specified style attributes. This is used by HtmlTextWriter to render out all
|
|
/// its collected style attributes.
|
|
/// </devdoc>
|
|
internal static void WriteAttributes(TextWriter writer, RenderStyle[] styles, int count) {
|
|
for (int i = 0; i < count; i++) {
|
|
RenderStyle style = styles[i];
|
|
WriteAttribute(writer, style.key, style.name, style.value);
|
|
}
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// Start rendering a new CSS rule with the given selector.
|
|
/// </devdoc>
|
|
public void WriteBeginCssRule(string selector) {
|
|
_writer.Write(selector);
|
|
_writer.Write(" { ");
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// End the current CSS rule that is being rendered.
|
|
/// </devdoc>
|
|
public void WriteEndCssRule() {
|
|
_writer.WriteLine(" }");
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
public override void WriteLine(string s) {
|
|
_writer.WriteLine(s);
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
public override void WriteLine() {
|
|
_writer.WriteLine();
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
public override void WriteLine(bool value) {
|
|
_writer.WriteLine(value);
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
public override void WriteLine(char value) {
|
|
_writer.WriteLine(value);
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
public override void WriteLine(char[] buffer) {
|
|
_writer.WriteLine(buffer);
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
public override void WriteLine(char[] buffer, int index, int count) {
|
|
_writer.WriteLine(buffer, index, count);
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
public override void WriteLine(double value) {
|
|
_writer.WriteLine(value);
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
public override void WriteLine(float value) {
|
|
_writer.WriteLine(value);
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
public override void WriteLine(int value) {
|
|
_writer.WriteLine(value);
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
public override void WriteLine(long value) {
|
|
_writer.WriteLine(value);
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
public override void WriteLine(object value) {
|
|
_writer.WriteLine(value);
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
public override void WriteLine(string format, object arg0) {
|
|
_writer.WriteLine(format, arg0);
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
public override void WriteLine(string format, object arg0, object arg1) {
|
|
_writer.WriteLine(format, arg0, arg1);
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
public override void WriteLine(string format, params object[] arg) {
|
|
_writer.WriteLine(format, arg);
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
public override void WriteLine(UInt32 value) {
|
|
_writer.WriteLine(value);
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// Writes out the specified URL value with the appropriate encoding
|
|
/// and url() syntax.
|
|
/// internal for unit testing.
|
|
/// </devdoc>
|
|
internal static void WriteUrlAttribute(TextWriter writer, string url) {
|
|
string urlValue = url;
|
|
|
|
char[] quotes = new char[] { '\'', '"'};
|
|
char? surroundingQuote = null;
|
|
|
|
if (StringUtil.StringStartsWith(url, "url(")) {
|
|
int urlIndex = 4;
|
|
int urlLength = url.Length - 4;
|
|
if (StringUtil.StringEndsWith(url, ')')) {
|
|
urlLength--;
|
|
}
|
|
|
|
// extract out the actual URL value
|
|
urlValue = url.Substring(urlIndex, urlLength).Trim();
|
|
}
|
|
|
|
// The CSS specification http://www.w3.org/TR/CSS2/syndata.html#uri says the ' and " characters are
|
|
// optional for specifying the url values.
|
|
// And we do not want to pass them to UrlPathEncode if they are present.
|
|
foreach (char quote in quotes) {
|
|
if (StringUtil.StringStartsWith(urlValue, quote) && StringUtil.StringEndsWith(urlValue, quote)) {
|
|
urlValue = urlValue.Trim(quote);
|
|
surroundingQuote = quote;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// write out the "url(" prefix
|
|
writer.Write("url(");
|
|
if (surroundingQuote != null) {
|
|
writer.Write(surroundingQuote);
|
|
}
|
|
|
|
writer.Write(HttpUtility.UrlPathEncode(urlValue));
|
|
|
|
if (surroundingQuote != null) {
|
|
writer.Write(surroundingQuote);
|
|
}
|
|
// write out the end of the "url()" syntax
|
|
writer.Write(")");
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// Holds information about each registered style attribute.
|
|
/// </devdoc>
|
|
private struct AttributeInformation {
|
|
public string name;
|
|
public bool isUrl;
|
|
public bool encode;
|
|
|
|
public AttributeInformation(string name, bool encode, bool isUrl) {
|
|
this.name = name;
|
|
this.encode = encode;
|
|
this.isUrl = isUrl;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// Holds information about each style attribute that needs to be rendered.
|
|
/// This is used by the tag rendering API of HtmlTextWriter.
|
|
/// </devdoc>
|
|
internal struct RenderStyle {
|
|
public string name;
|
|
public string value;
|
|
public HtmlTextWriterStyle key;
|
|
}
|
|
}
|