blob: 66838a252c5c324dd307fd8fe5b62cd493992bed [file] [log] [blame]
/*
* Copyright (C) 2000 Lars Knoll (knoll@kde.org)
* Copyright (C) 2003, 2004, 2006, 2007, 2008 Apple Inc. All right reserved.
* Copyright (C) 2011 Google, 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.
*
*/
#ifndef BidiRunList_h
#define BidiRunList_h
#include <wtf/Noncopyable.h>
namespace WebCore {
template <class Run>
class BidiRunList {
WTF_MAKE_NONCOPYABLE(BidiRunList);
public:
BidiRunList()
: m_lastRun(nullptr)
, m_logicallyLastRun(nullptr)
, m_runCount(0)
{
}
// FIXME: Once BidiResolver no longer owns the BidiRunList,
// then ~BidiRunList should call deleteRuns() automatically.
Run* firstRun() const { return m_firstRun.get(); }
Run* lastRun() const { return m_lastRun; }
Run* logicallyLastRun() const { return m_logicallyLastRun; }
unsigned runCount() const { return m_runCount; }
void appendRun(std::unique_ptr<Run>&&);
void prependRun(std::unique_ptr<Run>&&);
void moveRunToEnd(Run*);
void moveRunToBeginning(Run*);
void clear();
void reverseRuns(unsigned start, unsigned end);
void reorderRunsFromLevels();
void setLogicallyLastRun(Run* run) { m_logicallyLastRun = run; }
void replaceRunWithRuns(Run* toReplace, BidiRunList<Run>& newRuns);
private:
// The runs form a singly-linked-list, where the links (Run::m_next) imply ownership (and are of type std::unique_ptr).
// The raw pointers below point into the singly-linked-list.
std::unique_ptr<Run> m_firstRun; // The head of the list
Run* m_lastRun;
Run* m_logicallyLastRun;
unsigned m_runCount;
};
template <class Run>
inline void BidiRunList<Run>::appendRun(std::unique_ptr<Run>&& run)
{
if (!m_firstRun) {
m_firstRun = WTFMove(run);
m_lastRun = m_firstRun.get();
} else {
m_lastRun->setNext(WTFMove(run));
m_lastRun = m_lastRun->next();
}
m_runCount++;
}
template <class Run>
inline void BidiRunList<Run>::prependRun(std::unique_ptr<Run>&& run)
{
ASSERT(!run->next());
if (!m_lastRun)
m_lastRun = run.get();
else
run->setNext(WTFMove(m_firstRun));
m_firstRun = WTFMove(run);
m_runCount++;
}
template <class Run>
inline void BidiRunList<Run>::moveRunToEnd(Run* run)
{
ASSERT(m_firstRun);
ASSERT(m_lastRun);
ASSERT(run->next());
Run* previous = nullptr;
Run* current = m_firstRun.get();
while (current != run) {
previous = current;
current = previous->next();
}
if (!previous) {
ASSERT(m_firstRun.get() == run);
std::unique_ptr<Run> originalFirstRun = WTFMove(m_firstRun);
m_firstRun = originalFirstRun->takeNext();
m_lastRun->setNext(WTFMove(originalFirstRun));
} else {
std::unique_ptr<Run> target = previous->takeNext();
previous->setNext(current->takeNext());
m_lastRun->setNext(WTFMove(target));
}
}
template <class Run>
inline void BidiRunList<Run>::moveRunToBeginning(Run* run)
{
ASSERT(m_firstRun);
ASSERT(m_lastRun);
ASSERT(run != m_firstRun.get());
Run* previous = m_firstRun.get();
Run* current = previous->next();
while (current != run) {
previous = current;
current = previous->next();
}
std::unique_ptr<Run> target = previous->takeNext();
previous->setNext(run->takeNext());
if (run == m_lastRun)
m_lastRun = previous;
target->setNext(WTFMove(m_firstRun));
m_firstRun = WTFMove(target);
}
template <class Run>
void BidiRunList<Run>::replaceRunWithRuns(Run* toReplace, BidiRunList<Run>& newRuns)
{
ASSERT(newRuns.runCount());
ASSERT(m_firstRun);
ASSERT(toReplace);
m_runCount += newRuns.runCount() - 1; // We are adding the new runs and removing toReplace.
// Fix up any pointers which may end up stale.
if (m_lastRun == toReplace)
m_lastRun = newRuns.lastRun();
if (m_logicallyLastRun == toReplace)
m_logicallyLastRun = newRuns.logicallyLastRun();
if (m_firstRun.get() == toReplace) {
newRuns.m_lastRun->setNext(m_firstRun->takeNext());
m_firstRun = WTFMove(newRuns.m_firstRun);
} else {
// Find the run just before "toReplace" in the list of runs.
Run* previousRun = m_firstRun.get();
while (previousRun->next() != toReplace)
previousRun = previousRun->next();
ASSERT(previousRun);
std::unique_ptr<Run> target = previousRun->takeNext();
previousRun->setNext(WTFMove(newRuns.m_firstRun));
newRuns.m_lastRun->setNext(target->takeNext());
}
newRuns.clear();
}
template <class Run>
void BidiRunList<Run>::clear()
{
m_firstRun = nullptr;
m_lastRun = nullptr;
m_logicallyLastRun = nullptr;
m_runCount = 0;
}
template <class Run>
void BidiRunList<Run>::reverseRuns(unsigned start, unsigned end)
{
if (start >= end)
return;
ASSERT_WITH_SECURITY_IMPLICATION(end < m_runCount);
// Get the item before the start of the runs to reverse and put it in
// |beforeStart|. |curr| should point to the first run to reverse.
Run* curr = m_firstRun.get();
Run* beforeStart = nullptr;
unsigned i = 0;
for (; i < start; ++i) {
beforeStart = curr;
curr = curr->next();
}
Run* startRun = curr;
for (; i < end; ++i)
curr = curr->next();
if (!curr->next())
m_lastRun = startRun;
// Standard "sliding window" of 3 pointers
std::unique_ptr<Run> previous = curr->takeNext();
std::unique_ptr<Run> current = beforeStart ? beforeStart->takeNext() : WTFMove(m_firstRun);
while (current) {
std::unique_ptr<Run> next = current->takeNext();
current->setNext(WTFMove(previous));
previous = WTFMove(current);
current = WTFMove(next);
}
if (beforeStart)
beforeStart->setNext(WTFMove(previous));
else
m_firstRun = WTFMove(previous);
}
} // namespace WebCore
#endif // BidiRunList