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 
     21 #ifndef InlineFlowBox_h
     22 #define InlineFlowBox_h
     23 
     24 #include "core/rendering/InlineBox.h"
     25 #include "core/rendering/RenderOverflow.h"
     26 #include "core/rendering/style/ShadowData.h"
     27 
     28 namespace WebCore {
     29 
     30 class HitTestRequest;
     31 class HitTestResult;
     32 class InlineTextBox;
     33 class RenderLineBoxList;
     34 class SimpleFontData;
     35 class VerticalPositionCache;
     36 
     37 struct GlyphOverflow;
     38 
     39 typedef HashMap<const InlineTextBox*, pair<Vector<const SimpleFontData*>, GlyphOverflow> > GlyphOverflowAndFallbackFontsMap;
     40 
     41 class InlineFlowBox : public InlineBox {
     42 public:
     43     InlineFlowBox(RenderObject* obj)
     44         : InlineBox(obj)
     45         , m_firstChild(0)
     46         , m_lastChild(0)
     47         , m_prevLineBox(0)
     48         , m_nextLineBox(0)
     49         , m_includeLogicalLeftEdge(false)
     50         , m_includeLogicalRightEdge(false)
     51         , m_descendantsHaveSameLineHeightAndBaseline(true)
     52         , m_baselineType(AlphabeticBaseline)
     53         , m_hasAnnotationsBefore(false)
     54         , m_hasAnnotationsAfter(false)
     55 #ifndef NDEBUG
     56         , m_hasBadChildList(false)
     57 #endif
     58     {
     59         // Internet Explorer and Firefox always create a marker for list items, even when the list-style-type is none.  We do not make a marker
     60         // in the list-style-type: none case, since it is wasteful to do so.  However, in order to match other browsers we have to pretend like
     61         // an invisible marker exists.  The side effect of having an invisible marker is that the quirks mode behavior of shrinking lines with no
     62         // text children must not apply.  This change also means that gaps will exist between image bullet list items.  Even when the list bullet
     63         // is an image, the line is still considered to be immune from the quirk.
     64         m_hasTextChildren = obj->style()->display() == LIST_ITEM;
     65         m_hasTextDescendants = m_hasTextChildren;
     66     }
     67 
     68 #ifndef NDEBUG
     69     virtual ~InlineFlowBox();
     70 
     71     virtual void showLineTreeAndMark(const InlineBox* = 0, const char* = 0, const InlineBox* = 0, const char* = 0, const RenderObject* = 0, int = 0) const;
     72     virtual const char* boxName() const;
     73 #endif
     74 
     75     InlineFlowBox* prevLineBox() const { return m_prevLineBox; }
     76     InlineFlowBox* nextLineBox() const { return m_nextLineBox; }
     77     void setNextLineBox(InlineFlowBox* n) { m_nextLineBox = n; }
     78     void setPreviousLineBox(InlineFlowBox* p) { m_prevLineBox = p; }
     79 
     80     InlineBox* firstChild() const { checkConsistency(); return m_firstChild; }
     81     InlineBox* lastChild() const { checkConsistency(); return m_lastChild; }
     82 
     83     virtual bool isLeaf() const OVERRIDE FINAL { return false; }
     84 
     85     InlineBox* firstLeafChild() const;
     86     InlineBox* lastLeafChild() const;
     87 
     88     typedef void (*CustomInlineBoxRangeReverse)(void* userData, Vector<InlineBox*>::iterator first, Vector<InlineBox*>::iterator last);
     89     void collectLeafBoxesInLogicalOrder(Vector<InlineBox*>&, CustomInlineBoxRangeReverse customReverseImplementation = 0, void* userData = 0) const;
     90 
     91     virtual void setConstructed() OVERRIDE FINAL
     92     {
     93         InlineBox::setConstructed();
     94         for (InlineBox* child = firstChild(); child; child = child->nextOnLine())
     95             child->setConstructed();
     96     }
     97 
     98     void addToLine(InlineBox* child);
     99     virtual void deleteLine() OVERRIDE FINAL;
    100     virtual void extractLine() OVERRIDE FINAL;
    101     virtual void attachLine() OVERRIDE FINAL;
    102     virtual void adjustPosition(float dx, float dy);
    103 
    104     virtual void extractLineBoxFromRenderObject();
    105     virtual void attachLineBoxToRenderObject();
    106     virtual void removeLineBoxFromRenderObject();
    107 
    108     virtual void clearTruncation() OVERRIDE;
    109 
    110     IntRect roundedFrameRect() const;
    111 
    112     void paintBoxDecorations(PaintInfo&, const LayoutPoint&);
    113     void paintMask(PaintInfo&, const LayoutPoint&);
    114     void paintFillLayers(const PaintInfo&, const Color&, const FillLayer*, const LayoutRect&, CompositeOperator = CompositeSourceOver);
    115     void paintFillLayer(const PaintInfo&, const Color&, const FillLayer*, const LayoutRect&, CompositeOperator = CompositeSourceOver);
    116     void paintBoxShadow(const PaintInfo&, RenderStyle*, ShadowStyle, const LayoutRect&);
    117     virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom);
    118     virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom) OVERRIDE;
    119 
    120     bool boxShadowCanBeAppliedToBackground(const FillLayer&) const;
    121 
    122     virtual RenderLineBoxList* rendererLineBoxes() const;
    123 
    124     // logicalLeft = left in a horizontal line and top in a vertical line.
    125     LayoutUnit marginBorderPaddingLogicalLeft() const { return marginLogicalLeft() + borderLogicalLeft() + paddingLogicalLeft(); }
    126     LayoutUnit marginBorderPaddingLogicalRight() const { return marginLogicalRight() + borderLogicalRight() + paddingLogicalRight(); }
    127     LayoutUnit marginLogicalLeft() const
    128     {
    129         if (!includeLogicalLeftEdge())
    130             return 0;
    131         return isHorizontal() ? boxModelObject()->marginLeft() : boxModelObject()->marginTop();
    132     }
    133     LayoutUnit marginLogicalRight() const
    134     {
    135         if (!includeLogicalRightEdge())
    136             return 0;
    137         return isHorizontal() ? boxModelObject()->marginRight() : boxModelObject()->marginBottom();
    138     }
    139     int borderLogicalLeft() const
    140     {
    141         if (!includeLogicalLeftEdge())
    142             return 0;
    143         return isHorizontal() ? renderer()->style(isFirstLineStyle())->borderLeftWidth() : renderer()->style(isFirstLineStyle())->borderTopWidth();
    144     }
    145     int borderLogicalRight() const
    146     {
    147         if (!includeLogicalRightEdge())
    148             return 0;
    149         return isHorizontal() ? renderer()->style(isFirstLineStyle())->borderRightWidth() : renderer()->style(isFirstLineStyle())->borderBottomWidth();
    150     }
    151     int paddingLogicalLeft() const
    152     {
    153         if (!includeLogicalLeftEdge())
    154             return 0;
    155         return isHorizontal() ? boxModelObject()->paddingLeft() : boxModelObject()->paddingTop();
    156     }
    157     int paddingLogicalRight() const
    158     {
    159         if (!includeLogicalRightEdge())
    160             return 0;
    161         return isHorizontal() ? boxModelObject()->paddingRight() : boxModelObject()->paddingBottom();
    162     }
    163 
    164     bool includeLogicalLeftEdge() const { return m_includeLogicalLeftEdge; }
    165     bool includeLogicalRightEdge() const { return m_includeLogicalRightEdge; }
    166     void setEdges(bool includeLeft, bool includeRight)
    167     {
    168         m_includeLogicalLeftEdge = includeLeft;
    169         m_includeLogicalRightEdge = includeRight;
    170     }
    171 
    172     // Helper functions used during line construction and placement.
    173     void determineSpacingForFlowBoxes(bool lastLine, bool isLogicallyLastRunWrapped, RenderObject* logicallyLastRunRenderer);
    174     LayoutUnit getFlowSpacingLogicalWidth();
    175     float placeBoxesInInlineDirection(float logicalLeft, bool& needsWordSpacing, GlyphOverflowAndFallbackFontsMap&);
    176     float placeBoxRangeInInlineDirection(InlineBox* firstChild, InlineBox* lastChild, float& logicalLeft, float& minLogicalLeft, float& maxLogicalRight, bool& needsWordSpacing, GlyphOverflowAndFallbackFontsMap&);
    177     void beginPlacingBoxRangesInInlineDirection(float logicalLeft) { setLogicalLeft(logicalLeft); }
    178     void endPlacingBoxRangesInInlineDirection(float logicalLeft, float logicalRight, float minLogicalLeft, float maxLogicalRight)
    179     {
    180         setLogicalWidth(logicalRight - logicalLeft);
    181         if (knownToHaveNoOverflow() && (minLogicalLeft < logicalLeft || maxLogicalRight > logicalRight))
    182             clearKnownToHaveNoOverflow();
    183     }
    184 
    185     void computeLogicalBoxHeights(RootInlineBox*, LayoutUnit& maxPositionTop, LayoutUnit& maxPositionBottom,
    186                                   int& maxAscent, int& maxDescent, bool& setMaxAscent, bool& setMaxDescent,
    187                                   bool strictMode, GlyphOverflowAndFallbackFontsMap&, FontBaseline, VerticalPositionCache&);
    188     void adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent,
    189                                    int maxPositionTop, int maxPositionBottom);
    190     void placeBoxesInBlockDirection(LayoutUnit logicalTop, LayoutUnit maxHeight, int maxAscent, bool strictMode, LayoutUnit& lineTop, LayoutUnit& lineBottom, bool& setLineTop,
    191                                     LayoutUnit& lineTopIncludingMargins, LayoutUnit& lineBottomIncludingMargins, bool& hasAnnotationsBefore, bool& hasAnnotationsAfter, FontBaseline);
    192     void flipLinesInBlockDirection(LayoutUnit lineTop, LayoutUnit lineBottom);
    193     bool requiresIdeographicBaseline(const GlyphOverflowAndFallbackFontsMap&) const;
    194 
    195     LayoutUnit computeOverAnnotationAdjustment(LayoutUnit allowedPosition) const;
    196     LayoutUnit computeUnderAnnotationAdjustment(LayoutUnit allowedPosition) const;
    197 
    198     void computeOverflow(LayoutUnit lineTop, LayoutUnit lineBottom, GlyphOverflowAndFallbackFontsMap&);
    199 
    200     void removeChild(InlineBox* child);
    201 
    202     virtual RenderObject::SelectionState selectionState();
    203 
    204     virtual bool canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth) const OVERRIDE FINAL;
    205     virtual float placeEllipsisBox(bool ltr, float blockLeftEdge, float blockRightEdge, float ellipsisWidth, float &truncatedWidth, bool&) OVERRIDE;
    206 
    207     bool hasTextChildren() const { return m_hasTextChildren; }
    208     bool hasTextDescendants() const { return m_hasTextDescendants; }
    209     void setHasTextChildren() { m_hasTextChildren = true; setHasTextDescendants(); }
    210     void setHasTextDescendants() { m_hasTextDescendants = true; }
    211 
    212     void checkConsistency() const;
    213     void setHasBadChildList();
    214 
    215     // Line visual and layout overflow are in the coordinate space of the block.  This means that they aren't purely physical directions.
    216     // For horizontal-tb and vertical-lr they will match physical directions, but for horizontal-bt and vertical-rl, the top/bottom and left/right
    217     // respectively are flipped when compared to their physical counterparts.  For example minX is on the left in vertical-lr, but it is on the right in vertical-rl.
    218     LayoutRect layoutOverflowRect(LayoutUnit lineTop, LayoutUnit lineBottom) const
    219     {
    220         return m_overflow ? m_overflow->layoutOverflowRect() : enclosingLayoutRect(frameRectIncludingLineHeight(lineTop, lineBottom));
    221     }
    222     LayoutUnit logicalLeftLayoutOverflow() const
    223     {
    224         return m_overflow ? (isHorizontal() ? m_overflow->layoutOverflowRect().x() : m_overflow->layoutOverflowRect().y()) :
    225                             static_cast<LayoutUnit>(logicalLeft());
    226     }
    227     LayoutUnit logicalRightLayoutOverflow() const
    228     {
    229         return m_overflow ? (isHorizontal() ? m_overflow->layoutOverflowRect().maxX() : m_overflow->layoutOverflowRect().maxY()) :
    230                             static_cast<LayoutUnit>(ceilf(logicalRight()));
    231     }
    232     LayoutUnit logicalTopLayoutOverflow(LayoutUnit lineTop) const
    233     {
    234         if (m_overflow)
    235             return isHorizontal() ? m_overflow->layoutOverflowRect().y() : m_overflow->layoutOverflowRect().x();
    236         return lineTop;
    237     }
    238     LayoutUnit logicalBottomLayoutOverflow(LayoutUnit lineBottom) const
    239     {
    240         if (m_overflow)
    241             return isHorizontal() ? m_overflow->layoutOverflowRect().maxY() : m_overflow->layoutOverflowRect().maxX();
    242         return lineBottom;
    243     }
    244     LayoutRect logicalLayoutOverflowRect(LayoutUnit lineTop, LayoutUnit lineBottom) const
    245     {
    246         LayoutRect result = layoutOverflowRect(lineTop, lineBottom);
    247         if (!renderer()->isHorizontalWritingMode())
    248             result = result.transposedRect();
    249         return result;
    250     }
    251 
    252     LayoutRect visualOverflowRect(LayoutUnit lineTop, LayoutUnit lineBottom) const
    253     {
    254         return m_overflow ? m_overflow->visualOverflowRect() : enclosingLayoutRect(frameRectIncludingLineHeight(lineTop, lineBottom));
    255     }
    256     LayoutUnit logicalLeftVisualOverflow() const { return m_overflow ? (isHorizontal() ? m_overflow->visualOverflowRect().x() : m_overflow->visualOverflowRect().y()) : static_cast<LayoutUnit>(logicalLeft()); }
    257     LayoutUnit logicalRightVisualOverflow() const { return m_overflow ? (isHorizontal() ? m_overflow->visualOverflowRect().maxX() : m_overflow->visualOverflowRect().maxY()) : static_cast<LayoutUnit>(ceilf(logicalRight())); }
    258     LayoutUnit logicalTopVisualOverflow(LayoutUnit lineTop) const
    259     {
    260         if (m_overflow)
    261             return isHorizontal() ? m_overflow->visualOverflowRect().y() : m_overflow->visualOverflowRect().x();
    262         return lineTop;
    263     }
    264     LayoutUnit logicalBottomVisualOverflow(LayoutUnit lineBottom) const
    265     {
    266         if (m_overflow)
    267             return isHorizontal() ? m_overflow->visualOverflowRect().maxY() : m_overflow->visualOverflowRect().maxX();
    268         return lineBottom;
    269     }
    270     LayoutRect logicalVisualOverflowRect(LayoutUnit lineTop, LayoutUnit lineBottom) const
    271     {
    272         LayoutRect result = visualOverflowRect(lineTop, lineBottom);
    273         if (!renderer()->isHorizontalWritingMode())
    274             result = result.transposedRect();
    275         return result;
    276     }
    277 
    278     void setOverflowFromLogicalRects(const LayoutRect& logicalLayoutOverflow, const LayoutRect& logicalVisualOverflow, LayoutUnit lineTop, LayoutUnit lineBottom);
    279     void setLayoutOverflow(const LayoutRect&, LayoutUnit lineTop, LayoutUnit lineBottom);
    280     void setVisualOverflow(const LayoutRect&, LayoutUnit lineTop, LayoutUnit lineBottom);
    281 
    282     FloatRect frameRectIncludingLineHeight(LayoutUnit lineTop, LayoutUnit lineBottom) const
    283     {
    284         if (isHorizontal())
    285             return FloatRect(m_topLeft.x(), lineTop, width(), lineBottom - lineTop);
    286         return FloatRect(lineTop, m_topLeft.y(), lineBottom - lineTop, height());
    287     }
    288 
    289     FloatRect logicalFrameRectIncludingLineHeight(LayoutUnit lineTop, LayoutUnit lineBottom) const
    290     {
    291         return FloatRect(logicalLeft(), lineTop, logicalWidth(), lineBottom - lineTop);
    292     }
    293 
    294     bool descendantsHaveSameLineHeightAndBaseline() const { return m_descendantsHaveSameLineHeightAndBaseline; }
    295     void clearDescendantsHaveSameLineHeightAndBaseline()
    296     {
    297         m_descendantsHaveSameLineHeightAndBaseline = false;
    298         if (parent() && parent()->descendantsHaveSameLineHeightAndBaseline())
    299             parent()->clearDescendantsHaveSameLineHeightAndBaseline();
    300     }
    301 
    302 private:
    303     void addBoxShadowVisualOverflow(LayoutRect& logicalVisualOverflow);
    304     void addBorderOutsetVisualOverflow(LayoutRect& logicalVisualOverflow);
    305     void addTextBoxVisualOverflow(InlineTextBox*, GlyphOverflowAndFallbackFontsMap&, LayoutRect& logicalVisualOverflow);
    306     void addReplacedChildOverflow(const InlineBox*, LayoutRect& logicalLayoutOverflow, LayoutRect& logicalVisualOverflow);
    307     void constrainToLineTopAndBottomIfNeeded(LayoutRect&) const;
    308 
    309 protected:
    310     OwnPtr<RenderOverflow> m_overflow;
    311 
    312     virtual bool isInlineFlowBox() const OVERRIDE FINAL { return true; }
    313 
    314     InlineBox* m_firstChild;
    315     InlineBox* m_lastChild;
    316 
    317     InlineFlowBox* m_prevLineBox; // The previous box that also uses our RenderObject
    318     InlineFlowBox* m_nextLineBox; // The next box that also uses our RenderObject
    319 
    320 #if ENABLE(CSS3_TEXT)
    321     // Maximum logicalTop among all children of an InlineFlowBox. Used to
    322     // calculate the offset for TextUnderlinePositionUnder.
    323     void computeMaxLogicalTop(float& maxLogicalTop) const;
    324 #endif // CSS3_TEXT
    325 private:
    326     unsigned m_includeLogicalLeftEdge : 1;
    327     unsigned m_includeLogicalRightEdge : 1;
    328     unsigned m_hasTextChildren : 1;
    329     unsigned m_hasTextDescendants : 1;
    330     unsigned m_descendantsHaveSameLineHeightAndBaseline : 1;
    331 
    332 protected:
    333     // The following members are only used by RootInlineBox but moved here to keep the bits packed.
    334 
    335     // Whether or not this line uses alphabetic or ideographic baselines by default.
    336     unsigned m_baselineType : 1; // FontBaseline
    337 
    338     // If the line contains any ruby runs, then this will be true.
    339     unsigned m_hasAnnotationsBefore : 1;
    340     unsigned m_hasAnnotationsAfter : 1;
    341 
    342     unsigned m_lineBreakBidiStatusEor : 5; // WTF::Unicode::Direction
    343     unsigned m_lineBreakBidiStatusLastStrong : 5; // WTF::Unicode::Direction
    344     unsigned m_lineBreakBidiStatusLast : 5; // WTF::Unicode::Direction
    345 
    346     // End of RootInlineBox-specific members.
    347 
    348 #ifndef NDEBUG
    349 private:
    350     unsigned m_hasBadChildList : 1;
    351 #endif
    352 };
    353 
    354 inline InlineFlowBox* toInlineFlowBox(InlineBox* object)
    355 {
    356     ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isInlineFlowBox());
    357     return static_cast<InlineFlowBox*>(object);
    358 }
    359 
    360 inline const InlineFlowBox* toInlineFlowBox(const InlineBox* object)
    361 {
    362     ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isInlineFlowBox());
    363     return static_cast<const InlineFlowBox*>(object);
    364 }
    365 
    366 // This will catch anyone doing an unnecessary cast.
    367 void toInlineFlowBox(const InlineFlowBox*);
    368 
    369 #ifdef NDEBUG
    370 inline void InlineFlowBox::checkConsistency() const
    371 {
    372 }
    373 #endif
    374 
    375 inline void InlineFlowBox::setHasBadChildList()
    376 {
    377 #ifndef NDEBUG
    378     m_hasBadChildList = true;
    379 #endif
    380 }
    381 
    382 } // namespace WebCore
    383 
    384 #ifndef NDEBUG
    385 // Outside the WebCore namespace for ease of invocation from gdb.
    386 void showTree(const WebCore::InlineFlowBox*);
    387 #endif
    388 
    389 #endif // InlineFlowBox_h
    390