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 * |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
42 }; | 42 }; |
43 | 43 |
44 InlineIterator() | 44 InlineIterator() |
45 : m_root(0) | 45 : m_root(0) |
46 , m_obj(0) | 46 , m_obj(0) |
47 , m_nextBreakablePosition(-1) | 47 , m_nextBreakablePosition(-1) |
48 , m_pos(0) | 48 , m_pos(0) |
49 { | 49 { |
50 } | 50 } |
51 | 51 |
52 InlineIterator(RenderObject* root, RenderObject* o, unsigned p) | 52 InlineIterator(LayoutObject* root, LayoutObject* o, unsigned p) |
53 : m_root(root) | 53 : m_root(root) |
54 , m_obj(o) | 54 , m_obj(o) |
55 , m_nextBreakablePosition(-1) | 55 , m_nextBreakablePosition(-1) |
56 , m_pos(p) | 56 , m_pos(p) |
57 { | 57 { |
58 } | 58 } |
59 | 59 |
60 void clear() { moveTo(0, 0); } | 60 void clear() { moveTo(0, 0); } |
61 | 61 |
62 void moveToStartOf(RenderObject* object) | 62 void moveToStartOf(LayoutObject* object) |
63 { | 63 { |
64 moveTo(object, 0); | 64 moveTo(object, 0); |
65 } | 65 } |
66 | 66 |
67 void moveTo(RenderObject* object, unsigned offset, int nextBreak = -1) | 67 void moveTo(LayoutObject* object, unsigned offset, int nextBreak = -1) |
68 { | 68 { |
69 m_obj = object; | 69 m_obj = object; |
70 m_pos = offset; | 70 m_pos = offset; |
71 m_nextBreakablePosition = nextBreak; | 71 m_nextBreakablePosition = nextBreak; |
72 } | 72 } |
73 | 73 |
74 RenderObject* object() const { return m_obj; } | 74 LayoutObject* object() const { return m_obj; } |
75 void setObject(RenderObject* object) { m_obj = object; } | 75 void setObject(LayoutObject* object) { m_obj = object; } |
76 | 76 |
77 int nextBreakablePosition() const { return m_nextBreakablePosition; } | 77 int nextBreakablePosition() const { return m_nextBreakablePosition; } |
78 void setNextBreakablePosition(int position) { m_nextBreakablePosition = posi
tion; } | 78 void setNextBreakablePosition(int position) { m_nextBreakablePosition = posi
tion; } |
79 | 79 |
80 unsigned offset() const { return m_pos; } | 80 unsigned offset() const { return m_pos; } |
81 void setOffset(unsigned position) { m_pos = position; } | 81 void setOffset(unsigned position) { m_pos = position; } |
82 RenderObject* root() const { return m_root; } | 82 LayoutObject* root() const { return m_root; } |
83 | 83 |
84 void fastIncrementInTextNode(); | 84 void fastIncrementInTextNode(); |
85 void increment(InlineBidiResolver* = 0, IncrementRule = FastIncrementInTextN
ode); | 85 void increment(InlineBidiResolver* = 0, IncrementRule = FastIncrementInTextN
ode); |
86 bool atEnd() const; | 86 bool atEnd() const; |
87 | 87 |
88 inline bool atTextParagraphSeparator() const | 88 inline bool atTextParagraphSeparator() const |
89 { | 89 { |
90 return m_obj && m_obj->preservesNewline() && m_obj->isText() && toRender
Text(m_obj)->textLength() | 90 return m_obj && m_obj->preservesNewline() && m_obj->isText() && toRender
Text(m_obj)->textLength() |
91 && !toRenderText(m_obj)->isWordBreak() && toRenderText(m_obj)->chara
cterAt(m_pos) == '\n'; | 91 && !toRenderText(m_obj)->isWordBreak() && toRenderText(m_obj)->chara
cterAt(m_pos) == '\n'; |
92 } | 92 } |
93 | 93 |
94 inline bool atParagraphSeparator() const | 94 inline bool atParagraphSeparator() const |
95 { | 95 { |
96 return (m_obj && m_obj->isBR()) || atTextParagraphSeparator(); | 96 return (m_obj && m_obj->isBR()) || atTextParagraphSeparator(); |
97 } | 97 } |
98 | 98 |
99 UChar characterAt(unsigned) const; | 99 UChar characterAt(unsigned) const; |
100 UChar current() const; | 100 UChar current() const; |
101 UChar previousInSameNode() const; | 101 UChar previousInSameNode() const; |
102 ALWAYS_INLINE WTF::Unicode::Direction direction() const; | 102 ALWAYS_INLINE WTF::Unicode::Direction direction() const; |
103 | 103 |
104 private: | 104 private: |
105 RenderObject* m_root; | 105 LayoutObject* m_root; |
106 RenderObject* m_obj; | 106 LayoutObject* m_obj; |
107 | 107 |
108 int m_nextBreakablePosition; | 108 int m_nextBreakablePosition; |
109 unsigned m_pos; | 109 unsigned m_pos; |
110 }; | 110 }; |
111 | 111 |
112 inline bool operator==(const InlineIterator& it1, const InlineIterator& it2) | 112 inline bool operator==(const InlineIterator& it1, const InlineIterator& it2) |
113 { | 113 { |
114 return it1.offset() == it2.offset() && it1.object() == it2.object(); | 114 return it1.offset() == it2.offset() && it1.object() == it2.object(); |
115 } | 115 } |
116 | 116 |
117 inline bool operator!=(const InlineIterator& it1, const InlineIterator& it2) | 117 inline bool operator!=(const InlineIterator& it1, const InlineIterator& it2) |
118 { | 118 { |
119 return it1.offset() != it2.offset() || it1.object() != it2.object(); | 119 return it1.offset() != it2.offset() || it1.object() != it2.object(); |
120 } | 120 } |
121 | 121 |
122 static inline WTF::Unicode::Direction embedCharFromDirection(TextDirection dir,
EUnicodeBidi unicodeBidi) | 122 static inline WTF::Unicode::Direction embedCharFromDirection(TextDirection dir,
EUnicodeBidi unicodeBidi) |
123 { | 123 { |
124 using namespace WTF::Unicode; | 124 using namespace WTF::Unicode; |
125 if (unicodeBidi == Embed) | 125 if (unicodeBidi == Embed) |
126 return dir == RTL ? RightToLeftEmbedding : LeftToRightEmbedding; | 126 return dir == RTL ? RightToLeftEmbedding : LeftToRightEmbedding; |
127 return dir == RTL ? RightToLeftOverride : LeftToRightOverride; | 127 return dir == RTL ? RightToLeftOverride : LeftToRightOverride; |
128 } | 128 } |
129 | 129 |
130 template <class Observer> | 130 template <class Observer> |
131 static inline void notifyObserverEnteredObject(Observer* observer, RenderObject*
object) | 131 static inline void notifyObserverEnteredObject(Observer* observer, LayoutObject*
object) |
132 { | 132 { |
133 if (!observer || !object || !object->isRenderInline()) | 133 if (!observer || !object || !object->isRenderInline()) |
134 return; | 134 return; |
135 | 135 |
136 RenderStyle* style = object->style(); | 136 RenderStyle* style = object->style(); |
137 EUnicodeBidi unicodeBidi = style->unicodeBidi(); | 137 EUnicodeBidi unicodeBidi = style->unicodeBidi(); |
138 if (unicodeBidi == UBNormal) { | 138 if (unicodeBidi == UBNormal) { |
139 // http://dev.w3.org/csswg/css3-writing-modes/#unicode-bidi | 139 // http://dev.w3.org/csswg/css3-writing-modes/#unicode-bidi |
140 // "The element does not open an additional level of embedding with resp
ect to the bidirectional algorithm." | 140 // "The element does not open an additional level of embedding with resp
ect to the bidirectional algorithm." |
141 // Thus we ignore any possible dir= attribute on the span. | 141 // Thus we ignore any possible dir= attribute on the span. |
142 return; | 142 return; |
143 } | 143 } |
144 if (isIsolated(unicodeBidi)) { | 144 if (isIsolated(unicodeBidi)) { |
145 // Make sure that explicit embeddings are committed before we enter the
isolated content. | 145 // Make sure that explicit embeddings are committed before we enter the
isolated content. |
146 observer->commitExplicitEmbedding(observer->runs()); | 146 observer->commitExplicitEmbedding(observer->runs()); |
147 observer->enterIsolate(); | 147 observer->enterIsolate(); |
148 // Embedding/Override characters implied by dir= will be handled when | 148 // Embedding/Override characters implied by dir= will be handled when |
149 // we process the isolated span, not when laying out the "parent" run. | 149 // we process the isolated span, not when laying out the "parent" run. |
150 return; | 150 return; |
151 } | 151 } |
152 | 152 |
153 if (!observer->inIsolate()) | 153 if (!observer->inIsolate()) |
154 observer->embed(embedCharFromDirection(style->direction(), unicodeBidi),
FromStyleOrDOM); | 154 observer->embed(embedCharFromDirection(style->direction(), unicodeBidi),
FromStyleOrDOM); |
155 } | 155 } |
156 | 156 |
157 template <class Observer> | 157 template <class Observer> |
158 static inline void notifyObserverWillExitObject(Observer* observer, RenderObject
* object) | 158 static inline void notifyObserverWillExitObject(Observer* observer, LayoutObject
* object) |
159 { | 159 { |
160 if (!observer || !object || !object->isRenderInline()) | 160 if (!observer || !object || !object->isRenderInline()) |
161 return; | 161 return; |
162 | 162 |
163 EUnicodeBidi unicodeBidi = object->style()->unicodeBidi(); | 163 EUnicodeBidi unicodeBidi = object->style()->unicodeBidi(); |
164 if (unicodeBidi == UBNormal) | 164 if (unicodeBidi == UBNormal) |
165 return; // Nothing to do for unicode-bidi: normal | 165 return; // Nothing to do for unicode-bidi: normal |
166 if (isIsolated(unicodeBidi)) { | 166 if (isIsolated(unicodeBidi)) { |
167 observer->exitIsolate(); | 167 observer->exitIsolate(); |
168 return; | 168 return; |
169 } | 169 } |
170 | 170 |
171 // Otherwise we pop any embed/override character we added when we opened thi
s tag. | 171 // Otherwise we pop any embed/override character we added when we opened thi
s tag. |
172 if (!observer->inIsolate()) | 172 if (!observer->inIsolate()) |
173 observer->embed(WTF::Unicode::PopDirectionalFormat, FromStyleOrDOM); | 173 observer->embed(WTF::Unicode::PopDirectionalFormat, FromStyleOrDOM); |
174 } | 174 } |
175 | 175 |
176 static inline bool isIteratorTarget(RenderObject* object) | 176 static inline bool isIteratorTarget(LayoutObject* object) |
177 { | 177 { |
178 ASSERT(object); // The iterator will of course return 0, but its not an expe
cted argument to this function. | 178 ASSERT(object); // The iterator will of course return 0, but its not an expe
cted argument to this function. |
179 return object->isText() || object->isFloating() || object->isOutOfFlowPositi
oned() || object->isReplaced(); | 179 return object->isText() || object->isFloating() || object->isOutOfFlowPositi
oned() || object->isReplaced(); |
180 } | 180 } |
181 | 181 |
182 // This enum is only used for bidiNextShared() | 182 // This enum is only used for bidiNextShared() |
183 enum EmptyInlineBehavior { | 183 enum EmptyInlineBehavior { |
184 SkipEmptyInlines, | 184 SkipEmptyInlines, |
185 IncludeEmptyInlines, | 185 IncludeEmptyInlines, |
186 }; | 186 }; |
187 | 187 |
188 static bool isEmptyInline(RenderObject* object) | 188 static bool isEmptyInline(LayoutObject* object) |
189 { | 189 { |
190 if (!object->isRenderInline()) | 190 if (!object->isRenderInline()) |
191 return false; | 191 return false; |
192 | 192 |
193 for (RenderObject* curr = toRenderInline(object)->firstChild(); curr; curr =
curr->nextSibling()) { | 193 for (LayoutObject* curr = toRenderInline(object)->firstChild(); curr; curr =
curr->nextSibling()) { |
194 if (curr->isFloatingOrOutOfFlowPositioned()) | 194 if (curr->isFloatingOrOutOfFlowPositioned()) |
195 continue; | 195 continue; |
196 if (curr->isText() && toRenderText(curr)->isAllCollapsibleWhitespace()) | 196 if (curr->isText() && toRenderText(curr)->isAllCollapsibleWhitespace()) |
197 continue; | 197 continue; |
198 | 198 |
199 if (!isEmptyInline(curr)) | 199 if (!isEmptyInline(curr)) |
200 return false; | 200 return false; |
201 } | 201 } |
202 return true; | 202 return true; |
203 } | 203 } |
204 | 204 |
205 // 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. |
206 // This function will iterate over inlines within a block, optionally notifying | 206 // This function will iterate over inlines within a block, optionally notifying |
207 // 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). |
208 template <class Observer> | 208 template <class Observer> |
209 static inline RenderObject* bidiNextShared(RenderObject* root, RenderObject* cur
rent, Observer* observer = 0, EmptyInlineBehavior emptyInlineBehavior = SkipEmpt
yInlines, bool* endOfInlinePtr = 0) | 209 static inline LayoutObject* bidiNextShared(LayoutObject* root, LayoutObject* cur
rent, Observer* observer = 0, EmptyInlineBehavior emptyInlineBehavior = SkipEmpt
yInlines, bool* endOfInlinePtr = 0) |
210 { | 210 { |
211 RenderObject* next = 0; | 211 LayoutObject* next = 0; |
212 // 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. |
213 bool oldEndOfInline = endOfInlinePtr ? *endOfInlinePtr : false; | 213 bool oldEndOfInline = endOfInlinePtr ? *endOfInlinePtr : false; |
214 bool endOfInline = false; | 214 bool endOfInline = false; |
215 | 215 |
216 while (current) { | 216 while (current) { |
217 next = 0; | 217 next = 0; |
218 if (!oldEndOfInline && !isIteratorTarget(current)) { | 218 if (!oldEndOfInline && !isIteratorTarget(current)) { |
219 next = current->slowFirstChild(); | 219 next = current->slowFirstChild(); |
220 notifyObserverEnteredObject(observer, next); | 220 notifyObserverEnteredObject(observer, next); |
221 } | 221 } |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
257 current = next; | 257 current = next; |
258 } | 258 } |
259 | 259 |
260 if (endOfInlinePtr) | 260 if (endOfInlinePtr) |
261 *endOfInlinePtr = endOfInline; | 261 *endOfInlinePtr = endOfInline; |
262 | 262 |
263 return next; | 263 return next; |
264 } | 264 } |
265 | 265 |
266 template <class Observer> | 266 template <class Observer> |
267 static inline RenderObject* bidiNextSkippingEmptyInlines(RenderObject* root, Ren
derObject* current, Observer* observer) | 267 static inline LayoutObject* bidiNextSkippingEmptyInlines(LayoutObject* root, Lay
outObject* current, Observer* observer) |
268 { | 268 { |
269 // The SkipEmptyInlines callers never care about endOfInlinePtr. | 269 // The SkipEmptyInlines callers never care about endOfInlinePtr. |
270 return bidiNextShared(root, current, observer, SkipEmptyInlines); | 270 return bidiNextShared(root, current, observer, SkipEmptyInlines); |
271 } | 271 } |
272 | 272 |
273 // This makes callers cleaner as they don't have to specify a type for the obser
ver when not providing one. | 273 // This makes callers cleaner as they don't have to specify a type for the obser
ver when not providing one. |
274 static inline RenderObject* bidiNextSkippingEmptyInlines(RenderObject* root, Ren
derObject* current) | 274 static inline LayoutObject* bidiNextSkippingEmptyInlines(LayoutObject* root, Lay
outObject* current) |
275 { | 275 { |
276 InlineBidiResolver* observer = 0; | 276 InlineBidiResolver* observer = 0; |
277 return bidiNextSkippingEmptyInlines(root, current, observer); | 277 return bidiNextSkippingEmptyInlines(root, current, observer); |
278 } | 278 } |
279 | 279 |
280 static inline RenderObject* bidiNextIncludingEmptyInlines(RenderObject* root, Re
nderObject* current, bool* endOfInlinePtr = 0) | 280 static inline LayoutObject* bidiNextIncludingEmptyInlines(LayoutObject* root, La
youtObject* current, bool* endOfInlinePtr = 0) |
281 { | 281 { |
282 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. |
283 return bidiNextShared(root, current, observer, IncludeEmptyInlines, endOfInl
inePtr); | 283 return bidiNextShared(root, current, observer, IncludeEmptyInlines, endOfInl
inePtr); |
284 } | 284 } |
285 | 285 |
286 static inline RenderObject* bidiFirstSkippingEmptyInlines(RenderBlockFlow* root,
BidiRunList<BidiRun>& runs, InlineBidiResolver* resolver = 0) | 286 static inline LayoutObject* bidiFirstSkippingEmptyInlines(RenderBlockFlow* root,
BidiRunList<BidiRun>& runs, InlineBidiResolver* resolver = 0) |
287 { | 287 { |
288 RenderObject* o = root->firstChild(); | 288 LayoutObject* o = root->firstChild(); |
289 if (!o) | 289 if (!o) |
290 return 0; | 290 return 0; |
291 | 291 |
292 if (o->isRenderInline()) { | 292 if (o->isRenderInline()) { |
293 notifyObserverEnteredObject(resolver, o); | 293 notifyObserverEnteredObject(resolver, o); |
294 if (!isEmptyInline(o)) { | 294 if (!isEmptyInline(o)) { |
295 o = bidiNextSkippingEmptyInlines(root, o, resolver); | 295 o = bidiNextSkippingEmptyInlines(root, o, resolver); |
296 } else { | 296 } else { |
297 // Never skip empty inlines. | 297 // Never skip empty inlines. |
298 if (resolver) | 298 if (resolver) |
299 resolver->commitExplicitEmbedding(runs); | 299 resolver->commitExplicitEmbedding(runs); |
300 return o; | 300 return o; |
301 } | 301 } |
302 } | 302 } |
303 | 303 |
304 // FIXME: Unify this with the bidiNext call above. | 304 // FIXME: Unify this with the bidiNext call above. |
305 if (o && !isIteratorTarget(o)) | 305 if (o && !isIteratorTarget(o)) |
306 o = bidiNextSkippingEmptyInlines(root, o, resolver); | 306 o = bidiNextSkippingEmptyInlines(root, o, resolver); |
307 | 307 |
308 if (resolver) | 308 if (resolver) |
309 resolver->commitExplicitEmbedding(runs); | 309 resolver->commitExplicitEmbedding(runs); |
310 return o; | 310 return o; |
311 } | 311 } |
312 | 312 |
313 // 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. |
314 static inline RenderObject* bidiFirstIncludingEmptyInlines(RenderBlock* root) | 314 static inline LayoutObject* bidiFirstIncludingEmptyInlines(RenderBlock* root) |
315 { | 315 { |
316 RenderObject* o = root->firstChild(); | 316 LayoutObject* o = root->firstChild(); |
317 // 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 |
318 // then just return it. | 318 // then just return it. |
319 if (!o || o->isRenderInline() || isIteratorTarget(o)) | 319 if (!o || o->isRenderInline() || isIteratorTarget(o)) |
320 return o; | 320 return o; |
321 | 321 |
322 return bidiNextIncludingEmptyInlines(root, o); | 322 return bidiNextIncludingEmptyInlines(root, o); |
323 } | 323 } |
324 | 324 |
325 inline void InlineIterator::fastIncrementInTextNode() | 325 inline void InlineIterator::fastIncrementInTextNode() |
326 { | 326 { |
(...skipping 11 matching lines...) Expand all Loading... |
338 InlineWalker(RenderBlock* root) | 338 InlineWalker(RenderBlock* root) |
339 : m_root(root) | 339 : m_root(root) |
340 , m_current(0) | 340 , m_current(0) |
341 , m_atEndOfInline(false) | 341 , m_atEndOfInline(false) |
342 { | 342 { |
343 // 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. |
344 m_current = bidiFirstIncludingEmptyInlines(m_root); | 344 m_current = bidiFirstIncludingEmptyInlines(m_root); |
345 } | 345 } |
346 | 346 |
347 RenderBlock* root() { return m_root; } | 347 RenderBlock* root() { return m_root; } |
348 RenderObject* current() { return m_current; } | 348 LayoutObject* current() { return m_current; } |
349 | 349 |
350 bool atEndOfInline() { return m_atEndOfInline; } | 350 bool atEndOfInline() { return m_atEndOfInline; } |
351 bool atEnd() const { return !m_current; } | 351 bool atEnd() const { return !m_current; } |
352 | 352 |
353 RenderObject* advance() | 353 LayoutObject* advance() |
354 { | 354 { |
355 // FIXME: Support SkipEmptyInlines and observer parameters. | 355 // FIXME: Support SkipEmptyInlines and observer parameters. |
356 m_current = bidiNextIncludingEmptyInlines(m_root, m_current, &m_atEndOfI
nline); | 356 m_current = bidiNextIncludingEmptyInlines(m_root, m_current, &m_atEndOfI
nline); |
357 return m_current; | 357 return m_current; |
358 } | 358 } |
359 private: | 359 private: |
360 RenderBlock* m_root; | 360 RenderBlock* m_root; |
361 RenderObject* m_current; | 361 LayoutObject* m_current; |
362 bool m_atEndOfInline; | 362 bool m_atEndOfInline; |
363 }; | 363 }; |
364 | 364 |
365 static inline bool endOfLineHasIsolatedObjectAncestor(const InlineIterator& isol
atedIterator, const InlineIterator& ancestorItertor) | 365 static inline bool endOfLineHasIsolatedObjectAncestor(const InlineIterator& isol
atedIterator, const InlineIterator& ancestorItertor) |
366 { | 366 { |
367 if (!isolatedIterator.object() || !isIsolated(isolatedIterator.object()->sty
le()->unicodeBidi())) | 367 if (!isolatedIterator.object() || !isIsolated(isolatedIterator.object()->sty
le()->unicodeBidi())) |
368 return false; | 368 return false; |
369 | 369 |
370 RenderObject* innerIsolatedObject = isolatedIterator.object(); | 370 LayoutObject* innerIsolatedObject = isolatedIterator.object(); |
371 while (innerIsolatedObject && innerIsolatedObject != isolatedIterator.root()
) { | 371 while (innerIsolatedObject && innerIsolatedObject != isolatedIterator.root()
) { |
372 if (innerIsolatedObject == ancestorItertor.object()) | 372 if (innerIsolatedObject == ancestorItertor.object()) |
373 return true; | 373 return true; |
374 innerIsolatedObject = innerIsolatedObject->parent(); | 374 innerIsolatedObject = innerIsolatedObject->parent(); |
375 } | 375 } |
376 return false; | 376 return false; |
377 } | 377 } |
378 | 378 |
379 inline void InlineIterator::increment(InlineBidiResolver* resolver, IncrementRul
e rule) | 379 inline void InlineIterator::increment(InlineBidiResolver* resolver, IncrementRul
e rule) |
380 { | 380 { |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
472 firstSpace--; | 472 firstSpace--; |
473 } | 473 } |
474 | 474 |
475 return firstSpace; | 475 return firstSpace; |
476 } | 476 } |
477 | 477 |
478 template <> | 478 template <> |
479 inline int InlineBidiResolver::findFirstTrailingSpaceAtRun(BidiRun* run) | 479 inline int InlineBidiResolver::findFirstTrailingSpaceAtRun(BidiRun* run) |
480 { | 480 { |
481 ASSERT(run); | 481 ASSERT(run); |
482 RenderObject* lastObject = run->m_object; | 482 LayoutObject* lastObject = run->m_object; |
483 if (!lastObject->isText()) | 483 if (!lastObject->isText()) |
484 return run->m_stop; | 484 return run->m_stop; |
485 | 485 |
486 RenderText* lastText = toRenderText(lastObject); | 486 RenderText* lastText = toRenderText(lastObject); |
487 int firstSpace; | 487 int firstSpace; |
488 if (lastText->is8Bit()) | 488 if (lastText->is8Bit()) |
489 firstSpace = findFirstTrailingSpace(lastText, lastText->characters8(), r
un->start(), run->stop()); | 489 firstSpace = findFirstTrailingSpace(lastText, lastText->characters8(), r
un->start(), run->stop()); |
490 else | 490 else |
491 firstSpace = findFirstTrailingSpace(lastText, lastText->characters16(),
run->start(), run->stop()); | 491 firstSpace = findFirstTrailingSpace(lastText, lastText->characters16(),
run->start(), run->stop()); |
492 return firstSpace; | 492 return firstSpace; |
(...skipping 13 matching lines...) Expand all Loading... |
506 | 506 |
507 template <> | 507 template <> |
508 inline bool InlineBidiResolver::needsToApplyL1Rule(BidiRunList<BidiRun>& runs) | 508 inline bool InlineBidiResolver::needsToApplyL1Rule(BidiRunList<BidiRun>& runs) |
509 { | 509 { |
510 if (!runs.logicallyLastRun()->m_object->style()->breakOnlyAfterWhiteSpace() | 510 if (!runs.logicallyLastRun()->m_object->style()->breakOnlyAfterWhiteSpace() |
511 || !runs.logicallyLastRun()->m_object->style()->autoWrap()) | 511 || !runs.logicallyLastRun()->m_object->style()->autoWrap()) |
512 return false; | 512 return false; |
513 return true; | 513 return true; |
514 } | 514 } |
515 | 515 |
516 static inline bool isIsolatedInline(RenderObject* object) | 516 static inline bool isIsolatedInline(LayoutObject* object) |
517 { | 517 { |
518 ASSERT(object); | 518 ASSERT(object); |
519 return object->isRenderInline() && isIsolated(object->style()->unicodeBidi()
); | 519 return object->isRenderInline() && isIsolated(object->style()->unicodeBidi()
); |
520 } | 520 } |
521 | 521 |
522 static inline RenderObject* highestContainingIsolateWithinRoot(RenderObject* obj
ect, RenderObject* root) | 522 static inline LayoutObject* highestContainingIsolateWithinRoot(LayoutObject* obj
ect, LayoutObject* root) |
523 { | 523 { |
524 ASSERT(object); | 524 ASSERT(object); |
525 RenderObject* containingIsolateObj = 0; | 525 LayoutObject* containingIsolateObj = 0; |
526 while (object && object != root) { | 526 while (object && object != root) { |
527 if (isIsolatedInline(object)) | 527 if (isIsolatedInline(object)) |
528 containingIsolateObj = object; | 528 containingIsolateObj = object; |
529 | 529 |
530 object = object->parent(); | 530 object = object->parent(); |
531 } | 531 } |
532 return containingIsolateObj; | 532 return containingIsolateObj; |
533 } | 533 } |
534 | 534 |
535 static inline unsigned numberOfIsolateAncestors(const InlineIterator& iter) | 535 static inline unsigned numberOfIsolateAncestors(const InlineIterator& iter) |
536 { | 536 { |
537 RenderObject* object = iter.object(); | 537 LayoutObject* object = iter.object(); |
538 if (!object) | 538 if (!object) |
539 return 0; | 539 return 0; |
540 unsigned count = 0; | 540 unsigned count = 0; |
541 while (object && object != iter.root()) { | 541 while (object && object != iter.root()) { |
542 if (isIsolatedInline(object)) | 542 if (isIsolatedInline(object)) |
543 count++; | 543 count++; |
544 object = object->parent(); | 544 object = object->parent(); |
545 } | 545 } |
546 return count; | 546 return count; |
547 } | 547 } |
548 | 548 |
549 // FIXME: This belongs on InlineBidiResolver, except it's a template specializat
ion | 549 // FIXME: This belongs on InlineBidiResolver, except it's a template specializat
ion |
550 // of BidiResolver which knows nothing about RenderObjects. | 550 // of BidiResolver which knows nothing about LayoutObjects. |
551 static inline BidiRun* addPlaceholderRunForIsolatedInline(InlineBidiResolver& re
solver, RenderObject* obj, unsigned pos) | 551 static inline BidiRun* addPlaceholderRunForIsolatedInline(InlineBidiResolver& re
solver, LayoutObject* obj, unsigned pos) |
552 { | 552 { |
553 ASSERT(obj); | 553 ASSERT(obj); |
554 BidiRun* isolatedRun = new BidiRun(pos, pos, obj, resolver.context(), resolv
er.dir()); | 554 BidiRun* isolatedRun = new BidiRun(pos, pos, obj, resolver.context(), resolv
er.dir()); |
555 resolver.runs().addRun(isolatedRun); | 555 resolver.runs().addRun(isolatedRun); |
556 // FIXME: isolatedRuns() could be a hash of object->run and then we could ch
eaply | 556 // FIXME: isolatedRuns() could be a hash of object->run and then we could ch
eaply |
557 // ASSERT here that we didn't create multiple objects for the same inline. | 557 // ASSERT here that we didn't create multiple objects for the same inline. |
558 resolver.isolatedRuns().append(isolatedRun); | 558 resolver.isolatedRuns().append(isolatedRun); |
559 return isolatedRun; | 559 return isolatedRun; |
560 } | 560 } |
561 | 561 |
562 static inline BidiRun* createRun(int start, int end, RenderObject* obj, InlineBi
diResolver& resolver) | 562 static inline BidiRun* createRun(int start, int end, LayoutObject* obj, InlineBi
diResolver& resolver) |
563 { | 563 { |
564 return new BidiRun(start, end, obj, resolver.context(), resolver.dir()); | 564 return new BidiRun(start, end, obj, resolver.context(), resolver.dir()); |
565 } | 565 } |
566 | 566 |
567 enum AppendRunBehavior { | 567 enum AppendRunBehavior { |
568 AppendingFakeRun, | 568 AppendingFakeRun, |
569 AppendingRunsForObject | 569 AppendingRunsForObject |
570 }; | 570 }; |
571 | 571 |
572 class IsolateTracker { | 572 class IsolateTracker { |
(...skipping 18 matching lines...) Expand all Loading... |
591 if (!inIsolate()) | 591 if (!inIsolate()) |
592 m_haveAddedFakeRunForRootIsolate = false; | 592 m_haveAddedFakeRunForRootIsolate = false; |
593 } | 593 } |
594 bool inIsolate() const { return m_nestedIsolateCount; } | 594 bool inIsolate() const { return m_nestedIsolateCount; } |
595 | 595 |
596 // We don't care if we encounter bidi directional overrides. | 596 // We don't care if we encounter bidi directional overrides. |
597 void embed(WTF::Unicode::Direction, BidiEmbeddingSource) { } | 597 void embed(WTF::Unicode::Direction, BidiEmbeddingSource) { } |
598 void commitExplicitEmbedding(BidiRunList<BidiRun>&) { } | 598 void commitExplicitEmbedding(BidiRunList<BidiRun>&) { } |
599 BidiRunList<BidiRun>& runs() { return m_runs; } | 599 BidiRunList<BidiRun>& runs() { return m_runs; } |
600 | 600 |
601 void addFakeRunIfNecessary(RenderObject* obj, unsigned pos, unsigned end, In
lineBidiResolver& resolver) | 601 void addFakeRunIfNecessary(LayoutObject* obj, unsigned pos, unsigned end, In
lineBidiResolver& resolver) |
602 { | 602 { |
603 // We only need to add a fake run for a given isolated span once during
each call to createBidiRunsForLine. | 603 // We only need to add a fake run for a given isolated span once during
each call to createBidiRunsForLine. |
604 // We'll be called for every span inside the isolated span so we just ig
nore subsequent calls. | 604 // We'll be called for every span inside the isolated span so we just ig
nore subsequent calls. |
605 // We also avoid creating a fake run until we hit a child that warrants
one, e.g. we skip floats. | 605 // We also avoid creating a fake run until we hit a child that warrants
one, e.g. we skip floats. |
606 if (RenderBlockFlow::shouldSkipCreatingRunsForObject(obj)) | 606 if (RenderBlockFlow::shouldSkipCreatingRunsForObject(obj)) |
607 return; | 607 return; |
608 if (!m_haveAddedFakeRunForRootIsolate) { | 608 if (!m_haveAddedFakeRunForRootIsolate) { |
609 BidiRun* run = addPlaceholderRunForIsolatedInline(resolver, obj, pos
); | 609 BidiRun* run = addPlaceholderRunForIsolatedInline(resolver, obj, pos
); |
610 resolver.setMidpointStateForIsolatedRun(run, m_midpointStateForRootI
solate); | 610 resolver.setMidpointStateForIsolatedRun(run, m_midpointStateForRootI
solate); |
611 m_haveAddedFakeRunForRootIsolate = true; | 611 m_haveAddedFakeRunForRootIsolate = true; |
612 } | 612 } |
613 // obj and pos together denote a single position in the inline, from whi
ch the parsing of the isolate will start. | 613 // obj and pos together denote a single position in the inline, from whi
ch the parsing of the isolate will start. |
614 // We don't need to mark the end of the run because this is implicit: it
is either endOfLine or the end of the | 614 // We don't need to mark the end of the run because this is implicit: it
is either endOfLine or the end of the |
615 // isolate, when we call createBidiRunsForLine it will stop at whichever
comes first. | 615 // isolate, when we call createBidiRunsForLine it will stop at whichever
comes first. |
616 } | 616 } |
617 | 617 |
618 private: | 618 private: |
619 unsigned m_nestedIsolateCount; | 619 unsigned m_nestedIsolateCount; |
620 bool m_haveAddedFakeRunForRootIsolate; | 620 bool m_haveAddedFakeRunForRootIsolate; |
621 LineMidpointState m_midpointStateForRootIsolate; | 621 LineMidpointState m_midpointStateForRootIsolate; |
622 BidiRunList<BidiRun>& m_runs; | 622 BidiRunList<BidiRun>& m_runs; |
623 }; | 623 }; |
624 | 624 |
625 static void inline appendRunObjectIfNecessary(RenderObject* obj, unsigned start,
unsigned end, InlineBidiResolver& resolver, AppendRunBehavior behavior, Isolate
Tracker& tracker) | 625 static void inline appendRunObjectIfNecessary(LayoutObject* obj, unsigned start,
unsigned end, InlineBidiResolver& resolver, AppendRunBehavior behavior, Isolate
Tracker& tracker) |
626 { | 626 { |
627 // Trailing space code creates empty BidiRun objects, start == end, so | 627 // Trailing space code creates empty BidiRun objects, start == end, so |
628 // that case needs to be handled specifically. | 628 // that case needs to be handled specifically. |
629 bool addEmptyRun = (end == start); | 629 bool addEmptyRun = (end == start); |
630 | 630 |
631 // Append BidiRun objects, at most 64K chars at a time, until all | 631 // Append BidiRun objects, at most 64K chars at a time, until all |
632 // text between |start| and |end| is represented. | 632 // text between |start| and |end| is represented. |
633 while (end > start || addEmptyRun) { | 633 while (end > start || addEmptyRun) { |
634 addEmptyRun = false; | 634 addEmptyRun = false; |
635 const int limit = USHRT_MAX; // InlineTextBox stores text length as unsi
gned short. | 635 const int limit = USHRT_MAX; // InlineTextBox stores text length as unsi
gned short. |
636 unsigned limitedEnd = end; | 636 unsigned limitedEnd = end; |
637 if (end - start > limit) | 637 if (end - start > limit) |
638 limitedEnd = start + limit; | 638 limitedEnd = start + limit; |
639 if (behavior == AppendingFakeRun) | 639 if (behavior == AppendingFakeRun) |
640 tracker.addFakeRunIfNecessary(obj, start, limitedEnd, resolver); | 640 tracker.addFakeRunIfNecessary(obj, start, limitedEnd, resolver); |
641 else | 641 else |
642 resolver.runs().addRun(createRun(start, limitedEnd, obj, resolver)); | 642 resolver.runs().addRun(createRun(start, limitedEnd, obj, resolver)); |
643 start = limitedEnd; | 643 start = limitedEnd; |
644 } | 644 } |
645 } | 645 } |
646 | 646 |
647 static void adjustMidpointsAndAppendRunsForObjectIfNeeded(RenderObject* obj, uns
igned start, unsigned end, InlineBidiResolver& resolver, AppendRunBehavior behav
ior, IsolateTracker& tracker) | 647 static void adjustMidpointsAndAppendRunsForObjectIfNeeded(LayoutObject* obj, uns
igned start, unsigned end, InlineBidiResolver& resolver, AppendRunBehavior behav
ior, IsolateTracker& tracker) |
648 { | 648 { |
649 if (start > end || RenderBlockFlow::shouldSkipCreatingRunsForObject(obj)) | 649 if (start > end || RenderBlockFlow::shouldSkipCreatingRunsForObject(obj)) |
650 return; | 650 return; |
651 | 651 |
652 LineMidpointState& lineMidpointState = resolver.midpointState(); | 652 LineMidpointState& lineMidpointState = resolver.midpointState(); |
653 bool haveNextMidpoint = (lineMidpointState.currentMidpoint() < lineMidpointS
tate.numMidpoints()); | 653 bool haveNextMidpoint = (lineMidpointState.currentMidpoint() < lineMidpointS
tate.numMidpoints()); |
654 InlineIterator nextMidpoint; | 654 InlineIterator nextMidpoint; |
655 if (haveNextMidpoint) | 655 if (haveNextMidpoint) |
656 nextMidpoint = lineMidpointState.midpoints()[lineMidpointState.currentMi
dpoint()]; | 656 nextMidpoint = lineMidpointState.midpoints()[lineMidpointState.currentMi
dpoint()]; |
657 if (lineMidpointState.betweenMidpoints()) { | 657 if (lineMidpointState.betweenMidpoints()) { |
(...skipping 21 matching lines...) Expand all Loading... |
679 if (nextMidpoint.offset() + 1 > start) | 679 if (nextMidpoint.offset() + 1 > start) |
680 appendRunObjectIfNecessary(obj, start, nextMidpoint.offset()
+ 1, resolver, behavior, tracker); | 680 appendRunObjectIfNecessary(obj, start, nextMidpoint.offset()
+ 1, resolver, behavior, tracker); |
681 return adjustMidpointsAndAppendRunsForObjectIfNeeded(obj, nextMi
dpoint.offset() + 1, end, resolver, behavior, tracker); | 681 return adjustMidpointsAndAppendRunsForObjectIfNeeded(obj, nextMi
dpoint.offset() + 1, end, resolver, behavior, tracker); |
682 } | 682 } |
683 } else { | 683 } else { |
684 appendRunObjectIfNecessary(obj, start, end, resolver, behavior, trac
ker); | 684 appendRunObjectIfNecessary(obj, start, end, resolver, behavior, trac
ker); |
685 } | 685 } |
686 } | 686 } |
687 } | 687 } |
688 | 688 |
689 static inline void addFakeRunIfNecessary(RenderObject* obj, unsigned start, unsi
gned end, InlineBidiResolver& resolver, IsolateTracker& tracker) | 689 static inline void addFakeRunIfNecessary(LayoutObject* obj, unsigned start, unsi
gned end, InlineBidiResolver& resolver, IsolateTracker& tracker) |
690 { | 690 { |
691 tracker.setMidpointStateForRootIsolate(resolver.midpointState()); | 691 tracker.setMidpointStateForRootIsolate(resolver.midpointState()); |
692 adjustMidpointsAndAppendRunsForObjectIfNeeded(obj, start, obj->length(), res
olver, AppendingFakeRun, tracker); | 692 adjustMidpointsAndAppendRunsForObjectIfNeeded(obj, start, obj->length(), res
olver, AppendingFakeRun, tracker); |
693 } | 693 } |
694 | 694 |
695 template <> | 695 template <> |
696 inline void InlineBidiResolver::appendRun(BidiRunList<BidiRun>& runs) | 696 inline void InlineBidiResolver::appendRun(BidiRunList<BidiRun>& runs) |
697 { | 697 { |
698 if (!m_emptyRun && !m_eor.atEnd() && !m_reachedEndOfLine) { | 698 if (!m_emptyRun && !m_eor.atEnd() && !m_reachedEndOfLine) { |
699 // Keep track of when we enter/leave "unicode-bidi: isolate" inlines. | 699 // Keep track of when we enter/leave "unicode-bidi: isolate" inlines. |
700 // Initialize our state depending on if we're starting in the middle of
such an inline. | 700 // Initialize our state depending on if we're starting in the middle of
such an inline. |
701 // FIXME: Could this initialize from this->inIsolate() instead of walkin
g up the render tree? | 701 // FIXME: Could this initialize from this->inIsolate() instead of walkin
g up the render tree? |
702 IsolateTracker isolateTracker(runs, numberOfIsolateAncestors(m_sor)); | 702 IsolateTracker isolateTracker(runs, numberOfIsolateAncestors(m_sor)); |
703 int start = m_sor.offset(); | 703 int start = m_sor.offset(); |
704 RenderObject* obj = m_sor.object(); | 704 LayoutObject* obj = m_sor.object(); |
705 while (obj && obj != m_eor.object() && obj != m_endOfRunAtEndOfLine.obje
ct()) { | 705 while (obj && obj != m_eor.object() && obj != m_endOfRunAtEndOfLine.obje
ct()) { |
706 if (isolateTracker.inIsolate()) | 706 if (isolateTracker.inIsolate()) |
707 addFakeRunIfNecessary(obj, start, obj->length(), *this, isolateT
racker); | 707 addFakeRunIfNecessary(obj, start, obj->length(), *this, isolateT
racker); |
708 else | 708 else |
709 adjustMidpointsAndAppendRunsForObjectIfNeeded(obj, start, obj->l
ength(), *this, AppendingRunsForObject, isolateTracker); | 709 adjustMidpointsAndAppendRunsForObjectIfNeeded(obj, start, obj->l
ength(), *this, AppendingRunsForObject, isolateTracker); |
710 // FIXME: start/obj should be an InlineIterator instead of two separ
ate variables. | 710 // FIXME: start/obj should be an InlineIterator instead of two separ
ate variables. |
711 start = 0; | 711 start = 0; |
712 obj = bidiNextSkippingEmptyInlines(m_sor.root(), obj, &isolateTracke
r); | 712 obj = bidiNextSkippingEmptyInlines(m_sor.root(), obj, &isolateTracke
r); |
713 } | 713 } |
714 bool isEndOfLine = obj == m_endOfLine.object() && !m_endOfLine.offset(); | 714 bool isEndOfLine = obj == m_endOfLine.object() && !m_endOfLine.offset(); |
715 if (obj && !isEndOfLine) { | 715 if (obj && !isEndOfLine) { |
716 unsigned pos = obj == m_eor.object() ? m_eor.offset() : INT_MAX; | 716 unsigned pos = obj == m_eor.object() ? m_eor.offset() : INT_MAX; |
717 if (obj == m_endOfRunAtEndOfLine.object() && m_endOfRunAtEndOfLine.o
ffset() <= pos) { | 717 if (obj == m_endOfRunAtEndOfLine.object() && m_endOfRunAtEndOfLine.o
ffset() <= pos) { |
718 m_reachedEndOfLine = true; | 718 m_reachedEndOfLine = true; |
719 pos = m_endOfRunAtEndOfLine.offset(); | 719 pos = m_endOfRunAtEndOfLine.offset(); |
720 } | 720 } |
721 // It's OK to add runs for zero-length RenderObjects, just don't mak
e the run larger than it should be | 721 // It's OK to add runs for zero-length LayoutObjects, just don't mak
e the run larger than it should be |
722 int end = obj->length() ? pos + 1 : 0; | 722 int end = obj->length() ? pos + 1 : 0; |
723 if (isolateTracker.inIsolate()) | 723 if (isolateTracker.inIsolate()) |
724 addFakeRunIfNecessary(obj, start, end, *this, isolateTracker); | 724 addFakeRunIfNecessary(obj, start, end, *this, isolateTracker); |
725 else | 725 else |
726 adjustMidpointsAndAppendRunsForObjectIfNeeded(obj, start, end, *
this, AppendingRunsForObject, isolateTracker); | 726 adjustMidpointsAndAppendRunsForObjectIfNeeded(obj, start, end, *
this, AppendingRunsForObject, isolateTracker); |
727 } | 727 } |
728 | 728 |
729 if (isEndOfLine) | 729 if (isEndOfLine) |
730 m_reachedEndOfLine = true; | 730 m_reachedEndOfLine = true; |
731 // If isolateTrack is inIsolate, the next |start of run| can not be the
current isolated renderer. | 731 // If isolateTrack is inIsolate, the next |start of run| can not be the
current isolated renderer. |
732 if (isolateTracker.inIsolate()) | 732 if (isolateTracker.inIsolate()) |
733 m_eor.moveTo(bidiNextSkippingEmptyInlines(m_eor.root(), m_eor.object
()), 0); | 733 m_eor.moveTo(bidiNextSkippingEmptyInlines(m_eor.root(), m_eor.object
()), 0); |
734 else | 734 else |
735 m_eor.increment(); | 735 m_eor.increment(); |
736 m_sor = m_eor; | 736 m_sor = m_eor; |
737 } | 737 } |
738 | 738 |
739 m_direction = WTF::Unicode::OtherNeutral; | 739 m_direction = WTF::Unicode::OtherNeutral; |
740 m_status.eor = WTF::Unicode::OtherNeutral; | 740 m_status.eor = WTF::Unicode::OtherNeutral; |
741 } | 741 } |
742 | 742 |
743 } | 743 } |
744 | 744 |
745 #endif // InlineIterator_h | 745 #endif // InlineIterator_h |
OLD | NEW |