• 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, 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