// niklas@protocol7.com // 80 using System; using System.IO; using System.Net; using System.Xml; using System.Collections.Generic; using SharpVectors.Xml; using SharpVectors.Dom.Stylesheets; namespace SharpVectors.Dom.Css { /// /// A XmlDocument with CSS support /// public class CssXmlDocument : Document, IDocumentCss, ICssView { #region Private Fields internal List styleElements = new List(); internal MediaList _currentMedia = new MediaList("all"); public CssStyleSheet UserAgentStyleSheet; public CssStyleSheet UserStyleSheet; private bool _static; private StyleSheetList _StyleSheets; private CssPropertyProfile _cssPropertyProfile = new CssPropertyProfile(); #endregion #region Constructors and Destructor /// /// Initializes a new instance of CssXmlDocument /// public CssXmlDocument() : base() { setupNodeChangeListeners(); SharpVectors.Net.ExtendedHttpWebRequest.Register(); SharpVectors.Net.DataWebRequest.Register(); } /// /// Initializes a new instance of CssXmlDocument /// /// The name table to use public CssXmlDocument(XmlNameTable nt) : base(nt) { setupNodeChangeListeners(); SharpVectors.Net.ExtendedHttpWebRequest.Register(); SharpVectors.Net.DataWebRequest.Register(); } #endregion #region Public Properties /// /// Gets or sets a value indicating whether this handles DOM dynamic changes. /// Sometimes (when loading or rendering) this needs to be disabled. /// See for more information about use /// /// true if static; otherwise, false. public bool Static { get { return _static; } set { _static = value; } } public MediaList Media { get { return _currentMedia; } set { _currentMedia = value; } } public CssPropertyProfile CssPropertyProfile { get { return _cssPropertyProfile; } set { _cssPropertyProfile = value; } } public string Url { get { return BaseURI; } } /// /// All the stylesheets associated with this document /// public IStyleSheetList StyleSheets { get { if (_StyleSheets == null) { _StyleSheets = new StyleSheetList(this); } return _StyleSheets; } } #endregion #region Public Methods public override XmlElement CreateElement(string prefix, string localName, string ns) { return new CssXmlElement(prefix, localName, ns, this); } /// /// Loads a XML document, compare to XmlDocument.Load() /// /// public override void Load(string filename) { using (StaticSection.Use(this)) { // remove any hash (won't work for local files) int hashStart = filename.IndexOf("#"); if (hashStart > -1) { filename = filename.Substring(0, hashStart); } base.Load(filename); } } public override void LoadXml(string xml) { using (StaticSection.Use(this)) { //base.LoadXml(xml); // we use a stream here, only not to use SvgDocument.Load(XmlReader) using (var xmlStream = new StringReader(xml)) { Load(xmlStream); } } } //JR added in public override void Load(XmlReader reader) { using (StaticSection.Use(this)) { base.Load(reader); } } /// /// Adds a element type to be used as style elements (e.g. as in the HTML style element) /// /// The namespace URI of the element /// The local-name of the element public void AddStyleElement(string ns, string localName) { styleElements.Add(new string[] { ns, localName }); } /// /// Sets the user agent stylesheet for this document /// /// The URI to the stylesheet public void SetUserAgentStyleSheet(string href) { UserAgentStyleSheet = new CssStyleSheet(null, href, String.Empty, String.Empty, null, CssStyleSheetType.UserAgent); } /// /// Sets the user stylesheet for this document /// /// The URI to the stylesheet public void SetUserStyleSheet(string href) { UserStyleSheet = new CssStyleSheet(null, href, String.Empty, String.Empty, null, CssStyleSheetType.User); } public void AddStyleSheet(string href) { UserStyleSheet = new CssStyleSheet(null, href, String.Empty, String.Empty, null, CssStyleSheetType.User); } public WebResponse GetResource(Uri absoluteUri) { WebRequest request = WebRequest.Create(absoluteUri); WebResponse response = request.GetResponse(); return response; } #endregion #region IDocumentCss Members /// /// This method is used to retrieve the override style declaration for a specified element and a specified pseudo-element. /// /// The element whose style is to be modified. This parameter cannot be null. /// The pseudo-element or null if none. /// The override style declaration. public SharpVectors.Dom.Css.ICssStyleDeclaration GetOverrideStyle(System.Xml.XmlElement elt, string pseudoElt) { throw new NotImplementedException("CssXmlDocument.GetOverrideStyle()"); } #endregion #region IViewCss Members /// /// This method is used to get the computed style as it is defined in [CSS2]. /// /// The element whose style is to be computed. This parameter cannot be null. /// The pseudo-element or null if none. /// The computed style. The CSSStyleDeclaration is read-only and contains only absolute values. public SharpVectors.Dom.Css.ICssStyleDeclaration GetComputedStyle(System.Xml.XmlElement elt, string pseudoElt) { if (elt == null) throw new NullReferenceException(); else if (!(elt is CssXmlElement)) throw new DomException(DomExceptionType.SyntaxErr, "element must of type CssXmlElement"); else { return ((CssXmlElement)elt).GetComputedStyle(pseudoElt); } } #endregion #region Update handling private void setupNodeChangeListeners() { XmlNodeChangedEventHandler handler = new XmlNodeChangedEventHandler(NodeChangedEvent); NodeChanged += handler; NodeInserted += handler; //NodeRemoving += handler; NodeRemoved += handler; } public void NodeChangedEvent(Object src, XmlNodeChangedEventArgs args) { if (!Static) { #region Attribute updates // xmlns:xml is auto-inserted whenever a selectNode is performed, we don't want those events if (args.Node is XmlText && args.NewParent is XmlAttribute && args.NewParent.Name != "xmlns:xml") { XmlAttribute attr = args.NewParent as XmlAttribute; CssXmlElement elm = attr.OwnerElement as CssXmlElement; if (elm != null) { elm.AttributeChange(attr, args); } } else if (args.Node is XmlAttribute && args.Node.Name != "xmlns:xml") { // the cause of the change is a XmlAttribute => happens during inserting or removing CssXmlElement oldElm = args.OldParent as CssXmlElement; if (oldElm != null) oldElm.AttributeChange(args.Node, args); CssXmlElement newElm = args.NewParent as CssXmlElement; if (newElm != null) newElm.AttributeChange(args.Node, args); } #endregion #region OnElementChange if (args.Node is XmlText && args.NewParent is XmlElement) { CssXmlElement element = (CssXmlElement)args.NewParent; element.ElementChange(src, args); } else if (args.Node is CssXmlElement) { if (args.Action == XmlNodeChangedAction.Insert || args.Action == XmlNodeChangedAction.Change) { // Changes to a child XML node may affect the sibling offsets (for example in tspan) // By calling the parent's OnElementChange, invalidation will propogate back to Node CssXmlElement newParent = (CssXmlElement)args.NewParent; newParent.ElementChange(src, args); } if (args.Action == XmlNodeChangedAction.Remove) { // Removing a child XML node may affect the sibling offsets (for example in tspan) CssXmlElement oldParent = (CssXmlElement)args.OldParent; oldParent.ElementChange(src, args); } } #endregion } } #endregion } }