WebCore/rendering/RenderRubyRun.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     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 "RenderRubyRun.h"
       
    35 
       
    36 #include "RenderRubyBase.h"
       
    37 #include "RenderRubyText.h"
       
    38 #include "RenderView.h"
       
    39 
       
    40 using namespace std;
       
    41 
       
    42 namespace WebCore {
       
    43 
       
    44 RenderRubyRun::RenderRubyRun(Node* node)
       
    45     : RenderBlock(node)
       
    46     , m_beingDestroyed(false)
       
    47 {
       
    48     setReplaced(true);
       
    49     setInline(true);
       
    50 }
       
    51 
       
    52 RenderRubyRun::~RenderRubyRun()
       
    53 {
       
    54 }
       
    55 
       
    56 void RenderRubyRun::destroy()
       
    57 {
       
    58     // Mark if the run is being destroyed to avoid trouble in removeChild().
       
    59     m_beingDestroyed = true;
       
    60     RenderBlock::destroy();
       
    61 }
       
    62 
       
    63 bool RenderRubyRun::hasRubyText() const
       
    64 {
       
    65     // The only place where a ruby text can be is in the first position
       
    66     // Note: As anonymous blocks, ruby runs do not have ':before' or ':after' content themselves.
       
    67     return firstChild() && firstChild()->isRubyText();
       
    68 }
       
    69 
       
    70 bool RenderRubyRun::hasRubyBase() const
       
    71 {
       
    72     // The only place where a ruby base can be is in the last position
       
    73     // Note: As anonymous blocks, ruby runs do not have ':before' or ':after' content themselves.
       
    74     return lastChild() && lastChild()->isRubyBase();
       
    75 }
       
    76 
       
    77 bool RenderRubyRun::isEmpty() const
       
    78 {
       
    79     return !hasRubyText() && !hasRubyBase();
       
    80 }
       
    81 
       
    82 RenderRubyText* RenderRubyRun::rubyText() const
       
    83 {
       
    84     RenderObject* child = firstChild();
       
    85     return child && child->isRubyText() ? static_cast<RenderRubyText*>(child) : 0;
       
    86 }
       
    87 
       
    88 RenderRubyBase* RenderRubyRun::rubyBase() const
       
    89 {
       
    90     RenderObject* child = lastChild();
       
    91     return child && child->isRubyBase() ? static_cast<RenderRubyBase*>(child) : 0;
       
    92 }
       
    93 
       
    94 RenderRubyBase* RenderRubyRun::rubyBaseSafe()
       
    95 {
       
    96     RenderRubyBase* base = rubyBase();
       
    97     if (!base) {
       
    98         base = createRubyBase();
       
    99         RenderBlock::addChild(base);
       
   100     }
       
   101     return base;
       
   102 }
       
   103 
       
   104 RenderBlock* RenderRubyRun::firstLineBlock() const
       
   105 {
       
   106     return 0;
       
   107 }
       
   108 
       
   109 void RenderRubyRun::updateFirstLetter()
       
   110 {
       
   111 }
       
   112 
       
   113 bool RenderRubyRun::isChildAllowed(RenderObject* child, RenderStyle*) const
       
   114 {
       
   115     return child->isRubyText() || child->isInline();
       
   116 }
       
   117 
       
   118 void RenderRubyRun::addChild(RenderObject* child, RenderObject* beforeChild)
       
   119 {
       
   120     ASSERT(child);
       
   121 
       
   122     // If child is a ruby text
       
   123     if (child->isRubyText()) {
       
   124         if (!beforeChild) {
       
   125             // RenderRuby has already ascertained that we can add the child here.
       
   126             ASSERT(!hasRubyText());
       
   127             // prepend ruby texts as first child
       
   128             RenderBlock::addChild(child, firstChild());
       
   129         }  else if (beforeChild->isRubyText()) {
       
   130             // New text is inserted just before another.
       
   131             // In this case the new text takes the place of the old one, and
       
   132             // the old text goes into a new run that is inserted as next sibling.
       
   133             ASSERT(beforeChild->parent() == this);
       
   134             RenderObject* ruby = parent();
       
   135             ASSERT(ruby->isRuby());
       
   136             RenderBlock* newRun = staticCreateRubyRun(ruby);
       
   137             ruby->addChild(newRun, nextSibling());
       
   138             // Add the new ruby text and move the old one to the new run
       
   139             // Note: Doing it in this order and not using RenderRubyRun's methods,
       
   140             // in order to avoid automatic removal of the ruby run in case there is no
       
   141             // other child besides the old ruby text.
       
   142             RenderBlock::addChild(child, beforeChild);
       
   143             RenderBlock::removeChild(beforeChild);
       
   144             newRun->addChild(beforeChild);
       
   145         } else {
       
   146             ASSERT(hasRubyBase()); // Otherwise beforeChild would be borked.
       
   147             // Insertion before a ruby base object.
       
   148             // In this case we need insert a new run before the current one and split the base.
       
   149             RenderObject* ruby = parent();
       
   150             RenderRubyRun* newRun = staticCreateRubyRun(ruby);
       
   151             ruby->addChild(newRun, this);
       
   152             newRun->addChild(child);
       
   153             rubyBaseSafe()->moveChildren(newRun->rubyBaseSafe(), beforeChild);
       
   154         }
       
   155     } else {
       
   156         // child is not a text -> insert it into the base
       
   157         // (append it instead if beforeChild is the ruby text)
       
   158         if (beforeChild && beforeChild->isRubyText())
       
   159             beforeChild = 0;
       
   160         rubyBaseSafe()->addChild(child, beforeChild);
       
   161     }
       
   162 }
       
   163 
       
   164 void RenderRubyRun::removeChild(RenderObject* child)
       
   165 {
       
   166     // If the child is a ruby text, then merge the ruby base with the base of
       
   167     // the right sibling run, if possible.
       
   168     if (!m_beingDestroyed && !documentBeingDestroyed() && child->isRubyText()) {
       
   169         RenderRubyBase* base = rubyBase();
       
   170         RenderObject* rightNeighbour = nextSibling();
       
   171         if (base && rightNeighbour && rightNeighbour->isRubyRun()) {
       
   172             // Ruby run without a base can happen only at the first run.
       
   173             RenderRubyRun* rightRun = static_cast<RenderRubyRun*>(rightNeighbour);
       
   174             ASSERT(rightRun->hasRubyBase());
       
   175             RenderRubyBase* rightBase = rightRun->rubyBaseSafe();
       
   176             // Collect all children in a single base, then swap the bases.
       
   177             rightBase->moveChildren(base);
       
   178             moveChildTo(rightRun, base);
       
   179             rightRun->moveChildTo(this, rightBase);
       
   180             // The now empty ruby base will be removed below.
       
   181         }
       
   182     }
       
   183 
       
   184     RenderBlock::removeChild(child);
       
   185 
       
   186     if (!m_beingDestroyed && !documentBeingDestroyed()) {
       
   187         // Check if our base (if any) is now empty. If so, destroy it.
       
   188         RenderBlock* base = rubyBase();
       
   189         if (base && !base->firstChild()) {
       
   190             RenderBlock::removeChild(base);
       
   191             base->deleteLineBoxTree();
       
   192             base->destroy();
       
   193         }
       
   194 
       
   195         // If any of the above leaves the run empty, destroy it as well.
       
   196         if (isEmpty()) {
       
   197             parent()->removeChild(this);
       
   198             deleteLineBoxTree();
       
   199             destroy();
       
   200         }
       
   201     }
       
   202 }
       
   203 
       
   204 RenderRubyBase* RenderRubyRun::createRubyBase() const
       
   205 {
       
   206     RenderRubyBase* rb = new (renderArena()) RenderRubyBase(document() /* anonymous */);
       
   207     RefPtr<RenderStyle> newStyle = RenderStyle::create();
       
   208     newStyle->inheritFrom(style());
       
   209     newStyle->setDisplay(BLOCK);
       
   210     newStyle->setTextAlign(CENTER); // FIXME: use WEBKIT_CENTER?
       
   211     rb->setStyle(newStyle.release());
       
   212     return rb;
       
   213 }
       
   214 
       
   215 RenderRubyRun* RenderRubyRun::staticCreateRubyRun(const RenderObject* parentRuby)
       
   216 {
       
   217     ASSERT(parentRuby && parentRuby->isRuby());
       
   218     RenderRubyRun* rr = new (parentRuby->renderArena()) RenderRubyRun(parentRuby->document() /* anonymous */);
       
   219     RefPtr<RenderStyle> newStyle = RenderStyle::create();
       
   220     newStyle->inheritFrom(parentRuby->style());
       
   221     newStyle->setDisplay(INLINE_BLOCK);
       
   222     rr->setStyle(newStyle.release());
       
   223     return rr;
       
   224 }
       
   225 
       
   226 } // namespace WebCore
       
   227 
       
   228 #endif // ENABLE(RUBY)