Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / WebKit / Source / core / layout / BidiRunForLine.cpp
blob3a65ac884ed7ad21d7875979973e73040abc2f0a
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.
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
27 #include "config.h"
28 #include "core/layout/BidiRunForLine.h"
30 #include "core/layout/line/InlineIterator.h"
32 namespace blink {
34 using namespace WTF::Unicode;
36 static LayoutObject* firstLayoutObjectForDirectionalityDetermination(
37 LayoutObject* root, LayoutObject* current = nullptr)
39 LayoutObject* next = current;
40 while (current) {
41 if (isIsolated(current->style()->unicodeBidi())
42 && (current->isLayoutInline() || current->isLayoutBlock())) {
43 if (current != root)
44 current = nullptr;
45 else
46 current = next;
47 break;
49 current = current->parent();
52 if (!current)
53 current = root->slowFirstChild();
55 while (current) {
56 next = nullptr;
57 if (isIteratorTarget(LineLayoutItem(current)) && !(current->isText()
58 && toLayoutText(current)->isAllCollapsibleWhitespace()))
59 break;
61 if (!isIteratorTarget(LineLayoutItem(current))
62 && !isIsolated(current->style()->unicodeBidi()))
63 next = current->slowFirstChild();
65 if (!next) {
66 while (current && current != root) {
67 next = current->nextSibling();
68 if (next)
69 break;
70 current = current->parent();
74 if (!next)
75 break;
77 current = next;
80 return current;
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,
97 bool isOverride)
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);
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;
149 while (true) {
150 if (topResolver.isolatedRuns().isEmpty()) {
151 if (isolatedRunsStack.isEmpty())
152 break;
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
160 // resolve them all.
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(
182 isolatedRun);
183 EUnicodeBidi unicodeBidi = isolatedInline->style()->unicodeBidi();
184 TextDirection direction;
185 if (unicodeBidi == Plaintext) {
186 direction = determinePlaintextDirectionality(isolatedInline,
187 isNewUBAParagraph ? startObj : 0);
188 } else {
189 ASSERT(unicodeBidi == Isolate || unicodeBidi == IsolateOverride);
190 direction = isolatedInline->style()->direction();
192 isolatedResolver.setStatus(statusWithDirection(direction,
193 isOverride(unicodeBidi)));
195 setupResolverToResumeInIsolate(isolatedResolver, isolatedInline,
196 startObj);
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
218 // processing.
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);
229 } // namespace blink
231 #endif // BidiRunForLine_h