Home | History | Annotate | Download | only in rendering
      1 /*
      2  * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
      3  *
      4  * This library is free software; you can redistribute it and/or
      5  * modify it under the terms of the GNU Library General Public
      6  * License as published by the Free Software Foundation; either
      7  * version 2 of the License, or (at your option) any later version.
      8  *
      9  * This library is distributed in the hope that it will be useful,
     10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12  * Library General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU Library General Public License
     15  * along with this library; see the file COPYING.LIB.  If not, write to
     16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     17  * Boston, MA 02110-1301, USA.
     18  */
     19 
     20 #include "config.h"
     21 #include "InlineBox.h"
     22 
     23 #include "HitTestResult.h"
     24 #include "InlineFlowBox.h"
     25 #include "PaintInfo.h"
     26 #include "RenderArena.h"
     27 #include "RenderBlock.h"
     28 #include "RootInlineBox.h"
     29 
     30 using namespace std;
     31 
     32 namespace WebCore {
     33 
     34 #ifndef NDEBUG
     35 static bool inInlineBoxDetach;
     36 #endif
     37 
     38 #ifndef NDEBUG
     39 
     40 InlineBox::~InlineBox()
     41 {
     42     if (!m_hasBadParent && m_parent)
     43         m_parent->setHasBadChildList();
     44 }
     45 
     46 #endif
     47 
     48 void InlineBox::remove()
     49 {
     50     if (parent())
     51         parent()->removeChild(this);
     52 }
     53 
     54 void InlineBox::destroy(RenderArena* renderArena)
     55 {
     56 #ifndef NDEBUG
     57     inInlineBoxDetach = true;
     58 #endif
     59     delete this;
     60 #ifndef NDEBUG
     61     inInlineBoxDetach = false;
     62 #endif
     63 
     64     // Recover the size left there for us by operator delete and free the memory.
     65     renderArena->free(*(size_t *)this, this);
     66 }
     67 
     68 void* InlineBox::operator new(size_t sz, RenderArena* renderArena) throw()
     69 {
     70     return renderArena->allocate(sz);
     71 }
     72 
     73 void InlineBox::operator delete(void* ptr, size_t sz)
     74 {
     75     ASSERT(inInlineBoxDetach);
     76 
     77     // Stash size where destroy can find it.
     78     *(size_t *)ptr = sz;
     79 }
     80 
     81 #ifndef NDEBUG
     82 void InlineBox::showTreeForThis() const
     83 {
     84     if (m_renderer)
     85         m_renderer->showTreeForThis();
     86 }
     87 #endif
     88 
     89 int InlineBox::logicalHeight() const
     90 {
     91 #if ENABLE(SVG)
     92     if (hasVirtualLogicalHeight())
     93         return virtualLogicalHeight();
     94 #endif
     95 
     96     if (renderer()->isText())
     97         return m_isText ? renderer()->style(m_firstLine)->fontMetrics().height() : 0;
     98     if (renderer()->isBox() && parent())
     99         return isHorizontal() ? toRenderBox(m_renderer)->height() : toRenderBox(m_renderer)->width();
    100 
    101     ASSERT(isInlineFlowBox());
    102     RenderBoxModelObject* flowObject = boxModelObject();
    103     const FontMetrics& fontMetrics = renderer()->style(m_firstLine)->fontMetrics();
    104     int result = fontMetrics.height();
    105     if (parent())
    106         result += flowObject->borderAndPaddingLogicalHeight();
    107     return result;
    108 }
    109 
    110 int InlineBox::caretMinOffset() const
    111 {
    112     return m_renderer->caretMinOffset();
    113 }
    114 
    115 int InlineBox::caretMaxOffset() const
    116 {
    117     return m_renderer->caretMaxOffset();
    118 }
    119 
    120 unsigned InlineBox::caretMaxRenderedOffset() const
    121 {
    122     return 1;
    123 }
    124 
    125 void InlineBox::dirtyLineBoxes()
    126 {
    127     markDirty();
    128     for (InlineFlowBox* curr = parent(); curr && !curr->isDirty(); curr = curr->parent())
    129         curr->markDirty();
    130 }
    131 
    132 void InlineBox::deleteLine(RenderArena* arena)
    133 {
    134     if (!m_extracted && m_renderer->isBox())
    135         toRenderBox(m_renderer)->setInlineBoxWrapper(0);
    136     destroy(arena);
    137 }
    138 
    139 void InlineBox::extractLine()
    140 {
    141     m_extracted = true;
    142     if (m_renderer->isBox())
    143         toRenderBox(m_renderer)->setInlineBoxWrapper(0);
    144 }
    145 
    146 void InlineBox::attachLine()
    147 {
    148     m_extracted = false;
    149     if (m_renderer->isBox())
    150         toRenderBox(m_renderer)->setInlineBoxWrapper(this);
    151 }
    152 
    153 void InlineBox::adjustPosition(float dx, float dy)
    154 {
    155     m_x += dx;
    156     m_y += dy;
    157 
    158     if (m_renderer->isReplaced())
    159         toRenderBox(m_renderer)->move(dx, dy);
    160 }
    161 
    162 void InlineBox::paint(PaintInfo& paintInfo, int tx, int ty, int /* lineTop */, int /*lineBottom*/)
    163 {
    164     if (!paintInfo.shouldPaintWithinRoot(renderer()) || (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection))
    165         return;
    166 
    167     IntPoint childPoint = IntPoint(tx, ty);
    168     if (parent()->renderer()->style()->isFlippedBlocksWritingMode()) // Faster than calling containingBlock().
    169         childPoint = renderer()->containingBlock()->flipForWritingMode(toRenderBox(renderer()), childPoint, RenderBox::ParentToChildFlippingAdjustment);
    170 
    171     // Paint all phases of replaced elements atomically, as though the replaced element established its
    172     // own stacking context.  (See Appendix E.2, section 6.4 on inline block/table elements in the CSS2.1
    173     // specification.)
    174     bool preservePhase = paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip;
    175     PaintInfo info(paintInfo);
    176     info.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground;
    177     renderer()->paint(info, childPoint.x(), childPoint.y());
    178     if (!preservePhase) {
    179         info.phase = PaintPhaseChildBlockBackgrounds;
    180         renderer()->paint(info, childPoint.x(), childPoint.y());
    181         info.phase = PaintPhaseFloat;
    182         renderer()->paint(info, childPoint.x(), childPoint.y());
    183         info.phase = PaintPhaseForeground;
    184         renderer()->paint(info, childPoint.x(), childPoint.y());
    185         info.phase = PaintPhaseOutline;
    186         renderer()->paint(info, childPoint.x(), childPoint.y());
    187     }
    188 }
    189 
    190 bool InlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, int /* lineTop */, int /*lineBottom*/)
    191 {
    192     // Hit test all phases of replaced elements atomically, as though the replaced element established its
    193     // own stacking context.  (See Appendix E.2, section 6.4 on inline block/table elements in the CSS2.1
    194     // specification.)
    195     return renderer()->hitTest(request, result, IntPoint(x, y), tx, ty);
    196 }
    197 
    198 const RootInlineBox* InlineBox::root() const
    199 {
    200     if (m_parent)
    201         return m_parent->root();
    202     ASSERT(isRootInlineBox());
    203     return static_cast<const RootInlineBox*>(this);
    204 }
    205 
    206 RootInlineBox* InlineBox::root()
    207 {
    208     if (m_parent)
    209         return m_parent->root();
    210     ASSERT(isRootInlineBox());
    211     return static_cast<RootInlineBox*>(this);
    212 }
    213 
    214 bool InlineBox::nextOnLineExists() const
    215 {
    216     if (!m_determinedIfNextOnLineExists) {
    217         m_determinedIfNextOnLineExists = true;
    218 
    219         if (!parent())
    220             m_nextOnLineExists = false;
    221         else if (nextOnLine())
    222             m_nextOnLineExists = true;
    223         else
    224             m_nextOnLineExists = parent()->nextOnLineExists();
    225     }
    226     return m_nextOnLineExists;
    227 }
    228 
    229 bool InlineBox::prevOnLineExists() const
    230 {
    231     if (!m_determinedIfPrevOnLineExists) {
    232         m_determinedIfPrevOnLineExists = true;
    233 
    234         if (!parent())
    235             m_prevOnLineExists = false;
    236         else if (prevOnLine())
    237             m_prevOnLineExists = true;
    238         else
    239             m_prevOnLineExists = parent()->prevOnLineExists();
    240     }
    241     return m_prevOnLineExists;
    242 }
    243 
    244 InlineBox* InlineBox::nextLeafChild() const
    245 {
    246     InlineBox* leaf = 0;
    247     for (InlineBox* box = nextOnLine(); box && !leaf; box = box->nextOnLine())
    248         leaf = box->isLeaf() ? box : static_cast<InlineFlowBox*>(box)->firstLeafChild();
    249     if (!leaf && parent())
    250         leaf = parent()->nextLeafChild();
    251     return leaf;
    252 }
    253 
    254 InlineBox* InlineBox::prevLeafChild() const
    255 {
    256     InlineBox* leaf = 0;
    257     for (InlineBox* box = prevOnLine(); box && !leaf; box = box->prevOnLine())
    258         leaf = box->isLeaf() ? box : static_cast<InlineFlowBox*>(box)->lastLeafChild();
    259     if (!leaf && parent())
    260         leaf = parent()->prevLeafChild();
    261     return leaf;
    262 }
    263 
    264 RenderObject::SelectionState InlineBox::selectionState()
    265 {
    266     return renderer()->selectionState();
    267 }
    268 
    269 bool InlineBox::canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth)
    270 {
    271     // Non-replaced elements can always accommodate an ellipsis.
    272     if (!m_renderer || !m_renderer->isReplaced())
    273         return true;
    274 
    275     IntRect boxRect(m_x, 0, m_logicalWidth, 10);
    276     IntRect ellipsisRect(ltr ? blockEdge - ellipsisWidth : blockEdge, 0, ellipsisWidth, 10);
    277     return !(boxRect.intersects(ellipsisRect));
    278 }
    279 
    280 float InlineBox::placeEllipsisBox(bool, float, float, float, bool&)
    281 {
    282     // Use -1 to mean "we didn't set the position."
    283     return -1;
    284 }
    285 
    286 void InlineBox::clearKnownToHaveNoOverflow()
    287 {
    288     m_knownToHaveNoOverflow = false;
    289     if (parent() && parent()->knownToHaveNoOverflow())
    290         parent()->clearKnownToHaveNoOverflow();
    291 }
    292 
    293 FloatPoint InlineBox::locationIncludingFlipping()
    294 {
    295     if (!renderer()->style()->isFlippedBlocksWritingMode())
    296         return FloatPoint(x(), y());
    297     RenderBlock* block = root()->block();
    298     if (block->style()->isHorizontalWritingMode())
    299         return FloatPoint(x(), block->height() - height() - y());
    300     else
    301         return FloatPoint(block->width() - width() - x(), y());
    302 }
    303 
    304 void InlineBox::flipForWritingMode(FloatRect& rect)
    305 {
    306     if (!renderer()->style()->isFlippedBlocksWritingMode())
    307         return;
    308     root()->block()->flipForWritingMode(rect);
    309 }
    310 
    311 FloatPoint InlineBox::flipForWritingMode(const FloatPoint& point)
    312 {
    313     if (!renderer()->style()->isFlippedBlocksWritingMode())
    314         return point;
    315     return root()->block()->flipForWritingMode(point);
    316 }
    317 
    318 void InlineBox::flipForWritingMode(IntRect& rect)
    319 {
    320     if (!renderer()->style()->isFlippedBlocksWritingMode())
    321         return;
    322     root()->block()->flipForWritingMode(rect);
    323 }
    324 
    325 IntPoint InlineBox::flipForWritingMode(const IntPoint& point)
    326 {
    327     if (!renderer()->style()->isFlippedBlocksWritingMode())
    328         return point;
    329     return root()->block()->flipForWritingMode(point);
    330 }
    331 
    332 } // namespace WebCore
    333 
    334 #ifndef NDEBUG
    335 
    336 void showTree(const WebCore::InlineBox* b)
    337 {
    338     if (b)
    339         b->showTreeForThis();
    340 }
    341 
    342 #endif
    343