https://bugs.webkit.org/show_bug.cgi?id=153231
Reviewed by Darin Adler.
LayoutTests/imported/w3c:
Rebaselined the test now that all test cases pass.
* web-platform-tests/dom/nodes/Document-createElement-expected.txt:
Source/WebCore:
Use the newly added convertToASCIIUppercase to generate the string for tagName and nodeName.
Test: fast/dom/Element/tagName-must-be-ASCII-uppercase-in-HTML-document.html
* dom/QualifiedName.cpp:
(WebCore::QualifiedName::localNameUpper): Use convertToASCIIUppercase.
* html/HTMLElement.cpp:
(WebCore::HTMLElement::nodeName): Use convertToASCIIUppercase.
Source/WTF:
Added convertToASCIIUppercase to AtomicString, String, and StringImpl.
* wtf/text/AtomicString.cpp:
(WTF::AtomicString::convertASCIICase): Generalized from convertToASCIILowercase.
(WTF::AtomicString::convertToASCIILowercase):
(WTF::AtomicString::convertToASCIIUppercase):
* wtf/text/AtomicString.h:
* wtf/text/StringImpl.cpp:
(WTF::StringImpl::convertASCIICase): Generalized from convertToASCIILowercase.
(WTF::StringImpl::convertToASCIILowercase):
(WTF::StringImpl::convertToASCIIUppercase):
* wtf/text/StringImpl.h:
* wtf/text/WTFString.cpp:
(WTF::String::convertToASCIIUppercase): Added.
* wtf/text/WTFString.h:
LayoutTests:
Added a regression test since the rebaselined W3C test case is very simple and doesn't all permutations.
* fast/dom/Element/tagName-must-be-ASCII-uppercase-in-HTML-document-expected.txt: Added.
* fast/dom/Element/tagName-must-be-ASCII-uppercase-in-HTML-document.html: Added.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@195501
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2016-01-20 Ryosuke Niwa <rniwa@webkit.org>
+
+ HTMLElement::nodeName should not upper case non-ASCII characters
+ https://bugs.webkit.org/show_bug.cgi?id=153231
+
+ Reviewed by Darin Adler.
+
+ Added a regression test since the rebaselined W3C test case is very simple and doesn't all permutations.
+
+ * fast/dom/Element/tagName-must-be-ASCII-uppercase-in-HTML-document-expected.txt: Added.
+ * fast/dom/Element/tagName-must-be-ASCII-uppercase-in-HTML-document.html: Added.
+
2016-01-22 Brady Eidson <beidson@apple.com>
Modern IDB: Disable simultaneous transactions in the SQLite backend for now.
--- /dev/null
+Tests that tagName and nodeName uppercases ASCII and only ASCII letters in a HTML document.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+htmlDocument = document
+PASS htmlDocument.createElement("İnput").tagName is "İNPUT"
+PASS htmlDocument.createElement("ınput").tagName is "ıNPUT"
+PASS htmlDocument.createElement("xİnput").nodeName is "XİNPUT"
+PASS htmlDocument.createElement("xınput").nodeName is "XıNPUT"
+PASS htmlDocument.createElementNS("http://www.w3.org/1999/xhtml", "x:İnput").tagName is "X:İNPUT"
+PASS htmlDocument.createElementNS("http://www.w3.org/1999/xhtml", "xİ:ınput").tagName is "Xİ:ıNPUT"
+PASS htmlDocument.createElementNS("http://www.w3.org/1999/xhtml", "x:İnput").nodeName is "X:İNPUT"
+PASS htmlDocument.createElementNS("http://www.w3.org/1999/xhtml", "xı:İnput").nodeName is "Xı:İNPUT"
+
+xmlDocument = document.implementation.createDocument("http://www.w3.org/1999/xhtml", "html")
+PASS xmlDocument.createElement("İnput").tagName is "İnput"
+PASS xmlDocument.createElement("ınput").tagName is "ınput"
+PASS xmlDocument.createElement("xİnput").nodeName is "xİnput"
+PASS xmlDocument.createElement("xınput").nodeName is "xınput"
+PASS xmlDocument.createElementNS("http://www.w3.org/1999/xhtml", "x:İnput").tagName is "x:İnput"
+PASS xmlDocument.createElementNS("http://www.w3.org/1999/xhtml", "xİ:ınput").tagName is "xİ:ınput"
+PASS xmlDocument.createElementNS("http://www.w3.org/1999/xhtml", "x:İnput").nodeName is "x:İnput"
+PASS xmlDocument.createElementNS("http://www.w3.org/1999/xhtml", "xı:İnput").nodeName is "xı:İnput"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE html>
+<html>
+<body>
+<script src="../../../resources/js-test-pre.js"></script>
+<script>
+
+description('Tests that tagName and nodeName uppercases ASCII and only ASCII letters in a HTML document.');
+
+evalAndLog('htmlDocument = document');
+shouldBeEqualToString('htmlDocument.createElement("\u0130nput").tagName', '\u0130NPUT');
+shouldBeEqualToString('htmlDocument.createElement("\u0131nput").tagName', '\u0131NPUT');
+shouldBeEqualToString('htmlDocument.createElement("x\u0130nput").nodeName', 'X\u0130NPUT');
+shouldBeEqualToString('htmlDocument.createElement("x\u0131nput").nodeName', 'X\u0131NPUT');
+
+shouldBeEqualToString('htmlDocument.createElementNS("http://www.w3.org/1999/xhtml", "x:\u0130nput").tagName', 'X:\u0130NPUT');
+shouldBeEqualToString('htmlDocument.createElementNS("http://www.w3.org/1999/xhtml", "x\u0130:\u0131nput").tagName', 'X\u0130:\u0131NPUT');
+shouldBeEqualToString('htmlDocument.createElementNS("http://www.w3.org/1999/xhtml", "x:\u0130nput").nodeName', 'X:\u0130NPUT');
+shouldBeEqualToString('htmlDocument.createElementNS("http://www.w3.org/1999/xhtml", "x\u0131:\u0130nput").nodeName', 'X\u0131:\u0130NPUT');
+
+debug('');
+evalAndLog('xmlDocument = document.implementation.createDocument("http://www.w3.org/1999/xhtml", "html")');
+shouldBeEqualToString('xmlDocument.createElement("\u0130nput").tagName', '\u0130nput');
+shouldBeEqualToString('xmlDocument.createElement("\u0131nput").tagName', '\u0131nput');
+shouldBeEqualToString('xmlDocument.createElement("x\u0130nput").nodeName', 'x\u0130nput');
+shouldBeEqualToString('xmlDocument.createElement("x\u0131nput").nodeName', 'x\u0131nput');
+
+shouldBeEqualToString('xmlDocument.createElementNS("http://www.w3.org/1999/xhtml", "x:\u0130nput").tagName', 'x:\u0130nput');
+shouldBeEqualToString('xmlDocument.createElementNS("http://www.w3.org/1999/xhtml", "x\u0130:\u0131nput").tagName', 'x\u0130:\u0131nput');
+shouldBeEqualToString('xmlDocument.createElementNS("http://www.w3.org/1999/xhtml", "x:\u0130nput").nodeName', 'x:\u0130nput');
+shouldBeEqualToString('xmlDocument.createElementNS("http://www.w3.org/1999/xhtml", "x\u0131:\u0130nput").nodeName', 'x\u0131:\u0130nput');
+
+</script>
+<script src="../../../resources/js-test-post.js"></script>
+</body>
+</html>
+2016-01-20 Ryosuke Niwa <rniwa@webkit.org>
+
+ HTMLElement::nodeName should not upper case non-ASCII characters
+ https://bugs.webkit.org/show_bug.cgi?id=153231
+
+ Reviewed by Darin Adler.
+
+ Rebaselined the test now that all test cases pass.
+
+ * web-platform-tests/dom/nodes/Document-createElement-expected.txt:
+
2016-01-22 Chris Dumez <cdumez@apple.com>
document.charset should be an alias for document.characterSet
PASS createElement("FOO")
PASS createElement("marK")
PASS createElement("İnput")
-FAIL createElement("ınput") assert_equals: expected "ıNPUT" but got "INPUT"
+PASS createElement("ınput")
PASS createElement("")
PASS createElement("1foo")
PASS createElement("̀foo")
+2016-01-20 Ryosuke Niwa <rniwa@webkit.org>
+
+ HTMLElement::nodeName should not upper case non-ASCII characters
+ https://bugs.webkit.org/show_bug.cgi?id=153231
+
+ Reviewed by Darin Adler.
+
+ Added convertToASCIIUppercase to AtomicString, String, and StringImpl.
+
+ * wtf/text/AtomicString.cpp:
+ (WTF::AtomicString::convertASCIICase): Generalized from convertToASCIILowercase.
+ (WTF::AtomicString::convertToASCIILowercase):
+ (WTF::AtomicString::convertToASCIIUppercase):
+ * wtf/text/AtomicString.h:
+ * wtf/text/StringImpl.cpp:
+ (WTF::StringImpl::convertASCIICase): Generalized from convertToASCIILowercase.
+ (WTF::StringImpl::convertToASCIILowercase):
+ (WTF::StringImpl::convertToASCIIUppercase):
+ * wtf/text/StringImpl.h:
+ * wtf/text/WTFString.cpp:
+ (WTF::String::convertToASCIIUppercase): Added.
+ * wtf/text/WTFString.h:
+
2016-01-22 Chris Dumez <cdumez@apple.com>
Unreviewed attempt to fix the Windows build after r195452.
return result;
}
-AtomicString AtomicString::convertToASCIILowercase() const
+template<AtomicString::CaseConvertType type>
+ALWAYS_INLINE AtomicString AtomicString::convertASCIICase() const
{
StringImpl* impl = this->impl();
if (UNLIKELY(!impl))
const LChar* characters = impl->characters8();
unsigned failingIndex;
for (unsigned i = 0; i < length; ++i) {
- if (UNLIKELY(isASCIIUpper(characters[i]))) {
+ if (type == CaseConvertType::Lower ? UNLIKELY(isASCIIUpper(characters[i])) : LIKELY(isASCIILower(characters[i]))) {
failingIndex = i;
goto SlowPath;
}
for (unsigned i = 0; i < failingIndex; ++i)
localBuffer[i] = characters[i];
for (unsigned i = failingIndex; i < length; ++i)
- localBuffer[i] = toASCIILower(characters[i]);
+ localBuffer[i] = type == CaseConvertType::Lower ? toASCIILower(characters[i]) : toASCIIUpper(characters[i]);
return AtomicString(localBuffer, length);
}
- RefPtr<StringImpl> convertedString = impl->convertToASCIILowercase();
- if (LIKELY(convertedString == impl))
+ Ref<StringImpl> convertedString = type == CaseConvertType::Lower ? impl->convertToASCIILowercase() : impl->convertToASCIIUppercase();
+ if (LIKELY(convertedString.ptr() == impl))
return *this;
AtomicString result;
- result.m_string = AtomicStringImpl::add(convertedString.get());
+ result.m_string = AtomicStringImpl::add(convertedString.ptr());
return result;
}
+AtomicString AtomicString::convertToASCIILowercase() const
+{
+ return convertASCIICase<CaseConvertType::Lower>();
+}
+
+AtomicString AtomicString::convertToASCIIUppercase() const
+{
+ return convertASCIICase<CaseConvertType::Upper>();
+}
+
AtomicString AtomicString::number(int number)
{
return numberToStringSigned<AtomicString>(number);
{ return m_string.endsWith<matchLength>(prefix, caseSensitive); }
WTF_EXPORT_STRING_API AtomicString convertToASCIILowercase() const;
+ WTF_EXPORT_STRING_API AtomicString convertToASCIIUppercase() const;
WTF_EXPORT_STRING_API AtomicString lower() const;
AtomicString upper() const { return AtomicString(impl()->upper()); }
// The explicit constructors with AtomicString::ConstructFromLiteral must be used for literals.
AtomicString(ASCIILiteral);
+ enum class CaseConvertType { Upper, Lower };
+ template<CaseConvertType> AtomicString convertASCIICase() const;
+
WTF_EXPORT_STRING_API static AtomicString fromUTF8Internal(const char*, const char*);
String m_string;
return newImpl.releaseNonNull();
}
-Ref<StringImpl> StringImpl::convertToASCIILowercase()
-{
- if (is8Bit()) {
- unsigned failingIndex;
- for (unsigned i = 0; i < m_length; ++i) {
- LChar character = m_data8[i];
- if (UNLIKELY(isASCIIUpper(character))) {
- failingIndex = i;
- goto SlowPath;
- }
+template<StringImpl::CaseConvertType type, typename CharacterType>
+ALWAYS_INLINE Ref<StringImpl> StringImpl::convertASCIICase(StringImpl& impl, const CharacterType* data, unsigned length)
+{
+ unsigned failingIndex;
+ for (unsigned i = 0; i < length; ++i) {
+ CharacterType character = data[i];
+ if (type == CaseConvertType::Lower ? UNLIKELY(isASCIIUpper(character)) : LIKELY(isASCIILower(character))) {
+ failingIndex = i;
+ goto SlowPath;
}
- return *this;
+ }
+ return impl;
SlowPath:
- LChar* data8;
- Ref<StringImpl> newImpl = createUninitializedInternalNonEmpty(m_length, data8);
- for (unsigned i = 0; i < failingIndex; ++i)
- data8[i] = m_data8[i];
- for (unsigned i = failingIndex; i < m_length; ++i)
- data8[i] = toASCIILower(m_data8[i]);
- return newImpl;
- }
+ CharacterType* newData;
+ Ref<StringImpl> newImpl = createUninitializedInternalNonEmpty(length, newData);
+ for (unsigned i = 0; i < failingIndex; ++i)
+ newData[i] = data[i];
+ for (unsigned i = failingIndex; i < length; ++i)
+ newData[i] = type == CaseConvertType::Lower ? toASCIILower(data[i]) : toASCIIUpper(data[i]);
+ return newImpl;
+}
- bool noUpper = true;
- for (unsigned i = 0; i < m_length; ++i) {
- if (UNLIKELY(isASCIIUpper(m_data16[i])))
- noUpper = false;
- }
- if (noUpper)
- return *this;
+Ref<StringImpl> StringImpl::convertToASCIILowercase()
+{
+ if (is8Bit())
+ return convertASCIICase<CaseConvertType::Lower>(*this, m_data8, m_length);
+ return convertASCIICase<CaseConvertType::Lower>(*this, m_data16, m_length);
+}
- UChar* data16;
- Ref<StringImpl> newImpl = createUninitializedInternalNonEmpty(m_length, data16);
- for (unsigned i = 0; i < m_length; ++i)
- data16[i] = toASCIILower(m_data16[i]);
- return newImpl;
+Ref<StringImpl> StringImpl::convertToASCIIUppercase()
+{
+ if (is8Bit())
+ return convertASCIICase<CaseConvertType::Upper>(*this, m_data8, m_length);
+ return convertASCIICase<CaseConvertType::Upper>(*this, m_data16, m_length);
}
template <class UCharPredicate>
float toFloat(bool* ok = 0);
WTF_EXPORT_STRING_API Ref<StringImpl> convertToASCIILowercase();
+ WTF_EXPORT_STRING_API Ref<StringImpl> convertToASCIIUppercase();
WTF_EXPORT_STRING_API Ref<StringImpl> lower();
WTF_EXPORT_STRING_API Ref<StringImpl> upper();
WTF_EXPORT_STRING_API Ref<StringImpl> lower(const AtomicString& localeIdentifier);
// This number must be at least 2 to avoid sharing empty, null as well as 1 character strings from SmallStrings.
static const unsigned s_copyCharsInlineCutOff = 20;
+ enum class CaseConvertType { Upper, Lower };
+ template<CaseConvertType type, typename CharacterType> static Ref<StringImpl> convertASCIICase(StringImpl&, const CharacterType*, unsigned);
+
BufferOwnership bufferOwnership() const { return static_cast<BufferOwnership>(m_hashAndFlags & s_hashMaskBufferOwnership); }
template <class UCharPredicate> Ref<StringImpl> stripMatchedCharacters(UCharPredicate);
template <typename CharType, class UCharPredicate> Ref<StringImpl> simplifyMatchedCharactersToSpace(UCharPredicate);
return m_impl->convertToASCIILowercase();
}
+String String::convertToASCIIUppercase() const
+{
+ // FIXME: Should this function, and the many others like it, be inlined?
+ if (!m_impl)
+ return String();
+ return m_impl->convertToASCIIUppercase();
+}
+
String String::lower() const
{
if (!m_impl)
// want to do any conversion for non-ASCII letters.
WTF_EXPORT_STRING_API String convertToASCIILowercase() const;
WTF_EXPORT_STRING_API String lower() const;
+ WTF_EXPORT_STRING_API String convertToASCIIUppercase() const;
WTF_EXPORT_STRING_API String upper() const;
WTF_EXPORT_STRING_API String lower(const AtomicString& localeIdentifier) const;
+2016-01-20 Ryosuke Niwa <rniwa@webkit.org>
+
+ HTMLElement::nodeName should not upper case non-ASCII characters
+ https://bugs.webkit.org/show_bug.cgi?id=153231
+
+ Reviewed by Darin Adler.
+
+ Use the newly added convertToASCIIUppercase to generate the string for tagName and nodeName.
+
+ Test: fast/dom/Element/tagName-must-be-ASCII-uppercase-in-HTML-document.html
+
+ * dom/QualifiedName.cpp:
+ (WebCore::QualifiedName::localNameUpper): Use convertToASCIIUppercase.
+ * html/HTMLElement.cpp:
+ (WebCore::HTMLElement::nodeName): Use convertToASCIIUppercase.
+
2016-01-22 Brady Eidson <beidson@apple.com>
Modern IDB: Disable simultaneous transactions in the SQLite backend for now.
const AtomicString& QualifiedName::localNameUpper() const
{
if (!m_impl->m_localNameUpper)
- m_impl->m_localNameUpper = m_impl->m_localName.upper();
+ m_impl->m_localNameUpper = m_impl->m_localName.convertToASCIIUppercase();
return m_impl->m_localNameUpper;
}
// FIXME: Would be nice to have an AtomicString lookup based off uppercase
// ASCII characters that does not have to copy the string on a hit in the hash.
if (document().isHTMLDocument()) {
- if (!tagQName().hasPrefix())
+ if (LIKELY(!tagQName().hasPrefix()))
return tagQName().localNameUpper();
- return Element::nodeName().upper();
+ return Element::nodeName().convertToASCIIUppercase();
}
return Element::nodeName();
}