File indexing completed on 2024-04-28 15:23:56

0001 /*
0002  * This file is part of the render object implementation for KHTML.
0003  *
0004  * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org)
0005  *           (C) 1999-2003 Antti Koivisto (koivisto@kde.org)
0006  *           (C) 2002-2003 Dirk Mueller (mueller@kde.org)
0007  *           (C) 2003 Apple Computer, Inc.
0008  *
0009  * This library is free software; you can redistribute it and/or
0010  * modify it under the terms of the GNU Library General Public
0011  * License as published by the Free Software Foundation; either
0012  * version 2 of the License, or (at your option) any later version.
0013  *
0014  * This library is distributed in the hope that it will be useful,
0015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0017  * Library General Public License for more details.
0018  *
0019  * You should have received a copy of the GNU Library General Public License
0020  * along with this library; see the file COPYING.LIB.  If not, write to
0021  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0022  * Boston, MA 02110-1301, USA.
0023  *
0024  */
0025 
0026 #ifndef RENDER_BLOCK_H
0027 #define RENDER_BLOCK_H
0028 
0029 #include <QList>
0030 
0031 #include "render_flow.h"
0032 
0033 namespace DOM
0034 {
0035 class Position;
0036 }
0037 
0038 namespace khtml
0039 {
0040 
0041 class RenderBlock : public RenderFlow
0042 {
0043 public:
0044     RenderBlock(DOM::NodeImpl *node);
0045     virtual ~RenderBlock();
0046 
0047     const char *renderName() const override;
0048 
0049     bool isRenderBlock() const override
0050     {
0051         return true;
0052     }
0053     bool isBlockFlow() const override
0054     {
0055         return (!isInline() || isReplaced()) && !isTable();
0056     }
0057     bool isInlineFlow() const override
0058     {
0059         return isInline() && !isReplaced();
0060     }
0061     bool isInlineBlockOrInlineTable() const override
0062     {
0063         return isInline() && isReplaced();
0064     }
0065 
0066     bool childrenInline() const override
0067     {
0068         return m_childrenInline;
0069     }
0070     virtual void setChildrenInline(bool b)
0071     {
0072         m_childrenInline = b;
0073     }
0074     short baselinePosition(bool firstLine) const override;
0075 
0076     int getBaselineOfLastLineBox() const;
0077     void makeChildrenNonInline(RenderObject *insertionPoint = nullptr);
0078 
0079     void makePageBreakAvoidBlocks();
0080 
0081     // The height (and width) of a block when you include overflow spillage out of the bottom
0082     // of the block (e.g., a <div style="height:25px"> that has a 100px tall image inside
0083     // it would have an overflow height of borderTop() + paddingTop() + 100px.
0084     int overflowHeight() const override
0085     {
0086         return m_overflowHeight;
0087     }
0088     int overflowWidth() const override
0089     {
0090         return m_overflowWidth;
0091     }
0092     int overflowLeft() const override
0093     {
0094         return m_overflowLeft;
0095     }
0096     int overflowTop() const override
0097     {
0098         return m_overflowTop;
0099     }
0100     virtual void setOverflowHeight(int h)
0101     {
0102         m_overflowHeight = h;
0103     }
0104     virtual void setOverflowWidth(int w)
0105     {
0106         m_overflowWidth = w;
0107     }
0108     virtual void setOverflowLeft(int l)
0109     {
0110         m_overflowLeft = l;
0111     }
0112     virtual void setOverflowTop(int t)
0113     {
0114         m_overflowTop = t;
0115     }
0116 
0117     bool isSelfCollapsingBlock() const override;
0118     bool isTopMarginQuirk() const override
0119     {
0120         return m_topMarginQuirk;
0121     }
0122     bool isBottomMarginQuirk() const override
0123     {
0124         return m_bottomMarginQuirk;
0125     }
0126 
0127     short maxTopMargin(bool positive) const override
0128     {
0129         if (positive) {
0130             return m_maxTopPosMargin;
0131         } else {
0132             return m_maxTopNegMargin;
0133         }
0134     }
0135     short maxBottomMargin(bool positive) const override
0136     {
0137         if (positive) {
0138             return m_maxBottomPosMargin;
0139         } else {
0140             return m_maxBottomNegMargin;
0141         }
0142     }
0143 
0144     void initMaxMarginValues()
0145     {
0146         if (m_marginTop >= 0) {
0147             m_maxTopPosMargin = m_marginTop;
0148         } else {
0149             m_maxTopNegMargin = -m_marginTop;
0150         }
0151         if (m_marginBottom >= 0) {
0152             m_maxBottomPosMargin = m_marginBottom;
0153         } else {
0154             m_maxBottomNegMargin = -m_marginBottom;
0155         }
0156     }
0157 
0158     void addChildToFlow(RenderObject *newChild, RenderObject *beforeChild) override;
0159     void removeChild(RenderObject *oldChild) override;
0160 
0161     void setStyle(RenderStyle *_style) override;
0162     void attach() override;
0163     void updateFirstLetter();
0164 
0165     void layout() override;
0166     void layoutBlock(bool relayoutChildren);
0167     void layoutBlockChildren(bool relayoutChildren);
0168     void layoutInlineChildren(bool relayoutChildren, int breakBeforeLine = 0);
0169 
0170     void layoutPositionedObjects(bool relayoutChildren);
0171     void insertPositionedObject(RenderObject *o);
0172     void removePositionedObject(RenderObject *o);
0173 
0174     QRegion visibleFloatingRegion(int x, int y) const;
0175     // Called to lay out the legend for a fieldset.
0176     virtual RenderObject *layoutLegend(bool /*relayoutChildren*/)
0177     {
0178         return nullptr;
0179     }
0180 
0181     // the implementation of the following functions is in bidi.cpp
0182     void bidiReorderLine(const BidiIterator &start, const BidiIterator &end, BidiState &bidi);
0183     void fitBelowFloats(int widthToFit, int &availableWidth);
0184     BidiIterator findNextLineBreak(BidiIterator &start, BidiState &info);
0185     RootInlineBox *constructLine(const BidiIterator &start, const BidiIterator &end);
0186     InlineFlowBox *createLineBoxes(RenderObject *obj);
0187     bool inlineChildNeedsLineBox(RenderObject *obj);
0188     void computeHorizontalPositionsForLine(InlineFlowBox *lineBox, BidiState &bidi);
0189     void computeVerticalPositionsForLine(RootInlineBox *lineBox);
0190     bool clearLineOfPageBreaks(InlineFlowBox *lineBox);
0191     void checkLinesForOverflow();
0192     void deleteEllipsisLineBoxes();
0193     void checkLinesForTextOverflow();
0194     RootInlineBox *determineStartPosition(bool fullLayout, BidiIterator &start, BidiState &bidi);
0195     RootInlineBox *determineEndPosition(RootInlineBox *startLine, BidiIterator &cleanLineStart, BidiStatus &cleanLineBidiStatus, BidiContext *cleanLineBidiContext, int &yPos);
0196     bool matchedEndLine(const BidiIterator &start, const BidiStatus &status, BidiContext *context,
0197                         const BidiIterator &endLineStart, const BidiStatus &endLineStatus, BidiContext *endLineContext,
0198                         RootInlineBox *&endLine, int &endYPos);
0199     // end bidi.cpp functions
0200 
0201     void paint(PaintInfo &i, int tx, int ty) override;
0202     void paintObject(PaintInfo &i, int tx, int ty, bool paintOutline = true);
0203     void paintFloats(PaintInfo &i, int _tx, int _ty, bool paintSelection = false);
0204 
0205     void insertFloatingObject(RenderObject *o);
0206     void removeFloatingObject(RenderObject *o);
0207 
0208     // called from lineWidth, to position the floats added in the last line.
0209     void positionNewFloats();
0210     void clearFloats();
0211     int getClearDelta(RenderObject *child, int yPos);
0212     void markAllDescendantsWithFloatsForLayout(RenderObject *floatToRemove = nullptr) override;
0213 
0214     // FIXME: containsFloats() should not return true if the floating objects list
0215     // is empty. However, layoutInlineChildren() relies on the current behavior.
0216     // http://bugzilla.opendarwin.org/show_bug.cgi?id=7395#c3
0217     bool hasFloats() const override
0218     {
0219         return m_floatingObjects != nullptr;
0220     }
0221     bool containsFloat(RenderObject *o) const override;
0222 
0223     bool hasOverhangingFloats() const override
0224     {
0225         return floatBottom() > m_height;
0226     }
0227     void addOverHangingFloats(RenderBlock *block, int xoffset, int yoffset, bool child);
0228 
0229     int nearestFloatBottom(int height) const;
0230     int floatBottom() const;
0231     inline int leftBottom();
0232     inline int rightBottom();
0233 
0234     virtual unsigned short lineWidth(int y, bool *canClearLine = nullptr) const;
0235     int lowestPosition(bool includeOverflowInterior = true, bool includeSelf = true) const override;
0236     int rightmostPosition(bool includeOverflowInterior = true, bool includeSelf = true) const override;
0237     int leftmostPosition(bool includeOverflowInterior = true, bool includeSelf = true) const override;
0238     int highestPosition(bool includeOverflowInterior, bool includeSelf) const override;
0239     int lowestAbsolutePosition() const;
0240     int leftmostAbsolutePosition() const;
0241     int rightmostAbsolutePosition() const;
0242     int highestAbsolutePosition() const;
0243 
0244     int rightOffset() const;
0245     int rightRelOffset(int y, int fixedOffset, bool applyTextIndent = true, int *heightRemaining = nullptr, bool *canClearLine = nullptr) const;
0246     int rightOffset(int y, bool *canClearLine = nullptr) const
0247     {
0248         return rightRelOffset(y, rightOffset(), true, nullptr, canClearLine);
0249     }
0250 
0251     int leftOffset() const;
0252     int leftRelOffset(int y, int fixedOffset, bool applyTextIndent = true, int *heightRemaining = nullptr, bool *canClearLine = nullptr) const;
0253     int leftOffset(int y, bool *canClearLine = nullptr) const
0254     {
0255         return leftRelOffset(y, leftOffset(), true, nullptr, canClearLine);
0256     }
0257 
0258     bool nodeAtPoint(NodeInfo &info, int x, int y, int _tx, int _ty, HitTestAction hitTestAction = HitTestAll, bool inside = false) override;
0259 
0260     bool isPointInScrollbar(int x, int y, int tx, int ty);
0261 
0262     RenderPosition positionForCoordinates(int x, int y) override;
0263 
0264     void calcMinMaxWidth() override;
0265     void calcInlineMinMaxWidth();
0266     void calcBlockMinMaxWidth();
0267 
0268     void close() override;
0269 
0270     int getBaselineOfFirstLineBox() override;
0271 
0272     RootInlineBox *firstRootBox() const
0273     {
0274         return static_cast<RootInlineBox *>(m_firstLineBox);
0275     }
0276     RootInlineBox *lastRootBox() const
0277     {
0278         return static_cast<RootInlineBox *>(m_lastLineBox);
0279     }
0280 
0281     InlineFlowBox *getFirstLineBox() override;
0282 
0283     bool inRootBlockContext() const;
0284     void deleteLineBoxTree();
0285 
0286 #ifdef ENABLE_DUMP
0287     void printTree(int indent = 0) const override;
0288     void dump(QTextStream &stream, const QString &ind) const override;
0289 #endif
0290 
0291 protected:
0292     void newLine();
0293 
0294 private:
0295     RenderPosition positionForBox(InlineBox *box, bool start = true) const;
0296     RenderPosition positionForRenderer(RenderObject *renderer, bool start = true) const;
0297 
0298 protected:
0299     struct FloatingObject {
0300         enum Type {
0301             FloatLeft,
0302             FloatRight
0303         };
0304 
0305         FloatingObject(Type _type)
0306         {
0307             node = nullptr;
0308             startY = 0;
0309             endY = 0;
0310             type = _type;
0311             left = 0;
0312             width = 0;
0313             noPaint = false;
0314             crossedLayer = false;
0315 
0316         }
0317         RenderObject *node;
0318         int startY;
0319         int endY;
0320         short left;
0321         short width;
0322         KDE_BF_ENUM(Type) type : 1; // left or right aligned
0323         bool noPaint : 1;
0324         bool crossedLayer : 1; // lock noPaint flag
0325     };
0326 
0327     // The following helper functions and structs are used by layoutBlockChildren.
0328     class CompactInfo
0329     {
0330         // A compact child that needs to be collapsed into the margin of the following block.
0331         RenderObject *m_compact;
0332 
0333         // The block with the open margin that the compact child is going to place itself within.
0334         RenderObject *m_block;
0335         bool m_treatAsBlock : 1;
0336 
0337     public:
0338         RenderObject *compact() const
0339         {
0340             return m_compact;
0341         }
0342         RenderObject *block() const
0343         {
0344             return m_block;
0345         }
0346         void setTreatAsBlock(bool b)
0347         {
0348             m_treatAsBlock = b;
0349         }
0350         bool treatAsBlock() const
0351         {
0352             return m_treatAsBlock;
0353         }
0354         bool matches(RenderObject *child) const
0355         {
0356             return m_compact && m_block == child;
0357         }
0358 
0359         void clear()
0360         {
0361             set(nullptr, nullptr);
0362         }
0363         void set(RenderObject *c, RenderObject *b)
0364         {
0365             m_compact = c;
0366             m_block = b;
0367         }
0368 
0369         CompactInfo()
0370         {
0371             clear();
0372         }
0373     };
0374 
0375     class MarginInfo
0376     {
0377         // Collapsing flags for whether we can collapse our margins with our children's margins.
0378         bool m_canCollapseWithChildren : 1;
0379         bool m_canCollapseTopWithChildren : 1;
0380         bool m_canCollapseBottomWithChildren : 1;
0381 
0382         // Whether or not we are a quirky container, i.e., do we collapse away top and bottom
0383         // margins in our container.  Table cells and the body are the common examples. We
0384         // also have a custom style property for Safari RSS to deal with TypePad blog articles.
0385         bool m_quirkContainer : 1;
0386 
0387         // This flag tracks whether we are still looking at child margins that can all collapse together at the beginning of a block.
0388         // They may or may not collapse with the top margin of the block (|m_canCollapseTopWithChildren| tells us that), but they will
0389         // always be collapsing with one another.  This variable can remain set to true through multiple iterations
0390         // as long as we keep encountering self-collapsing blocks.
0391         bool m_atTopOfBlock : 1;
0392 
0393         // This flag is set when we know we're examining bottom margins and we know we're at the bottom of the block.
0394         bool m_atBottomOfBlock : 1;
0395 
0396         // If our last normal flow child was a self-collapsing block that cleared a float,
0397         // we track it in this variable.
0398         bool m_selfCollapsingBlockClearedFloat : 1;
0399 
0400         // These variables are used to detect quirky margins that we need to collapse away (in table cells
0401         // and in the body element).
0402         bool m_topQuirk : 1;
0403         bool m_bottomQuirk : 1;
0404         bool m_determinedTopQuirk : 1;
0405 
0406         // These flags track the previous maximal positive and negative margins.
0407         int m_posMargin;
0408         int m_negMargin;
0409 
0410     public:
0411         MarginInfo(RenderBlock *b, int top, int bottom);
0412 
0413         void setAtTopOfBlock(bool b)
0414         {
0415             m_atTopOfBlock = b;
0416         }
0417         void setAtBottomOfBlock(bool b)
0418         {
0419             m_atBottomOfBlock = b;
0420         }
0421         void clearMargin()
0422         {
0423             m_posMargin = m_negMargin = 0;
0424         }
0425         void setSelfCollapsingBlockClearedFloat(bool b)
0426         {
0427             m_selfCollapsingBlockClearedFloat = b;
0428         }
0429         void setTopQuirk(bool b)
0430         {
0431             m_topQuirk = b;
0432         }
0433         void setBottomQuirk(bool b)
0434         {
0435             m_bottomQuirk = b;
0436         }
0437         void setDeterminedTopQuirk(bool b)
0438         {
0439             m_determinedTopQuirk = b;
0440         }
0441         void setPosMargin(int p)
0442         {
0443             m_posMargin = p;
0444         }
0445         void setNegMargin(int n)
0446         {
0447             m_negMargin = n;
0448         }
0449         void setPosMarginIfLarger(int p)
0450         {
0451             if (p > m_posMargin) {
0452                 m_posMargin = p;
0453             }
0454         }
0455         void setNegMarginIfLarger(int n)
0456         {
0457             if (n > m_negMargin) {
0458                 m_negMargin = n;
0459             }
0460         }
0461 
0462         void setMargin(int p, int n)
0463         {
0464             m_posMargin = p;
0465             m_negMargin = n;
0466         }
0467 
0468         bool atTopOfBlock() const
0469         {
0470             return m_atTopOfBlock;
0471         }
0472         bool canCollapseWithTop() const
0473         {
0474             return m_atTopOfBlock && m_canCollapseTopWithChildren;
0475         }
0476         bool canCollapseWithBottom() const
0477         {
0478             return m_atBottomOfBlock && m_canCollapseBottomWithChildren;
0479         }
0480         bool canCollapseTopWithChildren() const
0481         {
0482             return m_canCollapseTopWithChildren;
0483         }
0484         bool canCollapseBottomWithChildren() const
0485         {
0486             return m_canCollapseBottomWithChildren;
0487         }
0488         bool selfCollapsingBlockClearedFloat() const
0489         {
0490             return m_selfCollapsingBlockClearedFloat;
0491         }
0492         bool quirkContainer() const
0493         {
0494             return m_quirkContainer;
0495         }
0496         bool determinedTopQuirk() const
0497         {
0498             return m_determinedTopQuirk;
0499         }
0500         bool topQuirk() const
0501         {
0502             return m_topQuirk;
0503         }
0504         bool bottomQuirk() const
0505         {
0506             return m_bottomQuirk;
0507         }
0508         int posMargin() const
0509         {
0510             return m_posMargin;
0511         }
0512         int negMargin() const
0513         {
0514             return m_negMargin;
0515         }
0516         int margin() const
0517         {
0518             return m_posMargin - m_negMargin;
0519         }
0520     };
0521 
0522     class PageBreakInfo
0523     {
0524         int m_pageBottom; // Next calculated page-break
0525         bool m_forcePageBreak : 1; // Must break before next block
0526         // ### to do better "page-break-after/before: avoid" this struct
0527         // should keep a pagebreakAvoid block and gather children in it
0528     public:
0529         PageBreakInfo(int pageBottom) : m_pageBottom(pageBottom), m_forcePageBreak(false) {}
0530         bool forcePageBreak()
0531         {
0532             return m_forcePageBreak;
0533         }
0534         void setForcePageBreak(bool b)
0535         {
0536             m_forcePageBreak = b;
0537         }
0538         int pageBottom()
0539         {
0540             return m_pageBottom;
0541         }
0542         void setPageBottom(int bottom)
0543         {
0544             m_pageBottom = bottom;
0545         }
0546     };
0547 
0548     bool canClear(RenderObject *child, PageBreakLevel level) override;
0549     void clearPageBreak(RenderObject *child, int pageBottom);
0550 
0551     void adjustPositionedBlock(RenderObject *child, const MarginInfo &marginInfo);
0552     void adjustFloatingBlock(const MarginInfo &marginInfo);
0553     RenderObject *handleSpecialChild(RenderObject *child, const MarginInfo &marginInfo, CompactInfo &compactInfo, bool &handled);
0554     RenderObject *handleFloatingChild(RenderObject *child, const MarginInfo &marginInfo, bool &handled);
0555     RenderObject *handlePositionedChild(RenderObject *child, const MarginInfo &marginInfo, bool &handled);
0556     RenderObject *handleCompactChild(RenderObject *child, CompactInfo &compactInfo, const MarginInfo &marginInfo, bool &handled);
0557     RenderObject *handleRunInChild(RenderObject *child, bool &handled);
0558     int collapseMargins(RenderObject *child, MarginInfo &marginInfo, int yPos);
0559     int clearFloatsIfNeeded(RenderObject *child, MarginInfo &marginInfo, int oldTopPosMargin, int oldTopNegMargin, int yPos);
0560     void adjustSizeForCompactIfNeeded(RenderObject *child, CompactInfo &compactInfo);
0561     void insertCompactIfNeeded(RenderObject *child, CompactInfo &compactInfo);
0562     int estimateVerticalPosition(RenderObject *child, const MarginInfo &info);
0563     void determineHorizontalPosition(RenderObject *child);
0564     void handleBottomOfBlock(int top, int bottom, MarginInfo &marginInfo);
0565     void setCollapsedBottomMargin(const MarginInfo &marginInfo);
0566     void clearChildOfPageBreaks(RenderObject *child, PageBreakInfo &pageBreakInfo, MarginInfo &marginInfo);
0567     // End helper functions and structs used by layoutBlockChildren.
0568 
0569 protected:
0570     // How much content overflows out of our block vertically or horizontally (all we support
0571     // for now is spillage out of the bottom and the right, which are the common cases).
0572     int m_overflowHeight;
0573     int m_overflowWidth;
0574 
0575     // Left and top overflow.
0576     int m_overflowTop;
0577     int m_overflowLeft;
0578 
0579     QList<FloatingObject *> *m_floatingObjects;
0580     QList<RenderObject *>   *m_positionedObjects;
0581 
0582 private:
0583     bool m_childrenInline : 1;
0584     bool m_firstLine      : 1; // used in inline layouting
0585     KDE_BF_ENUM(EClear) m_clearStatus  : 2; // used during layuting of paragraphs
0586     bool m_avoidPageBreak : 1; // anonymous avoid page-break block
0587     bool m_topMarginQuirk : 1;
0588     bool m_bottomMarginQuirk : 1;
0589 
0590     short m_maxTopPosMargin;
0591     short m_maxTopNegMargin;
0592     short m_maxBottomPosMargin;
0593     short m_maxBottomNegMargin;
0594 
0595 };
0596 
0597 } // namespace
0598 
0599 #endif // RENDER_BLOCK_H
0600