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