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 #include "core/rendering/RenderRubyRun.h"
     34 
     35 #include "core/rendering/LayoutRectRecorder.h"
     36 #include "core/rendering/RenderRubyBase.h"
     37 #include "core/rendering/RenderRubyText.h"
     38 #include "core/rendering/RenderText.h"
     39 
     40 using namespace std;
     41 
     42 namespace WebCore {
     43 
     44 RenderRubyRun::RenderRubyRun()
     45     : RenderBlockFlow(0)
     46 {
     47     setReplaced(true);
     48     setInline(true);
     49 }
     50 
     51 RenderRubyRun::~RenderRubyRun()
     52 {
     53 }
     54 
     55 bool RenderRubyRun::hasRubyText() const
     56 {
     57     // The only place where a ruby text can be is in the first position
     58     // Note: As anonymous blocks, ruby runs do not have ':before' or ':after' content themselves.
     59     return firstChild() && firstChild()->isRubyText();
     60 }
     61 
     62 bool RenderRubyRun::hasRubyBase() const
     63 {
     64     // The only place where a ruby base can be is in the last position
     65     // Note: As anonymous blocks, ruby runs do not have ':before' or ':after' content themselves.
     66     return lastChild() && lastChild()->isRubyBase();
     67 }
     68 
     69 bool RenderRubyRun::isEmpty() const
     70 {
     71     return !hasRubyText() && !hasRubyBase();
     72 }
     73 
     74 RenderRubyText* RenderRubyRun::rubyText() const
     75 {
     76     RenderObject* child = firstChild();
     77     // If in future it becomes necessary to support floating or positioned ruby text,
     78     // layout will have to be changed to handle them properly.
     79     ASSERT(!child || !child->isRubyText() || !child->isFloatingOrOutOfFlowPositioned());
     80     return child && child->isRubyText() ? static_cast<RenderRubyText*>(child) : 0;
     81 }
     82 
     83 RenderRubyBase* RenderRubyRun::rubyBase() const
     84 {
     85     RenderObject* child = lastChild();
     86     return child && child->isRubyBase() ? static_cast<RenderRubyBase*>(child) : 0;
     87 }
     88 
     89 RenderRubyBase* RenderRubyRun::rubyBaseSafe()
     90 {
     91     RenderRubyBase* base = rubyBase();
     92     if (!base) {
     93         base = createRubyBase();
     94         RenderBlock::addChild(base);
     95     }
     96     return base;
     97 }
     98 
     99 RenderBlock* RenderRubyRun::firstLineBlock() const
    100 {
    101     return 0;
    102 }
    103 
    104 void RenderRubyRun::updateFirstLetter()
    105 {
    106 }
    107 
    108 bool RenderRubyRun::isChildAllowed(RenderObject* child, RenderStyle*) const
    109 {
    110     return child->isRubyText() || child->isInline();
    111 }
    112 
    113 void RenderRubyRun::addChild(RenderObject* child, RenderObject* beforeChild)
    114 {
    115     ASSERT(child);
    116 
    117     if (child->isRubyText()) {
    118         if (!beforeChild) {
    119             // RenderRuby has already ascertained that we can add the child here.
    120             ASSERT(!hasRubyText());
    121             // prepend ruby texts as first child
    122             RenderBlock::addChild(child, firstChild());
    123         }  else if (beforeChild->isRubyText()) {
    124             // New text is inserted just before another.
    125             // In this case the new text takes the place of the old one, and
    126             // the old text goes into a new run that is inserted as next sibling.
    127             ASSERT(beforeChild->parent() == this);
    128             RenderObject* ruby = parent();
    129             ASSERT(ruby->isRuby());
    130             RenderBlock* newRun = staticCreateRubyRun(ruby);
    131             ruby->addChild(newRun, nextSibling());
    132             // Add the new ruby text and move the old one to the new run
    133             // Note: Doing it in this order and not using RenderRubyRun's methods,
    134             // in order to avoid automatic removal of the ruby run in case there is no
    135             // other child besides the old ruby text.
    136             RenderBlock::addChild(child, beforeChild);
    137             RenderBlock::removeChild(beforeChild);
    138             newRun->addChild(beforeChild);
    139         } else if (hasRubyBase()) {
    140             // Insertion before a ruby base object.
    141             // In this case we need insert a new run before the current one and split the base.
    142             RenderObject* ruby = parent();
    143             RenderRubyRun* newRun = staticCreateRubyRun(ruby);
    144             ruby->addChild(newRun, this);
    145             newRun->addChild(child);
    146             rubyBaseSafe()->moveChildren(newRun->rubyBaseSafe(), beforeChild);
    147         }
    148     } else {
    149         // child is not a text -> insert it into the base
    150         // (append it instead if beforeChild is the ruby text)
    151         if (beforeChild && beforeChild->isRubyText())
    152             beforeChild = 0;
    153         rubyBaseSafe()->addChild(child, beforeChild);
    154     }
    155 }
    156 
    157 void RenderRubyRun::removeChild(RenderObject* child)
    158 {
    159     // If the child is a ruby text, then merge the ruby base with the base of
    160     // the right sibling run, if possible.
    161     if (!beingDestroyed() && !documentBeingDestroyed() && child->isRubyText()) {
    162         RenderRubyBase* base = rubyBase();
    163         RenderObject* rightNeighbour = nextSibling();
    164         if (base && rightNeighbour && rightNeighbour->isRubyRun()) {
    165             // Ruby run without a base can happen only at the first run.
    166             RenderRubyRun* rightRun = toRenderRubyRun(rightNeighbour);
    167             if (rightRun->hasRubyBase()) {
    168                 RenderRubyBase* rightBase = rightRun->rubyBaseSafe();
    169                 // Collect all children in a single base, then swap the bases.
    170                 rightBase->moveChildren(base);
    171                 moveChildTo(rightRun, base);
    172                 rightRun->moveChildTo(this, rightBase);
    173                 // The now empty ruby base will be removed below.
    174                 ASSERT(!rubyBase()->firstChild());
    175             }
    176         }
    177     }
    178 
    179     RenderBlock::removeChild(child);
    180 
    181     if (!beingDestroyed() && !documentBeingDestroyed()) {
    182         // Check if our base (if any) is now empty. If so, destroy it.
    183         RenderBlock* base = rubyBase();
    184         if (base && !base->firstChild()) {
    185             RenderBlock::removeChild(base);
    186             base->deleteLineBoxTree();
    187             base->destroy();
    188         }
    189 
    190         // If any of the above leaves the run empty, destroy it as well.
    191         if (isEmpty()) {
    192             parent()->removeChild(this);
    193             deleteLineBoxTree();
    194             destroy();
    195         }
    196     }
    197 }
    198 
    199 RenderRubyBase* RenderRubyRun::createRubyBase() const
    200 {
    201     RenderRubyBase* renderer = RenderRubyBase::createAnonymous(&document());
    202     RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(style(), BLOCK);
    203     newStyle->setTextAlign(CENTER); // FIXME: use WEBKIT_CENTER?
    204     renderer->setStyle(newStyle.release());
    205     return renderer;
    206 }
    207 
    208 RenderRubyRun* RenderRubyRun::staticCreateRubyRun(const RenderObject* parentRuby)
    209 {
    210     ASSERT(parentRuby && parentRuby->isRuby());
    211     RenderRubyRun* rr = new RenderRubyRun();
    212     rr->setDocumentForAnonymous(&parentRuby->document());
    213     RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parentRuby->style(), INLINE_BLOCK);
    214     rr->setStyle(newStyle.release());
    215     return rr;
    216 }
    217 
    218 RenderObject* RenderRubyRun::layoutSpecialExcludedChild(bool relayoutChildren, SubtreeLayoutScope& layoutScope)
    219 {
    220     // Don't bother positioning the RenderRubyRun yet.
    221     RenderRubyText* rt = rubyText();
    222     if (!rt)
    223         return 0;
    224     if (relayoutChildren)
    225         layoutScope.setChildNeedsLayout(rt);
    226     rt->layoutIfNeeded();
    227     return rt;
    228 }
    229 
    230 void RenderRubyRun::layout()
    231 {
    232     LayoutRectRecorder recorder(*this);
    233     RenderBlock::layout();
    234 
    235     RenderRubyText* rt = rubyText();
    236     if (!rt)
    237         return;
    238 
    239     rt->setLogicalLeft(0);
    240 
    241     // Place the RenderRubyText such that its bottom is flush with the lineTop of the first line of the RenderRubyBase.
    242     LayoutUnit lastLineRubyTextBottom = rt->logicalHeight();
    243     LayoutUnit firstLineRubyTextTop = 0;
    244     RootInlineBox* rootBox = rt->lastRootBox();
    245     if (rootBox) {
    246         // In order to align, we have to ignore negative leading.
    247         firstLineRubyTextTop = rt->firstRootBox()->logicalTopLayoutOverflow();
    248         lastLineRubyTextBottom = rootBox->logicalBottomLayoutOverflow();
    249     }
    250 
    251     if (style()->isFlippedLinesWritingMode() == (style()->rubyPosition() == RubyPositionAfter)) {
    252         LayoutUnit firstLineTop = 0;
    253         if (RenderRubyBase* rb = rubyBase()) {
    254             RootInlineBox* rootBox = rb->firstRootBox();
    255             if (rootBox)
    256                 firstLineTop = rootBox->logicalTopLayoutOverflow();
    257             firstLineTop += rb->logicalTop();
    258         }
    259 
    260         rt->setLogicalTop(-lastLineRubyTextBottom + firstLineTop);
    261     } else {
    262         LayoutUnit lastLineBottom = logicalHeight();
    263         if (RenderRubyBase* rb = rubyBase()) {
    264             RootInlineBox* rootBox = rb->lastRootBox();
    265             if (rootBox)
    266                 lastLineBottom = rootBox->logicalBottomLayoutOverflow();
    267             lastLineBottom += rb->logicalTop();
    268         }
    269 
    270         rt->setLogicalTop(-firstLineRubyTextTop + lastLineBottom);
    271     }
    272 
    273     // Update our overflow to account for the new RenderRubyText position.
    274     computeOverflow(clientLogicalBottom());
    275 }
    276 
    277 void RenderRubyRun::getOverhang(bool firstLine, RenderObject* startRenderer, RenderObject* endRenderer, int& startOverhang, int& endOverhang) const
    278 {
    279     ASSERT(!needsLayout());
    280 
    281     startOverhang = 0;
    282     endOverhang = 0;
    283 
    284     RenderRubyBase* rubyBase = this->rubyBase();
    285     RenderRubyText* rubyText = this->rubyText();
    286 
    287     if (!rubyBase || !rubyText)
    288         return;
    289 
    290     if (!rubyBase->firstRootBox())
    291         return;
    292 
    293     int logicalWidth = this->logicalWidth();
    294     int logicalLeftOverhang = numeric_limits<int>::max();
    295     int logicalRightOverhang = numeric_limits<int>::max();
    296     for (RootInlineBox* rootInlineBox = rubyBase->firstRootBox(); rootInlineBox; rootInlineBox = rootInlineBox->nextRootBox()) {
    297         logicalLeftOverhang = min<int>(logicalLeftOverhang, rootInlineBox->logicalLeft());
    298         logicalRightOverhang = min<int>(logicalRightOverhang, logicalWidth - rootInlineBox->logicalRight());
    299     }
    300 
    301     startOverhang = style()->isLeftToRightDirection() ? logicalLeftOverhang : logicalRightOverhang;
    302     endOverhang = style()->isLeftToRightDirection() ? logicalRightOverhang : logicalLeftOverhang;
    303 
    304     if (!startRenderer || !startRenderer->isText() || startRenderer->style(firstLine)->fontSize() > rubyBase->style(firstLine)->fontSize())
    305         startOverhang = 0;
    306 
    307     if (!endRenderer || !endRenderer->isText() || endRenderer->style(firstLine)->fontSize() > rubyBase->style(firstLine)->fontSize())
    308         endOverhang = 0;
    309 
    310     // We overhang a ruby only if the neighboring render object is a text.
    311     // We can overhang the ruby by no more than half the width of the neighboring text
    312     // and no more than half the font size.
    313     int halfWidthOfFontSize = rubyText->style(firstLine)->fontSize() / 2;
    314     if (startOverhang)
    315         startOverhang = min<int>(startOverhang, min<int>(toRenderText(startRenderer)->minLogicalWidth(), halfWidthOfFontSize));
    316     if (endOverhang)
    317         endOverhang = min<int>(endOverhang, min<int>(toRenderText(endRenderer)->minLogicalWidth(), halfWidthOfFontSize));
    318 }
    319 
    320 } // namespace WebCore
    321