1 /*
2 * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
3 * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc.
4 * All right reserved.
5 * Copyright (C) 2010 Google Inc. All rights reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 *
22 */
23
24 #ifndef BidiRunForLine_h
25 #define BidiRunForLine_h
26
27 #include "config.h"
28 #include "core/rendering/BidiRunForLine.h"
29
30 #include "core/rendering/InlineIterator.h"
31
32 namespace blink {
33
34 using namespace WTF::Unicode;
35
firstRenderObjectForDirectionalityDetermination(RenderObject * root,RenderObject * current=0)36 static RenderObject* firstRenderObjectForDirectionalityDetermination(
37 RenderObject* root, RenderObject* current = 0)
38 {
39 RenderObject* next = current;
40 while (current) {
41 if (isIsolated(current->style()->unicodeBidi())
42 && (current->isRenderInline() || current->isRenderBlock())) {
43 if (current != root)
44 current = 0;
45 else
46 current = next;
47 break;
48 }
49 current = current->parent();
50 }
51
52 if (!current)
53 current = root->slowFirstChild();
54
55 while (current) {
56 next = 0;
57 if (isIteratorTarget(current) && !(current->isText()
58 && toRenderText(current)->isAllCollapsibleWhitespace()))
59 break;
60
61 if (!isIteratorTarget(current)
62 && !isIsolated(current->style()->unicodeBidi()))
63 next = current->slowFirstChild();
64
65 if (!next) {
66 while (current && current != root) {
67 next = current->nextSibling();
68 if (next)
69 break;
70 current = current->parent();
71 }
72 }
73
74 if (!next)
75 break;
76
77 current = next;
78 }
79
80 return current;
81 }
82
determinePlaintextDirectionality(RenderObject * root,RenderObject * current=0,unsigned pos=0)83 TextDirection determinePlaintextDirectionality(RenderObject* root,
84 RenderObject* current = 0, unsigned pos = 0)
85 {
86 InlineIterator iter(root,
87 firstRenderObjectForDirectionalityDetermination(root, current), pos);
88 InlineBidiResolver observer;
89 observer.setStatus(BidiStatus(root->style()->direction(),
90 isOverride(root->style()->unicodeBidi())));
91 observer.setPositionIgnoringNestedIsolates(iter);
92 return observer.determineParagraphDirectionality();
93 }
94
95 // FIXME: This should be a BidiStatus constructor or create method.
statusWithDirection(TextDirection textDirection,bool isOverride)96 static inline BidiStatus statusWithDirection(TextDirection textDirection,
97 bool isOverride)
98 {
99 WTF::Unicode::Direction direction = textDirection == LTR
100 ? LeftToRight
101 : RightToLeft;
102 RefPtr<BidiContext> context = BidiContext::create(
103 textDirection == LTR ? 0 : 1, direction, isOverride, FromStyleOrDOM);
104
105 // This copies BidiStatus and may churn the ref on BidiContext.
106 // I doubt it matters.
107 return BidiStatus(direction, direction, direction, context.release());
108 }
109
setupResolverToResumeInIsolate(InlineBidiResolver & resolver,RenderObject * root,RenderObject * startObject)110 static inline void setupResolverToResumeInIsolate(InlineBidiResolver& resolver,
111 RenderObject* root, RenderObject* startObject)
112 {
113 if (root != startObject) {
114 RenderObject* parent = startObject->parent();
115 setupResolverToResumeInIsolate(resolver, root, parent);
116 notifyObserverEnteredObject(&resolver, startObject);
117 }
118 }
119
restoreIsolatedMidpointStates(InlineBidiResolver & topResolver,InlineBidiResolver & isolatedResolver)120 static void restoreIsolatedMidpointStates(InlineBidiResolver& topResolver,
121 InlineBidiResolver& isolatedResolver)
122 {
123 while (!isolatedResolver.isolatedRuns().isEmpty()) {
124 BidiRun* run = isolatedResolver.isolatedRuns().last();
125 isolatedResolver.isolatedRuns().removeLast();
126 topResolver.setMidpointStateForIsolatedRun(run,
127 isolatedResolver.midpointStateForIsolatedRun(run));
128 }
129 }
130
constructBidiRunsForLine(InlineBidiResolver & topResolver,BidiRunList<BidiRun> & bidiRuns,const InlineIterator & endOfLine,VisualDirectionOverride override,bool previousLineBrokeCleanly,bool isNewUBAParagraph)131 void constructBidiRunsForLine(InlineBidiResolver& topResolver,
132 BidiRunList<BidiRun>& bidiRuns, const InlineIterator& endOfLine,
133 VisualDirectionOverride override, bool previousLineBrokeCleanly,
134 bool isNewUBAParagraph)
135 {
136 // FIXME: We should pass a BidiRunList into createBidiRunsForLine instead
137 // of the resolver owning the runs.
138 ASSERT(&topResolver.runs() == &bidiRuns);
139 ASSERT(topResolver.position() != endOfLine);
140 RenderObject* currentRoot = topResolver.position().root();
141 topResolver.createBidiRunsForLine(endOfLine, override,
142 previousLineBrokeCleanly);
143
144 while (!topResolver.isolatedRuns().isEmpty()) {
145 // It does not matter which order we resolve the runs as long as we
146 // resolve them all.
147 BidiRun* isolatedRun = topResolver.isolatedRuns().last();
148 topResolver.isolatedRuns().removeLast();
149
150 RenderObject* startObj = isolatedRun->object();
151
152 // Only inlines make sense with unicode-bidi: isolate (blocks are
153 // already isolated).
154 // FIXME: Because enterIsolate is not passed a RenderObject, we have to
155 // crawl up the tree to see which parent inline is the isolate. We could
156 // change enterIsolate to take a RenderObject and do this logic there,
157 // but that would be a layering violation for BidiResolver (which knows
158 // nothing about RenderObject).
159 RenderInline* isolatedInline = toRenderInline(
160 highestContainingIsolateWithinRoot(startObj, currentRoot));
161 ASSERT(isolatedInline);
162
163 InlineBidiResolver isolatedResolver;
164 LineMidpointState& isolatedLineMidpointState =
165 isolatedResolver.midpointState();
166 isolatedLineMidpointState = topResolver.midpointStateForIsolatedRun(
167 isolatedRun);
168 EUnicodeBidi unicodeBidi = isolatedInline->style()->unicodeBidi();
169 TextDirection direction;
170 if (unicodeBidi == Plaintext) {
171 direction = determinePlaintextDirectionality(isolatedInline,
172 isNewUBAParagraph ? startObj : 0);
173 } else {
174 ASSERT(unicodeBidi == Isolate || unicodeBidi == IsolateOverride);
175 direction = isolatedInline->style()->direction();
176 }
177 isolatedResolver.setStatus(statusWithDirection(direction,
178 isOverride(unicodeBidi)));
179
180 setupResolverToResumeInIsolate(isolatedResolver, isolatedInline,
181 startObj);
182
183 // The starting position is the beginning of the first run within the
184 // isolate that was identified during the earlier call to
185 // createBidiRunsForLine. This can be but is not necessarily the first
186 // run within the isolate.
187 InlineIterator iter = InlineIterator(isolatedInline, startObj,
188 isolatedRun->m_start);
189 isolatedResolver.setPositionIgnoringNestedIsolates(iter);
190 // We stop at the next end of line; we may re-enter this isolate in the
191 // next call to constructBidiRuns().
192 // FIXME: What should end and previousLineBrokeCleanly be?
193 // rniwa says previousLineBrokeCleanly is just a WinIE hack and could
194 // always be false here?
195 isolatedResolver.createBidiRunsForLine(endOfLine, NoVisualOverride,
196 previousLineBrokeCleanly);
197
198 ASSERT(isolatedResolver.runs().runCount());
199 if (isolatedResolver.runs().runCount())
200 bidiRuns.replaceRunWithRuns(isolatedRun, isolatedResolver.runs());
201
202 // If we encountered any nested isolate runs, just move them
203 // to the top resolver's list for later processing.
204 if (!isolatedResolver.isolatedRuns().isEmpty()) {
205 topResolver.isolatedRuns().appendVector(
206 isolatedResolver.isolatedRuns());
207 currentRoot = isolatedInline;
208 restoreIsolatedMidpointStates(topResolver, isolatedResolver);
209 }
210 }
211 }
212
213 } // namespace blink
214
215 #endif // BidiRunForLine_h
216