• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
3  * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009, 2010 Apple Inc. All right reserved.
4  * Copyright (C) 2010 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 InlineIterator_h
24 #define InlineIterator_h
25 
26 #include "BidiRun.h"
27 #include "RenderBlock.h"
28 #include "RenderText.h"
29 #include <wtf/AlwaysInline.h>
30 #include <wtf/StdLibExtras.h>
31 
32 namespace WebCore {
33 
34 class InlineIterator {
35 public:
InlineIterator()36     InlineIterator()
37         : block(0)
38         , obj(0)
39         , pos(0)
40         , nextBreakablePosition(-1)
41     {
42     }
43 
InlineIterator(RenderBlock * b,RenderObject * o,unsigned p)44     InlineIterator(RenderBlock* b, RenderObject* o, unsigned p)
45         : block(b)
46         , obj(o)
47         , pos(p)
48         , nextBreakablePosition(-1)
49     {
50     }
51 
52     void increment(InlineBidiResolver* resolver = 0);
53     bool atEnd() const;
54 
55     UChar current() const;
56     WTF::Unicode::Direction direction() const;
57 
58     RenderBlock* block;
59     RenderObject* obj;
60     unsigned pos;
61     int nextBreakablePosition;
62 };
63 
64 inline bool operator==(const InlineIterator& it1, const InlineIterator& it2)
65 {
66     return it1.pos == it2.pos && it1.obj == it2.obj;
67 }
68 
69 inline bool operator!=(const InlineIterator& it1, const InlineIterator& it2)
70 {
71     return it1.pos != it2.pos || it1.obj != it2.obj;
72 }
73 
74 static inline RenderObject* bidiNext(RenderBlock* block, RenderObject* current, InlineBidiResolver* resolver = 0, bool skipInlines = true, bool* endOfInlinePtr = 0)
75 {
76     RenderObject* next = 0;
77     bool oldEndOfInline = endOfInlinePtr ? *endOfInlinePtr : false;
78     bool endOfInline = false;
79 
80     while (current) {
81         next = 0;
82         if (!oldEndOfInline && !current->isFloating() && !current->isReplaced() && !current->isPositioned() && !current->isText()) {
83             next = current->firstChild();
84             if (next && resolver && next->isRenderInline()) {
85                 EUnicodeBidi ub = next->style()->unicodeBidi();
86                 if (ub != UBNormal) {
87                     TextDirection dir = next->style()->direction();
88                     WTF::Unicode::Direction d = (ub == Embed
89                         ? (dir == RTL ? WTF::Unicode::RightToLeftEmbedding : WTF::Unicode::LeftToRightEmbedding)
90                         : (dir == RTL ? WTF::Unicode::RightToLeftOverride : WTF::Unicode::LeftToRightOverride));
91                     resolver->embed(d);
92                 }
93             }
94         }
95 
96         if (!next) {
97             if (!skipInlines && !oldEndOfInline && current->isRenderInline()) {
98                 next = current;
99                 endOfInline = true;
100                 break;
101             }
102 
103             while (current && current != block) {
104                 if (resolver && current->isRenderInline() && current->style()->unicodeBidi() != UBNormal)
105                     resolver->embed(WTF::Unicode::PopDirectionalFormat);
106 
107                 next = current->nextSibling();
108                 if (next) {
109                     if (resolver && next->isRenderInline()) {
110                         EUnicodeBidi ub = next->style()->unicodeBidi();
111                         if (ub != UBNormal) {
112                             TextDirection dir = next->style()->direction();
113                             WTF::Unicode::Direction d = (ub == Embed
114                                 ? (dir == RTL ? WTF::Unicode::RightToLeftEmbedding: WTF::Unicode::LeftToRightEmbedding)
115                                 : (dir == RTL ? WTF::Unicode::RightToLeftOverride : WTF::Unicode::LeftToRightOverride));
116                             resolver->embed(d);
117                         }
118                     }
119                     break;
120                 }
121 
122                 current = current->parent();
123                 if (!skipInlines && current && current != block && current->isRenderInline()) {
124                     next = current;
125                     endOfInline = true;
126                     break;
127                 }
128             }
129         }
130 
131         if (!next)
132             break;
133 
134         if (next->isText() || next->isFloating() || next->isReplaced() || next->isPositioned()
135             || ((!skipInlines || !next->firstChild()) // Always return EMPTY inlines.
136                 && next->isRenderInline()))
137             break;
138         current = next;
139     }
140 
141     if (endOfInlinePtr)
142         *endOfInlinePtr = endOfInline;
143 
144     return next;
145 }
146 
147 static inline RenderObject* bidiFirst(RenderBlock* block, InlineBidiResolver* resolver, bool skipInlines = true)
148 {
149     if (!block->firstChild())
150         return 0;
151 
152     RenderObject* o = block->firstChild();
153     if (o->isRenderInline()) {
154         if (resolver) {
155             EUnicodeBidi ub = o->style()->unicodeBidi();
156             if (ub != UBNormal) {
157                 TextDirection dir = o->style()->direction();
158                 WTF::Unicode::Direction d = (ub == Embed
159                     ? (dir == RTL ? WTF::Unicode::RightToLeftEmbedding : WTF::Unicode::LeftToRightEmbedding)
160                     : (dir == RTL ? WTF::Unicode::RightToLeftOverride : WTF::Unicode::LeftToRightOverride));
161                 resolver->embed(d);
162             }
163         }
164         if (skipInlines && o->firstChild())
165             o = bidiNext(block, o, resolver, skipInlines);
166         else {
167             // Never skip empty inlines.
168             if (resolver)
169                 resolver->commitExplicitEmbedding();
170             return o;
171         }
172     }
173 
174     if (o && !o->isText() && !o->isReplaced() && !o->isFloating() && !o->isPositioned())
175         o = bidiNext(block, o, resolver, skipInlines);
176 
177     if (resolver)
178         resolver->commitExplicitEmbedding();
179     return o;
180 }
181 
increment(InlineBidiResolver * resolver)182 inline void InlineIterator::increment(InlineBidiResolver* resolver)
183 {
184     if (!obj)
185         return;
186     if (obj->isText()) {
187         pos++;
188         if (pos >= toRenderText(obj)->textLength()) {
189             obj = bidiNext(block, obj, resolver);
190             pos = 0;
191             nextBreakablePosition = -1;
192         }
193     } else {
194         obj = bidiNext(block, obj, resolver);
195         pos = 0;
196         nextBreakablePosition = -1;
197     }
198 }
199 
atEnd()200 inline bool InlineIterator::atEnd() const
201 {
202     return !obj;
203 }
204 
current()205 inline UChar InlineIterator::current() const
206 {
207     if (!obj || !obj->isText())
208         return 0;
209 
210     RenderText* text = toRenderText(obj);
211     if (pos >= text->textLength())
212         return 0;
213 
214     return text->characters()[pos];
215 }
216 
direction()217 ALWAYS_INLINE WTF::Unicode::Direction InlineIterator::direction() const
218 {
219     if (UChar c = current())
220         return WTF::Unicode::direction(c);
221 
222     if (obj && obj->isListMarker())
223         return obj->style()->direction() == LTR ? WTF::Unicode::LeftToRight : WTF::Unicode::RightToLeft;
224 
225     return WTF::Unicode::OtherNeutral;
226 }
227 
228 template<>
increment()229 inline void InlineBidiResolver::increment()
230 {
231     current.increment(this);
232 }
233 
234 template <>
appendRun()235 inline void InlineBidiResolver::appendRun()
236 {
237     if (!emptyRun && !eor.atEnd()) {
238         int start = sor.pos;
239         RenderObject *obj = sor.obj;
240         while (obj && obj != eor.obj && obj != endOfLine.obj) {
241             RenderBlock::appendRunsForObject(start, obj->length(), obj, *this);
242             start = 0;
243             obj = bidiNext(sor.block, obj);
244         }
245         if (obj) {
246             unsigned pos = obj == eor.obj ? eor.pos : UINT_MAX;
247             if (obj == endOfLine.obj && endOfLine.pos <= pos) {
248                 reachedEndOfLine = true;
249                 pos = endOfLine.pos;
250             }
251             // It's OK to add runs for zero-length RenderObjects, just don't make the run larger than it should be
252             int end = obj->length() ? pos+1 : 0;
253             RenderBlock::appendRunsForObject(start, end, obj, *this);
254         }
255 
256         eor.increment();
257         sor = eor;
258     }
259 
260     m_direction = WTF::Unicode::OtherNeutral;
261     m_status.eor = WTF::Unicode::OtherNeutral;
262 }
263 
264 }
265 
266 #endif // InlineIterator_h
267