blob: 0b663336eb447d0f34300cc2249ac41403b7022b [file] [log] [blame]
/*
* Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012 Apple Inc. All
* rights reserved.
* Copyright (C) 2005 Alexey Proskuryakov.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "core/editing/iterators/TextIteratorTextState.h"
#include "core/layout/LayoutText.h"
namespace blink {
TextIteratorTextState::TextIteratorTextState(bool emitsOriginalText)
: m_textLength(0),
m_singleCharacterBuffer(0),
m_positionNode(nullptr),
m_positionStartOffset(0),
m_positionEndOffset(0),
m_hasEmitted(false),
m_lastCharacter(0),
m_emitsOriginalText(emitsOriginalText) {}
UChar TextIteratorTextState::characterAt(unsigned index) const {
ASSERT_WITH_SECURITY_IMPLICATION(index < static_cast<unsigned>(length()));
if (!(index < static_cast<unsigned>(length())))
return 0;
if (m_singleCharacterBuffer) {
DCHECK_EQ(index, 0u);
DCHECK_EQ(length(), 1);
return m_singleCharacterBuffer;
}
return string()[positionStartOffset() + index];
}
String TextIteratorTextState::substring(unsigned position,
unsigned length) const {
ASSERT_WITH_SECURITY_IMPLICATION(position <=
static_cast<unsigned>(this->length()));
ASSERT_WITH_SECURITY_IMPLICATION(position + length <=
static_cast<unsigned>(this->length()));
if (!length)
return emptyString();
if (m_singleCharacterBuffer) {
DCHECK_EQ(position, 0u);
DCHECK_EQ(length, 1u);
return String(&m_singleCharacterBuffer, 1);
}
return string().substring(positionStartOffset() + position, length);
}
void TextIteratorTextState::appendTextToStringBuilder(
StringBuilder& builder,
unsigned position,
unsigned maxLength) const {
unsigned lengthToAppend =
std::min(static_cast<unsigned>(length()) - position, maxLength);
if (!lengthToAppend)
return;
if (m_singleCharacterBuffer) {
DCHECK_EQ(position, 0u);
builder.append(m_singleCharacterBuffer);
} else {
builder.append(string(), positionStartOffset() + position, lengthToAppend);
}
}
void TextIteratorTextState::updateForReplacedElement(Node* baseNode) {
m_hasEmitted = true;
m_positionNode = baseNode->parentNode();
m_positionOffsetBaseNode = baseNode;
m_positionStartOffset = 0;
m_positionEndOffset = 1;
m_singleCharacterBuffer = 0;
m_textLength = 0;
m_lastCharacter = 0;
}
void TextIteratorTextState::emitAltText(Node* node) {
m_text = toHTMLElement(node)->altText();
m_textLength = m_text.length();
m_lastCharacter = m_textLength ? m_text[m_textLength - 1] : 0;
}
void TextIteratorTextState::flushPositionOffsets() const {
if (!m_positionOffsetBaseNode)
return;
int index = m_positionOffsetBaseNode->nodeIndex();
m_positionStartOffset += index;
m_positionEndOffset += index;
m_positionOffsetBaseNode = nullptr;
}
void TextIteratorTextState::spliceBuffer(UChar c,
Node* textNode,
Node* offsetBaseNode,
int textStartOffset,
int textEndOffset) {
DCHECK(textNode);
m_hasEmitted = true;
// Remember information with which to construct the TextIterator::range().
// NOTE: textNode is often not a text node, so the range will specify child
// nodes of positionNode
m_positionNode = textNode;
m_positionOffsetBaseNode = offsetBaseNode;
m_positionStartOffset = textStartOffset;
m_positionEndOffset = textEndOffset;
// remember information with which to construct the TextIterator::characters()
// and length()
m_singleCharacterBuffer = c;
DCHECK(m_singleCharacterBuffer);
m_textLength = 1;
// remember some iteration state
m_lastCharacter = c;
}
void TextIteratorTextState::emitText(Node* textNode,
LayoutText* layoutObject,
int textStartOffset,
int textEndOffset) {
DCHECK(textNode);
m_text =
m_emitsOriginalText ? layoutObject->originalText() : layoutObject->text();
DCHECK(!m_text.isEmpty());
DCHECK_LE(0, textStartOffset);
DCHECK_LT(textStartOffset, static_cast<int>(m_text.length()));
DCHECK_LE(0, textEndOffset);
DCHECK_LE(textEndOffset, static_cast<int>(m_text.length()));
DCHECK_LE(textStartOffset, textEndOffset);
m_positionNode = textNode;
m_positionOffsetBaseNode = nullptr;
m_positionStartOffset = textStartOffset;
m_positionEndOffset = textEndOffset;
m_singleCharacterBuffer = 0;
m_textLength = textEndOffset - textStartOffset;
m_lastCharacter = m_text[textEndOffset - 1];
m_hasEmitted = true;
}
void TextIteratorTextState::appendTextTo(ForwardsTextBuffer* output,
unsigned position,
unsigned lengthToAppend) const {
ASSERT_WITH_SECURITY_IMPLICATION(position + lengthToAppend <=
static_cast<unsigned>(length()));
// Make sure there's no integer overflow.
ASSERT_WITH_SECURITY_IMPLICATION(position + lengthToAppend >= position);
if (!lengthToAppend)
return;
DCHECK(output);
if (m_singleCharacterBuffer) {
DCHECK_EQ(position, 0u);
DCHECK_EQ(length(), 1);
output->pushCharacters(m_singleCharacterBuffer, 1);
return;
}
if (positionNode()) {
flushPositionOffsets();
unsigned offset = positionStartOffset() + position;
if (string().is8Bit())
output->pushRange(string().characters8() + offset, lengthToAppend);
else
output->pushRange(string().characters16() + offset, lengthToAppend);
return;
}
// We shouldn't be attempting to append text that doesn't exist.
NOTREACHED();
}
} // namespace blink