TEST(StringBuilderTest, ToAtomicString) { StringBuilder builder; builder.append("123"); AtomicString atomicString = builder.toAtomicString(); EXPECT_EQ(String("123"), atomicString); builder.reserveCapacity(256); EXPECT_TRUE(builder.canShrink()); for (int i = builder.length(); i < 128; i++) builder.append('x'); AtomicString atomicString1 = builder.toAtomicString(); EXPECT_EQ(128u, atomicString1.length()); EXPECT_EQ('x', atomicString1[127]); // Later change of builder should not affect the atomic string. for (int i = builder.length(); i < 256; i++) builder.append('x'); EXPECT_EQ(128u, atomicString1.length()); EXPECT_FALSE(builder.canShrink()); String string = builder.toString(); AtomicString atomicString2 = builder.toAtomicString(); // They should share the same StringImpl. EXPECT_EQ(atomicString2.impl(), string.impl()); }
void Attr::childrenChanged(bool, Node*, Node*, int) { if (m_ignoreChildrenChanged > 0) return; invalidateNodeListCachesInAncestors(&qualifiedName(), m_element); // FIXME: We should include entity references in the value StringBuilder valueBuilder; for (Node *n = firstChild(); n; n = n->nextSibling()) { if (n->isTextNode()) valueBuilder.append(toText(n)->data()); } AtomicString newValue = valueBuilder.toAtomicString(); if (m_element) m_element->willModifyAttribute(qualifiedName(), value(), newValue); if (m_element) elementAttribute().setValue(newValue); else m_standaloneValue = newValue; if (m_element) m_element->attributeChanged(qualifiedName(), newValue); }
AtomicString extractMIMETypeFromMediaType(const AtomicString& mediaType) { StringBuilder mimeType; unsigned length = mediaType.length(); mimeType.reserveCapacity(length); for (unsigned i = 0; i < length; i++) { UChar c = mediaType[i]; if (c == ';') break; // While RFC 2616 does not allow it, other browsers allow multiple values in the HTTP media // type header field, Content-Type. In such cases, the media type string passed here may contain // the multiple values separated by commas. For now, this code ignores text after the first comma, // which prevents it from simply failing to parse such types altogether. Later for better // compatibility we could consider using the first or last valid MIME type instead. // See https://bugs.webkit.org/show_bug.cgi?id=25352 for more discussion. if (c == ',') break; // FIXME: The following is not correct. RFC 2616 allows linear white space before and // after the MIME type, but not within the MIME type itself. And linear white space // includes only a few specific ASCII characters; a small subset of isSpaceOrNewline. // See https://bugs.webkit.org/show_bug.cgi?id=8644 for a bug tracking part of this. if (isSpaceOrNewline(c)) continue; mimeType.append(c); } if (mimeType.length() == length) return mediaType; return mimeType.toAtomicString(); }
AtomicString SecurityOrigin::toRawAtomicString() const { if (m_protocol == "file") return AtomicString("file://", AtomicString::ConstructFromLiteral); StringBuilder result; buildRawString(result); return result.toAtomicString(); }
AtomicString SecurityOrigin::toRawAtomicString() const { if (m_protocol == "file") return AtomicString("file://"); StringBuilder result; buildRawString(result, true); return result.toAtomicString(); }
static AtomicString makeVisibleEmptyValue(const Vector<String>& symbols) { unsigned maximumLength = 0; for (unsigned index = 0; index < symbols.size(); ++index) maximumLength = std::max(maximumLength, numGraphemeClusters(symbols[index])); StringBuilder builder; builder.reserveCapacity(maximumLength); for (unsigned length = 0; length < maximumLength; ++length) builder.append('-'); return builder.toAtomicString(); }
// This returns an AtomicString because it is always passed as argument to // setValue() and setValue() takes an AtomicString in argument. AtomicString DOMTokenList::removeTokens(const AtomicString& input, const Vector<String>& tokens) { // Algorithm defined at // http://www.whatwg.org/specs/web-apps/current-work/multipage/common-microsyntaxes.html#remove-a-token-from-a-string // New spec is at https://dom.spec.whatwg.org/#remove-a-token-from-a-string unsigned inputLength = input.length(); StringBuilder output; // 3 output.reserveCapacity(inputLength); unsigned position = 0; // 4 // Step 5 while (position < inputLength) { if (isHTMLSpace<UChar>(input[position])) { // 6 position++; continue; // 6.3 } // Step 7 StringBuilder tokenBuilder; while (position < inputLength && isNotHTMLSpace<UChar>(input[position])) tokenBuilder.append(input[position++]); // Step 8 String token = tokenBuilder.toString(); if (tokens.contains(token)) { // Step 8.1 while (position < inputLength && isHTMLSpace<UChar>(input[position])) ++position; // Step 8.2 size_t j = output.length(); while (j > 0 && isHTMLSpace<UChar>(output[j - 1])) --j; output.resize(j); } else { output.append(token); // Step 9 } if (position < inputLength && !output.isEmpty()) output.append(' '); } size_t j = output.length(); if (j > 0 && isHTMLSpace<UChar>(output[j - 1])) output.resize(j - 1); return output.toAtomicString(); }
const AtomicString& DOMTokenList::value() const { if (m_cachedValue.isNull()) { // https://dom.spec.whatwg.org/#concept-ordered-set-serializer StringBuilder builder; for (auto& token : m_tokens) { if (!builder.isEmpty()) builder.append(' '); builder.append(token); } m_cachedValue = builder.toAtomicString(); ASSERT(!m_cachedValue.isNull()); } return m_cachedValue; }
AtomicString FrameTree::uniqueChildName(const AtomicString& requestedName) const { // If the requested name (the frame's "name" attribute) is unique, just use that. if (!requestedName.isEmpty() && !child(requestedName) && requestedName != "_blank") return requestedName; // The "name" attribute was not unique or absent. Generate a name based on the // new frame's location in the frame tree. The name uses HTML comment syntax to // avoid collisions with author names. // An example path for the third child of the second child of the root frame: // <!--framePath //<!--frame1-->/<!--frame2-->--> const char framePathPrefix[] = "<!--framePath "; const int framePathPrefixLength = 14; const int framePathSuffixLength = 3; // Find the nearest parent that has a frame with a path in it. Vector<Frame*, 16> chain; Frame* frame; for (frame = &m_thisFrame; frame; frame = frame->tree().parent()) { if (frame->tree().uniqueName().startsWith(framePathPrefix)) break; chain.append(frame); } StringBuilder name; name.append(framePathPrefix); if (frame) { name.append(frame->tree().uniqueName().string().substring(framePathPrefixLength, frame->tree().uniqueName().length() - framePathPrefixLength - framePathSuffixLength)); } for (int i = chain.size() - 1; i >= 0; --i) { frame = chain[i]; name.append('/'); if (frame->tree().parent()) { name.appendLiteral("<!--frame"); name.appendNumber(frame->tree().indexInParent()); name.appendLiteral("-->"); } } name.appendLiteral("/<!--frame"); name.appendNumber(childCount()); name.appendLiteral("-->-->"); return name.toAtomicString(); }
void MarkupAccumulator::generateUniquePrefix(QualifiedName& prefixedName, const Namespaces& namespaces) { // http://www.w3.org/TR/DOM-Level-3-Core/namespaces-algorithms.html#normalizeDocumentAlgo // Find a prefix following the pattern "NS" + index (starting at 1) and make sure this // prefix is not declared in the current scope. StringBuilder builder; do { builder.clear(); builder.append("NS"); builder.appendNumber(++m_prefixLevel); const AtomicString& name = builder.toAtomicString(); if (!namespaces.get(name.impl())) { prefixedName.setPrefix(name); return; } } while (true); }
// This returns an AtomicString because attribute names are always stored // as AtomicString types in Element (see setAttribute()). static AtomicString convertPropertyNameToAttributeName(const String& name) { StringBuilder builder; builder.appendLiteral("data-"); unsigned length = name.length(); for (unsigned i = 0; i < length; ++i) { UChar character = name[i]; if (isASCIIUpper(character)) { builder.append('-'); builder.append(toASCIILower(character)); } else builder.append(character); } return builder.toAtomicString(); }
TEST(StringBuilderTest, ToAtomicStringOnEmpty) { { // Default constructed. StringBuilder builder; AtomicString atomicString = builder.toAtomicString(); EXPECT_EQ(emptyAtom, atomicString); } { // With capacity. StringBuilder builder; builder.reserveCapacity(64); AtomicString atomicString = builder.toAtomicString(); EXPECT_EQ(emptyAtom, atomicString); } { // AtomicString constructed from a null string. StringBuilder builder; builder.append(String()); AtomicString atomicString = builder.toAtomicString(); EXPECT_EQ(emptyAtom, atomicString); } { // AtomicString constructed from an empty string. StringBuilder builder; builder.append(emptyString()); AtomicString atomicString = builder.toAtomicString(); EXPECT_EQ(emptyAtom, atomicString); } { // AtomicString constructed from an empty StringBuilder. StringBuilder builder; StringBuilder emptyBuilder; builder.append(emptyBuilder); AtomicString atomicString = builder.toAtomicString(); EXPECT_EQ(emptyAtom, atomicString); } { // AtomicString constructed from an empty char* string. StringBuilder builder; builder.append("", 0); AtomicString atomicString = builder.toAtomicString(); EXPECT_EQ(emptyAtom, atomicString); } { // Cleared StringBuilder. StringBuilder builder; builder.appendLiteral("WebKit"); builder.clear(); AtomicString atomicString = builder.toAtomicString(); EXPECT_EQ(emptyAtom, atomicString); } }
// This returns an AtomicString because it is always passed as argument to setValue() and setValue() // takes an AtomicString in argument. AtomicString DOMTokenList::addTokens(const AtomicString& input, const Vector<String>& tokens) { bool needsSpace = false; StringBuilder builder; if (!input.isEmpty()) { builder.append(input); needsSpace = !isHTMLSpace<UChar>(input[input.length() - 1]); } for (size_t i = 0; i < tokens.size(); ++i) { if (needsSpace) builder.append(' '); builder.append(tokens[i]); needsSpace = true; } return builder.toAtomicString(); }
AtomicString FrameTree::uniqueChildName(const AtomicString& requestedName) const { if (!requestedName.isEmpty() && !child(requestedName) && requestedName != "_blank") return requestedName; // Create a repeatable name for a child about to be added to us. The name must be // unique within the frame tree. The string we generate includes a "path" of names // from the root frame down to us. For this path to be unique, each set of siblings must // contribute a unique name to the path, which can't collide with any HTML-assigned names. // We generate this path component by index in the child list along with an unlikely // frame name that can't be set in HTML because it collides with comment syntax. const char framePathPrefix[] = "<!--framePath "; const int framePathPrefixLength = 14; const int framePathSuffixLength = 3; // Find the nearest parent that has a frame with a path in it. Vector<Frame*, 16> chain; Frame* frame; for (frame = &m_thisFrame; frame; frame = frame->tree().parent()) { if (frame->tree().uniqueName().startsWith(framePathPrefix)) break; chain.append(frame); } StringBuilder name; name.append(framePathPrefix); if (frame) { name.append(frame->tree().uniqueName().string().substring(framePathPrefixLength, frame->tree().uniqueName().length() - framePathPrefixLength - framePathSuffixLength)); } for (int i = chain.size() - 1; i >= 0; --i) { frame = chain[i]; name.append('/'); name.append(frame->tree().uniqueName()); } name.appendLiteral("/<!--frame"); name.appendNumber(childCount()); name.appendLiteral("-->-->"); return name.toAtomicString(); }
void Attr::childrenChanged(const ChildChange&) { if (m_ignoreChildrenChanged > 0) return; invalidateNodeListAndCollectionCachesInAncestors(&qualifiedName(), m_element); StringBuilder valueBuilder; TextNodeTraversal::appendContents(this, valueBuilder); AtomicString newValue = valueBuilder.toAtomicString(); if (m_element) m_element->willModifyAttribute(qualifiedName(), value(), newValue); if (m_element) elementAttribute().setValue(newValue); else m_standaloneValue = newValue; if (m_element) m_element->attributeChanged(qualifiedName(), newValue); }
AtomicString FormKeyGenerator::formKey(const HTMLFormControlElementWithState& control) { HTMLFormElement* form = ownerFormForState(control); if (!form) { DEFINE_STATIC_LOCAL(AtomicString, formKeyForNoOwner, ("No owner")); return formKeyForNoOwner; } FormToKeyMap::const_iterator it = m_formToKeyMap.find(form); if (it != m_formToKeyMap.end()) return it->second; String signature = formSignature(*form); ASSERT(!signature.isNull()); FormSignatureToNextIndexMap::AddResult result = m_formSignatureToNextIndexMap.add(signature, 0); unsigned nextIndex = result.iterator->second++; StringBuilder builder; builder.append(signature); builder.append(" #"); builder.append(String::number(nextIndex)); AtomicString formKey = builder.toAtomicString(); m_formToKeyMap.add(form, formKey); return formKey; }
AtomicString FormKeyGenerator::formKey(const HTMLFormControlElementWithState& control) { HTMLFormElement* form = ownerFormForState(control); if (!form) { static NeverDestroyed<AtomicString> formKeyForNoOwner("No owner", AtomicString::ConstructFromLiteral); return formKeyForNoOwner; } FormToKeyMap::const_iterator it = m_formToKeyMap.find(form); if (it != m_formToKeyMap.end()) return it->value; String signature = formSignature(*form); ASSERT(!signature.isNull()); FormSignatureToNextIndexMap::AddResult result = m_formSignatureToNextIndexMap.add(signature, 0); unsigned nextIndex = result.iterator->value++; StringBuilder builder; builder.append(signature); builder.appendLiteral(" #"); builder.appendNumber(nextIndex); AtomicString formKey = builder.toAtomicString(); m_formToKeyMap.add(form, formKey); return formKey; }