michael@0: /* michael@0: * Copyright (c) 2007 Henri Sivonen michael@0: * Copyright (c) 2007-2011 Mozilla Foundation michael@0: * michael@0: * Permission is hereby granted, free of charge, to any person obtaining a michael@0: * copy of this software and associated documentation files (the "Software"), michael@0: * to deal in the Software without restriction, including without limitation michael@0: * the rights to use, copy, modify, merge, publish, distribute, sublicense, michael@0: * and/or sell copies of the Software, and to permit persons to whom the michael@0: * Software is furnished to do so, subject to the following conditions: michael@0: * michael@0: * The above copyright notice and this permission notice shall be included in michael@0: * all copies or substantial portions of the Software. michael@0: * michael@0: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR michael@0: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, michael@0: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL michael@0: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER michael@0: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING michael@0: * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER michael@0: * DEALINGS IN THE SOFTWARE. michael@0: */ michael@0: michael@0: package nu.validator.htmlparser.impl; michael@0: michael@0: import nu.validator.htmlparser.annotation.Inline; michael@0: import nu.validator.htmlparser.annotation.Local; michael@0: import nu.validator.htmlparser.annotation.NsUri; michael@0: michael@0: final class StackNode { michael@0: final int flags; michael@0: michael@0: final @Local String name; michael@0: michael@0: final @Local String popName; michael@0: michael@0: final @NsUri String ns; michael@0: michael@0: final T node; michael@0: michael@0: // Only used on the list of formatting elements michael@0: HtmlAttributes attributes; michael@0: michael@0: private int refcount = 1; michael@0: michael@0: // [NOCPP[ michael@0: michael@0: private final TaintableLocatorImpl locator; michael@0: michael@0: public TaintableLocatorImpl getLocator() { michael@0: return locator; michael@0: } michael@0: michael@0: // ]NOCPP] michael@0: michael@0: @Inline public int getFlags() { michael@0: return flags; michael@0: } michael@0: michael@0: public int getGroup() { michael@0: return flags & ElementName.GROUP_MASK; michael@0: } michael@0: michael@0: public boolean isScoping() { michael@0: return (flags & ElementName.SCOPING) != 0; michael@0: } michael@0: michael@0: public boolean isSpecial() { michael@0: return (flags & ElementName.SPECIAL) != 0; michael@0: } michael@0: michael@0: public boolean isFosterParenting() { michael@0: return (flags & ElementName.FOSTER_PARENTING) != 0; michael@0: } michael@0: michael@0: public boolean isHtmlIntegrationPoint() { michael@0: return (flags & ElementName.HTML_INTEGRATION_POINT) != 0; michael@0: } michael@0: michael@0: // [NOCPP[ michael@0: michael@0: public boolean isOptionalEndTag() { michael@0: return (flags & ElementName.OPTIONAL_END_TAG) != 0; michael@0: } michael@0: michael@0: // ]NOCPP] michael@0: michael@0: /** michael@0: * Constructor for copying. This doesn't take another StackNode michael@0: * because in C++ the caller is reponsible for reobtaining the local names michael@0: * from another interner. michael@0: * michael@0: * @param flags michael@0: * @param ns michael@0: * @param name michael@0: * @param node michael@0: * @param popName michael@0: * @param attributes michael@0: */ michael@0: StackNode(int flags, @NsUri String ns, @Local String name, T node, michael@0: @Local String popName, HtmlAttributes attributes michael@0: // [NOCPP[ michael@0: , TaintableLocatorImpl locator michael@0: // ]NOCPP] michael@0: ) { michael@0: this.flags = flags; michael@0: this.name = name; michael@0: this.popName = popName; michael@0: this.ns = ns; michael@0: this.node = node; michael@0: this.attributes = attributes; michael@0: this.refcount = 1; michael@0: // [NOCPP[ michael@0: this.locator = locator; michael@0: // ]NOCPP] michael@0: } michael@0: michael@0: /** michael@0: * Short hand for well-known HTML elements. michael@0: * michael@0: * @param elementName michael@0: * @param node michael@0: */ michael@0: StackNode(ElementName elementName, T node michael@0: // [NOCPP[ michael@0: , TaintableLocatorImpl locator michael@0: // ]NOCPP] michael@0: ) { michael@0: this.flags = elementName.getFlags(); michael@0: this.name = elementName.name; michael@0: this.popName = elementName.name; michael@0: this.ns = "http://www.w3.org/1999/xhtml"; michael@0: this.node = node; michael@0: this.attributes = null; michael@0: this.refcount = 1; michael@0: assert !elementName.isCustom() : "Don't use this constructor for custom elements."; michael@0: // [NOCPP[ michael@0: this.locator = locator; michael@0: // ]NOCPP] michael@0: } michael@0: michael@0: /** michael@0: * Constructor for HTML formatting elements. michael@0: * michael@0: * @param elementName michael@0: * @param node michael@0: * @param attributes michael@0: */ michael@0: StackNode(ElementName elementName, T node, HtmlAttributes attributes michael@0: // [NOCPP[ michael@0: , TaintableLocatorImpl locator michael@0: // ]NOCPP] michael@0: ) { michael@0: this.flags = elementName.getFlags(); michael@0: this.name = elementName.name; michael@0: this.popName = elementName.name; michael@0: this.ns = "http://www.w3.org/1999/xhtml"; michael@0: this.node = node; michael@0: this.attributes = attributes; michael@0: this.refcount = 1; michael@0: assert !elementName.isCustom() : "Don't use this constructor for custom elements."; michael@0: // [NOCPP[ michael@0: this.locator = locator; michael@0: // ]NOCPP] michael@0: } michael@0: michael@0: /** michael@0: * The common-case HTML constructor. michael@0: * michael@0: * @param elementName michael@0: * @param node michael@0: * @param popName michael@0: */ michael@0: StackNode(ElementName elementName, T node, @Local String popName michael@0: // [NOCPP[ michael@0: , TaintableLocatorImpl locator michael@0: // ]NOCPP] michael@0: ) { michael@0: this.flags = elementName.getFlags(); michael@0: this.name = elementName.name; michael@0: this.popName = popName; michael@0: this.ns = "http://www.w3.org/1999/xhtml"; michael@0: this.node = node; michael@0: this.attributes = null; michael@0: this.refcount = 1; michael@0: // [NOCPP[ michael@0: this.locator = locator; michael@0: // ]NOCPP] michael@0: } michael@0: michael@0: /** michael@0: * Constructor for SVG elements. Note that the order of the arguments is michael@0: * what distinguishes this from the HTML constructor. This is ugly, but michael@0: * AFAICT the least disruptive way to make this work with Java's generics michael@0: * and without unnecessary branches. :-( michael@0: * michael@0: * @param elementName michael@0: * @param popName michael@0: * @param node michael@0: */ michael@0: StackNode(ElementName elementName, @Local String popName, T node michael@0: // [NOCPP[ michael@0: , TaintableLocatorImpl locator michael@0: // ]NOCPP] michael@0: ) { michael@0: this.flags = prepareSvgFlags(elementName.getFlags()); michael@0: this.name = elementName.name; michael@0: this.popName = popName; michael@0: this.ns = "http://www.w3.org/2000/svg"; michael@0: this.node = node; michael@0: this.attributes = null; michael@0: this.refcount = 1; michael@0: // [NOCPP[ michael@0: this.locator = locator; michael@0: // ]NOCPP] michael@0: } michael@0: michael@0: /** michael@0: * Constructor for MathML. michael@0: * michael@0: * @param elementName michael@0: * @param node michael@0: * @param popName michael@0: * @param markAsIntegrationPoint michael@0: */ michael@0: StackNode(ElementName elementName, T node, @Local String popName, michael@0: boolean markAsIntegrationPoint michael@0: // [NOCPP[ michael@0: , TaintableLocatorImpl locator michael@0: // ]NOCPP] michael@0: ) { michael@0: this.flags = prepareMathFlags(elementName.getFlags(), michael@0: markAsIntegrationPoint); michael@0: this.name = elementName.name; michael@0: this.popName = popName; michael@0: this.ns = "http://www.w3.org/1998/Math/MathML"; michael@0: this.node = node; michael@0: this.attributes = null; michael@0: this.refcount = 1; michael@0: // [NOCPP[ michael@0: this.locator = locator; michael@0: // ]NOCPP] michael@0: } michael@0: michael@0: private static int prepareSvgFlags(int flags) { michael@0: flags &= ~(ElementName.FOSTER_PARENTING | ElementName.SCOPING michael@0: | ElementName.SPECIAL | ElementName.OPTIONAL_END_TAG); michael@0: if ((flags & ElementName.SCOPING_AS_SVG) != 0) { michael@0: flags |= (ElementName.SCOPING | ElementName.SPECIAL | ElementName.HTML_INTEGRATION_POINT); michael@0: } michael@0: return flags; michael@0: } michael@0: michael@0: private static int prepareMathFlags(int flags, michael@0: boolean markAsIntegrationPoint) { michael@0: flags &= ~(ElementName.FOSTER_PARENTING | ElementName.SCOPING michael@0: | ElementName.SPECIAL | ElementName.OPTIONAL_END_TAG); michael@0: if ((flags & ElementName.SCOPING_AS_MATHML) != 0) { michael@0: flags |= (ElementName.SCOPING | ElementName.SPECIAL); michael@0: } michael@0: if (markAsIntegrationPoint) { michael@0: flags |= ElementName.HTML_INTEGRATION_POINT; michael@0: } michael@0: return flags; michael@0: } michael@0: michael@0: @SuppressWarnings("unused") private void destructor() { michael@0: Portability.delete(attributes); michael@0: } michael@0: michael@0: public void dropAttributes() { michael@0: attributes = null; michael@0: } michael@0: michael@0: // [NOCPP[ michael@0: /** michael@0: * @see java.lang.Object#toString() michael@0: */ michael@0: @Override public @Local String toString() { michael@0: return name; michael@0: } michael@0: michael@0: // ]NOCPP] michael@0: michael@0: public void retain() { michael@0: refcount++; michael@0: } michael@0: michael@0: public void release() { michael@0: refcount--; michael@0: if (refcount == 0) { michael@0: Portability.delete(this); michael@0: } michael@0: } michael@0: }