OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2000 Lars Knoll (knoll@kde.org) | 2 * Copyright (C) 2000 Lars Knoll (knoll@kde.org) |
3 * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009, 2010 Apple Inc. All right r
eserved. | 3 * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009, 2010 Apple Inc. All right r
eserved. |
4 * Copyright (C) 2010 Google Inc. All rights reserved. | 4 * Copyright (C) 2010 Google Inc. All rights reserved. |
5 * | 5 * |
6 * This library is free software; you can redistribute it and/or | 6 * This library is free software; you can redistribute it and/or |
7 * modify it under the terms of the GNU Library General Public | 7 * modify it under the terms of the GNU Library General Public |
8 * License as published by the Free Software Foundation; either | 8 * License as published by the Free Software Foundation; either |
9 * version 2 of the License, or (at your option) any later version. | 9 * version 2 of the License, or (at your option) any later version. |
10 * | 10 * |
11 * This library is distributed in the hope that it will be useful, | 11 * This library is distributed in the hope that it will be useful, |
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 * Library General Public License for more details. | 14 * Library General Public License for more details. |
15 * | 15 * |
16 * You should have received a copy of the GNU Library General Public License | 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 | 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, | 18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
19 * Boston, MA 02110-1301, USA. | 19 * Boston, MA 02110-1301, USA. |
20 * | 20 * |
21 */ | 21 */ |
22 | 22 |
23 #ifndef InlineIterator_h | 23 #ifndef InlineIterator_h |
24 #define InlineIterator_h | 24 #define InlineIterator_h |
25 | 25 |
26 #include "core/rendering/BidiRun.h" | 26 #include "core/rendering/BidiRun.h" |
27 #include "core/rendering/RenderBlockFlow.h" | 27 #include "core/rendering/RenderBlockFlow.h" |
| 28 #include "core/rendering/RenderInline.h" |
28 #include "core/rendering/RenderText.h" | 29 #include "core/rendering/RenderText.h" |
29 #include "wtf/StdLibExtras.h" | 30 #include "wtf/StdLibExtras.h" |
30 | 31 |
31 namespace WebCore { | 32 namespace WebCore { |
32 | 33 |
33 // This class is used to RenderInline subtrees, stepping by character within the | 34 // This class is used to RenderInline subtrees, stepping by character within the |
34 // text children. InlineIterator will use bidiNext to find the next RenderText | 35 // text children. InlineIterator will use bidiNext to find the next RenderText |
35 // optionally notifying a BidiResolver every time it steps into/out of a RenderI
nline. | 36 // optionally notifying a BidiResolver every time it steps into/out of a RenderI
nline. |
36 class InlineIterator { | 37 class InlineIterator { |
37 public: | 38 public: |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
182 enum EmptyInlineBehavior { | 183 enum EmptyInlineBehavior { |
183 SkipEmptyInlines, | 184 SkipEmptyInlines, |
184 IncludeEmptyInlines, | 185 IncludeEmptyInlines, |
185 }; | 186 }; |
186 | 187 |
187 static bool isEmptyInline(RenderObject* object) | 188 static bool isEmptyInline(RenderObject* object) |
188 { | 189 { |
189 if (!object->isRenderInline()) | 190 if (!object->isRenderInline()) |
190 return false; | 191 return false; |
191 | 192 |
192 for (RenderObject* curr = object->firstChild(); curr; curr = curr->nextSibli
ng()) { | 193 for (RenderObject* curr = toRenderInline(object)->firstChild(); curr; curr =
curr->nextSibling()) { |
193 if (curr->isFloatingOrOutOfFlowPositioned()) | 194 if (curr->isFloatingOrOutOfFlowPositioned()) |
194 continue; | 195 continue; |
195 if (curr->isText() && toRenderText(curr)->isAllCollapsibleWhitespace()) | 196 if (curr->isText() && toRenderText(curr)->isAllCollapsibleWhitespace()) |
196 continue; | 197 continue; |
197 | 198 |
198 if (!isEmptyInline(curr)) | 199 if (!isEmptyInline(curr)) |
199 return false; | 200 return false; |
200 } | 201 } |
201 return true; | 202 return true; |
202 } | 203 } |
203 | 204 |
204 // FIXME: This function is misleadingly named. It has little to do with bidi. | 205 // FIXME: This function is misleadingly named. It has little to do with bidi. |
205 // This function will iterate over inlines within a block, optionally notifying | 206 // This function will iterate over inlines within a block, optionally notifying |
206 // a bidi resolver as it enters/exits inlines (so it can push/pop embedding leve
ls). | 207 // a bidi resolver as it enters/exits inlines (so it can push/pop embedding leve
ls). |
207 template <class Observer> | 208 template <class Observer> |
208 static inline RenderObject* bidiNextShared(RenderObject* root, RenderObject* cur
rent, Observer* observer = 0, EmptyInlineBehavior emptyInlineBehavior = SkipEmpt
yInlines, bool* endOfInlinePtr = 0) | 209 static inline RenderObject* bidiNextShared(RenderObject* root, RenderObject* cur
rent, Observer* observer = 0, EmptyInlineBehavior emptyInlineBehavior = SkipEmpt
yInlines, bool* endOfInlinePtr = 0) |
209 { | 210 { |
210 RenderObject* next = 0; | 211 RenderObject* next = 0; |
211 // oldEndOfInline denotes if when we last stopped iterating if we were at th
e end of an inline. | 212 // oldEndOfInline denotes if when we last stopped iterating if we were at th
e end of an inline. |
212 bool oldEndOfInline = endOfInlinePtr ? *endOfInlinePtr : false; | 213 bool oldEndOfInline = endOfInlinePtr ? *endOfInlinePtr : false; |
213 bool endOfInline = false; | 214 bool endOfInline = false; |
214 | 215 |
215 while (current) { | 216 while (current) { |
216 next = 0; | 217 next = 0; |
217 if (!oldEndOfInline && !isIteratorTarget(current)) { | 218 if (!oldEndOfInline && !isIteratorTarget(current)) { |
218 next = current->firstChild(); | 219 next = current->slowFirstChild(); |
219 notifyObserverEnteredObject(observer, next); | 220 notifyObserverEnteredObject(observer, next); |
220 } | 221 } |
221 | 222 |
222 // We hit this when either current has no children, or when current is n
ot a renderer we care about. | 223 // We hit this when either current has no children, or when current is n
ot a renderer we care about. |
223 if (!next) { | 224 if (!next) { |
224 // If it is a renderer we care about, and we're doing our inline-wal
k, return it. | 225 // If it is a renderer we care about, and we're doing our inline-wal
k, return it. |
225 if (emptyInlineBehavior == IncludeEmptyInlines && !oldEndOfInline &&
current->isRenderInline()) { | 226 if (emptyInlineBehavior == IncludeEmptyInlines && !oldEndOfInline &&
current->isRenderInline()) { |
226 next = current; | 227 next = current; |
227 endOfInline = true; | 228 endOfInline = true; |
228 break; | 229 break; |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
275 InlineBidiResolver* observer = 0; | 276 InlineBidiResolver* observer = 0; |
276 return bidiNextSkippingEmptyInlines(root, current, observer); | 277 return bidiNextSkippingEmptyInlines(root, current, observer); |
277 } | 278 } |
278 | 279 |
279 static inline RenderObject* bidiNextIncludingEmptyInlines(RenderObject* root, Re
nderObject* current, bool* endOfInlinePtr = 0) | 280 static inline RenderObject* bidiNextIncludingEmptyInlines(RenderObject* root, Re
nderObject* current, bool* endOfInlinePtr = 0) |
280 { | 281 { |
281 InlineBidiResolver* observer = 0; // Callers who include empty inlines, neve
r use an observer. | 282 InlineBidiResolver* observer = 0; // Callers who include empty inlines, neve
r use an observer. |
282 return bidiNextShared(root, current, observer, IncludeEmptyInlines, endOfInl
inePtr); | 283 return bidiNextShared(root, current, observer, IncludeEmptyInlines, endOfInl
inePtr); |
283 } | 284 } |
284 | 285 |
285 static inline RenderObject* bidiFirstSkippingEmptyInlines(RenderObject* root, In
lineBidiResolver* resolver = 0) | 286 static inline RenderObject* bidiFirstSkippingEmptyInlines(RenderBlockFlow* root,
InlineBidiResolver* resolver = 0) |
286 { | 287 { |
287 RenderObject* o = root->firstChild(); | 288 RenderObject* o = root->firstChild(); |
288 if (!o) | 289 if (!o) |
289 return 0; | 290 return 0; |
290 | 291 |
291 if (o->isRenderInline()) { | 292 if (o->isRenderInline()) { |
292 notifyObserverEnteredObject(resolver, o); | 293 notifyObserverEnteredObject(resolver, o); |
293 if (!isEmptyInline(o)) | 294 if (!isEmptyInline(o)) |
294 o = bidiNextSkippingEmptyInlines(root, o, resolver); | 295 o = bidiNextSkippingEmptyInlines(root, o, resolver); |
295 else { | 296 else { |
296 // Never skip empty inlines. | 297 // Never skip empty inlines. |
297 if (resolver) | 298 if (resolver) |
298 resolver->commitExplicitEmbedding(); | 299 resolver->commitExplicitEmbedding(); |
299 return o; | 300 return o; |
300 } | 301 } |
301 } | 302 } |
302 | 303 |
303 // FIXME: Unify this with the bidiNext call above. | 304 // FIXME: Unify this with the bidiNext call above. |
304 if (o && !isIteratorTarget(o)) | 305 if (o && !isIteratorTarget(o)) |
305 o = bidiNextSkippingEmptyInlines(root, o, resolver); | 306 o = bidiNextSkippingEmptyInlines(root, o, resolver); |
306 | 307 |
307 if (resolver) | 308 if (resolver) |
308 resolver->commitExplicitEmbedding(); | 309 resolver->commitExplicitEmbedding(); |
309 return o; | 310 return o; |
310 } | 311 } |
311 | 312 |
312 // FIXME: This method needs to be renamed when bidiNext finds a good name. | 313 // FIXME: This method needs to be renamed when bidiNext finds a good name. |
313 static inline RenderObject* bidiFirstIncludingEmptyInlines(RenderObject* root) | 314 static inline RenderObject* bidiFirstIncludingEmptyInlines(RenderBlock* root) |
314 { | 315 { |
315 RenderObject* o = root->firstChild(); | 316 RenderObject* o = root->firstChild(); |
316 // If either there are no children to walk, or the first one is correct | 317 // If either there are no children to walk, or the first one is correct |
317 // then just return it. | 318 // then just return it. |
318 if (!o || o->isRenderInline() || isIteratorTarget(o)) | 319 if (!o || o->isRenderInline() || isIteratorTarget(o)) |
319 return o; | 320 return o; |
320 | 321 |
321 return bidiNextIncludingEmptyInlines(root, o); | 322 return bidiNextIncludingEmptyInlines(root, o); |
322 } | 323 } |
323 | 324 |
324 inline void InlineIterator::fastIncrementInTextNode() | 325 inline void InlineIterator::fastIncrementInTextNode() |
325 { | 326 { |
326 ASSERT(m_obj); | 327 ASSERT(m_obj); |
327 ASSERT(m_obj->isText()); | 328 ASSERT(m_obj->isText()); |
328 ASSERT(m_pos <= toRenderText(m_obj)->textLength()); | 329 ASSERT(m_pos <= toRenderText(m_obj)->textLength()); |
329 if (m_pos < INT_MAX) | 330 if (m_pos < INT_MAX) |
330 m_pos++; | 331 m_pos++; |
331 } | 332 } |
332 | 333 |
333 // FIXME: This is used by RenderBlockFlow for simplified layout, and has nothing
to do with bidi | 334 // FIXME: This is used by RenderBlockFlow for simplified layout, and has nothing
to do with bidi |
334 // it shouldn't use functions called bidiFirst and bidiNext. | 335 // it shouldn't use functions called bidiFirst and bidiNext. |
335 class InlineWalker { | 336 class InlineWalker { |
336 public: | 337 public: |
337 InlineWalker(RenderObject* root) | 338 InlineWalker(RenderBlock* root) |
338 : m_root(root) | 339 : m_root(root) |
339 , m_current(0) | 340 , m_current(0) |
340 , m_atEndOfInline(false) | 341 , m_atEndOfInline(false) |
341 { | 342 { |
342 // FIXME: This class should be taught how to do the SkipEmptyInlines cod
epath as well. | 343 // FIXME: This class should be taught how to do the SkipEmptyInlines cod
epath as well. |
343 m_current = bidiFirstIncludingEmptyInlines(m_root); | 344 m_current = bidiFirstIncludingEmptyInlines(m_root); |
344 } | 345 } |
345 | 346 |
346 RenderObject* root() { return m_root; } | 347 RenderBlock* root() { return m_root; } |
347 RenderObject* current() { return m_current; } | 348 RenderObject* current() { return m_current; } |
348 | 349 |
349 bool atEndOfInline() { return m_atEndOfInline; } | 350 bool atEndOfInline() { return m_atEndOfInline; } |
350 bool atEnd() const { return !m_current; } | 351 bool atEnd() const { return !m_current; } |
351 | 352 |
352 RenderObject* advance() | 353 RenderObject* advance() |
353 { | 354 { |
354 // FIXME: Support SkipEmptyInlines and observer parameters. | 355 // FIXME: Support SkipEmptyInlines and observer parameters. |
355 m_current = bidiNextIncludingEmptyInlines(m_root, m_current, &m_atEndOfI
nline); | 356 m_current = bidiNextIncludingEmptyInlines(m_root, m_current, &m_atEndOfI
nline); |
356 return m_current; | 357 return m_current; |
357 } | 358 } |
358 private: | 359 private: |
359 RenderObject* m_root; | 360 RenderBlock* m_root; |
360 RenderObject* m_current; | 361 RenderObject* m_current; |
361 bool m_atEndOfInline; | 362 bool m_atEndOfInline; |
362 }; | 363 }; |
363 | 364 |
364 static inline bool endOfLineHasIsolatedObjectAncestor(const InlineIterator& isol
atedIterator, const InlineIterator& ancestorItertor) | 365 static inline bool endOfLineHasIsolatedObjectAncestor(const InlineIterator& isol
atedIterator, const InlineIterator& ancestorItertor) |
365 { | 366 { |
366 if (!isolatedIterator.object() || !isIsolated(isolatedIterator.object()->sty
le()->unicodeBidi())) | 367 if (!isolatedIterator.object() || !isIsolated(isolatedIterator.object()->sty
le()->unicodeBidi())) |
367 return false; | 368 return false; |
368 | 369 |
369 RenderObject* innerIsolatedObject = isolatedIterator.object(); | 370 RenderObject* innerIsolatedObject = isolatedIterator.object(); |
(...skipping 348 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
718 m_sor = m_eor; | 719 m_sor = m_eor; |
719 } | 720 } |
720 | 721 |
721 m_direction = WTF::Unicode::OtherNeutral; | 722 m_direction = WTF::Unicode::OtherNeutral; |
722 m_status.eor = WTF::Unicode::OtherNeutral; | 723 m_status.eor = WTF::Unicode::OtherNeutral; |
723 } | 724 } |
724 | 725 |
725 } | 726 } |
726 | 727 |
727 #endif // InlineIterator_h | 728 #endif // InlineIterator_h |
OLD | NEW |