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());
}
Example #2
0
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();
}
Example #4
0
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();
}
Example #7
0
// 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();
}
Example #8
0
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;
}
Example #9
0
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);
    }
}
Example #13
0
// 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();
}
Example #14
0
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();
}
Example #15
0
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);
}
Example #16
0
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;
}