2 * Copyright (C) 2009 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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
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.
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.
33 #include "core/layout/LayoutRuby.h"
35 #include "core/frame/UseCounter.h"
36 #include "core/layout/LayoutRubyRun.h"
40 // === generic helper functions to avoid excessive code duplication ===
42 static LayoutRubyRun
* lastRubyRun(const LayoutObject
* ruby
)
44 LayoutObject
* child
= ruby
->slowLastChild();
45 ASSERT(!child
|| child
->isRubyRun());
46 return toLayoutRubyRun(child
);
49 static inline LayoutRubyRun
* findRubyRunParent(LayoutObject
* child
)
51 while (child
&& !child
->isRubyRun())
52 child
= child
->parent();
53 return toLayoutRubyRun(child
);
56 // === ruby as inline object ===
58 LayoutRubyAsInline::LayoutRubyAsInline(Element
* element
)
59 : LayoutInline(element
)
61 UseCounter::count(document(), UseCounter::RenderRuby
);
64 LayoutRubyAsInline::~LayoutRubyAsInline()
68 void LayoutRubyAsInline::styleDidChange(StyleDifference diff
, const ComputedStyle
* oldStyle
)
70 LayoutInline::styleDidChange(diff
, oldStyle
);
71 propagateStyleToAnonymousChildren();
74 void LayoutRubyAsInline::addChild(LayoutObject
* child
, LayoutObject
* beforeChild
)
76 // If the child is a ruby run, just add it normally.
77 if (child
->isRubyRun()) {
78 LayoutInline::addChild(child
, beforeChild
);
83 // insert child into run
84 LayoutObject
* run
= beforeChild
;
85 while (run
&& !run
->isRubyRun())
88 if (beforeChild
== run
)
89 beforeChild
= toLayoutRubyRun(beforeChild
)->firstChild();
90 ASSERT(!beforeChild
|| beforeChild
->isDescendantOf(run
));
91 run
->addChild(child
, beforeChild
);
94 ASSERT_NOT_REACHED(); // beforeChild should always have a run as parent!
95 // Emergency fallback: fall through and just append.
98 // If the new child would be appended, try to add the child to the previous run
99 // if possible, or create a new run otherwise.
100 // (The LayoutRubyRun object will handle the details)
101 LayoutRubyRun
* lastRun
= lastRubyRun(this);
102 if (!lastRun
|| lastRun
->hasRubyText()) {
103 lastRun
= LayoutRubyRun::staticCreateRubyRun(this);
104 LayoutInline::addChild(lastRun
, beforeChild
);
106 lastRun
->addChild(child
);
109 void LayoutRubyAsInline::removeChild(LayoutObject
* child
)
111 // If the child's parent is *this (must be a ruby run), just use the normal remove method.
112 if (child
->parent() == this) {
113 ASSERT(child
->isRubyRun());
114 LayoutInline::removeChild(child
);
118 // Otherwise find the containing run and remove it from there.
119 LayoutRubyRun
* run
= findRubyRunParent(child
);
121 run
->removeChild(child
);
124 // === ruby as block object ===
126 LayoutRubyAsBlock::LayoutRubyAsBlock(Element
* element
)
127 : LayoutBlockFlow(element
)
129 UseCounter::count(document(), UseCounter::RenderRuby
);
132 LayoutRubyAsBlock::~LayoutRubyAsBlock()
136 void LayoutRubyAsBlock::styleDidChange(StyleDifference diff
, const ComputedStyle
* oldStyle
)
138 LayoutBlockFlow::styleDidChange(diff
, oldStyle
);
139 propagateStyleToAnonymousChildren();
142 void LayoutRubyAsBlock::addChild(LayoutObject
* child
, LayoutObject
* beforeChild
)
144 // If the child is a ruby run, just add it normally.
145 if (child
->isRubyRun()) {
146 LayoutBlockFlow::addChild(child
, beforeChild
);
151 // insert child into run
152 LayoutObject
* run
= beforeChild
;
153 while (run
&& !run
->isRubyRun())
156 if (beforeChild
== run
)
157 beforeChild
= toLayoutRubyRun(beforeChild
)->firstChild();
158 ASSERT(!beforeChild
|| beforeChild
->isDescendantOf(run
));
159 run
->addChild(child
, beforeChild
);
162 ASSERT_NOT_REACHED(); // beforeChild should always have a run as parent!
163 // Emergency fallback: fall through and just append.
166 // If the new child would be appended, try to add the child to the previous run
167 // if possible, or create a new run otherwise.
168 // (The LayoutRubyRun object will handle the details)
169 LayoutRubyRun
* lastRun
= lastRubyRun(this);
170 if (!lastRun
|| lastRun
->hasRubyText()) {
171 lastRun
= LayoutRubyRun::staticCreateRubyRun(this);
172 LayoutBlockFlow::addChild(lastRun
, beforeChild
);
174 lastRun
->addChild(child
);
177 void LayoutRubyAsBlock::removeChild(LayoutObject
* child
)
179 // If the child's parent is *this (must be a ruby run), just use the normal remove method.
180 if (child
->parent() == this) {
181 ASSERT(child
->isRubyRun());
182 LayoutBlockFlow::removeChild(child
);
186 // Otherwise find the containing run and remove it from there.
187 LayoutRubyRun
* run
= findRubyRunParent(child
);
189 run
->removeChild(child
);