OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2009 Google Inc. All rights reserved. | 2 * Copyright (C) 2009 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
(...skipping 30 matching lines...) Expand all Loading... |
41 | 41 |
42 RenderRubyBase::~RenderRubyBase() | 42 RenderRubyBase::~RenderRubyBase() |
43 { | 43 { |
44 } | 44 } |
45 | 45 |
46 bool RenderRubyBase::isChildAllowed(RenderObject* child, RenderStyle*) const | 46 bool RenderRubyBase::isChildAllowed(RenderObject* child, RenderStyle*) const |
47 { | 47 { |
48 return child->isInline(); | 48 return child->isInline(); |
49 } | 49 } |
50 | 50 |
51 void RenderRubyBase::splitToLeft(RenderBlock* leftBase, RenderObject* beforeChil
d) | 51 bool RenderRubyBase::hasOnlyWrappedInlineChildren(RenderObject* beforeChild) con
st |
| 52 { |
| 53 // Tests whether all children in the base before beforeChild are either floa
ted/positioned, |
| 54 // or inline objects wrapped in anonymous blocks. |
| 55 // Note that beforeChild may be 0, in which case all children are looked at. |
| 56 for (RenderObject* child = firstChild(); child != beforeChild; child = child
->nextSibling()) { |
| 57 if (!child->isFloatingOrPositioned() && !(child->isAnonymousBlock() && c
hild->childrenInline())) |
| 58 return false; |
| 59 } |
| 60 return true; |
| 61 } |
| 62 |
| 63 void RenderRubyBase::moveChildren(RenderRubyBase* toBase, RenderObject* fromBefo
reChild) |
52 { | 64 { |
53 // This function removes all children that are before (!) beforeChild | 65 // This function removes all children that are before (!) beforeChild |
54 // and appends them to leftBase. | 66 // and appends them to toBase. |
55 ASSERT(leftBase); | 67 ASSERT(toBase); |
| 68 |
| 69 // First make sure that beforeChild (if set) is indeed a direct child of thi
s. |
| 70 // Inline children might be wrapped in an anonymous block if there's a conti
nuation. |
| 71 // Theoretically, in ruby bases, this can happen with only the first such a
child, |
| 72 // so it should be OK to just climb the tree. |
| 73 while (fromBeforeChild && fromBeforeChild->parent() != this) |
| 74 fromBeforeChild = fromBeforeChild->parent(); |
56 | 75 |
57 // First make sure that beforeChild (if set) is indeed a direct child of thi
s. | 76 if (childrenInline()) |
58 // Fallback: climb up the tree to make sure. This may result in somewhat inc
orrect rendering. | 77 moveInlineChildren(toBase, fromBeforeChild); |
59 // FIXME: Can this happen? Is there a better/more correct way to solve this? | 78 else |
60 ASSERT(!beforeChild || beforeChild->parent() == this); | 79 moveBlockChildren(toBase, fromBeforeChild); |
61 while (beforeChild && beforeChild->parent() != this) | |
62 beforeChild = beforeChild->parent(); | |
63 | 80 |
64 RenderObject* child = firstChild(); | 81 setNeedsLayoutAndPrefWidthsRecalc(); |
65 while (child != beforeChild) { | 82 toBase->setNeedsLayoutAndPrefWidthsRecalc(); |
66 RenderObject* nextChild = child->nextSibling(); | |
67 moveChildTo(leftBase, leftBase->children(), child); | |
68 child = nextChild; | |
69 } | |
70 } | 83 } |
71 | 84 |
72 void RenderRubyBase::mergeWithRight(RenderBlock* rightBase) | 85 void RenderRubyBase::moveInlineChildren(RenderRubyBase* toBase, RenderObject* fr
omBeforeChild) |
73 { | 86 { |
74 // This function removes all children and prepends (!) them to rightBase. | 87 RenderBlock* toBlock; |
75 ASSERT(rightBase); | |
76 | 88 |
77 RenderObject* firstPos = rightBase->firstChild(); | 89 if (toBase->childrenInline()) { |
78 RenderObject* child = lastChild(); | 90 // The standard and easy case: move the children into the target base |
79 while (child) { | 91 toBlock = toBase; |
80 moveChildTo(rightBase, rightBase->children(), firstPos, child); | 92 } else { |
81 firstPos = child; | 93 // We need to wrap the inline objects into an anonymous block. |
82 child = lastChild(); | 94 // If toBase has a suitable block, we re-use it, otherwise create a new
one. |
| 95 RenderObject* lastChild = toBase->lastChild(); |
| 96 if (lastChild && lastChild->isAnonymousBlock() && lastChild->childrenInl
ine()) |
| 97 toBlock = toRenderBlock(lastChild); |
| 98 else { |
| 99 toBlock = toBase->createAnonymousBlock(); |
| 100 toBase->children()->appendChildNode(toBase, toBlock); |
| 101 } |
83 } | 102 } |
| 103 // Move our inline children into the target block we determined above. |
| 104 for (RenderObject* child = firstChild(); child != fromBeforeChild; child = f
irstChild()) |
| 105 moveChildTo(toBlock, toBlock->children(), child); |
| 106 } |
| 107 |
| 108 void RenderRubyBase::moveBlockChildren(RenderRubyBase* toBase, RenderObject* fro
mBeforeChild) |
| 109 { |
| 110 if (toBase->childrenInline()) { |
| 111 // First check whether we move only wrapped inline objects. |
| 112 if (hasOnlyWrappedInlineChildren(fromBeforeChild)) { |
| 113 // The reason why the base is in block flow must be after beforeChil
d. |
| 114 // We therefore can extract the inline objects and move them to toBa
se. |
| 115 for (RenderObject* child = firstChild(); child != fromBeforeChild; c
hild = firstChild()) { |
| 116 if (child->isAnonymousBlock()) { |
| 117 RenderBlock* anonBlock = toRenderBlock(child); |
| 118 ASSERT(anonBlock->childrenInline()); |
| 119 ASSERT(!anonBlock->inlineContinuation()); |
| 120 anonBlock->moveAllChildrenTo(toBase, toBase->children()); |
| 121 anonBlock->deleteLineBoxTree(); |
| 122 anonBlock->destroy(); |
| 123 } else { |
| 124 ASSERT(child->isFloatingOrPositioned()); |
| 125 moveChildTo(toBase, toBase->children(), child); |
| 126 } |
| 127 } |
| 128 } else { |
| 129 // Moving block children -> have to set toBase as block flow |
| 130 toBase->makeChildrenNonInline(); |
| 131 // Move children, potentially collapsing anonymous block wrappers. |
| 132 mergeBlockChildren(toBase, fromBeforeChild); |
| 133 |
| 134 // Now we need to check if the leftover children are all inline. |
| 135 // If so, make this base inline again. |
| 136 if (hasOnlyWrappedInlineChildren()) { |
| 137 RenderObject* next = 0; |
| 138 for (RenderObject* child = firstChild(); child; child = next) { |
| 139 next = child->nextSibling(); |
| 140 if (child->isFloatingOrPositioned()) |
| 141 continue; |
| 142 ASSERT(child->isAnonymousBlock()); |
| 143 |
| 144 RenderBlock* anonBlock = toRenderBlock(child); |
| 145 ASSERT(anonBlock->childrenInline()); |
| 146 ASSERT(!anonBlock->inlineContinuation()); |
| 147 // Move inline children out of anonymous block. |
| 148 anonBlock->moveAllChildrenTo(this, children(), anonBlock); |
| 149 anonBlock->deleteLineBoxTree(); |
| 150 anonBlock->destroy(); |
| 151 } |
| 152 setChildrenInline(true); |
| 153 } |
| 154 } |
| 155 } else |
| 156 mergeBlockChildren(toBase, fromBeforeChild); |
| 157 } |
| 158 |
| 159 void RenderRubyBase::mergeBlockChildren(RenderRubyBase* toBase, RenderObject* fr
omBeforeChild) |
| 160 { |
| 161 // This function removes all children that are before fromBeforeChild and ap
pends them to toBase. |
| 162 ASSERT(!childrenInline()); |
| 163 ASSERT(toBase); |
| 164 ASSERT(!toBase->childrenInline()); |
| 165 |
| 166 // Quick check whether we have anything to do, to simplify the following cod
e. |
| 167 if (fromBeforeChild != firstChild()) |
| 168 return; |
| 169 |
| 170 // If an anonymous block would be put next to another such block, then merge
those. |
| 171 RenderObject* firstChildHere = firstChild(); |
| 172 RenderObject* lastChildThere = toBase->lastChild(); |
| 173 if (firstChildHere && firstChildHere->isAnonymousBlock() && firstChildHere->
childrenInline() |
| 174 && lastChildThere && lastChildThere->isAnonymousBlock() && lastChild
There->childrenInline()) { |
| 175 RenderBlock* anonBlockHere = toRenderBlock(firstChildHere); |
| 176 RenderBlock* anonBlockThere = toRenderBlock(lastChildThere); |
| 177 anonBlockHere->moveAllChildrenTo(anonBlockThere, anonBlockThere->childre
n()); |
| 178 anonBlockHere->deleteLineBoxTree(); |
| 179 anonBlockHere->destroy(); |
| 180 } |
| 181 // Move all remaining children normally. |
| 182 for (RenderObject* child = firstChild(); child != fromBeforeChild; child = f
irstChild()) |
| 183 moveChildTo(toBase, toBase->children(), child); |
84 } | 184 } |
85 | 185 |
86 } // namespace WebCore | 186 } // namespace WebCore |
OLD | NEW |