| 1 | /* |
| 2 | * Copyright (C) 2000 Lars Knoll (knoll@kde.org) |
| 3 | * Copyright (C) 2003, 2004, 2006, 2007, 2008 Apple Inc. All right reserved. |
| 4 | * Copyright (C) 2011 Google, Inc. All rights reserved. |
| 5 | * |
| 6 | * This library is free software; you can redistribute it and/or |
| 7 | * modify it under the terms of the GNU Library General Public |
| 8 | * License as published by the Free Software Foundation; either |
| 9 | * version 2 of the License, or (at your option) any later version. |
| 10 | * |
| 11 | * This library is distributed in the hope that it will be useful, |
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 14 | * Library General Public License for more details. |
| 15 | * |
| 16 | * You should have received a copy of the GNU Library General Public License |
| 17 | * along with this library; see the file COPYING.LIB. If not, write to |
| 18 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| 19 | * Boston, MA 02110-1301, USA. |
| 20 | * |
| 21 | */ |
| 22 | |
| 23 | #ifndef BidiRunList_h |
| 24 | #define BidiRunList_h |
| 25 | |
| 26 | #include <wtf/Noncopyable.h> |
| 27 | |
| 28 | namespace WebCore { |
| 29 | |
| 30 | template <class Run> |
| 31 | class BidiRunList { |
| 32 | WTF_MAKE_NONCOPYABLE(BidiRunList); |
| 33 | public: |
| 34 | BidiRunList() |
| 35 | : m_lastRun(nullptr) |
| 36 | , m_logicallyLastRun(nullptr) |
| 37 | , m_runCount(0) |
| 38 | { |
| 39 | } |
| 40 | |
| 41 | // FIXME: Once BidiResolver no longer owns the BidiRunList, |
| 42 | // then ~BidiRunList should call deleteRuns() automatically. |
| 43 | |
| 44 | Run* firstRun() const { return m_firstRun.get(); } |
| 45 | Run* lastRun() const { return m_lastRun; } |
| 46 | Run* logicallyLastRun() const { return m_logicallyLastRun; } |
| 47 | unsigned runCount() const { return m_runCount; } |
| 48 | |
| 49 | void appendRun(std::unique_ptr<Run>&&); |
| 50 | void prependRun(std::unique_ptr<Run>&&); |
| 51 | |
| 52 | void moveRunToEnd(Run*); |
| 53 | void moveRunToBeginning(Run*); |
| 54 | |
| 55 | void clear(); |
| 56 | void reverseRuns(unsigned start, unsigned end); |
| 57 | void reorderRunsFromLevels(); |
| 58 | |
| 59 | void setLogicallyLastRun(Run* run) { m_logicallyLastRun = run; } |
| 60 | |
| 61 | void replaceRunWithRuns(Run* toReplace, BidiRunList<Run>& newRuns); |
| 62 | |
| 63 | private: |
| 64 | |
| 65 | // The runs form a singly-linked-list, where the links (Run::m_next) imply ownership (and are of type std::unique_ptr). |
| 66 | // The raw pointers below point into the singly-linked-list. |
| 67 | std::unique_ptr<Run> m_firstRun; // The head of the list |
| 68 | Run* m_lastRun; |
| 69 | Run* m_logicallyLastRun; |
| 70 | unsigned m_runCount; |
| 71 | }; |
| 72 | |
| 73 | template <class Run> |
| 74 | inline void BidiRunList<Run>::appendRun(std::unique_ptr<Run>&& run) |
| 75 | { |
| 76 | if (!m_firstRun) { |
| 77 | m_firstRun = WTFMove(run); |
| 78 | m_lastRun = m_firstRun.get(); |
| 79 | } else { |
| 80 | m_lastRun->setNext(WTFMove(run)); |
| 81 | m_lastRun = m_lastRun->next(); |
| 82 | } |
| 83 | m_runCount++; |
| 84 | } |
| 85 | |
| 86 | template <class Run> |
| 87 | inline void BidiRunList<Run>::prependRun(std::unique_ptr<Run>&& run) |
| 88 | { |
| 89 | ASSERT(!run->next()); |
| 90 | |
| 91 | if (!m_lastRun) |
| 92 | m_lastRun = run.get(); |
| 93 | else |
| 94 | run->setNext(WTFMove(m_firstRun)); |
| 95 | m_firstRun = WTFMove(run); |
| 96 | m_runCount++; |
| 97 | } |
| 98 | |
| 99 | template <class Run> |
| 100 | inline void BidiRunList<Run>::moveRunToEnd(Run* run) |
| 101 | { |
| 102 | ASSERT(m_firstRun); |
| 103 | ASSERT(m_lastRun); |
| 104 | ASSERT(run->next()); |
| 105 | |
| 106 | Run* previous = nullptr; |
| 107 | Run* current = m_firstRun.get(); |
| 108 | while (current != run) { |
| 109 | previous = current; |
| 110 | current = previous->next(); |
| 111 | } |
| 112 | |
| 113 | if (!previous) { |
| 114 | ASSERT(m_firstRun.get() == run); |
| 115 | std::unique_ptr<Run> originalFirstRun = WTFMove(m_firstRun); |
| 116 | m_firstRun = originalFirstRun->takeNext(); |
| 117 | m_lastRun->setNext(WTFMove(originalFirstRun)); |
| 118 | } else { |
| 119 | std::unique_ptr<Run> target = previous->takeNext(); |
| 120 | previous->setNext(current->takeNext()); |
| 121 | m_lastRun->setNext(WTFMove(target)); |
| 122 | } |
| 123 | } |
| 124 | |
| 125 | template <class Run> |
| 126 | inline void BidiRunList<Run>::moveRunToBeginning(Run* run) |
| 127 | { |
| 128 | ASSERT(m_firstRun); |
| 129 | ASSERT(m_lastRun); |
| 130 | ASSERT(run != m_firstRun.get()); |
| 131 | |
| 132 | Run* previous = m_firstRun.get(); |
| 133 | Run* current = previous->next(); |
| 134 | while (current != run) { |
| 135 | previous = current; |
| 136 | current = previous->next(); |
| 137 | } |
| 138 | |
| 139 | std::unique_ptr<Run> target = previous->takeNext(); |
| 140 | previous->setNext(run->takeNext()); |
| 141 | if (run == m_lastRun) |
| 142 | m_lastRun = previous; |
| 143 | |
| 144 | target->setNext(WTFMove(m_firstRun)); |
| 145 | m_firstRun = WTFMove(target); |
| 146 | } |
| 147 | |
| 148 | template <class Run> |
| 149 | void BidiRunList<Run>::replaceRunWithRuns(Run* toReplace, BidiRunList<Run>& newRuns) |
| 150 | { |
| 151 | ASSERT(newRuns.runCount()); |
| 152 | ASSERT(m_firstRun); |
| 153 | ASSERT(toReplace); |
| 154 | |
| 155 | m_runCount += newRuns.runCount() - 1; // We are adding the new runs and removing toReplace. |
| 156 | |
| 157 | // Fix up any pointers which may end up stale. |
| 158 | if (m_lastRun == toReplace) |
| 159 | m_lastRun = newRuns.lastRun(); |
| 160 | if (m_logicallyLastRun == toReplace) |
| 161 | m_logicallyLastRun = newRuns.logicallyLastRun(); |
| 162 | |
| 163 | if (m_firstRun.get() == toReplace) { |
| 164 | newRuns.m_lastRun->setNext(m_firstRun->takeNext()); |
| 165 | m_firstRun = WTFMove(newRuns.m_firstRun); |
| 166 | } else { |
| 167 | // Find the run just before "toReplace" in the list of runs. |
| 168 | Run* previousRun = m_firstRun.get(); |
| 169 | while (previousRun->next() != toReplace) |
| 170 | previousRun = previousRun->next(); |
| 171 | ASSERT(previousRun); |
| 172 | |
| 173 | std::unique_ptr<Run> target = previousRun->takeNext(); |
| 174 | previousRun->setNext(WTFMove(newRuns.m_firstRun)); |
| 175 | newRuns.m_lastRun->setNext(target->takeNext()); |
| 176 | } |
| 177 | |
| 178 | newRuns.clear(); |
| 179 | } |
| 180 | |
| 181 | template <class Run> |
| 182 | void BidiRunList<Run>::clear() |
| 183 | { |
| 184 | m_firstRun = nullptr; |
| 185 | m_lastRun = nullptr; |
| 186 | m_logicallyLastRun = nullptr; |
| 187 | m_runCount = 0; |
| 188 | } |
| 189 | |
| 190 | template <class Run> |
| 191 | void BidiRunList<Run>::reverseRuns(unsigned start, unsigned end) |
| 192 | { |
| 193 | if (start >= end) |
| 194 | return; |
| 195 | |
| 196 | ASSERT_WITH_SECURITY_IMPLICATION(end < m_runCount); |
| 197 | |
| 198 | // Get the item before the start of the runs to reverse and put it in |
| 199 | // |beforeStart|. |curr| should point to the first run to reverse. |
| 200 | Run* curr = m_firstRun.get(); |
| 201 | Run* beforeStart = nullptr; |
| 202 | unsigned i = 0; |
| 203 | for (; i < start; ++i) { |
| 204 | beforeStart = curr; |
| 205 | curr = curr->next(); |
| 206 | } |
| 207 | Run* startRun = curr; |
| 208 | |
| 209 | for (; i < end; ++i) |
| 210 | curr = curr->next(); |
| 211 | |
| 212 | if (!curr->next()) |
| 213 | m_lastRun = startRun; |
| 214 | |
| 215 | // Standard "sliding window" of 3 pointers |
| 216 | std::unique_ptr<Run> previous = curr->takeNext(); |
| 217 | std::unique_ptr<Run> current = beforeStart ? beforeStart->takeNext() : WTFMove(m_firstRun); |
| 218 | while (current) { |
| 219 | std::unique_ptr<Run> next = current->takeNext(); |
| 220 | current->setNext(WTFMove(previous)); |
| 221 | previous = WTFMove(current); |
| 222 | current = WTFMove(next); |
| 223 | } |
| 224 | |
| 225 | if (beforeStart) |
| 226 | beforeStart->setNext(WTFMove(previous)); |
| 227 | else |
| 228 | m_firstRun = WTFMove(previous); |
| 229 | } |
| 230 | |
| 231 | } // namespace WebCore |
| 232 | |
| 233 | #endif // BidiRunList |
| 234 | |