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 "RenderArena.h"
     26 #include "RenderBox.h"
     27 #include "RootInlineBox.h"
     28 
     29 using namespace std;
     30 
     31 namespace WebCore {
     32 
     33 #ifndef NDEBUG
     34 static bool inInlineBoxDetach;
     35 #endif
     36 
     37 #ifndef NDEBUG
     38 
     39 InlineBox::~InlineBox()
     40 {
     41     if (!m_hasBadParent && m_parent)
     42         m_parent->setHasBadChildList();
     43 }
     44 
     45 #endif
     46 
     47 void InlineBox::remove()
     48 {
     49     if (parent())
     50         parent()->removeChild(this);
     51 }
     52 
     53 void InlineBox::destroy(RenderArena* renderArena)
     54 {
     55 #ifndef NDEBUG
     56     inInlineBoxDetach = true;
     57 #endif
     58     delete this;
     59 #ifndef NDEBUG
     60     inInlineBoxDetach = false;
     61 #endif
     62 
     63     // Recover the size left there for us by operator delete and free the memory.
     64     renderArena->free(*(size_t *)this, this);
     65 }
     66 
     67 void* InlineBox::operator new(size_t sz, RenderArena* renderArena) throw()
     68 {
     69     return renderArena->allocate(sz);
     70 }
     71 
     72 void InlineBox::operator delete(void* ptr, size_t sz)
     73 {
     74     ASSERT(inInlineBoxDetach);
     75 
     76     // Stash size where destroy can find it.
     77     *(size_t *)ptr = sz;
     78 }
     79 
     80 #ifndef NDEBUG
     81 void InlineBox::showTreeForThis() const
     82 {
     83     if (m_renderer)
     84         m_renderer->showTreeForThis();
     85 }
     86 #endif
     87 
     88 int InlineBox::height() const
     89 {
     90 #if ENABLE(SVG)
     91     if (hasVirtualHeight())
     92         return virtualHeight();
     93 #endif
     94 
     95     if (renderer()->isText())
     96         return m_isText ? renderer()->style(m_firstLine)->font().height() : 0;
     97     if (renderer()->isBox() && parent())
     98         return toRenderBox(m_renderer)->height();
     99 
    100     ASSERT(isInlineFlowBox());
    101     RenderBoxModelObject* flowObject = boxModelObject();
    102     const Font& font = renderer()->style(m_firstLine)->font();
    103     int result = font.height();
    104     if (parent())
    105         result += flowObject->borderTop() + flowObject->paddingTop() + flowObject->borderBottom() + flowObject->paddingBottom();
    106     return result;
    107 }
    108 
    109 int InlineBox::caretMinOffset() const
    110 {
    111     return m_renderer->caretMinOffset();
    112 }
    113 
    114 int InlineBox::caretMaxOffset() const
    115 {
    116     return m_renderer->caretMaxOffset();
    117 }
    118 
    119 unsigned InlineBox::caretMaxRenderedOffset() const
    120 {
    121     return 1;
    122 }
    123 
    124 void InlineBox::dirtyLineBoxes()
    125 {
    126     markDirty();
    127     for (InlineFlowBox* curr = parent(); curr && !curr->isDirty(); curr = curr->parent())
    128         curr->markDirty();
    129 }
    130 
    131 void InlineBox::deleteLine(RenderArena* arena)
    132 {
    133     if (!m_extracted && m_renderer->isBox())
    134         toRenderBox(m_renderer)->setInlineBoxWrapper(0);
    135     destroy(arena);
    136 }
    137 
    138 void InlineBox::extractLine()
    139 {
    140     m_extracted = true;
    141     if (m_renderer->isBox())
    142         toRenderBox(m_renderer)->setInlineBoxWrapper(0);
    143 }
    144 
    145 void InlineBox::attachLine()
    146 {
    147     m_extracted = false;
    148     if (m_renderer->isBox())
    149         toRenderBox(m_renderer)->setInlineBoxWrapper(this);
    150 }
    151 
    152 void InlineBox::adjustPosition(int dx, int dy)
    153 {
    154     m_x += dx;
    155     m_y += dy;
    156     if (m_renderer->isReplaced()) {
    157         RenderBox* box = toRenderBox(m_renderer);
    158         box->move(dx, dy);
    159     }
    160 }
    161 
    162 void InlineBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
    163 {
    164     if (!renderer()->shouldPaintWithinRoot(paintInfo) || (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection))
    165         return;
    166 
    167     // Paint all phases of replaced elements atomically, as though the replaced element established its
    168     // own stacking context.  (See Appendix E.2, section 6.4 on inline block/table elements in the CSS2.1
    169     // specification.)
    170     bool preservePhase = paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip;
    171     RenderObject::PaintInfo info(paintInfo);
    172     info.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground;
    173     renderer()->paint(info, tx, ty);
    174     if (!preservePhase) {
    175         info.phase = PaintPhaseChildBlockBackgrounds;
    176         renderer()->paint(info, tx, ty);
    177         info.phase = PaintPhaseFloat;
    178         renderer()->paint(info, tx, ty);
    179         info.phase = PaintPhaseForeground;
    180         renderer()->paint(info, tx, ty);
    181         info.phase = PaintPhaseOutline;
    182         renderer()->paint(info, tx, ty);
    183     }
    184 }
    185 
    186 bool InlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty)
    187 {
    188     // Hit test all phases of replaced elements atomically, as though the replaced element established its
    189     // own stacking context.  (See Appendix E.2, section 6.4 on inline block/table elements in the CSS2.1
    190     // specification.)
    191     return renderer()->hitTest(request, result, IntPoint(x, y), tx, ty);
    192 }
    193 
    194 const RootInlineBox* InlineBox::root() const
    195 {
    196     if (m_parent)
    197         return m_parent->root();
    198     ASSERT(isRootInlineBox());
    199     return static_cast<const RootInlineBox*>(this);
    200 }
    201 
    202 RootInlineBox* InlineBox::root()
    203 {
    204     if (m_parent)
    205         return m_parent->root();
    206     ASSERT(isRootInlineBox());
    207     return static_cast<RootInlineBox*>(this);
    208 }
    209 
    210 bool InlineBox::nextOnLineExists() const
    211 {
    212     if (!m_determinedIfNextOnLineExists) {
    213         m_determinedIfNextOnLineExists = true;
    214 
    215         if (!parent())
    216             m_nextOnLineExists = false;
    217         else if (nextOnLine())
    218             m_nextOnLineExists = true;
    219         else
    220             m_nextOnLineExists = parent()->nextOnLineExists();
    221     }
    222     return m_nextOnLineExists;
    223 }
    224 
    225 bool InlineBox::prevOnLineExists() const
    226 {
    227     if (!m_determinedIfPrevOnLineExists) {
    228         m_determinedIfPrevOnLineExists = true;
    229 
    230         if (!parent())
    231             m_prevOnLineExists = false;
    232         else if (prevOnLine())
    233             m_prevOnLineExists = true;
    234         else
    235             m_prevOnLineExists = parent()->prevOnLineExists();
    236     }
    237     return m_prevOnLineExists;
    238 }
    239 
    240 InlineBox* InlineBox::nextLeafChild() const
    241 {
    242     InlineBox* leaf = 0;
    243     for (InlineBox* box = nextOnLine(); box && !leaf; box = box->nextOnLine())
    244         leaf = box->isLeaf() ? box : static_cast<InlineFlowBox*>(box)->firstLeafChild();
    245     if (!leaf && parent())
    246         leaf = parent()->nextLeafChild();
    247     return leaf;
    248 }
    249 
    250 InlineBox* InlineBox::prevLeafChild() const
    251 {
    252     InlineBox* leaf = 0;
    253     for (InlineBox* box = prevOnLine(); box && !leaf; box = box->prevOnLine())
    254         leaf = box->isLeaf() ? box : static_cast<InlineFlowBox*>(box)->lastLeafChild();
    255     if (!leaf && parent())
    256         leaf = parent()->prevLeafChild();
    257     return leaf;
    258 }
    259 
    260 RenderObject::SelectionState InlineBox::selectionState()
    261 {
    262     return renderer()->selectionState();
    263 }
    264 
    265 bool InlineBox::canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth)
    266 {
    267     // Non-replaced elements can always accommodate an ellipsis.
    268     if (!m_renderer || !m_renderer->isReplaced())
    269         return true;
    270 
    271     IntRect boxRect(m_x, 0, m_width, 10);
    272     IntRect ellipsisRect(ltr ? blockEdge - ellipsisWidth : blockEdge, 0, ellipsisWidth, 10);
    273     return !(boxRect.intersects(ellipsisRect));
    274 }
    275 
    276 int InlineBox::placeEllipsisBox(bool, int, int, int, bool&)
    277 {
    278     // Use -1 to mean "we didn't set the position."
    279     return -1;
    280 }
    281 
    282 } // namespace WebCore
    283 
    284 #ifndef NDEBUG
    285 
    286 void showTree(const WebCore::InlineBox* b)
    287 {
    288     if (b)
    289         b->showTreeForThis();
    290 }
    291 
    292 #endif
    293