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 "core/rendering/InlineBox.h"
     22 
     23 #include "core/rendering/InlineFlowBox.h"
     24 #include "core/rendering/PaintInfo.h"
     25 #include "core/rendering/RenderBlockFlow.h"
     26 #include "core/rendering/RootInlineBox.h"
     27 #include "platform/Partitions.h"
     28 #include "platform/fonts/FontMetrics.h"
     29 
     30 #ifndef NDEBUG
     31 #include <stdio.h>
     32 #endif
     33 
     34 using namespace std;
     35 
     36 namespace WebCore {
     37 
     38 struct SameSizeAsInlineBox {
     39     virtual ~SameSizeAsInlineBox() { }
     40     void* a[4];
     41     FloatPoint b;
     42     float c;
     43     uint32_t d : 32;
     44 #ifndef NDEBUG
     45     bool f;
     46 #endif
     47 };
     48 
     49 COMPILE_ASSERT(sizeof(InlineBox) == sizeof(SameSizeAsInlineBox), InlineBox_size_guard);
     50 
     51 #ifndef NDEBUG
     52 
     53 InlineBox::~InlineBox()
     54 {
     55     if (!m_hasBadParent && m_parent)
     56         m_parent->setHasBadChildList();
     57 }
     58 
     59 #endif
     60 
     61 void InlineBox::remove()
     62 {
     63     if (parent())
     64         parent()->removeChild(this);
     65 }
     66 
     67 void* InlineBox::operator new(size_t sz)
     68 {
     69     return partitionAlloc(Partitions::getRenderingPartition(), sz);
     70 }
     71 
     72 void InlineBox::operator delete(void* ptr)
     73 {
     74     partitionFree(ptr);
     75 }
     76 
     77 #ifndef NDEBUG
     78 const char* InlineBox::boxName() const
     79 {
     80     return "InlineBox";
     81 }
     82 
     83 void InlineBox::showTreeForThis() const
     84 {
     85     if (m_renderer)
     86         m_renderer->showTreeForThis();
     87 }
     88 
     89 void InlineBox::showLineTreeForThis() const
     90 {
     91     if (m_renderer)
     92         m_renderer->containingBlock()->showLineTreeAndMark(this, "*");
     93 }
     94 
     95 void InlineBox::showLineTreeAndMark(const InlineBox* markedBox1, const char* markedLabel1, const InlineBox* markedBox2, const char* markedLabel2, const RenderObject* obj, int depth) const
     96 {
     97     int printedCharacters = 0;
     98     if (this == markedBox1)
     99         printedCharacters += fprintf(stderr, "%s", markedLabel1);
    100     if (this == markedBox2)
    101         printedCharacters += fprintf(stderr, "%s", markedLabel2);
    102     if (renderer() == obj)
    103         printedCharacters += fprintf(stderr, "*");
    104     for (; printedCharacters < depth * 2; printedCharacters++)
    105         fputc(' ', stderr);
    106 
    107     showBox(printedCharacters);
    108 }
    109 
    110 void InlineBox::showBox(int printedCharacters) const
    111 {
    112     printedCharacters += fprintf(stderr, "%s\t%p", boxName(), this);
    113     for (; printedCharacters < showTreeCharacterOffset; printedCharacters++)
    114         fputc(' ', stderr);
    115     fprintf(stderr, "\t%s %p\n", renderer() ? renderer()->renderName() : "No Renderer", renderer());
    116 }
    117 #endif
    118 
    119 float InlineBox::logicalHeight() const
    120 {
    121     if (hasVirtualLogicalHeight())
    122         return virtualLogicalHeight();
    123 
    124     if (renderer()->isText())
    125         return m_bitfields.isText() ? renderer()->style(isFirstLineStyle())->fontMetrics().height() : 0;
    126     if (renderer()->isBox() && parent())
    127         return isHorizontal() ? toRenderBox(m_renderer)->height() : toRenderBox(m_renderer)->width();
    128 
    129     ASSERT(isInlineFlowBox());
    130     RenderBoxModelObject* flowObject = boxModelObject();
    131     const FontMetrics& fontMetrics = renderer()->style(isFirstLineStyle())->fontMetrics();
    132     float result = fontMetrics.height();
    133     if (parent())
    134         result += flowObject->borderAndPaddingLogicalHeight();
    135     return result;
    136 }
    137 
    138 int InlineBox::baselinePosition(FontBaseline baselineType) const
    139 {
    140     return boxModelObject()->baselinePosition(baselineType, m_bitfields.firstLine(), isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine);
    141 }
    142 
    143 LayoutUnit InlineBox::lineHeight() const
    144 {
    145     return boxModelObject()->lineHeight(m_bitfields.firstLine(), isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine);
    146 }
    147 
    148 int InlineBox::caretMinOffset() const
    149 {
    150     return m_renderer->caretMinOffset();
    151 }
    152 
    153 int InlineBox::caretMaxOffset() const
    154 {
    155     return m_renderer->caretMaxOffset();
    156 }
    157 
    158 void InlineBox::dirtyLineBoxes()
    159 {
    160     markDirty();
    161     for (InlineFlowBox* curr = parent(); curr && !curr->isDirty(); curr = curr->parent())
    162         curr->markDirty();
    163 }
    164 
    165 void InlineBox::deleteLine()
    166 {
    167     if (!m_bitfields.extracted() && m_renderer->isBox())
    168         toRenderBox(m_renderer)->setInlineBoxWrapper(0);
    169     destroy();
    170 }
    171 
    172 void InlineBox::extractLine()
    173 {
    174     m_bitfields.setExtracted(true);
    175     if (m_renderer->isBox())
    176         toRenderBox(m_renderer)->setInlineBoxWrapper(0);
    177 }
    178 
    179 void InlineBox::attachLine()
    180 {
    181     m_bitfields.setExtracted(false);
    182     if (m_renderer->isBox())
    183         toRenderBox(m_renderer)->setInlineBoxWrapper(this);
    184 }
    185 
    186 void InlineBox::adjustPosition(float dx, float dy)
    187 {
    188     m_topLeft.move(dx, dy);
    189 
    190     if (m_renderer->isReplaced())
    191         toRenderBox(m_renderer)->move(dx, dy);
    192 }
    193 
    194 void InlineBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit /* lineTop */, LayoutUnit /*lineBottom*/)
    195 {
    196     if (!paintInfo.shouldPaintWithinRoot(renderer()) || (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection))
    197         return;
    198 
    199     LayoutPoint childPoint = paintOffset;
    200     if (parent()->renderer()->style()->isFlippedBlocksWritingMode()) // Faster than calling containingBlock().
    201         childPoint = renderer()->containingBlock()->flipForWritingModeForChild(toRenderBox(renderer()), childPoint);
    202 
    203     RenderBlock::paintAsInlineBlock(renderer(), paintInfo, childPoint);
    204 }
    205 
    206 bool InlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit /* lineTop */, LayoutUnit /*lineBottom*/)
    207 {
    208     // Hit test all phases of replaced elements atomically, as though the replaced element established its
    209     // own stacking context.  (See Appendix E.2, section 6.4 on inline block/table elements in the CSS2.1
    210     // specification.)
    211     LayoutPoint childPoint = accumulatedOffset;
    212     if (parent()->renderer()->style()->isFlippedBlocksWritingMode()) // Faster than calling containingBlock().
    213         childPoint = renderer()->containingBlock()->flipForWritingModeForChild(toRenderBox(renderer()), childPoint);
    214 
    215     return renderer()->hitTest(request, result, locationInContainer, childPoint);
    216 }
    217 
    218 const RootInlineBox* InlineBox::root() const
    219 {
    220     if (m_parent)
    221         return m_parent->root();
    222     ASSERT(isRootInlineBox());
    223     return static_cast<const RootInlineBox*>(this);
    224 }
    225 
    226 RootInlineBox* InlineBox::root()
    227 {
    228     if (m_parent)
    229         return m_parent->root();
    230     ASSERT(isRootInlineBox());
    231     return static_cast<RootInlineBox*>(this);
    232 }
    233 
    234 bool InlineBox::nextOnLineExists() const
    235 {
    236     if (!m_bitfields.determinedIfNextOnLineExists()) {
    237         m_bitfields.setDeterminedIfNextOnLineExists(true);
    238 
    239         if (!parent())
    240             m_bitfields.setNextOnLineExists(false);
    241         else if (nextOnLine())
    242             m_bitfields.setNextOnLineExists(true);
    243         else
    244             m_bitfields.setNextOnLineExists(parent()->nextOnLineExists());
    245     }
    246     return m_bitfields.nextOnLineExists();
    247 }
    248 
    249 InlineBox* InlineBox::nextLeafChild() const
    250 {
    251     InlineBox* leaf = 0;
    252     for (InlineBox* box = nextOnLine(); box && !leaf; box = box->nextOnLine())
    253         leaf = box->isLeaf() ? box : toInlineFlowBox(box)->firstLeafChild();
    254     if (!leaf && parent())
    255         leaf = parent()->nextLeafChild();
    256     return leaf;
    257 }
    258 
    259 InlineBox* InlineBox::prevLeafChild() const
    260 {
    261     InlineBox* leaf = 0;
    262     for (InlineBox* box = prevOnLine(); box && !leaf; box = box->prevOnLine())
    263         leaf = box->isLeaf() ? box : toInlineFlowBox(box)->lastLeafChild();
    264     if (!leaf && parent())
    265         leaf = parent()->prevLeafChild();
    266     return leaf;
    267 }
    268 
    269 InlineBox* InlineBox::nextLeafChildIgnoringLineBreak() const
    270 {
    271     InlineBox* leaf = nextLeafChild();
    272     if (leaf && leaf->isLineBreak())
    273         return 0;
    274     return leaf;
    275 }
    276 
    277 InlineBox* InlineBox::prevLeafChildIgnoringLineBreak() const
    278 {
    279     InlineBox* leaf = prevLeafChild();
    280     if (leaf && leaf->isLineBreak())
    281         return 0;
    282     return leaf;
    283 }
    284 
    285 RenderObject::SelectionState InlineBox::selectionState()
    286 {
    287     return renderer()->selectionState();
    288 }
    289 
    290 bool InlineBox::canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth) const
    291 {
    292     // Non-replaced elements can always accommodate an ellipsis.
    293     if (!m_renderer || !m_renderer->isReplaced())
    294         return true;
    295 
    296     IntRect boxRect(left(), 0, m_logicalWidth, 10);
    297     IntRect ellipsisRect(ltr ? blockEdge - ellipsisWidth : blockEdge, 0, ellipsisWidth, 10);
    298     return !(boxRect.intersects(ellipsisRect));
    299 }
    300 
    301 float InlineBox::placeEllipsisBox(bool, float, float, float, float& truncatedWidth, bool&)
    302 {
    303     // Use -1 to mean "we didn't set the position."
    304     truncatedWidth += logicalWidth();
    305     return -1;
    306 }
    307 
    308 void InlineBox::clearKnownToHaveNoOverflow()
    309 {
    310     m_bitfields.setKnownToHaveNoOverflow(false);
    311     if (parent() && parent()->knownToHaveNoOverflow())
    312         parent()->clearKnownToHaveNoOverflow();
    313 }
    314 
    315 FloatPoint InlineBox::locationIncludingFlipping()
    316 {
    317     if (!renderer()->style()->isFlippedBlocksWritingMode())
    318         return FloatPoint(x(), y());
    319     RenderBlockFlow* block = root()->block();
    320     if (block->style()->isHorizontalWritingMode())
    321         return FloatPoint(x(), block->height() - height() - y());
    322     else
    323         return FloatPoint(block->width() - width() - x(), y());
    324 }
    325 
    326 void InlineBox::flipForWritingMode(FloatRect& rect)
    327 {
    328     if (!renderer()->style()->isFlippedBlocksWritingMode())
    329         return;
    330     root()->block()->flipForWritingMode(rect);
    331 }
    332 
    333 FloatPoint InlineBox::flipForWritingMode(const FloatPoint& point)
    334 {
    335     if (!renderer()->style()->isFlippedBlocksWritingMode())
    336         return point;
    337     return root()->block()->flipForWritingMode(point);
    338 }
    339 
    340 void InlineBox::flipForWritingMode(LayoutRect& rect)
    341 {
    342     if (!renderer()->style()->isFlippedBlocksWritingMode())
    343         return;
    344     root()->block()->flipForWritingMode(rect);
    345 }
    346 
    347 LayoutPoint InlineBox::flipForWritingMode(const LayoutPoint& point)
    348 {
    349     if (!renderer()->style()->isFlippedBlocksWritingMode())
    350         return point;
    351     return root()->block()->flipForWritingMode(point);
    352 }
    353 
    354 } // namespace WebCore
    355 
    356 #ifndef NDEBUG
    357 
    358 void showTree(const WebCore::InlineBox* b)
    359 {
    360     if (b)
    361         b->showTreeForThis();
    362 }
    363 
    364 void showLineTree(const WebCore::InlineBox* b)
    365 {
    366     if (b)
    367         b->showLineTreeForThis();
    368 }
    369 
    370 #endif
    371