2 * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
3 * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc.
5 * Copyright (C) 2010 Google Inc. All rights reserved.
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.
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.
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.
24 #ifndef BidiRunForLine_h
25 #define BidiRunForLine_h
28 #include "core/layout/BidiRunForLine.h"
30 #include "core/layout/line/InlineIterator.h"
34 using namespace WTF::Unicode
;
36 static LayoutObject
* firstLayoutObjectForDirectionalityDetermination(
37 LayoutObject
* root
, LayoutObject
* current
= nullptr)
39 LayoutObject
* next
= current
;
41 if (isIsolated(current
->style()->unicodeBidi())
42 && (current
->isLayoutInline() || current
->isLayoutBlock())) {
49 current
= current
->parent();
53 current
= root
->slowFirstChild();
57 if (isIteratorTarget(LineLayoutItem(current
)) && !(current
->isText()
58 && toLayoutText(current
)->isAllCollapsibleWhitespace()))
61 if (!isIteratorTarget(LineLayoutItem(current
))
62 && !isIsolated(current
->style()->unicodeBidi()))
63 next
= current
->slowFirstChild();
66 while (current
&& current
!= root
) {
67 next
= current
->nextSibling();
70 current
= current
->parent();
83 TextDirection
determinePlaintextDirectionality(LayoutObject
* root
,
84 LayoutObject
* current
= 0, unsigned pos
= 0)
86 LayoutObject
* firstLayoutObject
= firstLayoutObjectForDirectionalityDetermination(root
, current
);
87 InlineIterator
iter(LineLayoutItem(root
), LineLayoutItem(firstLayoutObject
), firstLayoutObject
== current
? pos
: 0);
88 InlineBidiResolver observer
;
89 observer
.setStatus(BidiStatus(root
->style()->direction(),
90 isOverride(root
->style()->unicodeBidi())));
91 observer
.setPositionIgnoringNestedIsolates(iter
);
92 return observer
.determineParagraphDirectionality();
95 // FIXME: This should be a BidiStatus constructor or create method.
96 static inline BidiStatus
statusWithDirection(TextDirection textDirection
,
99 WTF::Unicode::Direction direction
= textDirection
== LTR
102 RefPtr
<BidiContext
> context
= BidiContext::create(
103 textDirection
== LTR
? 0 : 1, direction
, isOverride
, FromStyleOrDOM
);
105 // This copies BidiStatus and may churn the ref on BidiContext.
106 // I doubt it matters.
107 return BidiStatus(direction
, direction
, direction
, context
.release());
110 static inline void setupResolverToResumeInIsolate(InlineBidiResolver
& resolver
,
111 LayoutObject
* root
, LayoutObject
* startObject
)
113 if (root
!= startObject
) {
114 LayoutObject
* parent
= startObject
->parent();
115 setupResolverToResumeInIsolate(resolver
, root
, parent
);
116 notifyObserverEnteredObject(&resolver
, LineLayoutItem(startObject
));
120 static void restoreIsolatedMidpointStates(InlineBidiResolver
& topResolver
,
121 InlineBidiResolver
& isolatedResolver
)
123 while (!isolatedResolver
.isolatedRuns().isEmpty()) {
124 BidiRun
* run
= isolatedResolver
.isolatedRuns().last();
125 isolatedResolver
.isolatedRuns().removeLast();
126 topResolver
.setMidpointStateForIsolatedRun(run
,
127 isolatedResolver
.midpointStateForIsolatedRun(run
));
131 void constructBidiRunsForLine(InlineBidiResolver
& topResolver
,
132 BidiRunList
<BidiRun
>& bidiRuns
, const InlineIterator
& endOfLine
,
133 VisualDirectionOverride override
, bool previousLineBrokeCleanly
,
134 bool isNewUBAParagraph
)
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 const LayoutObject
* currentRoot
= topResolver
.position().root();
141 topResolver
.createBidiRunsForLine(endOfLine
, override
,
142 previousLineBrokeCleanly
);
143 struct BidiRunsWithRoot
{
144 const LayoutObject
* root
;
145 Vector
<BidiRun
*> isolatedRuns
;
147 Vector
<BidiRunsWithRoot
> isolatedRunsStack
;
150 if (topResolver
.isolatedRuns().isEmpty()) {
151 if (isolatedRunsStack
.isEmpty())
153 topResolver
.isolatedRuns().appendVector(isolatedRunsStack
.last().isolatedRuns
);
154 ASSERT(!topResolver
.isolatedRuns().isEmpty());
155 currentRoot
= isolatedRunsStack
.last().root
;
156 isolatedRunsStack
.removeLast();
159 // It does not matter which order we resolve the runs as long as we
161 BidiRun
* isolatedRun
= topResolver
.isolatedRuns().last();
162 topResolver
.isolatedRuns().removeLast();
164 LayoutObject
* startObj
= isolatedRun
->object();
166 // Only inlines make sense with unicode-bidi: isolate (blocks are
167 // already isolated).
168 // FIXME: Because enterIsolate is not passed a LayoutObject, we have to
169 // crawl up the tree to see which parent inline is the isolate. We could
170 // change enterIsolate to take a LayoutObject and do this logic there,
171 // but that would be a layering violation for BidiResolver (which knows
172 // nothing about LayoutObject).
173 LayoutInline
* isolatedInline
= toLayoutInline(
174 highestContainingIsolateWithinRoot(LineLayoutItem(startObj
),
175 LineLayoutItem(const_cast<LayoutObject
*>(currentRoot
))));
176 ASSERT(isolatedInline
);
178 InlineBidiResolver isolatedResolver
;
179 LineMidpointState
& isolatedLineMidpointState
=
180 isolatedResolver
.midpointState();
181 isolatedLineMidpointState
= topResolver
.midpointStateForIsolatedRun(
183 EUnicodeBidi unicodeBidi
= isolatedInline
->style()->unicodeBidi();
184 TextDirection direction
;
185 if (unicodeBidi
== Plaintext
) {
186 direction
= determinePlaintextDirectionality(isolatedInline
,
187 isNewUBAParagraph
? startObj
: 0);
189 ASSERT(unicodeBidi
== Isolate
|| unicodeBidi
== IsolateOverride
);
190 direction
= isolatedInline
->style()->direction();
192 isolatedResolver
.setStatus(statusWithDirection(direction
,
193 isOverride(unicodeBidi
)));
195 setupResolverToResumeInIsolate(isolatedResolver
, isolatedInline
,
198 // The starting position is the beginning of the first run within the
199 // isolate that was identified during the earlier call to
200 // createBidiRunsForLine. This can be but is not necessarily the first
201 // run within the isolate.
202 InlineIterator iter
= InlineIterator(LineLayoutItem(isolatedInline
), LineLayoutItem(startObj
),
203 isolatedRun
->m_start
);
204 isolatedResolver
.setPositionIgnoringNestedIsolates(iter
);
205 // We stop at the next end of line; we may re-enter this isolate in the
206 // next call to constructBidiRuns().
207 // FIXME: What should end and previousLineBrokeCleanly be?
208 // rniwa says previousLineBrokeCleanly is just a WinIE hack and could
209 // always be false here?
210 isolatedResolver
.createBidiRunsForLine(endOfLine
, NoVisualOverride
,
211 previousLineBrokeCleanly
);
213 ASSERT(isolatedResolver
.runs().runCount());
214 if (isolatedResolver
.runs().runCount())
215 bidiRuns
.replaceRunWithRuns(isolatedRun
, isolatedResolver
.runs());
217 // If we encountered any nested isolate runs, save them for later
219 if (!isolatedResolver
.isolatedRuns().isEmpty()) {
220 isolatedRunsStack
.resize(isolatedRunsStack
.size() + 1);
221 isolatedRunsStack
.last().isolatedRuns
.appendVector(
222 isolatedResolver
.isolatedRuns());
223 isolatedRunsStack
.last().root
= isolatedInline
;
224 restoreIsolatedMidpointStates(topResolver
, isolatedResolver
);
231 #endif // BidiRunForLine_h