void StyledMarkupAccumulator::appendText(StringBuilder& out, Text* text) { const bool parentIsTextarea = text->parentElement() && text->parentElement()->tagQName() == textareaTag; const bool wrappingSpan = shouldApplyWrappingStyle(text) && !parentIsTextarea; if (wrappingSpan) { RefPtr<EditingStyle> wrappingStyle = m_wrappingStyle->copy(); // FIXME: <rdar://problem/5371536> Style rules that match pasted content can change it's appearance // Make sure spans are inline style in paste side e.g. span { display: block }. wrappingStyle->forceInline(); // FIXME: Should this be included in forceInline? wrappingStyle->style()->setProperty(CSSPropertyFloat, CSSValueNone); StringBuilder openTag; appendStyleNodeOpenTag(openTag, wrappingStyle->style(), text->document()); out.append(openTag.characters(), openTag.length()); } if (!shouldAnnotate() || parentIsTextarea) MarkupAccumulator::appendText(out, text); else { const bool useRenderedText = !enclosingNodeWithTag(firstPositionInNode(text), selectTag); String content = useRenderedText ? renderedText(text, m_range) : stringValueForRange(text, m_range); StringBuilder buffer; appendCharactersReplacingEntities(buffer, content.characters(), content.length(), EntityMaskInPCDATA); out.append(convertHTMLTextToInterchangeFormat(buffer.toString(), text)); } if (wrappingSpan) out.append(styleNodeCloseTag()); }
// http://www.whatwg.org/specs/web-apps/current-work/#rules-for-parsing-integers bool parseHTMLInteger(const String& input, int& value) { // Step 1 // Step 2 const UChar* position = input.characters(); const UChar* end = position + input.length(); // Step 3 int sign = 1; // Step 4 while (position < end) { if (!isHTMLSpace(*position)) break; ++position; } // Step 5 if (position == end) return false; ASSERT(position < end); // Step 6 if (*position == '-') { sign = -1; ++position; } else if (*position == '+') ++position; if (position == end) return false; ASSERT(position < end); // Step 7 if (!isASCIIDigit(*position)) return false; // Step 8 StringBuilder digits; while (position < end) { if (!isASCIIDigit(*position)) break; digits.append(*position++); } // Step 9 bool ok; value = sign * charactersToIntStrict(digits.characters(), digits.length(), &ok); return ok; }
TEST(StringBuilderTest, ToStringPreserveCapacity) { StringBuilder builder; builder.append("0123456789"); String string = builder.toStringPreserveCapacity(); ASSERT_EQ(String("0123456789"), string); ASSERT_EQ(string.impl(), builder.toStringPreserveCapacity().impl()); ASSERT_EQ(string.characters(), builder.characters()); // Changing the StringBuilder should not affect the original result of toStringPreserveCapacity(). builder.append("abcdefghijklmnopqrstuvwxyz"); ASSERT_EQ(String("0123456789"), string); // Changing the StringBuilder should not affect the original result of toStringPreserveCapacity() in case the capacity is not changed. builder.reserveCapacity(200); string = builder.toStringPreserveCapacity(); ASSERT_EQ(string.characters(), builder.characters()); ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyz"), string); builder.append("ABC"); ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyz"), string); // Changing the original result of toStringPreserveCapacity() should not affect the content of the StringBuilder. String string1 = builder.toStringPreserveCapacity(); ASSERT_EQ(string1.characters(), builder.characters()); ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyzABC"), string1); string1.append("DEF"); ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyzABC"), builder.toStringPreserveCapacity()); ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyzABCDEF"), string1); // Resizing the StringBuilder should not affect the original result of toStringPreserveCapacity(). string1 = builder.toStringPreserveCapacity(); ASSERT_EQ(string.characters(), builder.characters()); builder.resize(10); builder.append("###"); ASSERT_EQ(String("0123456789abcdefghijklmnopqrstuvwxyzABC"), string1); }
// http://www.whatwg.org/specs/web-apps/current-work/#rules-for-parsing-non-negative-integers bool parseHTMLNonNegativeInteger(const String& input, unsigned int& value) { // Step 1 // Step 2 const UChar* position = input.characters(); const UChar* end = position + input.length(); // Step 3 while (position < end) { if (!isHTMLSpace(*position)) break; ++position; } // Step 4 if (position == end) return false; ASSERT(position < end); // Step 5 if (*position == '+') ++position; // Step 6 if (position == end) return false; ASSERT(position < end); // Step 7 if (!isASCIIDigit(*position)) return false; // Step 8 StringBuilder digits; while (position < end) { if (!isASCIIDigit(*position)) break; digits.append(*position++); } // Step 9 bool ok; value = charactersToUIntStrict(digits.characters(), digits.length(), &ok); return ok; }
TEST(StringBuilderTest, Append) { StringBuilder builder; builder.append(String("0123456789")); expectBuilderContent("0123456789", builder); builder.append("abcd"); expectBuilderContent("0123456789abcd", builder); builder.append("efgh", 3); expectBuilderContent("0123456789abcdefg", builder); builder.append(""); expectBuilderContent("0123456789abcdefg", builder); builder.append('#'); expectBuilderContent("0123456789abcdefg#", builder); builder.toString(); // Test after reifyString(). StringBuilder builder1; builder.append("", 0); expectBuilderContent("0123456789abcdefg#", builder); builder1.append(builder.characters(), builder.length()); builder1.append("XYZ"); builder.append(builder1.characters(), builder1.length()); expectBuilderContent("0123456789abcdefg#0123456789abcdefg#XYZ", builder); }
// http://www.whatwg.org/specs/web-apps/current-work/multipage/rendering.html#fonts-and-colors static bool parseFontSize(const String& input, int& size) { // Step 1 // Step 2 const UChar* position = input.characters(); const UChar* end = position + input.length(); // Step 3 while (position < end) { if (!isHTMLSpace(*position)) break; ++position; } // Step 4 if (position == end) return false; ASSERT(position < end); // Step 5 enum { RelativePlus, RelativeMinus, Absolute } mode; switch (*position) { case '+': mode = RelativePlus; ++position; break; case '-': mode = RelativeMinus; ++position; break; default: mode = Absolute; break; } // Step 6 StringBuilder digits; digits.reserveCapacity(16); while (position < end) { if (!isASCIIDigit(*position)) break; digits.append(*position++); } // Step 7 if (digits.isEmpty()) return false; // Step 8 int value = charactersToIntStrict(digits.characters(), digits.length()); // Step 9 if (mode == RelativePlus) value += 3; else if (mode == RelativeMinus) value = 3 - value; // Step 10 if (value > 7) value = 7; // Step 11 if (value < 1) value = 1; size = value; return true; }
void expectEmpty(const StringBuilder& builder) { EXPECT_EQ(0U, builder.length()); EXPECT_TRUE(builder.isEmpty()); EXPECT_EQ(0, builder.characters()); }
void expectBuilderContent(const char* expected, const StringBuilder& builder) { // Not using builder.toString() or builder.toStringPreserveCapacity() because they all // change internal state of builder. EXPECT_EQ(String(expected), String(builder.characters(), builder.length())); }