Bug 1355479 - Remove isindex on the Java side and allow the C++ side to reduce malloc in attribute handling.

Tag UXP Issue #1344
This commit is contained in:
Gaming4JC 2020-01-18 14:01:12 -05:00 committed by Roy Tam
commit 67a2c5cb06
10 changed files with 180 additions and 336 deletions

View file

@ -33,7 +33,6 @@ import nu.validator.htmlparser.annotation.NsUri;
import nu.validator.htmlparser.annotation.Prefix;
import nu.validator.htmlparser.annotation.QName;
import nu.validator.htmlparser.annotation.Unsigned;
import nu.validator.htmlparser.annotation.Virtual;
import nu.validator.htmlparser.common.Interner;
public final class AttributeName
@ -275,35 +274,19 @@ public final class AttributeName
*/
static AttributeName nameByBuffer(@NoLength char[] buf, int offset,
int length
// [NOCPP[
, boolean checkNcName
// ]NOCPP]
, Interner interner) {
// XXX deal with offset
@Unsigned int hash = AttributeName.bufToHash(buf, length);
int index = Arrays.binarySearch(AttributeName.ATTRIBUTE_HASHES, hash);
if (index < 0) {
return AttributeName.createAttributeName(
Portability.newLocalNameFromBuffer(buf, offset, length,
interner)
// [NOCPP[
, checkNcName
// ]NOCPP]
);
} else {
AttributeName attributeName = AttributeName.ATTRIBUTE_NAMES[index];
@Local String name = attributeName.getLocal(AttributeName.HTML);
if (!Portability.localEqualsBuffer(name, buf, offset, length)) {
return AttributeName.createAttributeName(
Portability.newLocalNameFromBuffer(buf, offset, length,
interner)
// [NOCPP[
, checkNcName
// ]NOCPP]
);
}
return attributeName;
return null;
}
AttributeName attributeName = AttributeName.ATTRIBUTE_NAMES[index];
@Local String name = attributeName.getLocal(AttributeName.HTML);
if (!Portability.localEqualsBuffer(name, buf, offset, length)) {
return null;
}
return attributeName;
}
/**
@ -385,6 +368,8 @@ public final class AttributeName
*/
private final @Prefix @NoLength String[] prefix;
// CPPONLY: private final boolean custom;
// [NOCPP[
private final int flags;
@ -410,7 +395,7 @@ public final class AttributeName
* @param xmlns
* whether this is an xmlns attribute
*/
protected AttributeName(@NsUri @NoLength String[] uri,
private AttributeName(@NsUri @NoLength String[] uri,
@Local @NoLength String[] local, @Prefix @NoLength String[] prefix
// [NOCPP[
, int flags
@ -423,8 +408,27 @@ public final class AttributeName
this.qName = COMPUTE_QNAME(local, prefix);
this.flags = flags;
// ]NOCPP]
// CPPONLY: this.custom = false;
}
// CPPONLY: public AttributeName() {
// CPPONLY: this.uri = AttributeName.ALL_NO_NS;
// CPPONLY: this.local = AttributeName.SAME_LOCAL(null);
// CPPONLY: this.prefix = ALL_NO_PREFIX;
// CPPONLY: this.custom = true;
// CPPONLY: }
// CPPONLY:
// CPPONLY: public boolean isInterned() {
// CPPONLY: return !custom;
// CPPONLY: }
// CPPONLY:
// CPPONLY: public void setNameForNonInterned(@Local String name) {
// CPPONLY: assert custom;
// CPPONLY: local[0] = name;
// CPPONLY: local[1] = name;
// CPPONLY: local[2] = name;
// CPPONLY: }
/**
* Creates an <code>AttributeName</code> for a local name.
*
@ -434,7 +438,7 @@ public final class AttributeName
* whether to check ncnameness
* @return an <code>AttributeName</code>
*/
private static AttributeName createAttributeName(@Local String name
static AttributeName createAttributeName(@Local String name
// [NOCPP[
, boolean checkNcName
// ]NOCPP]
@ -451,33 +455,13 @@ public final class AttributeName
AttributeName.SAME_LOCAL(name), ALL_NO_PREFIX, flags);
}
/**
* Deletes runtime-allocated instances in C++.
*/
@Virtual void release() {
// No-op in Java.
// Implement as |delete this;| in subclass.
}
/**
* The C++ destructor.
*/
@SuppressWarnings("unused") @Virtual private void destructor() {
@SuppressWarnings("unused") private void destructor() {
Portability.deleteArray(local);
}
/**
* Clones the attribute using an interner. Returns <code>this</code> in Java
* and for non-dynamic instances in C++.
*
* @param interner
* an interner
* @return a clone
*/
@Virtual public AttributeName cloneAttributeName(Interner interner) {
return this;
}
// [NOCPP[
/**
* Creator for use when the XML violation policy requires an attribute name

View file

@ -22,10 +22,10 @@
package nu.validator.htmlparser.impl;
import nu.validator.htmlparser.annotation.NoLength;
import org.xml.sax.SAXException;
import nu.validator.htmlparser.annotation.NoLength;
/**
* A common superclass for tree builders that coalesce their text nodes.
*
@ -48,13 +48,6 @@ public abstract class CoalescingTreeBuilder<T> extends TreeBuilder<T> {
appendCharacters(parent, new String(buf, start, length));
}
/**
* @see nu.validator.htmlparser.impl.TreeBuilder#appendIsindexPrompt(java.lang.Object)
*/
@Override protected void appendIsindexPrompt(T parent) throws SAXException {
appendCharacters(parent, "This is a searchable index. Enter search keywords: ");
}
protected abstract void appendCharacters(T parent, String text) throws SAXException;
/**

View file

@ -192,6 +192,11 @@ public final class ElementName
assert this.flags == (TreeBuilder.OTHER | NOT_INTERNED);
}
// CPPONLY: public static final ElementName ISINDEX = new ElementName("isindex", "isindex", TreeBuilder.ISINDEX | SPECIAL);
// [NOCPP[
public static final ElementName ISINDEX = new ElementName("isindex", "isindex", TreeBuilder.OTHER);
// ]NOCPP]
// START CODE ONLY USED FOR GENERATING CODE uncomment and run to regenerate
// /**
@ -421,6 +426,9 @@ public final class ElementName
// }
// for (int i = 0; i < ELEMENT_NAMES.length; i++) {
// ElementName el = ELEMENT_NAMES[i];
// if ("isindex".equals(el.name)) {
// continue;
// }
// System.out.println("public static final ElementName "
// + el.constName() + " = new ElementName" + el.toString()
// + ";");
@ -439,6 +447,7 @@ public final class ElementName
// System.out.println("};");
// }
// START GENERATED CODE
public static final ElementName AND = new ElementName("and", "and", TreeBuilder.OTHER);
public static final ElementName ARG = new ElementName("arg", "arg", TreeBuilder.OTHER);
@ -828,7 +837,6 @@ public final class ElementName
public static final ElementName APPROX = new ElementName("approx", "approx", TreeBuilder.OTHER);
public static final ElementName FECOLORMATRIX = new ElementName("fecolormatrix", "feColorMatrix", TreeBuilder.OTHER);
public static final ElementName FECONVOLVEMATRIX = new ElementName("feconvolvematrix", "feConvolveMatrix", TreeBuilder.OTHER);
public static final ElementName ISINDEX = new ElementName("isindex", "isindex", TreeBuilder.ISINDEX | SPECIAL);
public static final ElementName MATRIX = new ElementName("matrix", "matrix", TreeBuilder.OTHER);
public static final ElementName APPLY = new ElementName("apply", "apply", TreeBuilder.OTHER);
public static final ElementName BODY = new ElementName("body", "body", TreeBuilder.BODY | SPECIAL | OPTIONAL_END_TAG);

View file

@ -25,7 +25,9 @@
package nu.validator.htmlparser.impl;
import nu.validator.htmlparser.annotation.Auto;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import nu.validator.htmlparser.annotation.IdType;
import nu.validator.htmlparser.annotation.Local;
import nu.validator.htmlparser.annotation.NsUri;
@ -34,9 +36,6 @@ import nu.validator.htmlparser.annotation.QName;
import nu.validator.htmlparser.common.Interner;
import nu.validator.htmlparser.common.XmlViolationPolicy;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
/**
* Be careful with this class. QName is the name in from HTML tokenization.
* Otherwise, please refer to the interface doc.
@ -46,14 +45,10 @@ import org.xml.sax.SAXException;
*/
public final class HtmlAttributes implements Attributes {
// [NOCPP[
private static final AttributeName[] EMPTY_ATTRIBUTENAMES = new AttributeName[0];
private static final String[] EMPTY_STRINGS = new String[0];
// ]NOCPP]
public static final HtmlAttributes EMPTY_ATTRIBUTES = new HtmlAttributes(
AttributeName.HTML);
@ -61,13 +56,9 @@ public final class HtmlAttributes implements Attributes {
private int length;
private @Auto AttributeName[] names;
private AttributeName[] names;
private @Auto String[] values; // XXX perhaps make this @NoLength?
// CPPONLY: private @Auto int[] lines; // XXX perhaps make this @NoLength?
// [NOCPP[
private String[] values;
private String idValue;
@ -77,21 +68,15 @@ public final class HtmlAttributes implements Attributes {
private String[] xmlnsValues;
// ]NOCPP]
public HtmlAttributes(int mode) {
this.mode = mode;
this.length = 0;
/*
* The length of 5 covers covers 98.3% of elements
* according to Hixie, but lets round to the next power of two for
* jemalloc.
* according to Hixie.
*/
this.names = new AttributeName[8];
this.values = new String[8];
// CPPONLY: this.lines = new int[8];
// [NOCPP[
this.names = new AttributeName[5];
this.values = new String[5];
this.idValue = null;
@ -101,25 +86,6 @@ public final class HtmlAttributes implements Attributes {
this.xmlnsValues = HtmlAttributes.EMPTY_STRINGS;
// ]NOCPP]
}
/*
public HtmlAttributes(HtmlAttributes other) {
this.mode = other.mode;
this.length = other.length;
this.names = new AttributeName[other.length];
this.values = new String[other.length];
// [NOCPP[
this.idValue = other.idValue;
this.xmlnsLength = other.xmlnsLength;
this.xmlnsNames = new AttributeName[other.xmlnsLength];
this.xmlnsValues = new String[other.xmlnsLength];
// ]NOCPP]
}
*/
void destructor() {
clear(0);
}
/**
@ -161,7 +127,6 @@ public final class HtmlAttributes implements Attributes {
* @return the local name at index
*/
public @Local String getLocalNameNoBoundsCheck(int index) {
// CPPONLY: assert index < length && index >= 0: "Index out of bounds";
return names[index].getLocal(mode);
}
@ -171,7 +136,6 @@ public final class HtmlAttributes implements Attributes {
* @return the namespace URI at index
*/
public @NsUri String getURINoBoundsCheck(int index) {
// CPPONLY: assert index < length && index >= 0: "Index out of bounds";
return names[index].getUri(mode);
}
@ -181,7 +145,6 @@ public final class HtmlAttributes implements Attributes {
* @return the namespace prefix at index
*/
public @Prefix String getPrefixNoBoundsCheck(int index) {
// CPPONLY: assert index < length && index >= 0: "Index out of bounds";
return names[index].getPrefix(mode);
}
@ -191,7 +154,6 @@ public final class HtmlAttributes implements Attributes {
* @return the attribute value at index
*/
public String getValueNoBoundsCheck(int index) {
// CPPONLY: assert index < length && index >= 0: "Index out of bounds";
return values[index];
}
@ -201,21 +163,9 @@ public final class HtmlAttributes implements Attributes {
* @return the attribute name at index
*/
public AttributeName getAttributeNameNoBoundsCheck(int index) {
// CPPONLY: assert index < length && index >= 0: "Index out of bounds";
return names[index];
}
// CPPONLY: /**
// CPPONLY: * Obtains a line number without bounds check.
// CPPONLY: * @param index a valid attribute index
// CPPONLY: * @return the line number at index or -1 if unknown
// CPPONLY: */
// CPPONLY: public int getLineNoBoundsCheck(int index) {
// CPPONLY: assert index < length && index >= 0: "Index out of bounds";
// CPPONLY: return lines[index];
// CPPONLY: }
// [NOCPP[
/**
* Variant of <code>getQName(int index)</code> without bounds check.
@ -404,15 +354,9 @@ public final class HtmlAttributes implements Attributes {
}
}
// ]NOCPP]
void addAttribute(AttributeName name, String value
// [NOCPP[
, XmlViolationPolicy xmlnsPolicy
// ]NOCPP]
// CPPONLY: , int line
) throws SAXException {
// [NOCPP[
if (name == AttributeName.ID) {
idValue = value;
}
@ -441,8 +385,6 @@ public final class HtmlAttributes implements Attributes {
}
}
// ]NOCPP]
if (names.length == length) {
int newLen = length << 1; // The first growth covers virtually
// 100% of elements according to
@ -453,53 +395,25 @@ public final class HtmlAttributes implements Attributes {
String[] newValues = new String[newLen];
System.arraycopy(values, 0, newValues, 0, values.length);
values = newValues;
// CPPONLY: int[] newLines = new int[newLen];
// CPPONLY: System.arraycopy(lines, 0, newLines, 0, lines.length);
// CPPONLY: lines = newLines;
}
names[length] = name;
values[length] = value;
// CPPONLY: lines[length] = line;
length++;
}
void clear(int m) {
for (int i = 0; i < length; i++) {
names[i].release();
names[i] = null;
Portability.releaseString(values[i]);
values[i] = null;
}
length = 0;
mode = m;
// [NOCPP[
idValue = null;
for (int i = 0; i < xmlnsLength; i++) {
xmlnsNames[i] = null;
xmlnsValues[i] = null;
}
xmlnsLength = 0;
// ]NOCPP]
}
/**
* This is used in C++ to release special <code>isindex</code>
* attribute values whose ownership is not transferred.
*/
void releaseValue(int i) {
Portability.releaseString(values[i]);
}
/**
* This is only used for <code>AttributeName</code> ownership transfer
* in the isindex case to avoid freeing custom names twice in C++.
*/
void clearWithoutReleasingContents() {
for (int i = 0; i < length; i++) {
names[i] = null;
values[i] = null;
}
length = 0;
}
boolean contains(AttributeName name) {
@ -508,13 +422,11 @@ public final class HtmlAttributes implements Attributes {
return true;
}
}
// [NOCPP[
for (int i = 0; i < xmlnsLength; i++) {
if (name.equalsAnother(xmlnsNames[i])) {
return true;
}
}
// ]NOCPP]
return false;
}
@ -529,27 +441,20 @@ public final class HtmlAttributes implements Attributes {
public HtmlAttributes cloneAttributes(Interner interner)
throws SAXException {
assert (length == 0
// [NOCPP[
&& xmlnsLength == 0
// ]NOCPP]
)
|| mode == 0 || mode == 3;
HtmlAttributes clone = new HtmlAttributes(0);
for (int i = 0; i < length; i++) {
clone.addAttribute(names[i].cloneAttributeName(interner),
Portability.newStringFromString(values[i])
// [NOCPP[
clone.addAttribute(names[i],
values[i]
, XmlViolationPolicy.ALLOW
// ]NOCPP]
// CPPONLY: , lines[i]
);
}
// [NOCPP[
for (int i = 0; i < xmlnsLength; i++) {
clone.addAttribute(xmlnsNames[i], xmlnsValues[i],
XmlViolationPolicy.ALLOW);
}
// ]NOCPP]
return clone; // XXX!!!
}
@ -568,9 +473,10 @@ public final class HtmlAttributes implements Attributes {
for (int j = 0; j < otherLength; j++) {
if (ownLocal == other.names[j].getLocal(AttributeName.HTML)) {
found = true;
if (!Portability.stringEqualsString(values[i], other.values[j])) {
if (!values[i].equals(other.values[j])) {
return false;
}
break;
}
}
if (!found) {
@ -579,9 +485,7 @@ public final class HtmlAttributes implements Attributes {
}
return true;
}
// [NOCPP[
void processNonNcNames(TreeBuilder<?> treeBuilder, XmlViolationPolicy namePolicy) throws SAXException {
for (int i = 0; i < length; i++) {
AttributeName attName = names[i];
@ -613,8 +517,4 @@ public final class HtmlAttributes implements Attributes {
}
}
}
// ]NOCPP]
}

View file

@ -434,6 +434,8 @@ public class Tokenizer implements Locator {
*/
protected AttributeName attributeName = null;
// CPPONLY: private AttributeName nonInternedAttributeName = null;
// [NOCPP[
/**
@ -530,6 +532,7 @@ public class Tokenizer implements Locator {
this.tagName = null;
this.nonInternedTagName = new ElementName();
this.attributeName = null;
// CPPONLY: this.nonInternedAttributeName = new AttributeName();
this.doctypeName = null;
this.publicIdentifier = null;
this.systemIdentifier = null;
@ -560,6 +563,7 @@ public class Tokenizer implements Locator {
this.tagName = null;
this.nonInternedTagName = new ElementName();
this.attributeName = null;
// CPPONLY: this.nonInternedAttributeName = new AttributeName();
this.doctypeName = null;
this.publicIdentifier = null;
this.systemIdentifier = null;
@ -1174,11 +1178,17 @@ public class Tokenizer implements Locator {
}
private void attributeNameComplete() throws SAXException {
attributeName = AttributeName.nameByBuffer(strBuf, 0, strBufLen
// [NOCPP[
, namePolicy != XmlViolationPolicy.ALLOW
// ]NOCPP]
, interner);
attributeName = AttributeName.nameByBuffer(strBuf, 0, strBufLen, interner);
if (attributeName == null) {
// [NOCPP[
attributeName = AttributeName.createAttributeName(
Portability.newLocalNameFromBuffer(strBuf, 0, strBufLen,
interner),
namePolicy != XmlViolationPolicy.ALLOW);
// ]NOCPP]
// CPPONLY: nonInternedAttributeName.setNameForNonInterned(Portability.newLocalNameFromBuffer(strBuf, 0, strBufLen, interner));
// CPPONLY: attributeName = nonInternedAttributeName;
}
clearStrBufAfterUse();
if (attributes == null) {
@ -1195,7 +1205,6 @@ public class Tokenizer implements Locator {
*/
if (attributes.contains(attributeName)) {
errDuplicateAttribute();
attributeName.release();
attributeName = null;
}
}
@ -1244,8 +1253,7 @@ public class Tokenizer implements Locator {
// [NOCPP[
}
// ]NOCPP]
attributeName = null; // attributeName has been adopted by the
// |attributes| object
attributeName = null;
} else {
clearStrBufAfterUse();
}
@ -1276,8 +1284,7 @@ public class Tokenizer implements Locator {
// ]NOCPP]
// CPPONLY: , attributeLine
);
attributeName = null; // attributeName has been adopted by the
// |attributes| object
attributeName = null;
} else {
// We have a duplicate attribute. Explicitly discard its value.
clearStrBufAfterUse();
@ -6667,10 +6674,8 @@ public class Tokenizer implements Locator {
}
tagName = null;
nonInternedTagName.setNameForNonInterned(null);
if (attributeName != null) {
attributeName.release();
attributeName = null;
}
attributeName = null;
// CPPONLY: nonInternedAttributeName.setNameForNonInterned(null);
tokenHandler.endTokenization();
if (attributes != null) {
// [NOCPP[
@ -6747,13 +6752,8 @@ public class Tokenizer implements Locator {
endTag = false;
shouldSuspend = false;
initDoctypeFields();
if (tagName != null) {
tagName = null;
}
if (attributeName != null) {
attributeName.release();
attributeName = null;
}
tagName = null;
attributeName = null;
if (newAttributesEachTime) {
if (attributes != null) {
Portability.delete(attributes);
@ -6818,22 +6818,27 @@ public class Tokenizer implements Locator {
} else if (other.tagName.isInterned()) {
tagName = other.tagName;
} else {
// In the C++ case, We might be loading state from another
// tokenizer that has atoms from a different tokenizer-scoped
// atom table. Therefore, we have to obtain the correspoding
// atom from our own atom table.
// In the C++ case, the atoms in the other tokenizer are from a
// different tokenizer-scoped atom table. Therefore, we have to
// obtain the correspoding atom from our own atom table.
nonInternedTagName.setNameForNonInterned(Portability.newLocalFromLocal(other.tagName.getName(), interner));
tagName = nonInternedTagName;
}
if (attributeName != null) {
attributeName.release();
}
if (other.attributeName == null) {
attributeName = null;
} else {
attributeName = other.attributeName.cloneAttributeName(interner);
}
// [NOCPP[
attributeName = other.attributeName;
// ]NOCPP]
// CPPONLY: if (other.attributeName == null) {
// CPPONLY: attributeName = null;
// CPPONLY: } else if (other.attributeName.isInterned()) {
// CPPONLY: attributeName = other.attributeName;
// CPPONLY: } else {
// CPPONLY: // In the C++ case, the atoms in the other tokenizer are from a
// CPPONLY: // different tokenizer-scoped atom table. Therefore, we have to
// CPPONLY: // obtain the correspoding atom from our own atom table.
// CPPONLY: nonInternedAttributeName.setNameForNonInterned(Portability.newLocalFromLocal(other.attributeName.getLocal(AttributeName.HTML), interner));
// CPPONLY: attributeName = nonInternedAttributeName;
// CPPONLY: }
Portability.delete(attributes);
if (other.attributes == null) {
@ -7075,6 +7080,7 @@ public class Tokenizer implements Locator {
void destructor() {
Portability.delete(nonInternedTagName);
// CPPONLY: Portability.delete(nonInternedAttributeName);
nonInternedTagName = null;
// The translator will write refcount tracing stuff here
Portability.delete(attributes);

View file

@ -2326,85 +2326,74 @@ public abstract class TreeBuilder<T> implements TokenHandler,
selfClosing = false;
attributes = null; // CPP
break starttagloop;
case ISINDEX:
errIsindex();
if (formPointer != null && !isTemplateContents()) {
break starttagloop;
}
implicitlyCloseP();
HtmlAttributes formAttrs = new HtmlAttributes(0);
int actionIndex = attributes.getIndex(AttributeName.ACTION);
if (actionIndex > -1) {
formAttrs.addAttribute(
AttributeName.ACTION,
attributes.getValueNoBoundsCheck(actionIndex)
// [NOCPP[
, XmlViolationPolicy.ALLOW
// ]NOCPP]
// CPPONLY: , attributes.getLineNoBoundsCheck(actionIndex)
);
}
appendToCurrentNodeAndPushFormElementMayFoster(formAttrs);
appendVoidElementToCurrentMayFoster(
ElementName.HR,
HtmlAttributes.EMPTY_ATTRIBUTES);
appendToCurrentNodeAndPushElementMayFoster(
ElementName.LABEL,
HtmlAttributes.EMPTY_ATTRIBUTES);
int promptIndex = attributes.getIndex(AttributeName.PROMPT);
if (promptIndex > -1) {
@Auto char[] prompt = Portability.newCharArrayFromString(attributes.getValueNoBoundsCheck(promptIndex));
appendCharacters(stack[currentPtr].node,
prompt, 0, prompt.length);
} else {
appendIsindexPrompt(stack[currentPtr].node);
}
HtmlAttributes inputAttributes = new HtmlAttributes(
0);
inputAttributes.addAttribute(
AttributeName.NAME,
Portability.newStringFromLiteral("isindex")
// [NOCPP[
, XmlViolationPolicy.ALLOW
// ]NOCPP]
// CPPONLY: , tokenizer.getLineNumber()
);
for (int i = 0; i < attributes.getLength(); i++) {
AttributeName attributeQName = attributes.getAttributeNameNoBoundsCheck(i);
if (AttributeName.NAME == attributeQName
|| AttributeName.PROMPT == attributeQName) {
attributes.releaseValue(i);
} else if (AttributeName.ACTION != attributeQName) {
inputAttributes.addAttribute(
attributeQName,
attributes.getValueNoBoundsCheck(i)
// [NOCPP[
, XmlViolationPolicy.ALLOW
// ]NOCPP]
// CPPONLY: , attributes.getLineNoBoundsCheck(i)
);
}
}
attributes.clearWithoutReleasingContents();
appendVoidElementToCurrentMayFoster(
"input",
inputAttributes, formPointer);
pop(); // label
appendVoidElementToCurrentMayFoster(
ElementName.HR,
HtmlAttributes.EMPTY_ATTRIBUTES);
pop(); // form
if (!isTemplateContents()) {
formPointer = null;
}
selfClosing = false;
// Portability.delete(formAttrs);
// Portability.delete(inputAttributes);
// Don't delete attributes, they are deleted
// later
break starttagloop;
// CPPONLY:case ISINDEX:
// CPPONLY: errIsindex();
// CPPONLY: if (formPointer != null && !isTemplateContents()) {
// CPPONLY: break starttagloop;
// CPPONLY: }
// CPPONLY: implicitlyCloseP();
// CPPONLY: HtmlAttributes formAttrs = new HtmlAttributes(0);
// CPPONLY: int actionIndex = attributes.getIndex(AttributeName.ACTION);
// CPPONLY: if (actionIndex > -1) {
// CPPONLY: formAttrs.addAttribute(
// CPPONLY: AttributeName.ACTION,
// CPPONLY: attributes.getValueNoBoundsCheck(actionIndex),
// CPPONLY: attributes.getLineNoBoundsCheck(actionIndex)
// CPPONLY: );
// CPPONLY: }
// CPPONLY: appendToCurrentNodeAndPushFormElementMayFoster(formAttrs);
// CPPONLY: appendVoidElementToCurrentMayFoster(
// CPPONLY: ElementName.HR,
// CPPONLY: HtmlAttributes.EMPTY_ATTRIBUTES);
// CPPONLY: appendToCurrentNodeAndPushElementMayFoster(
// CPPONLY: ElementName.LABEL,
// CPPONLY: HtmlAttributes.EMPTY_ATTRIBUTES);
// CPPONLY: int promptIndex = attributes.getIndex(AttributeName.PROMPT);
// CPPONLY: if (promptIndex > -1) {
// CPPONLY: @Auto char[] prompt = Portability.newCharArrayFromString(attributes.getValueNoBoundsCheck(promptIndex));
// CPPONLY: appendCharacters(stack[currentPtr].node,
// CPPONLY: prompt, 0, prompt.length);
// CPPONLY: } else {
// CPPONLY: appendIsindexPrompt(stack[currentPtr].node);
// CPPONLY: }
// CPPONLY: HtmlAttributes inputAttributes = new HtmlAttributes(
// CPPONLY: 0);
// CPPONLY: inputAttributes.addAttribute(
// CPPONLY: AttributeName.NAME,
// CPPONLY: Portability.newStringFromLiteral("isindex"),
// CPPONLY: tokenizer.getLineNumber()
// CPPONLY: );
// CPPONLY: for (int i = 0; i < attributes.getLength(); i++) {
// CPPONLY: @Local String attributeQName = attributes.getLocalNameNoBoundsCheck(i);
// CPPONLY: if ("name" == attributeQName
// CPPONLY: || "prompt" == attributeQName) {
// CPPONLY: attributes.releaseValue(i);
// CPPONLY: } else if ("action" != attributeQName) {
// CPPONLY: inputAttributes.AddAttributeWithLocal(
// CPPONLY: attributeQName,
// CPPONLY: attributes.getValueNoBoundsCheck(i),
// CPPONLY: attributes.getLineNoBoundsCheck(i)
// CPPONLY: );
// CPPONLY: }
// CPPONLY: }
// CPPONLY: attributes.clearWithoutReleasingContents();
// CPPONLY: appendVoidElementToCurrentMayFoster(
// CPPONLY: "input",
// CPPONLY: inputAttributes, formPointer);
// CPPONLY: pop(); // label
// CPPONLY: appendVoidElementToCurrentMayFoster(
// CPPONLY: ElementName.HR,
// CPPONLY: HtmlAttributes.EMPTY_ATTRIBUTES);
// CPPONLY: pop(); // form
// CPPONLY:
// CPPONLY: if (!isTemplateContents()) {
// CPPONLY: formPointer = null;
// CPPONLY: }
// CPPONLY:
// CPPONLY: selfClosing = false;
// CPPONLY: // Don't delete attributes, they are deleted
// CPPONLY: // later
// CPPONLY: break starttagloop;
case TEXTAREA:
appendToCurrentNodeAndPushElementMayFoster(
elementName,
@ -3837,7 +3826,7 @@ public abstract class TreeBuilder<T> implements TokenHandler,
case INPUT:
case KEYGEN: // XXX??
case HR:
case ISINDEX:
// CPPONLY: case ISINDEX:
case IFRAME:
case NOEMBED: // XXX???
case NOFRAMES: // XXX??
@ -5681,7 +5670,7 @@ public abstract class TreeBuilder<T> implements TokenHandler,
protected abstract void appendCharacters(T parent, @NoLength char[] buf,
int start, int length) throws SAXException;
protected abstract void appendIsindexPrompt(T parent) throws SAXException;
// CPPONLY: protected abstract void appendIsindexPrompt(T parent) throws SAXException;
protected abstract void appendComment(T parent, @NoLength char[] buf,
int start, int length) throws SAXException;
@ -6377,9 +6366,9 @@ public abstract class TreeBuilder<T> implements TokenHandler,
err("Saw a start tag \u201Cimage\u201D.");
}
private void errIsindex() throws SAXException {
err("\u201Cisindex\u201D seen.");
}
// CPPONLY: private void errIsindex() throws SAXException {
// CPPONLY: err("\u201Cisindex\u201D seen.");
// CPPONLY: }
private void errFooSeenWhenFooOpen(@Local String name) throws SAXException {
if (errorHandler == null) {

View file

@ -23,26 +23,24 @@
package nu.validator.htmlparser.sax;
import nu.validator.htmlparser.impl.HtmlAttributes;
import nu.validator.htmlparser.impl.TreeBuilder;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.ext.LexicalHandler;
class SAXStreamer extends TreeBuilder<Attributes>{
import nu.validator.htmlparser.impl.HtmlAttributes;
import nu.validator.htmlparser.impl.TreeBuilder;
private static final char[] ISINDEX_PROMPT = "This is a searchable index. Enter search keywords: ".toCharArray();
class SAXStreamer extends TreeBuilder<Attributes>{
private ContentHandler contentHandler = null;
private LexicalHandler lexicalHandler = null;
SAXStreamer() {
super();
}
@Override
protected void addAttributesToElement(Attributes element, HtmlAttributes attributes) throws SAXException {
Attributes existingAttrs = element;
@ -59,14 +57,6 @@ class SAXStreamer extends TreeBuilder<Attributes>{
contentHandler.characters(buf, start, length);
}
/**
* @see nu.validator.htmlparser.impl.TreeBuilder#appendIsindexPrompt(java.lang.Object)
*/
@Override protected void appendIsindexPrompt(Attributes parent)
throws SAXException {
contentHandler.characters(ISINDEX_PROMPT, 0, ISINDEX_PROMPT.length);
}
@Override
protected void appendChildrenToNewParent(Attributes oldParent, Attributes newParent) throws SAXException {
fatal();

View file

@ -23,6 +23,8 @@
package nu.validator.htmlparser.sax;
import org.xml.sax.SAXException;
import nu.validator.htmlparser.impl.HtmlAttributes;
import nu.validator.htmlparser.impl.TreeBuilder;
import nu.validator.saxtree.Characters;
@ -34,12 +36,8 @@ import nu.validator.saxtree.Element;
import nu.validator.saxtree.Node;
import nu.validator.saxtree.ParentNode;
import org.xml.sax.SAXException;
class SAXTreeBuilder extends TreeBuilder<Element> {
private static final char[] ISINDEX_PROMPT = "This is a searchable index. Enter search keywords: ".toCharArray();
private Document document;
private Node cachedTable = null;
@ -65,14 +63,6 @@ class SAXTreeBuilder extends TreeBuilder<Element> {
parent.appendChild(new Characters(tokenizer, buf, start, length));
}
/**
* @see nu.validator.htmlparser.impl.TreeBuilder#appendIsindexPrompt(java.lang.Object)
*/
@Override protected void appendIsindexPrompt(Element parent)
throws SAXException {
parent.appendChild(new Characters(tokenizer, ISINDEX_PROMPT, 0, ISINDEX_PROMPT.length));
}
@Override
protected boolean hasChildren(Element element) {
return element.getFirstChild() != null;