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. |
| 4 * All right reserved. |
4 * Copyright (C) 2010 Google Inc. All rights reserved. | 5 * Copyright (C) 2010 Google Inc. All rights reserved. |
5 * | 6 * |
6 * This library is free software; you can redistribute it and/or | 7 * This library is free software; you can redistribute it and/or |
7 * modify it under the terms of the GNU Library General Public | 8 * modify it under the terms of the GNU Library General Public |
8 * License as published by the Free Software Foundation; either | 9 * License as published by the Free Software Foundation; either |
9 * version 2 of the License, or (at your option) any later version. | 10 * version 2 of the License, or (at your option) any later version. |
10 * | 11 * |
11 * This library is distributed in the hope that it will be useful, | 12 * This library is distributed in the hope that it will be useful, |
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
47 | 48 |
48 LineLayoutItem object; | 49 LineLayoutItem object; |
49 LineLayoutItem root; | 50 LineLayoutItem root; |
50 BidiRun& runToReplace; | 51 BidiRun& runToReplace; |
51 unsigned position; | 52 unsigned position; |
52 unsigned char level; | 53 unsigned char level; |
53 }; | 54 }; |
54 | 55 |
55 // This class is used to LayoutInline subtrees, stepping by character within the | 56 // This class is used to LayoutInline subtrees, stepping by character within the |
56 // text children. InlineIterator will use bidiNext to find the next LayoutText | 57 // text children. InlineIterator will use bidiNext to find the next LayoutText |
57 // optionally notifying a BidiResolver every time it steps into/out of a LayoutI
nline. | 58 // optionally notifying a BidiResolver every time it steps into/out of a |
| 59 // LayoutInline. |
58 class InlineIterator { | 60 class InlineIterator { |
59 DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); | 61 DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); |
60 | 62 |
61 public: | 63 public: |
62 enum IncrementRule { FastIncrementInIsolatedLayout, FastIncrementInTextNode }; | 64 enum IncrementRule { FastIncrementInIsolatedLayout, FastIncrementInTextNode }; |
63 | 65 |
64 InlineIterator() | 66 InlineIterator() |
65 : m_root(nullptr), | 67 : m_root(nullptr), |
66 m_lineLayoutItem(nullptr), | 68 m_lineLayoutItem(nullptr), |
67 m_nextBreakablePosition(-1), | 69 m_nextBreakablePosition(-1), |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
154 template <class Observer> | 156 template <class Observer> |
155 static inline void notifyObserverEnteredObject(Observer* observer, | 157 static inline void notifyObserverEnteredObject(Observer* observer, |
156 LineLayoutItem object) { | 158 LineLayoutItem object) { |
157 if (!observer || !object || !object.isLayoutInline()) | 159 if (!observer || !object || !object.isLayoutInline()) |
158 return; | 160 return; |
159 | 161 |
160 const ComputedStyle& style = object.styleRef(); | 162 const ComputedStyle& style = object.styleRef(); |
161 EUnicodeBidi unicodeBidi = style.unicodeBidi(); | 163 EUnicodeBidi unicodeBidi = style.unicodeBidi(); |
162 if (unicodeBidi == UBNormal) { | 164 if (unicodeBidi == UBNormal) { |
163 // http://dev.w3.org/csswg/css3-writing-modes/#unicode-bidi | 165 // http://dev.w3.org/csswg/css3-writing-modes/#unicode-bidi |
164 // "The element does not open an additional level of embedding with respect
to the bidirectional algorithm." | 166 // "The element does not open an additional level of embedding with respect |
| 167 // to the bidirectional algorithm." |
165 // Thus we ignore any possible dir= attribute on the span. | 168 // Thus we ignore any possible dir= attribute on the span. |
166 return; | 169 return; |
167 } | 170 } |
168 if (treatAsIsolated(style)) { | 171 if (treatAsIsolated(style)) { |
169 // Make sure that explicit embeddings are committed before we enter the isol
ated content. | 172 // Make sure that explicit embeddings are committed before we enter the |
| 173 // isolated content. |
170 observer->commitExplicitEmbedding(observer->runs()); | 174 observer->commitExplicitEmbedding(observer->runs()); |
171 observer->enterIsolate(); | 175 observer->enterIsolate(); |
172 // Embedding/Override characters implied by dir= will be handled when | 176 // Embedding/Override characters implied by dir= will be handled when |
173 // we process the isolated span, not when laying out the "parent" run. | 177 // we process the isolated span, not when laying out the "parent" run. |
174 return; | 178 return; |
175 } | 179 } |
176 | 180 |
177 if (!observer->inIsolate()) | 181 if (!observer->inIsolate()) |
178 observer->embed(embedCharFromDirection(style.direction(), unicodeBidi), | 182 observer->embed(embedCharFromDirection(style.direction(), unicodeBidi), |
179 FromStyleOrDOM); | 183 FromStyleOrDOM); |
180 } | 184 } |
181 | 185 |
182 template <class Observer> | 186 template <class Observer> |
183 static inline void notifyObserverWillExitObject(Observer* observer, | 187 static inline void notifyObserverWillExitObject(Observer* observer, |
184 LineLayoutItem object) { | 188 LineLayoutItem object) { |
185 if (!observer || !object || !object.isLayoutInline()) | 189 if (!observer || !object || !object.isLayoutInline()) |
186 return; | 190 return; |
187 | 191 |
188 EUnicodeBidi unicodeBidi = object.style()->unicodeBidi(); | 192 EUnicodeBidi unicodeBidi = object.style()->unicodeBidi(); |
189 if (unicodeBidi == UBNormal) | 193 if (unicodeBidi == UBNormal) |
190 return; // Nothing to do for unicode-bidi: normal | 194 return; // Nothing to do for unicode-bidi: normal |
191 if (treatAsIsolated(object.styleRef())) { | 195 if (treatAsIsolated(object.styleRef())) { |
192 observer->exitIsolate(); | 196 observer->exitIsolate(); |
193 return; | 197 return; |
194 } | 198 } |
195 | 199 |
196 // Otherwise we pop any embed/override character we added when we opened this
tag. | 200 // Otherwise we pop any embed/override character we added when we opened this |
| 201 // tag. |
197 if (!observer->inIsolate()) | 202 if (!observer->inIsolate()) |
198 observer->embed(WTF::Unicode::PopDirectionalFormat, FromStyleOrDOM); | 203 observer->embed(WTF::Unicode::PopDirectionalFormat, FromStyleOrDOM); |
199 } | 204 } |
200 | 205 |
201 static inline bool isIteratorTarget(LineLayoutItem object) { | 206 static inline bool isIteratorTarget(LineLayoutItem object) { |
202 ASSERT( | 207 // The iterator will of course return 0, but its not an expected argument to |
203 object); // The iterator will of course return 0, but its not an expected
argument to this function. | 208 // this function. |
| 209 DCHECK(object); |
204 return object.isText() || object.isFloating() || | 210 return object.isText() || object.isFloating() || |
205 object.isOutOfFlowPositioned() || object.isAtomicInlineLevel(); | 211 object.isOutOfFlowPositioned() || object.isAtomicInlineLevel(); |
206 } | 212 } |
207 | 213 |
208 // This enum is only used for bidiNextShared() | 214 // This enum is only used for bidiNextShared() |
209 enum EmptyInlineBehavior { | 215 enum EmptyInlineBehavior { |
210 SkipEmptyInlines, | 216 SkipEmptyInlines, |
211 IncludeEmptyInlines, | 217 IncludeEmptyInlines, |
212 }; | 218 }; |
213 | 219 |
214 static bool isEmptyInline(LineLayoutItem object) { | 220 static bool isEmptyInline(LineLayoutItem object) { |
215 if (!object.isLayoutInline()) | 221 if (!object.isLayoutInline()) |
216 return false; | 222 return false; |
217 | 223 |
218 for (LineLayoutItem curr = LineLayoutInline(object).firstChild(); curr; | 224 for (LineLayoutItem curr = LineLayoutInline(object).firstChild(); curr; |
219 curr = curr.nextSibling()) { | 225 curr = curr.nextSibling()) { |
220 if (curr.isFloatingOrOutOfFlowPositioned()) | 226 if (curr.isFloatingOrOutOfFlowPositioned()) |
221 continue; | 227 continue; |
222 if (curr.isText() && LineLayoutText(curr).isAllCollapsibleWhitespace()) | 228 if (curr.isText() && LineLayoutText(curr).isAllCollapsibleWhitespace()) |
223 continue; | 229 continue; |
224 | 230 |
225 if (!isEmptyInline(curr)) | 231 if (!isEmptyInline(curr)) |
226 return false; | 232 return false; |
227 } | 233 } |
228 return true; | 234 return true; |
229 } | 235 } |
230 | 236 |
231 // FIXME: This function is misleadingly named. It has little to do with bidi. | 237 // FIXME: This function is misleadingly named. It has little to do with bidi. |
232 // This function will iterate over inlines within a block, optionally notifying | 238 // This function will iterate over inlines within a block, optionally notifying |
233 // a bidi resolver as it enters/exits inlines (so it can push/pop embedding leve
ls). | 239 // a bidi resolver as it enters/exits inlines (so it can push/pop embedding |
| 240 // levels). |
234 template <class Observer> | 241 template <class Observer> |
235 static inline LineLayoutItem bidiNextShared( | 242 static inline LineLayoutItem bidiNextShared( |
236 LineLayoutItem root, | 243 LineLayoutItem root, |
237 LineLayoutItem current, | 244 LineLayoutItem current, |
238 Observer* observer = 0, | 245 Observer* observer = 0, |
239 EmptyInlineBehavior emptyInlineBehavior = SkipEmptyInlines, | 246 EmptyInlineBehavior emptyInlineBehavior = SkipEmptyInlines, |
240 bool* endOfInlinePtr = nullptr) { | 247 bool* endOfInlinePtr = nullptr) { |
241 LineLayoutItem next = nullptr; | 248 LineLayoutItem next = nullptr; |
242 // oldEndOfInline denotes if when we last stopped iterating if we were at the
end of an inline. | 249 // oldEndOfInline denotes if when we last stopped iterating if we were at the |
| 250 // end of an inline. |
243 bool oldEndOfInline = endOfInlinePtr ? *endOfInlinePtr : false; | 251 bool oldEndOfInline = endOfInlinePtr ? *endOfInlinePtr : false; |
244 bool endOfInline = false; | 252 bool endOfInline = false; |
245 | 253 |
246 while (current) { | 254 while (current) { |
247 next = 0; | 255 next = 0; |
248 if (!oldEndOfInline && !isIteratorTarget(current)) { | 256 if (!oldEndOfInline && !isIteratorTarget(current)) { |
249 next = current.slowFirstChild(); | 257 next = current.slowFirstChild(); |
250 notifyObserverEnteredObject(observer, next); | 258 notifyObserverEnteredObject(observer, next); |
251 } | 259 } |
252 | 260 |
253 // We hit this when either current has no children, or when current is not a
layoutObject we care about. | 261 // We hit this when either current has no children, or when current is not a |
| 262 // layoutObject we care about. |
254 if (!next) { | 263 if (!next) { |
255 // If it is a layoutObject we care about, and we're doing our inline-walk,
return it. | 264 // If it is a layoutObject we care about, and we're doing our inline-walk, |
| 265 // return it. |
256 if (emptyInlineBehavior == IncludeEmptyInlines && !oldEndOfInline && | 266 if (emptyInlineBehavior == IncludeEmptyInlines && !oldEndOfInline && |
257 current.isLayoutInline()) { | 267 current.isLayoutInline()) { |
258 next = current; | 268 next = current; |
259 endOfInline = true; | 269 endOfInline = true; |
260 break; | 270 break; |
261 } | 271 } |
262 | 272 |
263 while (current && current != root) { | 273 while (current && current != root) { |
264 notifyObserverWillExitObject(observer, current); | 274 notifyObserverWillExitObject(observer, current); |
265 | 275 |
(...skipping 28 matching lines...) Expand all Loading... |
294 *endOfInlinePtr = endOfInline; | 304 *endOfInlinePtr = endOfInline; |
295 | 305 |
296 return next; | 306 return next; |
297 } | 307 } |
298 | 308 |
299 template <class Observer> | 309 template <class Observer> |
300 static inline LineLayoutItem bidiNextSkippingEmptyInlines( | 310 static inline LineLayoutItem bidiNextSkippingEmptyInlines( |
301 LineLayoutItem root, | 311 LineLayoutItem root, |
302 LineLayoutItem current, | 312 LineLayoutItem current, |
303 Observer* observer) { | 313 Observer* observer) { |
304 // TODO(rhogan): Rename this caller. It's used for a detailed walk of every ob
ject in an inline flow, for example during line layout. | 314 // TODO(rhogan): Rename this caller. It's used for a detailed walk of every |
305 // We always return empty inlines in bidiNextShared, which gives lie to the bi
diNext[Skipping|Including]EmptyInlines | 315 // object in an inline flow, for example during line layout. |
306 // naming scheme we use to call it. bidiNextSkippingEmptyInlines is the less f
ussy of the two callers, | 316 // We always return empty inlines in bidiNextShared, which gives lie to the |
307 // it will always try to advance and will return what it finds if it's a line
layout object in isIteratorTarget or if | 317 // bidiNext[Skipping|Including]EmptyInlines naming scheme we use to call it. |
308 // it's an empty LayoutInline. If the LayoutInline has content, it will advanc
e past the start of the LayoutLine and try to return | 318 // bidiNextSkippingEmptyInlines is the less fussy of the two callers, it will |
309 // one of its children. | 319 // always try to advance and will return what it finds if it's a line layout |
310 // The SkipEmptyInlines callers never care about endOfInlinePtr. | 320 // object in isIteratorTarget or if it's an empty LayoutInline. If the |
| 321 // LayoutInline has content, it will advance past the start of the LayoutLine |
| 322 // and try to return one of its children. The SkipEmptyInlines callers never |
| 323 // care about endOfInlinePtr. |
311 return bidiNextShared(root, current, observer, SkipEmptyInlines); | 324 return bidiNextShared(root, current, observer, SkipEmptyInlines); |
312 } | 325 } |
313 | 326 |
314 // This makes callers cleaner as they don't have to specify a type for the obser
ver when not providing one. | 327 // This makes callers cleaner as they don't have to specify a type for the |
| 328 // observer when not providing one. |
315 static inline LineLayoutItem bidiNextSkippingEmptyInlines( | 329 static inline LineLayoutItem bidiNextSkippingEmptyInlines( |
316 LineLayoutItem root, | 330 LineLayoutItem root, |
317 LineLayoutItem current) { | 331 LineLayoutItem current) { |
318 InlineBidiResolver* observer = nullptr; | 332 InlineBidiResolver* observer = nullptr; |
319 return bidiNextSkippingEmptyInlines(root, current, observer); | 333 return bidiNextSkippingEmptyInlines(root, current, observer); |
320 } | 334 } |
321 | 335 |
322 static inline LineLayoutItem bidiNextIncludingEmptyInlines( | 336 static inline LineLayoutItem bidiNextIncludingEmptyInlines( |
323 LineLayoutItem root, | 337 LineLayoutItem root, |
324 LineLayoutItem current, | 338 LineLayoutItem current, |
325 bool* endOfInlinePtr = nullptr) { | 339 bool* endOfInlinePtr = nullptr) { |
326 // TODO(rhogan): Rename this caller. It's used for quick and dirty walks of in
line children by InlineWalker, which isn't | 340 // TODO(rhogan): Rename this caller. It's used for quick and dirty walks of |
327 // interested in the contents of inlines. Use cases include dirtying objects o
r simplified layout that leaves lineboxes intact. | 341 // inline children by InlineWalker, which isn't interested in the contents of |
328 // bidiNextIncludingEmptyInlines will return if the iterator is at the start o
f a LayoutInline (even if it hasn't | 342 // inlines. Use cases include dirtying objects or simplified layout that |
329 // advanced yet) unless it previously stopped at the start of the same LayoutI
nline the last time it tried to iterate. | 343 // leaves lineboxes intact. bidiNextIncludingEmptyInlines will return if the |
330 // If it finds itself inside a LayoutInline that doesn't have anything in isIt
eratorTarget it will return the enclosing | 344 // iterator is at the start of a LayoutInline (even if it hasn't advanced yet) |
331 // LayoutInline. | 345 // unless it previously stopped at the start of the same LayoutInline the last |
| 346 // time it tried to iterate. |
| 347 // If it finds itself inside a LayoutInline that doesn't have anything in |
| 348 // isIteratorTarget it will return the enclosing LayoutInline. |
332 InlineBidiResolver* observer = | 349 InlineBidiResolver* observer = |
333 nullptr; // Callers who include empty inlines, never use an observer. | 350 nullptr; // Callers who include empty inlines, never use an observer. |
334 return bidiNextShared(root, current, observer, IncludeEmptyInlines, | 351 return bidiNextShared(root, current, observer, IncludeEmptyInlines, |
335 endOfInlinePtr); | 352 endOfInlinePtr); |
336 } | 353 } |
337 | 354 |
338 static inline LineLayoutItem bidiFirstSkippingEmptyInlines( | 355 static inline LineLayoutItem bidiFirstSkippingEmptyInlines( |
339 LineLayoutBlockFlow root, | 356 LineLayoutBlockFlow root, |
340 BidiRunList<BidiRun>& runs, | 357 BidiRunList<BidiRun>& runs, |
341 InlineBidiResolver* resolver = nullptr) { | 358 InlineBidiResolver* resolver = nullptr) { |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
377 } | 394 } |
378 | 395 |
379 inline void InlineIterator::fastIncrementInTextNode() { | 396 inline void InlineIterator::fastIncrementInTextNode() { |
380 ASSERT(m_lineLayoutItem); | 397 ASSERT(m_lineLayoutItem); |
381 ASSERT(m_lineLayoutItem.isText()); | 398 ASSERT(m_lineLayoutItem.isText()); |
382 ASSERT(m_pos <= LineLayoutText(m_lineLayoutItem).textLength()); | 399 ASSERT(m_pos <= LineLayoutText(m_lineLayoutItem).textLength()); |
383 if (m_pos < INT_MAX) | 400 if (m_pos < INT_MAX) |
384 m_pos++; | 401 m_pos++; |
385 } | 402 } |
386 | 403 |
387 // FIXME: This is used by LayoutBlockFlow for simplified layout, and has nothing
to do with bidi | 404 // FIXME: This is used by LayoutBlockFlow for simplified layout, and has nothing |
388 // it shouldn't use functions called bidiFirst and bidiNext. | 405 // to do with bidi it shouldn't use functions called bidiFirst and bidiNext. |
389 class InlineWalker { | 406 class InlineWalker { |
390 STACK_ALLOCATED(); | 407 STACK_ALLOCATED(); |
391 | 408 |
392 public: | 409 public: |
393 InlineWalker(LineLayoutBlockFlow root) | 410 InlineWalker(LineLayoutBlockFlow root) |
394 : m_root(root), m_current(nullptr), m_atEndOfInline(false) { | 411 : m_root(root), m_current(nullptr), m_atEndOfInline(false) { |
395 // FIXME: This class should be taught how to do the SkipEmptyInlines codepat
h as well. | 412 // FIXME: This class should be taught how to do the SkipEmptyInlines |
| 413 // codepath as well. |
396 m_current = bidiFirstIncludingEmptyInlines(m_root); | 414 m_current = bidiFirstIncludingEmptyInlines(m_root); |
397 } | 415 } |
398 | 416 |
399 LineLayoutBlockFlow root() { return m_root; } | 417 LineLayoutBlockFlow root() { return m_root; } |
400 LineLayoutItem current() { return m_current; } | 418 LineLayoutItem current() { return m_current; } |
401 | 419 |
402 bool atEndOfInline() { return m_atEndOfInline; } | 420 bool atEndOfInline() { return m_atEndOfInline; } |
403 bool atEnd() const { return !m_current; } | 421 bool atEnd() const { return !m_current; } |
404 | 422 |
405 LineLayoutItem advance() { | 423 LineLayoutItem advance() { |
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
604 return 0; | 622 return 0; |
605 unsigned count = 0; | 623 unsigned count = 0; |
606 while (object && object != iter.root()) { | 624 while (object && object != iter.root()) { |
607 if (isIsolatedInline(object)) | 625 if (isIsolatedInline(object)) |
608 count++; | 626 count++; |
609 object = object.parent(); | 627 object = object.parent(); |
610 } | 628 } |
611 return count; | 629 return count; |
612 } | 630 } |
613 | 631 |
614 // FIXME: This belongs on InlineBidiResolver, except it's a template specializat
ion | 632 // FIXME: This belongs on InlineBidiResolver, except it's a template |
615 // of BidiResolver which knows nothing about LayoutObjects. | 633 // specialization of BidiResolver which knows nothing about LayoutObjects. |
616 static inline BidiRun* addPlaceholderRunForIsolatedInline( | 634 static inline BidiRun* addPlaceholderRunForIsolatedInline( |
617 InlineBidiResolver& resolver, | 635 InlineBidiResolver& resolver, |
618 LineLayoutItem obj, | 636 LineLayoutItem obj, |
619 unsigned pos, | 637 unsigned pos, |
620 LineLayoutItem root) { | 638 LineLayoutItem root) { |
621 ASSERT(obj); | 639 ASSERT(obj); |
622 BidiRun* isolatedRun = | 640 BidiRun* isolatedRun = |
623 new BidiRun(pos, pos, obj, resolver.context(), resolver.dir()); | 641 new BidiRun(pos, pos, obj, resolver.context(), resolver.dir()); |
624 resolver.runs().addRun(isolatedRun); | 642 resolver.runs().addRun(isolatedRun); |
625 // FIXME: isolatedRuns() could be a hash of object->run and then we could chea
ply | 643 // FIXME: isolatedRuns() could be a hash of object->run and then we could |
626 // ASSERT here that we didn't create multiple objects for the same inline. | 644 // cheaply ASSERT here that we didn't create multiple objects for the same |
| 645 // inline. |
627 resolver.isolatedRuns().append(BidiIsolatedRun(obj, pos, root, *isolatedRun, | 646 resolver.isolatedRuns().append(BidiIsolatedRun(obj, pos, root, *isolatedRun, |
628 resolver.context()->level())); | 647 resolver.context()->level())); |
629 return isolatedRun; | 648 return isolatedRun; |
630 } | 649 } |
631 | 650 |
632 static inline BidiRun* createRun(int start, | 651 static inline BidiRun* createRun(int start, |
633 int end, | 652 int end, |
634 LineLayoutItem obj, | 653 LineLayoutItem obj, |
635 InlineBidiResolver& resolver) { | 654 InlineBidiResolver& resolver) { |
636 return new BidiRun(start, end, obj, resolver.context(), resolver.dir()); | 655 return new BidiRun(start, end, obj, resolver.context(), resolver.dir()); |
(...skipping 27 matching lines...) Expand all Loading... |
664 // We don't care if we encounter bidi directional overrides. | 683 // We don't care if we encounter bidi directional overrides. |
665 void embed(WTF::Unicode::CharDirection, BidiEmbeddingSource) {} | 684 void embed(WTF::Unicode::CharDirection, BidiEmbeddingSource) {} |
666 void commitExplicitEmbedding(BidiRunList<BidiRun>&) {} | 685 void commitExplicitEmbedding(BidiRunList<BidiRun>&) {} |
667 BidiRunList<BidiRun>& runs() { return m_runs; } | 686 BidiRunList<BidiRun>& runs() { return m_runs; } |
668 | 687 |
669 void addFakeRunIfNecessary(LineLayoutItem obj, | 688 void addFakeRunIfNecessary(LineLayoutItem obj, |
670 unsigned pos, | 689 unsigned pos, |
671 unsigned end, | 690 unsigned end, |
672 LineLayoutItem root, | 691 LineLayoutItem root, |
673 InlineBidiResolver& resolver) { | 692 InlineBidiResolver& resolver) { |
674 // We only need to add a fake run for a given isolated span once during each
call to createBidiRunsForLine. | 693 // We only need to add a fake run for a given isolated span once during each |
675 // We'll be called for every span inside the isolated span so we just ignore
subsequent calls. | 694 // call to createBidiRunsForLine. We'll be called for every span inside the |
676 // We also avoid creating a fake run until we hit a child that warrants one,
e.g. we skip floats. | 695 // isolated span so we just ignore subsequent calls. |
| 696 // We also avoid creating a fake run until we hit a child that warrants one, |
| 697 // e.g. we skip floats. |
677 if (LayoutBlockFlow::shouldSkipCreatingRunsForObject(obj)) | 698 if (LayoutBlockFlow::shouldSkipCreatingRunsForObject(obj)) |
678 return; | 699 return; |
679 if (!m_haveAddedFakeRunForRootIsolate) { | 700 if (!m_haveAddedFakeRunForRootIsolate) { |
680 BidiRun* run = | 701 BidiRun* run = |
681 addPlaceholderRunForIsolatedInline(resolver, obj, pos, root); | 702 addPlaceholderRunForIsolatedInline(resolver, obj, pos, root); |
682 resolver.setMidpointStateForIsolatedRun(*run, | 703 resolver.setMidpointStateForIsolatedRun(*run, |
683 m_midpointStateForRootIsolate); | 704 m_midpointStateForRootIsolate); |
684 m_haveAddedFakeRunForRootIsolate = true; | 705 m_haveAddedFakeRunForRootIsolate = true; |
685 } | 706 } |
686 // obj and pos together denote a single position in the inline, from which t
he parsing of the isolate will start. | 707 // obj and pos together denote a single position in the inline, from which |
687 // We don't need to mark the end of the run because this is implicit: it is
either endOfLine or the end of the | 708 // the parsing of the isolate will start. |
688 // isolate, when we call createBidiRunsForLine it will stop at whichever com
es first. | 709 // We don't need to mark the end of the run because this is implicit: it is |
| 710 // either endOfLine or the end of the isolate, when we call |
| 711 // createBidiRunsForLine it will stop at whichever comes first. |
689 } | 712 } |
690 | 713 |
691 private: | 714 private: |
692 unsigned m_nestedIsolateCount; | 715 unsigned m_nestedIsolateCount; |
693 bool m_haveAddedFakeRunForRootIsolate; | 716 bool m_haveAddedFakeRunForRootIsolate; |
694 LineMidpointState m_midpointStateForRootIsolate; | 717 LineMidpointState m_midpointStateForRootIsolate; |
695 BidiRunList<BidiRun>& m_runs; | 718 BidiRunList<BidiRun>& m_runs; |
696 }; | 719 }; |
697 | 720 |
698 static void inline appendRunObjectIfNecessary(LineLayoutItem obj, | 721 static void inline appendRunObjectIfNecessary(LineLayoutItem obj, |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
757 appendRunObjectIfNecessary(obj, start, end, root, resolver, behavior, | 780 appendRunObjectIfNecessary(obj, start, end, root, resolver, behavior, |
758 tracker); | 781 tracker); |
759 return; | 782 return; |
760 } | 783 } |
761 | 784 |
762 // An end midpoint has been encountered within our object. We | 785 // An end midpoint has been encountered within our object. We |
763 // need to go ahead and append a run with our endpoint. | 786 // need to go ahead and append a run with our endpoint. |
764 if (nextMidpoint.offset() + 1 <= end) { | 787 if (nextMidpoint.offset() + 1 <= end) { |
765 lineMidpointState.setBetweenMidpoints(true); | 788 lineMidpointState.setBetweenMidpoints(true); |
766 lineMidpointState.incrementCurrentMidpoint(); | 789 lineMidpointState.incrementCurrentMidpoint(); |
767 if (nextMidpoint.offset() != | 790 // UINT_MAX means stop at the object and don't include any of it. |
768 UINT_MAX) { // UINT_MAX means stop at the object and don't nclude a
ny of it. | 791 if (nextMidpoint.offset() != UINT_MAX) { |
769 if (nextMidpoint.offset() + 1 > start) | 792 if (nextMidpoint.offset() + 1 > start) |
770 appendRunObjectIfNecessary(obj, start, nextMidpoint.offset() + 1, | 793 appendRunObjectIfNecessary(obj, start, nextMidpoint.offset() + 1, |
771 root, resolver, behavior, tracker); | 794 root, resolver, behavior, tracker); |
772 start = nextMidpoint.offset() + 1; | 795 start = nextMidpoint.offset() + 1; |
773 continue; | 796 continue; |
774 } | 797 } |
775 } else { | 798 } else { |
776 appendRunObjectIfNecessary(obj, start, end, root, resolver, behavior, | 799 appendRunObjectIfNecessary(obj, start, end, root, resolver, behavior, |
777 tracker); | 800 tracker); |
778 } | 801 } |
(...skipping 10 matching lines...) Expand all Loading... |
789 IsolateTracker& tracker) { | 812 IsolateTracker& tracker) { |
790 tracker.setMidpointStateForRootIsolate(resolver.midpointState()); | 813 tracker.setMidpointStateForRootIsolate(resolver.midpointState()); |
791 adjustMidpointsAndAppendRunsForObjectIfNeeded( | 814 adjustMidpointsAndAppendRunsForObjectIfNeeded( |
792 obj, start, obj.length(), root, resolver, AppendingFakeRun, tracker); | 815 obj, start, obj.length(), root, resolver, AppendingFakeRun, tracker); |
793 } | 816 } |
794 | 817 |
795 template <> | 818 template <> |
796 inline void InlineBidiResolver::appendRun(BidiRunList<BidiRun>& runs) { | 819 inline void InlineBidiResolver::appendRun(BidiRunList<BidiRun>& runs) { |
797 if (!m_emptyRun && !m_eor.atEnd() && !m_reachedEndOfLine) { | 820 if (!m_emptyRun && !m_eor.atEnd() && !m_reachedEndOfLine) { |
798 // Keep track of when we enter/leave "unicode-bidi: isolate" inlines. | 821 // Keep track of when we enter/leave "unicode-bidi: isolate" inlines. |
799 // Initialize our state depending on if we're starting in the middle of such
an inline. | 822 // Initialize our state depending on if we're starting in the middle of such |
800 // FIXME: Could this initialize from this->inIsolate() instead of walking up
the layout tree? | 823 // an inline. |
| 824 // FIXME: Could this initialize from this->inIsolate() instead of walking up |
| 825 // the layout tree? |
801 IsolateTracker isolateTracker(runs, numberOfIsolateAncestors(m_sor)); | 826 IsolateTracker isolateTracker(runs, numberOfIsolateAncestors(m_sor)); |
802 int start = m_sor.offset(); | 827 int start = m_sor.offset(); |
803 LineLayoutItem obj = m_sor.getLineLayoutItem(); | 828 LineLayoutItem obj = m_sor.getLineLayoutItem(); |
804 while (obj && obj != m_eor.getLineLayoutItem() && | 829 while (obj && obj != m_eor.getLineLayoutItem() && |
805 obj != m_endOfRunAtEndOfLine.getLineLayoutItem()) { | 830 obj != m_endOfRunAtEndOfLine.getLineLayoutItem()) { |
806 if (isolateTracker.inIsolate()) | 831 if (isolateTracker.inIsolate()) |
807 addFakeRunIfNecessary(obj, start, obj.length(), m_sor.root(), *this, | 832 addFakeRunIfNecessary(obj, start, obj.length(), m_sor.root(), *this, |
808 isolateTracker); | 833 isolateTracker); |
809 else | 834 else |
810 adjustMidpointsAndAppendRunsForObjectIfNeeded( | 835 adjustMidpointsAndAppendRunsForObjectIfNeeded( |
811 obj, start, obj.length(), m_sor.root(), *this, | 836 obj, start, obj.length(), m_sor.root(), *this, |
812 AppendingRunsForObject, isolateTracker); | 837 AppendingRunsForObject, isolateTracker); |
813 // FIXME: start/obj should be an InlineIterator instead of two separate va
riables. | 838 // FIXME: start/obj should be an InlineIterator instead of two separate |
| 839 // variables. |
814 start = 0; | 840 start = 0; |
815 obj = bidiNextSkippingEmptyInlines(m_sor.root(), obj, &isolateTracker); | 841 obj = bidiNextSkippingEmptyInlines(m_sor.root(), obj, &isolateTracker); |
816 } | 842 } |
817 bool isEndOfLine = | 843 bool isEndOfLine = |
818 obj == m_endOfLine.getLineLayoutItem() && !m_endOfLine.offset(); | 844 obj == m_endOfLine.getLineLayoutItem() && !m_endOfLine.offset(); |
819 if (obj && !isEndOfLine) { | 845 if (obj && !isEndOfLine) { |
820 unsigned pos = | 846 unsigned pos = |
821 obj == m_eor.getLineLayoutItem() ? m_eor.offset() : INT_MAX; | 847 obj == m_eor.getLineLayoutItem() ? m_eor.offset() : INT_MAX; |
822 if (obj == m_endOfRunAtEndOfLine.getLineLayoutItem() && | 848 if (obj == m_endOfRunAtEndOfLine.getLineLayoutItem() && |
823 m_endOfRunAtEndOfLine.offset() <= pos) { | 849 m_endOfRunAtEndOfLine.offset() <= pos) { |
824 m_reachedEndOfLine = true; | 850 m_reachedEndOfLine = true; |
825 pos = m_endOfRunAtEndOfLine.offset(); | 851 pos = m_endOfRunAtEndOfLine.offset(); |
826 } | 852 } |
827 // It's OK to add runs for zero-length LayoutObjects, just don't make the
run larger than it should be | 853 // It's OK to add runs for zero-length LayoutObjects, just don't make the |
| 854 // run larger than it should be |
828 int end = obj.length() ? pos + 1 : 0; | 855 int end = obj.length() ? pos + 1 : 0; |
829 if (isolateTracker.inIsolate()) | 856 if (isolateTracker.inIsolate()) |
830 addFakeRunIfNecessary(obj, start, end, m_sor.root(), *this, | 857 addFakeRunIfNecessary(obj, start, end, m_sor.root(), *this, |
831 isolateTracker); | 858 isolateTracker); |
832 else | 859 else |
833 adjustMidpointsAndAppendRunsForObjectIfNeeded( | 860 adjustMidpointsAndAppendRunsForObjectIfNeeded( |
834 obj, start, end, m_sor.root(), *this, AppendingRunsForObject, | 861 obj, start, end, m_sor.root(), *this, AppendingRunsForObject, |
835 isolateTracker); | 862 isolateTracker); |
836 } | 863 } |
837 | 864 |
838 if (isEndOfLine) | 865 if (isEndOfLine) |
839 m_reachedEndOfLine = true; | 866 m_reachedEndOfLine = true; |
840 // If isolateTrack is inIsolate, the next |start of run| can not be the curr
ent isolated layoutObject. | 867 // If isolateTrack is inIsolate, the next |start of run| can not be the |
| 868 // current isolated layoutObject. |
841 if (isolateTracker.inIsolate()) | 869 if (isolateTracker.inIsolate()) |
842 m_eor.moveTo( | 870 m_eor.moveTo( |
843 bidiNextSkippingEmptyInlines(m_eor.root(), m_eor.getLineLayoutItem()), | 871 bidiNextSkippingEmptyInlines(m_eor.root(), m_eor.getLineLayoutItem()), |
844 0); | 872 0); |
845 else | 873 else |
846 m_eor.increment(); | 874 m_eor.increment(); |
847 m_sor = m_eor; | 875 m_sor = m_eor; |
848 } | 876 } |
849 | 877 |
850 m_direction = WTF::Unicode::OtherNeutral; | 878 m_direction = WTF::Unicode::OtherNeutral; |
851 m_status.eor = WTF::Unicode::OtherNeutral; | 879 m_status.eor = WTF::Unicode::OtherNeutral; |
852 } | 880 } |
853 | 881 |
854 } // namespace blink | 882 } // namespace blink |
855 | 883 |
856 #endif // InlineIterator_h | 884 #endif // InlineIterator_h |
OLD | NEW |