Home | History | Annotate | Download | only in rendering
      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