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 #if ENABLE(RUBY) 34 #include "RenderRuby.h" 35 36 #include "RenderRubyRun.h" 37 38 namespace WebCore { 39 40 //=== generic helper functions to avoid excessive code duplication === 41 42 static RenderRubyRun* lastRubyRun(const RenderObject* ruby) 43 { 44 RenderObject* child = ruby->lastChild(); 45 if (child && ruby->isAfterContent(child)) 46 child = child->previousSibling(); 47 ASSERT(!child || child->isRubyRun()); 48 return static_cast<RenderRubyRun*>(child); 49 } 50 51 static inline RenderRubyRun* findRubyRunParent(RenderObject* child) 52 { 53 while (child && !child->isRubyRun()) 54 child = child->parent(); 55 return static_cast<RenderRubyRun*>(child); 56 } 57 58 //=== ruby as inline object === 59 60 RenderRubyAsInline::RenderRubyAsInline(Node* node) 61 : RenderInline(node) 62 { 63 } 64 65 RenderRubyAsInline::~RenderRubyAsInline() 66 { 67 } 68 69 bool RenderRubyAsInline::isChildAllowed(RenderObject* child, RenderStyle*) const 70 { 71 return child->isRubyText() 72 || child->isRubyRun() 73 || child->isInline(); 74 } 75 76 void RenderRubyAsInline::addChild(RenderObject* child, RenderObject* beforeChild) 77 { 78 // Note: ':after' content is handled implicitely below 79 80 // if child is a ruby run, just add it normally 81 if (child->isRubyRun()) { 82 RenderInline::addChild(child, beforeChild); 83 return; 84 } 85 86 if (beforeChild && !isAfterContent(beforeChild)) { 87 // insert child into run 88 ASSERT(!beforeChild->isRubyRun()); 89 RenderRubyRun* run = findRubyRunParent(beforeChild); 90 ASSERT(run); // beforeChild should always have a run as parent 91 if (run) { 92 run->addChild(child, beforeChild); 93 return; 94 } 95 ASSERT(false); // beforeChild should always have a run as parent! 96 // Emergency fallback: fall through and just append. 97 } 98 99 // If the new child would be appended, try to add the child to the previous run 100 // if possible, or create a new run otherwise. 101 // (The RenderRubyRun object will handle the details) 102 RenderRubyRun* lastRun = lastRubyRun(this); 103 if (!lastRun || lastRun->hasRubyText()) { 104 lastRun = RenderRubyRun::staticCreateRubyRun(this); 105 RenderInline::addChild(lastRun); 106 } 107 lastRun->addChild(child); 108 } 109 110 void RenderRubyAsInline::removeChild(RenderObject* child) 111 { 112 // If the child's parent is *this, i.e. a ruby run or ':after' content, 113 // just use the normal remove method. 114 if (child->parent() == this) { 115 ASSERT(child->isRubyRun() || child->isAfterContent()); 116 RenderInline::removeChild(child); 117 return; 118 } 119 120 // Find the containing run 121 RenderRubyRun* run = findRubyRunParent(child); 122 ASSERT(run); 123 run->removeChild(child); 124 } 125 126 127 //=== ruby as block object === 128 129 RenderRubyAsBlock::RenderRubyAsBlock(Node* node) 130 : RenderBlock(node) 131 { 132 } 133 134 RenderRubyAsBlock::~RenderRubyAsBlock() 135 { 136 } 137 138 bool RenderRubyAsBlock::isChildAllowed(RenderObject* child, RenderStyle*) const 139 { 140 return child->isRubyText() 141 || child->isRubyRun() 142 || child->isInline(); 143 } 144 145 void RenderRubyAsBlock::addChild(RenderObject* child, RenderObject* beforeChild) 146 { 147 // Note: ':after' content is handled implicitely below 148 149 // if child is a ruby run, just add it normally 150 if (child->isRubyRun()) { 151 RenderBlock::addChild(child, beforeChild); 152 return; 153 } 154 155 if (beforeChild && !isAfterContent(beforeChild)) { 156 // insert child into run 157 ASSERT(!beforeChild->isRubyRun()); 158 RenderObject* run = beforeChild; 159 while (run && !run->isRubyRun()) 160 run = run->parent(); 161 if (run) { 162 run->addChild(child, beforeChild); 163 return; 164 } 165 ASSERT(false); // beforeChild should always have a run as parent! 166 // Emergency fallback: fall through and just append. 167 } 168 169 // If the new child would be appended, try to add the child to the previous run 170 // if possible, or create a new run otherwise. 171 // (The RenderRubyRun object will handle the details) 172 RenderRubyRun* lastRun = lastRubyRun(this); 173 if (!lastRun || lastRun->hasRubyText()) { 174 lastRun = RenderRubyRun::staticCreateRubyRun(this); 175 RenderBlock::addChild(lastRun); 176 } 177 lastRun->addChild(child); 178 } 179 180 void RenderRubyAsBlock::removeChild(RenderObject* child) 181 { 182 // If the child's parent is *this, just use the normal remove method. 183 if (child->parent() == this) { 184 // This should happen only during destruction of the whole ruby element, though. 185 RenderBlock::removeChild(child); 186 return; 187 } 188 189 // Find the containing run 190 RenderRubyRun* run = findRubyRunParent(child); 191 ASSERT(run); 192 run->removeChild(child); 193 } 194 195 } // namespace WebCore 196 197 #endif 198