1 /* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 4 */ 5 /* 6 * Licensed to the Apache Software Foundation (ASF) under one or more 7 * contributor license agreements. See the NOTICE file distributed with 8 * this work for additional information regarding copyright ownership. 9 * The ASF licenses this file to You under the Apache License, Version 2.0 10 * (the "License"); you may not use this file except in compliance with 11 * the License. You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, software 16 * distributed under the License is distributed on an "AS IS" BASIS, 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 */ 21 22 package com.sun.org.apache.xml.internal.serializer; 23 24 /** 25 * This class is a stack frame that consists of 26 * information about the element currently being processed 27 * by a serializer. Consider this example: 28 * <pre> 29 * <A> 30 * <B1> 31 * </B1> 32 * <B2> 33 * </B2> 34 * <A> 35 * </pre> 36 * 37 * A stack frame will be pushed for "A" at depth 1, 38 * then another one for "B1" at depth 2. 39 * Then "B1" stackframe is popped. When the stack frame for "B2" is 40 * pushed, this implementation re-uses the old stack fram object used 41 * by "B1" to be efficient at not creating too many of these object. 42 * 43 * This is by no means a public class, and neither are its fields or methods, 44 * they are all helper fields for a serializer. 45 * 46 * The purpose of this class is to be more consistent with pushing information 47 * when a new element is being serialized and more quickly restoring the old 48 * information about the parent element with a simple pop() when the 49 * child element is done. Previously there was some redundant and error-prone 50 * calculations going on to retore information. 51 * 52 * @xsl.usage internal 53 */ 54 final class ElemContext 55 { 56 // Fields that form the context of the element 57 58 /** 59 * The nesting depth of the element inside other elements. 60 */ 61 final int m_currentElemDepth; 62 63 /** HTML field, the element description of the HTML element */ 64 ElemDesc m_elementDesc = null; 65 66 /** 67 * The local name of the element. 68 */ 69 String m_elementLocalName = null; 70 71 /** 72 * The fully qualified name of the element (with prefix, if any). 73 */ 74 String m_elementName = null; 75 76 /** 77 * The URI of the element. 78 */ 79 String m_elementURI = null; 80 81 /** If the element is in the cdata-section-names list 82 * then the value is true. If it is true the text children of the element 83 * should be output in CDATA section blocks. 84 */ 85 boolean m_isCdataSection; 86 87 /** True if the current element has output escaping disabled. 88 * This is true for SCRIPT and STYLE elements. 89 */ 90 boolean m_isRaw = false; 91 92 /** The next element "stack frame". This value will only be 93 * set once as deeper stack frames are not deleted when popped off, 94 * but are rather re-used when a push is required. 95 * 96 * This makes for very fast pushing and popping of stack frames 97 * because very few stack frame objects are ever created, they are 98 * mostly re-used. This re-use saves object creation but it also means 99 * that connections between the frames via m_next and m_prev 100 * never changes either. Just the contents of the frames change 101 * as they are re-used. Only the reference to the current stack frame, which 102 * is held by the serializer is changed via a quick pop() or push(). 103 */ 104 private ElemContext m_next; 105 106 /** The previous element "stack frame". */ 107 final ElemContext m_prev; 108 109 /** 110 * Set to true when a start tag is started, or open, but not all the 111 * attributes or namespace information is yet collected. 112 */ 113 boolean m_startTagOpen = false; 114 115 /** 116 * Constructor to create the root of the element contexts. 117 * 118 */ ElemContext()119 ElemContext() 120 { 121 // this assignment means can never pop this context off 122 m_prev = this; 123 // depth 0 because it doesn't correspond to any element 124 m_currentElemDepth = 0; 125 } 126 127 /** 128 * Constructor to create the "stack frame" for a given element depth. 129 * 130 * This implementation will re-use the context at each depth. If 131 * a documents deepest element depth is N then there will be (N+1) 132 * such objects created, no more than that. 133 * 134 * @param previous The "stack frame" corresponding to the new 135 * elements parent element. 136 */ ElemContext(final ElemContext previous)137 private ElemContext(final ElemContext previous) 138 { 139 m_prev = previous; 140 m_currentElemDepth = previous.m_currentElemDepth + 1; 141 } 142 143 /** 144 * Pop the current "stack frame". 145 * @return Returns the parent "stack frame" of the one popped. 146 */ pop()147 final ElemContext pop() 148 { 149 /* a very simple pop. No clean up is done of the deeper 150 * stack frame. All deeper stack frames are still attached 151 * but dormant, just waiting to be re-used. 152 */ 153 return this.m_prev; 154 } 155 156 /** 157 * This method pushes an element "stack frame" 158 * but with no initialization of values in that frame. 159 * This method is used for optimization purposes, like when pushing 160 * a stack frame for an HTML "IMG" tag which has no children and 161 * the stack frame will almost immediately be popped. 162 */ push()163 final ElemContext push() 164 { 165 ElemContext frame = this.m_next; 166 if (frame == null) 167 { 168 /* We have never been at this depth yet, and there is no 169 * stack frame to re-use, so we now make a new one. 170 */ 171 frame = new ElemContext(this); 172 this.m_next = frame; 173 } 174 /* 175 * We shouldn't need to set this true because we should just 176 * be pushing a dummy stack frame that will be instantly popped. 177 * Yet we need to be ready in case this element does have 178 * unexpected children. 179 */ 180 frame.m_startTagOpen = true; 181 return frame; 182 } 183 184 /** 185 * Push an element context on the stack. This context keeps track of 186 * information gathered about the element. 187 * @param uri The URI for the namespace for the element name, 188 * can be null if it is not yet known. 189 * @param localName The local name of the element (no prefix), 190 * can be null. 191 * @param qName The qualified name (with prefix, if any) 192 * of the element, this parameter is required. 193 */ push( final String uri, final String localName, final String qName)194 final ElemContext push( 195 final String uri, 196 final String localName, 197 final String qName) 198 { 199 ElemContext frame = this.m_next; 200 if (frame == null) 201 { 202 /* We have never been at this depth yet, and there is no 203 * stack frame to re-use, so we now make a new one. 204 */ 205 frame = new ElemContext(this); 206 this.m_next = frame; 207 } 208 209 // Initialize, or reset values in the new or re-used stack frame. 210 frame.m_elementName = qName; 211 frame.m_elementLocalName = localName; 212 frame.m_elementURI = uri; 213 frame.m_isCdataSection = false; 214 frame.m_startTagOpen = true; 215 216 // is_Raw is already set in the HTML startElement() method 217 // frame.m_isRaw = false; 218 return frame; 219 } 220 } 221