OSDN Git Service

Merge WebKit at r78450: Initial merge by git.
[android-x86/external-webkit.git] / Source / WebCore / rendering / RenderRubyRun.cpp
1 /*
2  * Copyright (C) 2009 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32
33 #include "RenderRubyRun.h"
34
35 #include "RenderRubyBase.h"
36 #include "RenderRubyText.h"
37 #include "RenderView.h"
38
39 using namespace std;
40
41 namespace WebCore {
42
43 RenderRubyRun::RenderRubyRun(Node* node)
44     : RenderBlock(node)
45 {
46     setReplaced(true);
47     setInline(true);
48 }
49
50 RenderRubyRun::~RenderRubyRun()
51 {
52 }
53
54 bool RenderRubyRun::hasRubyText() const
55 {
56     // The only place where a ruby text can be is in the first position
57     // Note: As anonymous blocks, ruby runs do not have ':before' or ':after' content themselves.
58     return firstChild() && firstChild()->isRubyText();
59 }
60
61 bool RenderRubyRun::hasRubyBase() const
62 {
63     // The only place where a ruby base can be is in the last position
64     // Note: As anonymous blocks, ruby runs do not have ':before' or ':after' content themselves.
65     return lastChild() && lastChild()->isRubyBase();
66 }
67
68 bool RenderRubyRun::isEmpty() const
69 {
70     return !hasRubyText() && !hasRubyBase();
71 }
72
73 RenderRubyText* RenderRubyRun::rubyText() const
74 {
75     RenderObject* child = firstChild();
76     return child && child->isRubyText() ? static_cast<RenderRubyText*>(child) : 0;
77 }
78
79 RenderRubyBase* RenderRubyRun::rubyBase() const
80 {
81     RenderObject* child = lastChild();
82     return child && child->isRubyBase() ? static_cast<RenderRubyBase*>(child) : 0;
83 }
84
85 RenderRubyBase* RenderRubyRun::rubyBaseSafe()
86 {
87     RenderRubyBase* base = rubyBase();
88     if (!base) {
89         base = createRubyBase();
90         RenderBlock::addChild(base);
91     }
92     return base;
93 }
94
95 RenderBlock* RenderRubyRun::firstLineBlock() const
96 {
97     return 0;
98 }
99
100 void RenderRubyRun::updateFirstLetter()
101 {
102 }
103
104 bool RenderRubyRun::isChildAllowed(RenderObject* child, RenderStyle*) const
105 {
106     return child->isRubyText() || child->isInline();
107 }
108
109 void RenderRubyRun::addChild(RenderObject* child, RenderObject* beforeChild)
110 {
111     ASSERT(child);
112
113     // If child is a ruby text
114     if (child->isRubyText()) {
115         if (!beforeChild) {
116             // RenderRuby has already ascertained that we can add the child here.
117             ASSERT(!hasRubyText());
118             // prepend ruby texts as first child
119             RenderBlock::addChild(child, firstChild());
120         }  else if (beforeChild->isRubyText()) {
121             // New text is inserted just before another.
122             // In this case the new text takes the place of the old one, and
123             // the old text goes into a new run that is inserted as next sibling.
124             ASSERT(beforeChild->parent() == this);
125             RenderObject* ruby = parent();
126             ASSERT(ruby->isRuby());
127             RenderBlock* newRun = staticCreateRubyRun(ruby);
128             ruby->addChild(newRun, nextSibling());
129             // Add the new ruby text and move the old one to the new run
130             // Note: Doing it in this order and not using RenderRubyRun's methods,
131             // in order to avoid automatic removal of the ruby run in case there is no
132             // other child besides the old ruby text.
133             RenderBlock::addChild(child, beforeChild);
134             RenderBlock::removeChild(beforeChild);
135             newRun->addChild(beforeChild);
136         } else {
137             if (hasRubyBase()) {
138                 // Insertion before a ruby base object.
139                 // In this case we need insert a new run before the current one and split the base.
140                 RenderObject* ruby = parent();
141                 RenderRubyRun* newRun = staticCreateRubyRun(ruby);
142                 ruby->addChild(newRun, this);
143                 newRun->addChild(child);
144                 rubyBaseSafe()->moveChildren(newRun->rubyBaseSafe(), beforeChild);
145             }
146         }
147     } else {
148         // child is not a text -> insert it into the base
149         // (append it instead if beforeChild is the ruby text)
150         if (beforeChild && beforeChild->isRubyText())
151             beforeChild = 0;
152         rubyBaseSafe()->addChild(child, beforeChild);
153     }
154 }
155
156 void RenderRubyRun::removeChild(RenderObject* child)
157 {
158     // If the child is a ruby text, then merge the ruby base with the base of
159     // the right sibling run, if possible.
160     if (!beingDestroyed() && !documentBeingDestroyed() && child->isRubyText()) {
161         RenderRubyBase* base = rubyBase();
162         RenderObject* rightNeighbour = nextSibling();
163         if (base && rightNeighbour && rightNeighbour->isRubyRun()) {
164             // Ruby run without a base can happen only at the first run.
165             RenderRubyRun* rightRun = static_cast<RenderRubyRun*>(rightNeighbour);
166             if (rightRun->hasRubyBase()) {
167                 RenderRubyBase* rightBase = rightRun->rubyBaseSafe();
168                 // Collect all children in a single base, then swap the bases.
169                 rightBase->moveChildren(base);
170                 moveChildTo(rightRun, base);
171                 rightRun->moveChildTo(this, rightBase);
172                 // The now empty ruby base will be removed below.
173             }
174         }
175     }
176
177     RenderBlock::removeChild(child);
178
179     if (!beingDestroyed() && !documentBeingDestroyed()) {
180         // Check if our base (if any) is now empty. If so, destroy it.
181         RenderBlock* base = rubyBase();
182         if (base && !base->firstChild()) {
183             RenderBlock::removeChild(base);
184             base->deleteLineBoxTree();
185             base->destroy();
186         }
187
188         // If any of the above leaves the run empty, destroy it as well.
189         if (isEmpty()) {
190             parent()->removeChild(this);
191             deleteLineBoxTree();
192             destroy();
193         }
194     }
195 }
196
197 RenderRubyBase* RenderRubyRun::createRubyBase() const
198 {
199     RenderRubyBase* rb = new (renderArena()) RenderRubyBase(document() /* anonymous */);
200     RefPtr<RenderStyle> newStyle = RenderStyle::create();
201     newStyle->inheritFrom(style());
202     newStyle->setDisplay(BLOCK);
203     newStyle->setTextAlign(CENTER); // FIXME: use WEBKIT_CENTER?
204     rb->setStyle(newStyle.release());
205     return rb;
206 }
207
208 RenderRubyRun* RenderRubyRun::staticCreateRubyRun(const RenderObject* parentRuby)
209 {
210     ASSERT(parentRuby && parentRuby->isRuby());
211     RenderRubyRun* rr = new (parentRuby->renderArena()) RenderRubyRun(parentRuby->document() /* anonymous */);
212     RefPtr<RenderStyle> newStyle = RenderStyle::create();
213     newStyle->inheritFrom(parentRuby->style());
214     newStyle->setDisplay(INLINE_BLOCK);
215     rr->setStyle(newStyle.release());
216     return rr;
217 }
218
219 RenderObject* RenderRubyRun::layoutSpecialExcludedChild(bool relayoutChildren)
220 {
221     // Don't bother positioning the RenderRubyRun yet.
222     RenderRubyText* rt = rubyText();
223     if (!rt)
224         return 0;
225     if (relayoutChildren)
226         rt->setChildNeedsLayout(true, false);
227     rt->layoutIfNeeded();
228     return rt;
229 }
230
231 void RenderRubyRun::layout()
232 {
233     RenderBlock::layout();
234     
235     // Place the RenderRubyText such that its bottom is flush with the lineTop of the first line of the RenderRubyBase.
236     RenderRubyText* rt = rubyText();
237     if (!rt)
238         return;
239     
240     int lastLineRubyTextBottom = rt->logicalHeight();
241     int firstLineRubyTextTop = 0;
242     RootInlineBox* rootBox = rt->lastRootBox();
243     if (rootBox) {
244         // In order to align, we have to ignore negative leading.
245         firstLineRubyTextTop = rt->firstRootBox()->logicalTopLayoutOverflow();
246         lastLineRubyTextBottom = rootBox->logicalBottomLayoutOverflow();
247     }
248
249     if (!style()->isFlippedLinesWritingMode()) {
250         int firstLineTop = 0;
251         if (RenderRubyBase* rb = rubyBase()) {
252             RootInlineBox* rootBox = rb->firstRootBox();
253             if (rootBox)
254                 firstLineTop = rootBox->logicalTopLayoutOverflow();
255             firstLineTop += rb->logicalTop();
256         }
257         
258         rt->setLogicalTop(-lastLineRubyTextBottom + firstLineTop);
259     } else {
260         int lastLineBottom = logicalHeight();
261         if (RenderRubyBase* rb = rubyBase()) {
262             RootInlineBox* rootBox = rb->lastRootBox();
263             if (rootBox)
264                 lastLineBottom = rootBox->logicalBottomLayoutOverflow();
265             lastLineBottom += rb->logicalTop();
266         }
267
268         rt->setLogicalTop(-firstLineRubyTextTop + lastLineBottom);
269     }
270
271     // Update our overflow to account for the new RenderRubyText position.
272     m_overflow.clear();
273     computeOverflow(clientLogicalBottom());
274 }
275
276 } // namespace WebCore