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 "InlineBox.h"
     25 #include "RenderOverflow.h"
     26 #include "ShadowData.h"
     27 
     28 namespace WebCore {
     29 
     30 class HitTestRequest;
     31 class HitTestResult;
     32 class InlineTextBox;
     33 class RenderLineBoxList;
     34 class VerticalPositionCache;
     35 
     36 typedef HashMap<const InlineTextBox*, pair<Vector<const SimpleFontData*>, GlyphOverflow> > GlyphOverflowAndFallbackFontsMap;
     37 
     38 class InlineFlowBox : public InlineBox {
     39 public:
     40     InlineFlowBox(RenderObject* obj)
     41         : InlineBox(obj)
     42         , m_firstChild(0)
     43         , m_lastChild(0)
     44         , m_prevLineBox(0)
     45         , m_nextLineBox(0)
     46         , m_includeLogicalLeftEdge(false)
     47         , m_includeLogicalRightEdge(false)
     48         , m_descendantsHaveSameLineHeightAndBaseline(true)
     49 #ifndef NDEBUG
     50         , m_hasBadChildList(false)
     51 #endif
     52     {
     53         // 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
     54         // 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
     55         // an invisible marker exists.  The side effect of having an invisible marker is that the quirks mode behavior of shrinking lines with no
     56         // text children must not apply.  This change also means that gaps will exist between image bullet list items.  Even when the list bullet
     57         // is an image, the line is still considered to be immune from the quirk.
     58         m_hasTextChildren = obj->style()->display() == LIST_ITEM;
     59         m_hasTextDescendants = m_hasTextChildren;
     60     }
     61 
     62 #ifndef NDEBUG
     63     virtual ~InlineFlowBox();
     64 #endif
     65 
     66     InlineFlowBox* prevLineBox() const { return m_prevLineBox; }
     67     InlineFlowBox* nextLineBox() const { return m_nextLineBox; }
     68     void setNextLineBox(InlineFlowBox* n) { m_nextLineBox = n; }
     69     void setPreviousLineBox(InlineFlowBox* p) { m_prevLineBox = p; }
     70 
     71     InlineBox* firstChild() const { checkConsistency(); return m_firstChild; }
     72     InlineBox* lastChild() const { checkConsistency(); return m_lastChild; }
     73 
     74     virtual bool isLeaf() const { return false; }
     75 
     76     InlineBox* firstLeafChild() const;
     77     InlineBox* lastLeafChild() const;
     78 
     79     typedef void (*CustomInlineBoxRangeReverse)(void* userData, Vector<InlineBox*>::iterator first, Vector<InlineBox*>::iterator last);
     80     void collectLeafBoxesInLogicalOrder(Vector<InlineBox*>&, CustomInlineBoxRangeReverse customReverseImplementation = 0, void* userData = 0) const;
     81 
     82     virtual void setConstructed()
     83     {
     84         InlineBox::setConstructed();
     85         for (InlineBox* child = firstChild(); child; child = child->next())
     86             child->setConstructed();
     87     }
     88 
     89     void addToLine(InlineBox* child);
     90     virtual void deleteLine(RenderArena*);
     91     virtual void extractLine();
     92     virtual void attachLine();
     93     virtual void adjustPosition(float dx, float dy);
     94 
     95     virtual void extractLineBoxFromRenderObject();
     96     virtual void attachLineBoxToRenderObject();
     97     virtual void removeLineBoxFromRenderObject();
     98 
     99     virtual void clearTruncation();
    100 
    101     IntRect roundedFrameRect() const;
    102 
    103     virtual void paintBoxDecorations(PaintInfo&, int tx, int ty);
    104     virtual void paintMask(PaintInfo&, int tx, int ty);
    105     void paintFillLayers(const PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int w, int h, CompositeOperator = CompositeSourceOver);
    106     void paintFillLayer(const PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int w, int h, CompositeOperator = CompositeSourceOver);
    107     void paintBoxShadow(GraphicsContext*, RenderStyle*, ShadowStyle, int tx, int ty, int w, int h);
    108     virtual void paint(PaintInfo&, int tx, int ty, int lineTop, int lineBottom);
    109     virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, int lineTop, int lineBottom);
    110 
    111     virtual RenderLineBoxList* rendererLineBoxes() const;
    112 
    113     // logicalLeft = left in a horizontal line and top in a vertical line.
    114     int marginBorderPaddingLogicalLeft() const { return marginLogicalLeft() + borderLogicalLeft() + paddingLogicalLeft(); }
    115     int marginBorderPaddingLogicalRight() const { return marginLogicalRight() + borderLogicalRight() + paddingLogicalRight(); }
    116     int marginLogicalLeft() const
    117     {
    118         if (!includeLogicalLeftEdge())
    119             return 0;
    120         return isHorizontal() ? boxModelObject()->marginLeft() : boxModelObject()->marginTop();
    121     }
    122     int marginLogicalRight() const
    123     {
    124         if (!includeLogicalRightEdge())
    125             return 0;
    126         return isHorizontal() ? boxModelObject()->marginRight() : boxModelObject()->marginBottom();
    127     }
    128     int borderLogicalLeft() const
    129     {
    130         if (!includeLogicalLeftEdge())
    131             return 0;
    132         return isHorizontal() ? renderer()->style()->borderLeftWidth() : renderer()->style()->borderTopWidth();
    133     }
    134     int borderLogicalRight() const
    135     {
    136         if (!includeLogicalRightEdge())
    137             return 0;
    138         return isHorizontal() ? renderer()->style()->borderRightWidth() : renderer()->style()->borderBottomWidth();
    139     }
    140     int paddingLogicalLeft() const
    141     {
    142         if (!includeLogicalLeftEdge())
    143             return 0;
    144         return isHorizontal() ? boxModelObject()->paddingLeft() : boxModelObject()->paddingTop();
    145     }
    146     int paddingLogicalRight() const
    147     {
    148         if (!includeLogicalRightEdge())
    149             return 0;
    150         return isHorizontal() ? boxModelObject()->paddingRight() : boxModelObject()->paddingBottom();
    151     }
    152 
    153     bool includeLogicalLeftEdge() const { return m_includeLogicalLeftEdge; }
    154     bool includeLogicalRightEdge() const { return m_includeLogicalRightEdge; }
    155     void setEdges(bool includeLeft, bool includeRight)
    156     {
    157         m_includeLogicalLeftEdge = includeLeft;
    158         m_includeLogicalRightEdge = includeRight;
    159     }
    160 
    161     // Helper functions used during line construction and placement.
    162     void determineSpacingForFlowBoxes(bool lastLine, bool isLogicallyLastRunWrapped, RenderObject* logicallyLastRunRenderer);
    163     int getFlowSpacingLogicalWidth();
    164     float placeBoxesInInlineDirection(float logicalLeft, bool& needsWordSpacing, GlyphOverflowAndFallbackFontsMap&);
    165     void computeLogicalBoxHeights(RootInlineBox*, int& maxPositionTop, int& maxPositionBottom,
    166                                   int& maxAscent, int& maxDescent, bool& setMaxAscent, bool& setMaxDescent,
    167                                   bool strictMode, GlyphOverflowAndFallbackFontsMap&, FontBaseline, VerticalPositionCache&);
    168     void adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent,
    169                                    int maxPositionTop, int maxPositionBottom);
    170     void placeBoxesInBlockDirection(int logicalTop, int maxHeight, int maxAscent, bool strictMode, int& lineTop, int& lineBottom, bool& setLineTop,
    171                                     int& lineTopIncludingMargins, int& lineBottomIncludingMargins, bool& hasAnnotationsBefore, bool& hasAnnotationsAfter, FontBaseline);
    172     void flipLinesInBlockDirection(int lineTop, int lineBottom);
    173     bool requiresIdeographicBaseline(const GlyphOverflowAndFallbackFontsMap&) const;
    174 
    175     int computeOverAnnotationAdjustment(int allowedPosition) const;
    176     int computeUnderAnnotationAdjustment(int allowedPosition) const;
    177 
    178     void computeOverflow(int lineTop, int lineBottom, GlyphOverflowAndFallbackFontsMap&);
    179 
    180     void removeChild(InlineBox* child);
    181 
    182     virtual RenderObject::SelectionState selectionState();
    183 
    184     virtual bool canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth);
    185     virtual float placeEllipsisBox(bool ltr, float blockLeftEdge, float blockRightEdge, float ellipsisWidth, bool&);
    186 
    187     bool hasTextChildren() const { return m_hasTextChildren; }
    188     bool hasTextDescendants() const { return m_hasTextDescendants; }
    189 
    190     void checkConsistency() const;
    191     void setHasBadChildList();
    192 
    193     // Line visual and layout overflow are in the coordinate space of the block.  This means that they aren't purely physical directions.
    194     // For horizontal-tb and vertical-lr they will match physical directions, but for horizontal-bt and vertical-rl, the top/bottom and left/right
    195     // 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.
    196     IntRect layoutOverflowRect(int lineTop, int lineBottom) const
    197     {
    198         return m_overflow ? m_overflow->layoutOverflowRect() : enclosingIntRect(frameRectIncludingLineHeight(lineTop, lineBottom));
    199     }
    200     int logicalLeftLayoutOverflow() const { return m_overflow ? (isHorizontal() ? m_overflow->minXLayoutOverflow() : m_overflow->minYLayoutOverflow()) : logicalLeft(); }
    201     int logicalRightLayoutOverflow() const { return m_overflow ? (isHorizontal() ? m_overflow->maxXLayoutOverflow() : m_overflow->maxYLayoutOverflow()) : ceilf(logicalRight()); }
    202     int logicalTopLayoutOverflow(int lineTop) const
    203     {
    204         if (m_overflow)
    205             return isHorizontal() ? m_overflow->minYLayoutOverflow() : m_overflow->minXLayoutOverflow();
    206         return lineTop;
    207     }
    208     int logicalBottomLayoutOverflow(int lineBottom) const
    209     {
    210         if (m_overflow)
    211             return isHorizontal() ? m_overflow->maxYLayoutOverflow() : m_overflow->maxXLayoutOverflow();
    212         return lineBottom;
    213     }
    214     IntRect logicalLayoutOverflowRect(int lineTop, int lineBottom) const
    215     {
    216         IntRect result = layoutOverflowRect(lineTop, lineBottom);
    217         if (!renderer()->isHorizontalWritingMode())
    218             result = result.transposedRect();
    219         return result;
    220     }
    221 
    222     IntRect visualOverflowRect(int lineTop, int lineBottom) const
    223     {
    224         return m_overflow ? m_overflow->visualOverflowRect() : enclosingIntRect(frameRectIncludingLineHeight(lineTop, lineBottom));
    225     }
    226     int logicalLeftVisualOverflow() const { return m_overflow ? (isHorizontal() ? m_overflow->minXVisualOverflow() : m_overflow->minYVisualOverflow()) : logicalLeft(); }
    227     int logicalRightVisualOverflow() const { return m_overflow ? (isHorizontal() ? m_overflow->maxXVisualOverflow() : m_overflow->maxYVisualOverflow()) : ceilf(logicalRight()); }
    228     int logicalTopVisualOverflow(int lineTop) const
    229     {
    230         if (m_overflow)
    231             return isHorizontal() ? m_overflow->minYVisualOverflow() : m_overflow->minXVisualOverflow();
    232         return lineTop;
    233     }
    234     int logicalBottomVisualOverflow(int lineBottom) const
    235     {
    236         if (m_overflow)
    237             return isHorizontal() ? m_overflow->maxYVisualOverflow() : m_overflow->maxXVisualOverflow();
    238         return lineBottom;
    239     }
    240     IntRect logicalVisualOverflowRect(int lineTop, int lineBottom) const
    241     {
    242         IntRect result = visualOverflowRect(lineTop, lineBottom);
    243         if (!renderer()->isHorizontalWritingMode())
    244             result = result.transposedRect();
    245         return result;
    246     }
    247 
    248     void setOverflowFromLogicalRects(const IntRect& logicalLayoutOverflow, const IntRect& logicalVisualOverflow, int lineTop, int lineBottom);
    249     void setLayoutOverflow(const IntRect&, int lineTop, int lineBottom);
    250     void setVisualOverflow(const IntRect&, int lineTop, int lineBottom);
    251 
    252     FloatRect frameRectIncludingLineHeight(int lineTop, int lineBottom) const
    253     {
    254         if (isHorizontal())
    255             return FloatRect(m_x, lineTop, width(), lineBottom - lineTop);
    256         return FloatRect(lineTop, m_y, lineBottom - lineTop, height());
    257     }
    258 
    259     FloatRect logicalFrameRectIncludingLineHeight(int lineTop, int lineBottom) const
    260     {
    261         return FloatRect(logicalLeft(), lineTop, logicalWidth(), lineBottom - lineTop);
    262     }
    263 
    264     bool descendantsHaveSameLineHeightAndBaseline() const { return m_descendantsHaveSameLineHeightAndBaseline; }
    265     void clearDescendantsHaveSameLineHeightAndBaseline()
    266     {
    267         m_descendantsHaveSameLineHeightAndBaseline = false;
    268         if (parent() && parent()->descendantsHaveSameLineHeightAndBaseline())
    269             parent()->clearDescendantsHaveSameLineHeightAndBaseline();
    270     }
    271 
    272 private:
    273     void addBoxShadowVisualOverflow(IntRect& logicalVisualOverflow);
    274     void addTextBoxVisualOverflow(InlineTextBox*, GlyphOverflowAndFallbackFontsMap&, IntRect& logicalVisualOverflow);
    275     void addReplacedChildOverflow(const InlineBox*, IntRect& logicalLayoutOverflow, IntRect& logicalVisualOverflow);
    276 
    277 protected:
    278     OwnPtr<RenderOverflow> m_overflow;
    279 
    280     virtual bool isInlineFlowBox() const { return true; }
    281 
    282     InlineBox* m_firstChild;
    283     InlineBox* m_lastChild;
    284 
    285     InlineFlowBox* m_prevLineBox; // The previous box that also uses our RenderObject
    286     InlineFlowBox* m_nextLineBox; // The next box that also uses our RenderObject
    287 
    288     bool m_includeLogicalLeftEdge : 1;
    289     bool m_includeLogicalRightEdge : 1;
    290     bool m_hasTextChildren : 1;
    291     bool m_hasTextDescendants : 1;
    292     bool m_descendantsHaveSameLineHeightAndBaseline : 1;
    293 
    294 #ifndef NDEBUG
    295     bool m_hasBadChildList;
    296 #endif
    297 };
    298 
    299 #ifdef NDEBUG
    300 inline void InlineFlowBox::checkConsistency() const
    301 {
    302 }
    303 #endif
    304 
    305 inline void InlineFlowBox::setHasBadChildList()
    306 {
    307 #ifndef NDEBUG
    308     m_hasBadChildList = true;
    309 #endif
    310 }
    311 
    312 } // namespace WebCore
    313 
    314 #ifndef NDEBUG
    315 // Outside the WebCore namespace for ease of invocation from gdb.
    316 void showTree(const WebCore::InlineFlowBox*);
    317 #endif
    318 
    319 #endif // InlineFlowBox_h
    320