StackNode.java (10794B)
1 /* 2 * Copyright (c) 2007 Henri Sivonen 3 * Copyright (c) 2007-2011 Mozilla Foundation 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be included in 13 * all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 */ 23 24 package nu.validator.htmlparser.impl; 25 26 import nu.validator.htmlparser.annotation.Inline; 27 import nu.validator.htmlparser.annotation.Local; 28 import nu.validator.htmlparser.annotation.NsUri; 29 30 final class StackNode<T> { 31 // Index where this stack node is stored in the tree builder's list of stack nodes. 32 // A value of -1 indicates that the stack node is not owned by a tree builder and 33 // must delete itself when its refcount reaches 0. 34 final int idxInTreeBuilder; 35 36 int flags; 37 38 @Local String name; 39 40 @Local String popName; 41 42 @NsUri String ns; 43 44 T node; 45 46 // Only used on the list of formatting elements 47 HtmlAttributes attributes; 48 49 private int refcount = 0; 50 51 /* 52 * Only valid for formatting elements 53 */ 54 // CPPONLY: private @HtmlCreator Object htmlCreator; 55 56 // [NOCPP[ 57 58 private TaintableLocatorImpl locator; 59 60 public TaintableLocatorImpl getLocator() { 61 return locator; 62 } 63 64 // ]NOCPP] 65 66 @Inline public int getFlags() { 67 return flags; 68 } 69 70 public int getGroup() { 71 return flags & ElementName.GROUP_MASK; 72 } 73 74 public boolean isScoping() { 75 return (flags & ElementName.SCOPING) != 0; 76 } 77 78 public boolean isSpecial() { 79 return (flags & ElementName.SPECIAL) != 0; 80 } 81 82 public boolean isFosterParenting() { 83 return (flags & ElementName.FOSTER_PARENTING) != 0; 84 } 85 86 public boolean isHtmlIntegrationPoint() { 87 return (flags & ElementName.HTML_INTEGRATION_POINT) != 0; 88 } 89 90 // [NOCPP[ 91 92 public boolean isOptionalEndTag() { 93 return (flags & ElementName.OPTIONAL_END_TAG) != 0; 94 } 95 96 // ]NOCPP] 97 98 StackNode(int idxInTreeBuilder) { 99 this.idxInTreeBuilder = idxInTreeBuilder; 100 this.flags = 0; 101 this.name = null; 102 this.popName = null; 103 // CPPONLY: this.ns = 0; 104 this.node = null; 105 this.attributes = null; 106 this.refcount = 0; 107 // CPPONLY: this.htmlCreator = null; 108 } 109 110 // CPPONLY: public @HtmlCreator Object getHtmlCreator() { 111 // CPPONLY: return htmlCreator; 112 // CPPONLY: } 113 114 /** 115 * Setter for copying. This doesn't take another <code>StackNode</code> 116 * because in C++ the caller is responsible for reobtaining the local names 117 * from another interner. 118 * 119 * @param flags 120 * @param ns 121 * @param name 122 * @param node 123 * @param popName 124 * @param attributes 125 */ 126 void setValues(int flags, @NsUri String ns, @Local String name, T node, 127 @Local String popName, HtmlAttributes attributes, 128 // CPPONLY: @HtmlCreator Object htmlCreator 129 // [NOCPP[ 130 TaintableLocatorImpl locator 131 // ]NOCPP] 132 ) { 133 assert isUnused(); 134 this.flags = flags; 135 this.name = name; 136 this.popName = popName; 137 this.ns = ns; 138 this.node = node; 139 this.attributes = attributes; 140 this.refcount = 1; 141 /* 142 * Need to track creator for formatting elements when copying. 143 */ 144 // CPPONLY: this.htmlCreator = htmlCreator; 145 // [NOCPP[ 146 this.locator = locator; 147 // ]NOCPP] 148 } 149 150 /** 151 * Short hand for well-known HTML elements. 152 * 153 * @param elementName 154 * @param node 155 */ 156 void setValues(ElementName elementName, T node 157 // [NOCPP[ 158 , TaintableLocatorImpl locator 159 // ]NOCPP] 160 ) { 161 assert isUnused(); 162 this.flags = elementName.getFlags(); 163 this.name = elementName.getName(); 164 this.popName = elementName.getName(); 165 this.ns = "http://www.w3.org/1999/xhtml"; 166 this.node = node; 167 this.attributes = null; 168 this.refcount = 1; 169 assert elementName.isInterned() : "Don't use this constructor for custom elements."; 170 /* 171 * Not used for formatting elements, so no need to track creator. 172 */ 173 // CPPONLY: this.htmlCreator = null; 174 // [NOCPP[ 175 this.locator = locator; 176 // ]NOCPP] 177 } 178 179 /** 180 * Setter for HTML formatting elements. 181 * 182 * @param elementName 183 * @param node 184 * @param attributes 185 */ 186 void setValues(ElementName elementName, T node, HtmlAttributes attributes 187 // [NOCPP[ 188 , TaintableLocatorImpl locator 189 // ]NOCPP] 190 ) { 191 assert isUnused(); 192 this.flags = elementName.getFlags(); 193 this.name = elementName.getName(); 194 this.popName = elementName.getName(); 195 this.ns = "http://www.w3.org/1999/xhtml"; 196 this.node = node; 197 this.attributes = attributes; 198 this.refcount = 1; 199 assert elementName.isInterned() : "Don't use this constructor for custom elements."; 200 /* 201 * Need to track creator for formatting elements in order to be able 202 * to clone them. 203 */ 204 // CPPONLY: this.htmlCreator = elementName.getHtmlCreator(); 205 // [NOCPP[ 206 this.locator = locator; 207 // ]NOCPP] 208 } 209 210 /** 211 * The common-case HTML setter. 212 * 213 * @param elementName 214 * @param node 215 * @param popName 216 */ 217 void setValues(ElementName elementName, T node, @Local String popName 218 // [NOCPP[ 219 , TaintableLocatorImpl locator 220 // ]NOCPP] 221 ) { 222 assert isUnused(); 223 this.flags = elementName.getFlags(); 224 this.name = elementName.getName(); 225 this.popName = popName; 226 this.ns = "http://www.w3.org/1999/xhtml"; 227 this.node = node; 228 this.attributes = null; 229 this.refcount = 1; 230 /* 231 * Not used for formatting elements, so no need to track creator. 232 */ 233 // CPPONLY: this.htmlCreator = null; 234 // [NOCPP[ 235 this.locator = locator; 236 // ]NOCPP] 237 } 238 239 /** 240 * Setter for SVG elements. Note that the order of the arguments is 241 * what distinguishes this from the HTML setter. This is ugly, but 242 * AFAICT the least disruptive way to make this work with Java's generics 243 * and without unnecessary branches. :-( 244 * 245 * @param elementName 246 * @param popName 247 * @param node 248 */ 249 void setValues(ElementName elementName, @Local String popName, T node 250 // [NOCPP[ 251 , TaintableLocatorImpl locator 252 // ]NOCPP] 253 ) { 254 assert isUnused(); 255 this.flags = prepareSvgFlags(elementName.getFlags()); 256 this.name = elementName.getName(); 257 this.popName = popName; 258 this.ns = "http://www.w3.org/2000/svg"; 259 this.node = node; 260 this.attributes = null; 261 this.refcount = 1; 262 /* 263 * Not used for formatting elements, so no need to track creator. 264 */ 265 // CPPONLY: this.htmlCreator = null; 266 // [NOCPP[ 267 this.locator = locator; 268 // ]NOCPP] 269 } 270 271 /** 272 * Setter for MathML. 273 * 274 * @param elementName 275 * @param node 276 * @param popName 277 * @param markAsIntegrationPoint 278 */ 279 void setValues(ElementName elementName, T node, @Local String popName, 280 boolean markAsIntegrationPoint 281 // [NOCPP[ 282 , TaintableLocatorImpl locator 283 // ]NOCPP] 284 ) { 285 assert isUnused(); 286 this.flags = prepareMathFlags(elementName.getFlags(), 287 markAsIntegrationPoint); 288 this.name = elementName.getName(); 289 this.popName = popName; 290 this.ns = "http://www.w3.org/1998/Math/MathML"; 291 this.node = node; 292 this.attributes = null; 293 this.refcount = 1; 294 /* 295 * Not used for formatting elements, so no need to track creator. 296 */ 297 // CPPONLY: this.htmlCreator = null; 298 // [NOCPP[ 299 this.locator = locator; 300 // ]NOCPP] 301 } 302 303 private static int prepareSvgFlags(int flags) { 304 flags &= ~(ElementName.FOSTER_PARENTING | ElementName.SCOPING 305 | ElementName.SPECIAL | ElementName.OPTIONAL_END_TAG); 306 if ((flags & ElementName.SCOPING_AS_SVG) != 0) { 307 flags |= (ElementName.SCOPING | ElementName.SPECIAL | ElementName.HTML_INTEGRATION_POINT); 308 } 309 return flags; 310 } 311 312 private static int prepareMathFlags(int flags, 313 boolean markAsIntegrationPoint) { 314 flags &= ~(ElementName.FOSTER_PARENTING | ElementName.SCOPING 315 | ElementName.SPECIAL | ElementName.OPTIONAL_END_TAG); 316 if ((flags & ElementName.SCOPING_AS_MATHML) != 0) { 317 flags |= (ElementName.SCOPING | ElementName.SPECIAL); 318 } 319 if (markAsIntegrationPoint) { 320 flags |= ElementName.HTML_INTEGRATION_POINT; 321 } 322 return flags; 323 } 324 325 @SuppressWarnings("unused") private void destructor() { 326 // The translator adds refcount debug code here. 327 } 328 329 public void dropAttributes() { 330 attributes = null; 331 } 332 333 // [NOCPP[ 334 /** 335 * @see java.lang.Object#toString() 336 */ 337 @Override public @Local String toString() { 338 return name; 339 } 340 341 // ]NOCPP] 342 343 public void retain() { 344 refcount++; 345 } 346 347 public void release(TreeBuilder<T> owningTreeBuilder) { 348 refcount--; 349 assert refcount >= 0; 350 if (refcount == 0) { 351 Portability.delete(attributes); 352 if (idxInTreeBuilder >= 0) { 353 owningTreeBuilder.notifyUnusedStackNode(idxInTreeBuilder); 354 } else { 355 assert owningTreeBuilder == null; 356 Portability.delete(this); 357 } 358 } 359 } 360 361 boolean isUnused() { 362 return refcount == 0; 363 } 364 }