blob: 51f21764f2805f595ad58c5de2ea27d890fae8f8 [file] [log] [blame]
/*
Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "platform/text/SegmentedString.h"
namespace blink {
unsigned SegmentedString::length() const {
unsigned length = current_string_.length();
if (IsComposite()) {
for (auto& substring : substrings_)
length += substring.length();
}
return length;
}
void SegmentedString::SetExcludeLineNumbers() {
current_string_.SetExcludeLineNumbers();
if (IsComposite()) {
for (auto& substring : substrings_)
substring.SetExcludeLineNumbers();
}
}
void SegmentedString::Clear() {
current_string_.Clear();
number_of_characters_consumed_prior_to_current_string_ = 0;
number_of_characters_consumed_prior_to_current_line_ = 0;
current_line_ = 0;
substrings_.clear();
closed_ = false;
empty_ = true;
}
void SegmentedString::Append(const SegmentedSubstring& s) {
DCHECK(!closed_);
if (!s.length())
return;
if (!current_string_.length()) {
number_of_characters_consumed_prior_to_current_string_ +=
current_string_.NumberOfCharactersConsumed();
current_string_ = s;
} else {
substrings_.push_back(s);
}
empty_ = false;
}
void SegmentedString::Push(UChar c) {
DCHECK(c);
// pushIfPossible attempts to rewind the pointer in the SegmentedSubstring,
// however it will fail if the SegmentedSubstring is empty, or
// when we prepended some text while consuming a SegmentedSubstring by
// document.write().
if (current_string_.PushIfPossible(c))
return;
Prepend(SegmentedString(String(&c, 1)), PrependType::kUnconsume);
}
void SegmentedString::Prepend(const SegmentedSubstring& s, PrependType type) {
DCHECK(!s.NumberOfCharactersConsumed());
if (!s.length())
return;
// FIXME: We're also ASSERTing that s is a fresh SegmentedSubstring.
// The assumption is sufficient for our current use, but we might
// need to handle the more elaborate cases in the future.
number_of_characters_consumed_prior_to_current_string_ +=
current_string_.NumberOfCharactersConsumed();
if (type == PrependType::kUnconsume)
number_of_characters_consumed_prior_to_current_string_ -= s.length();
if (!current_string_.length()) {
current_string_ = s;
} else {
// Shift our m_currentString into our list.
substrings_.push_front(current_string_);
current_string_ = s;
}
empty_ = false;
}
void SegmentedString::Close() {
// Closing a stream twice is likely a coding mistake.
DCHECK(!closed_);
closed_ = true;
}
void SegmentedString::Append(const SegmentedString& s) {
DCHECK(!closed_);
Append(s.current_string_);
if (s.IsComposite()) {
for (auto& substring : s.substrings_)
Append(substring);
}
}
void SegmentedString::Prepend(const SegmentedString& s, PrependType type) {
if (s.IsComposite()) {
auto it = s.substrings_.rbegin();
auto e = s.substrings_.rend();
for (; it != e; ++it)
Prepend(*it, type);
}
Prepend(s.current_string_, type);
}
void SegmentedString::AdvanceSubstring() {
if (IsComposite()) {
number_of_characters_consumed_prior_to_current_string_ +=
current_string_.NumberOfCharactersConsumed();
current_string_ = substrings_.TakeFirst();
// If we've previously consumed some characters of the non-current
// string, we now account for those characters as part of the current
// string, not as part of "prior to current string."
number_of_characters_consumed_prior_to_current_string_ -=
current_string_.NumberOfCharactersConsumed();
} else {
current_string_.Clear();
empty_ = true;
}
}
String SegmentedString::ToString() const {
StringBuilder result;
current_string_.AppendTo(result);
if (IsComposite()) {
for (auto& substring : substrings_)
substring.AppendTo(result);
}
return result.ToString();
}
void SegmentedString::Advance(unsigned count, UChar* consumed_characters) {
SECURITY_DCHECK(count <= length());
for (unsigned i = 0; i < count; ++i) {
consumed_characters[i] = CurrentChar();
Advance();
}
}
OrdinalNumber SegmentedString::CurrentLine() const {
return OrdinalNumber::FromZeroBasedInt(current_line_);
}
OrdinalNumber SegmentedString::CurrentColumn() const {
int zero_based_column = NumberOfCharactersConsumed() -
number_of_characters_consumed_prior_to_current_line_;
return OrdinalNumber::FromZeroBasedInt(zero_based_column);
}
void SegmentedString::SetCurrentPosition(OrdinalNumber line,
OrdinalNumber column_aftre_prolog,
int prolog_length) {
current_line_ = line.ZeroBasedInt();
number_of_characters_consumed_prior_to_current_line_ =
NumberOfCharactersConsumed() + prolog_length -
column_aftre_prolog.ZeroBasedInt();
}
} // namespace blink