blob: 92d8bc35399914a20ae9e64d2a239fa761e05767 [file] [log] [blame]
/*
* Copyright (C) 2010 Google, Inc. All Rights Reserved.
*
* 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 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 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.
*/
#pragma once
#include "SegmentedString.h"
#include <wtf/text/OrdinalNumber.h>
namespace WebCore {
// The InputStream is made up of a sequence of SegmentedStrings:
//
// [--current--][--next--][--next--] ... [--next--]
// /\ (also called m_last)
// L_ current insertion point
//
// The current segmented string is stored in InputStream. Each of the
// afterInsertionPoint buffers are stored in InsertionPointRecords on the
// stack.
//
// We remove characters from the "current" string in the InputStream.
// document.write() will add characters at the current insertion point,
// which appends them to the "current" string.
//
// m_last is a pointer to the last of the afterInsertionPoint strings.
// The network adds data at the end of the InputStream, which appends
// them to the "last" string.
class HTMLInputStream {
WTF_MAKE_NONCOPYABLE(HTMLInputStream);
public:
HTMLInputStream()
: m_last(&m_first)
{
}
void appendToEnd(SegmentedString&& string)
{
m_last->append(WTFMove(string));
}
void insertAtCurrentInsertionPoint(SegmentedString&& string)
{
m_first.append(WTFMove(string));
}
bool hasInsertionPoint() const
{
return &m_first != m_last;
}
void markEndOfFile()
{
m_last->append(String { &kEndOfFileMarker, 1 });
m_last->close();
}
void closeWithoutMarkingEndOfFile()
{
m_last->close();
}
bool haveSeenEndOfFile() const
{
return m_last->isClosed();
}
SegmentedString& current() { return m_first; }
const SegmentedString& current() const { return m_first; }
void splitInto(SegmentedString& next)
{
next = WTFMove(m_first);
if (m_last == &m_first) {
// We used to only have one SegmentedString in the InputStream
// but now we have two. That means m_first is no longer also
// the m_last string, |next| is now the last one.
m_last = &next;
}
}
void mergeFrom(SegmentedString& next)
{
m_first.append(next);
if (m_last == &next) {
// The string |next| used to be the last SegmentedString in
// the InputStream. Now that it's been merged into m_first,
// that makes m_first the last one.
m_last = &m_first;
}
if (next.isClosed()) {
// We also need to merge the "closed" state from next to
// m_first. Arguably, this work could be done in append().
m_first.close();
}
}
private:
SegmentedString m_first;
SegmentedString* m_last;
};
class InsertionPointRecord {
WTF_MAKE_NONCOPYABLE(InsertionPointRecord);
public:
explicit InsertionPointRecord(HTMLInputStream& inputStream)
: m_inputStream(&inputStream)
{
m_line = m_inputStream->current().currentLine();
m_column = m_inputStream->current().currentColumn();
m_inputStream->splitInto(m_next);
// We 'fork' current position and use it for the generated script part.
// This is a bit weird, because generated part does not have positions within an HTML document.
m_inputStream->current().setCurrentPosition(m_line, m_column, 0);
}
~InsertionPointRecord()
{
// Some inserted text may have remained in input stream. E.g. if script has written "&amp" or "<table",
// it stays in buffer because it cannot be properly tokenized before we see next part.
int unparsedRemainderLength = m_inputStream->current().length();
m_inputStream->mergeFrom(m_next);
// We restore position for the character that goes right after unparsed remainder.
m_inputStream->current().setCurrentPosition(m_line, m_column, unparsedRemainderLength);
}
private:
HTMLInputStream* m_inputStream;
SegmentedString m_next;
OrdinalNumber m_line;
OrdinalNumber m_column;
};
} // namespace WebCore