File indexing completed on 2024-04-21 14:58:00

0001 /*
0002  * This file is part of the line box implementation for KDE.
0003  *
0004  * Copyright (C) 2003 Apple Computer, Inc.
0005  *
0006  * This library is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU Library General Public
0008  * License as published by the Free Software Foundation; either
0009  * version 2 of the License, or (at your option) any later version.
0010  *
0011  * This library is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014  * Library General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU Library General Public License
0017  * along with this library; see the file COPYING.LIB.  If not, write to
0018  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019  * Boston, MA 02110-1301, USA.
0020  *
0021  */
0022 #ifndef RENDER_LINE_H
0023 #define RENDER_LINE_H
0024 
0025 #include "render_object.h"
0026 
0027 namespace khtml
0028 {
0029 
0030 class EllipsisBox;
0031 class InlineFlowBox;
0032 class RootInlineBox;
0033 class RenderArena;
0034 struct BidiStatus;
0035 class BidiContext;
0036 
0037 // InlineBox represents a rectangle that occurs on a line.  It corresponds to
0038 // some RenderObject (i.e., it represents a portion of that RenderObject).
0039 class InlineBox
0040 {
0041 public:
0042     InlineBox(RenderObject *obj)
0043         : m_object(obj), m_x(0), m_width(0), m_y(0), m_height(0), m_baseline(0),
0044           m_firstLine(false), m_constructed(false), m_dirty(false), m_extracted(false), m_endsWithBreak(false)
0045     {
0046         m_next = nullptr;
0047         m_prev = nullptr;
0048         m_parent = nullptr;
0049     }
0050 
0051     virtual ~InlineBox() {}
0052 
0053     virtual void detach(RenderArena *renderArena, bool noRemove = false);
0054 
0055     virtual void paint(RenderObject::PaintInfo &i, int _tx, int _ty);
0056     virtual bool nodeAtPoint(RenderObject::NodeInfo &i, int x, int y, int tx, int ty);
0057 
0058     // Overloaded new operator.
0059     void *operator new(size_t sz, RenderArena *renderArena) throw();
0060 
0061     // Overridden to prevent the normal delete from being called.
0062     void operator delete(void *ptr, size_t sz);
0063 
0064 #ifdef ENABLE_DUMP
0065     QString information() const;
0066     void printTree(int indent = 0) const;
0067 #endif
0068 
0069 private:
0070     // The normal operator new is disallowed.
0071     void *operator new(size_t sz) throw();
0072 
0073 public:
0074     virtual bool isPlaceHolderBox() const
0075     {
0076         return false;
0077     }
0078     virtual bool isInlineFlowBox() const
0079     {
0080         return false;
0081     }
0082     virtual bool isContainer() const
0083     {
0084         return false;
0085     }
0086     virtual bool isInlineTextBox() const
0087     {
0088         return false;
0089     }
0090     virtual bool isRootInlineBox() const
0091     {
0092         return false;
0093     }
0094     // SVG
0095     virtual bool isSVGRootInlineBox() const
0096     {
0097         return false;
0098     }
0099 
0100     bool isConstructed() const
0101     {
0102         return m_constructed;
0103     }
0104     virtual void setConstructed()
0105     {
0106         m_constructed = true;
0107         if (m_next) {
0108             m_next->setConstructed();
0109         }
0110     }
0111 
0112     void setFirstLineStyleBit(bool f)
0113     {
0114         m_firstLine = f;
0115     }
0116 
0117     InlineBox *nextOnLine() const
0118     {
0119         return m_next;
0120     }
0121     InlineBox *prevOnLine() const
0122     {
0123         return m_prev;
0124     }
0125     void setNextOnLine(InlineBox *next)
0126     {
0127         m_next = next;
0128     }
0129     void setPrevOnLine(InlineBox *prev)
0130     {
0131         m_prev = prev;
0132     }
0133     bool nextOnLineExists() const;
0134     bool prevOnLineExists() const;
0135 
0136     virtual InlineBox *firstLeafChild();
0137     virtual InlineBox *lastLeafChild();
0138     InlineBox *closestLeafChildForXPos(int _x, int _tx);
0139 
0140     RenderObject *object() const
0141     {
0142         return m_object;
0143     }
0144 
0145     InlineFlowBox *parent() const
0146     {
0147         return m_parent;
0148     }
0149     void setParent(InlineFlowBox *par)
0150     {
0151         m_parent = par;
0152     }
0153 
0154     RootInlineBox *root();
0155 
0156     void setWidth(short w)
0157     {
0158         m_width = w;
0159     }
0160     short width() const
0161     {
0162         return m_width;
0163     }
0164 
0165     void setXPos(short x)
0166     {
0167         m_x = x;
0168     }
0169     short xPos() const
0170     {
0171         return m_x;
0172     }
0173 
0174     void setYPos(int y)
0175     {
0176         m_y = y;
0177     }
0178     int yPos() const
0179     {
0180         return m_y;
0181     }
0182 
0183     void setHeight(int h)
0184     {
0185         m_height = h;
0186     }
0187     int height() const
0188     {
0189         return m_height;
0190     }
0191 
0192     void setBaseline(int b)
0193     {
0194         m_baseline = b;
0195     }
0196     int baseline() const
0197     {
0198         return m_baseline;
0199     }
0200 
0201     virtual bool hasTextChildren() const
0202     {
0203         return true;
0204     }
0205     virtual bool hasTextDescendant() const
0206     {
0207         return true;
0208     }
0209 
0210     virtual int topOverflow() const
0211     {
0212         return yPos();
0213     }
0214     virtual int bottomOverflow() const
0215     {
0216         return yPos() + height();
0217     }
0218 
0219     virtual long caretMinOffset() const;
0220     virtual long caretMaxOffset() const;
0221     virtual unsigned long caretMaxRenderedOffset() const;
0222 
0223     bool isDirty() const
0224     {
0225         return m_dirty;
0226     }
0227     void markDirty(bool dirty = true)
0228     {
0229         m_dirty = dirty;
0230     }
0231 
0232     void setExtracted(bool b = true)
0233     {
0234         m_extracted = b;
0235     }
0236     void remove();
0237 
0238     void dirtyInlineBoxes();
0239     virtual void deleteLine(RenderArena *arena);
0240     virtual void extractLine();
0241     virtual void attachLine();
0242     void adjustPosition(int dx, int dy);
0243 
0244     virtual void clearTruncation() {}
0245 
0246     virtual bool canAccommodateEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth);
0247     virtual int placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool &);
0248 
0249 public: // FIXME: Would like to make this protected, but methods are accessing these
0250     // members over in the part.
0251     RenderObject *m_object;
0252 
0253     short m_x;
0254     short m_width;
0255     int m_y;
0256     int m_height;
0257     int m_baseline;
0258 
0259     bool m_firstLine : 1;
0260     bool m_constructed : 1;
0261     bool m_dirty : 1;
0262     bool m_extracted : 1;
0263     bool m_endsWithBreak : 1;
0264 
0265     InlineBox *m_next; // The next element on the same line as us.
0266     InlineBox *m_prev; // The previous element on the same line as us.
0267 
0268     InlineFlowBox *m_parent; // The box that contains us.
0269 };
0270 
0271 class PlaceHolderBox: public InlineBox
0272 {
0273 public:
0274     PlaceHolderBox(RenderObject *obj): InlineBox(obj) {}
0275     bool isPlaceHolderBox() const override
0276     {
0277         return true;
0278     }
0279 };
0280 
0281 class InlineRunBox : public InlineBox
0282 {
0283 public:
0284     InlineRunBox(RenderObject *obj)
0285         : InlineBox(obj)
0286     {
0287         m_prevLine = nullptr;
0288         m_nextLine = nullptr;
0289     }
0290 
0291     InlineRunBox *prevLineBox() const
0292     {
0293         return m_prevLine;
0294     }
0295     InlineRunBox *nextLineBox() const
0296     {
0297         return m_nextLine;
0298     }
0299     void setNextLineBox(InlineRunBox *n)
0300     {
0301         m_nextLine = n;
0302     }
0303     void setPreviousLineBox(InlineRunBox *p)
0304     {
0305         m_prevLine = p;
0306     }
0307 
0308     virtual void paintBackgroundAndBorder(RenderObject::PaintInfo &, int /*_tx*/, int /*_ty*/) {}
0309     virtual void paintDecorations(RenderObject::PaintInfo &, int /*_tx*/, int /*_ty*/, bool /*paintedChildren*/ = false) {}
0310 
0311 protected:
0312     InlineRunBox *m_prevLine;  // The previous box that also uses our RenderObject
0313     InlineRunBox *m_nextLine;  // The next box that also uses our RenderObject
0314 };
0315 
0316 class InlineFlowBox : public InlineRunBox
0317 {
0318 public:
0319     InlineFlowBox(RenderObject *obj)
0320         : InlineRunBox(obj)
0321     {
0322         m_firstChild = nullptr;
0323         m_lastChild = nullptr;
0324         m_includeLeftEdge = m_includeRightEdge = false;
0325         m_hasTextChildren = false;
0326         m_hasTextDescendant = false;
0327         m_afterPageBreak = false;
0328     }
0329 
0330     ~InlineFlowBox();
0331 
0332     bool isInlineFlowBox() const override
0333     {
0334         return true;
0335     }
0336 
0337     InlineFlowBox *prevFlowBox() const
0338     {
0339         return static_cast<InlineFlowBox *>(m_prevLine);
0340     }
0341     InlineFlowBox *nextFlowBox() const
0342     {
0343         return static_cast<InlineFlowBox *>(m_nextLine);
0344     }
0345 
0346     InlineBox *firstChild() const
0347     {
0348         return m_firstChild;
0349     }
0350     InlineBox *lastChild() const
0351     {
0352         return m_lastChild;
0353     }
0354 
0355     InlineBox *firstLeafChild() override;
0356     InlineBox *lastLeafChild() override;
0357     InlineBox *closestChildForXPos(int _x, int _tx);
0358 
0359     void setConstructed() override
0360     {
0361         InlineBox::setConstructed();
0362         if (m_firstChild) {
0363             m_firstChild->setConstructed();
0364         }
0365     }
0366     void addToLine(InlineBox *child)
0367     {
0368         if (!m_firstChild) {
0369             m_firstChild = m_lastChild = child;
0370         } else {
0371             m_lastChild->m_next = child;
0372             child->m_prev = m_lastChild;
0373             m_lastChild = child;
0374         }
0375         child->setFirstLineStyleBit(m_firstLine);
0376         child->setParent(this);
0377         if (!m_hasTextChildren && child->isInlineTextBox()) {
0378             m_hasTextDescendant = m_hasTextChildren = true;
0379             for (InlineFlowBox *p = m_parent; p && !p->hasTextDescendant(); p = p->parent()) {
0380                 p->m_hasTextDescendant = true;
0381             }
0382         }
0383     }
0384 
0385     void clearTruncation() override;
0386 
0387     void removeFromLine(InlineBox *child);
0388     void paintBackgroundAndBorder(RenderObject::PaintInfo &, int _tx, int _ty) override;
0389     void paintAllBackgrounds(QPainter *p, const QColor &c, const BackgroundLayer *bgLayer,
0390                              QRect clipr, int _tx, int _ty, int w, int h);
0391     void paintOneBackground(QPainter *p, const QColor &c, const BackgroundLayer *bgLayer,
0392                             QRect clipr, int _tx, int _ty, int w, int h);
0393     void paint(RenderObject::PaintInfo &i, int _tx, int _ty) override;
0394     void paintDecorations(RenderObject::PaintInfo &, int _tx, int _ty, bool paintedChildren = false) override;
0395     bool nodeAtPoint(RenderObject::NodeInfo &i, int x, int y, int tx, int ty) override;
0396 
0397     int marginBorderPaddingLeft() const;
0398     int marginBorderPaddingRight() const;
0399     int marginLeft() const;
0400     int marginRight()const;
0401     int borderLeft() const
0402     {
0403         if (includeLeftEdge()) {
0404             return object()->borderLeft();
0405         } return 0;
0406     }
0407     int borderRight() const
0408     {
0409         if (includeRightEdge()) {
0410             return object()->borderRight();
0411         } return 0;
0412     }
0413     int paddingLeft() const
0414     {
0415         if (includeLeftEdge()) {
0416             return object()->paddingLeft();
0417         } return 0;
0418     }
0419     int paddingRight() const
0420     {
0421         if (includeRightEdge()) {
0422             return object()->paddingRight();
0423         } return 0;
0424     }
0425 
0426     bool includeLeftEdge() const
0427     {
0428         return m_includeLeftEdge;
0429     }
0430     bool includeRightEdge() const
0431     {
0432         return m_includeRightEdge;
0433     }
0434     void setEdges(bool includeLeft, bool includeRight)
0435     {
0436         m_includeLeftEdge = includeLeft;
0437         m_includeRightEdge = includeRight;
0438     }
0439     bool hasTextChildren() const override
0440     {
0441         return m_hasTextChildren;
0442     }
0443     bool hasTextDescendant() const override
0444     {
0445         return m_hasTextDescendant;
0446     }
0447 
0448     // Helper functions used during line construction and placement.
0449     void determineSpacingForFlowBoxes(bool lastLine, RenderObject *endObject);
0450     int getFlowSpacingWidth() const;
0451     bool nextOnLineExists();
0452     bool prevOnLineExists();
0453     bool onEndChain(RenderObject *endObject);
0454     int placeBoxesHorizontally(int x);
0455     void verticallyAlignBoxes(int &heightOfBlock);
0456     void computeLogicalBoxHeights(int &maxPositionTop, int &maxPositionBottom,
0457                                   int &maxAscent, int &maxDescent, bool strictMode);
0458     void adjustMaxAscentAndDescent(int &maxAscent, int &maxDescent,
0459                                    int maxPositionTop, int maxPositionBottom);
0460     void placeBoxesVertically(int y, int maxHeight, int maxAscent, bool strictMode,
0461                               int &topPosition, int &bottomPosition);
0462     void shrinkBoxesWithNoTextChildren(int topPosition, int bottomPosition);
0463 
0464     virtual void setOverflowPositions(int /*top*/, int /*bottom*/) {}
0465 
0466     void setAfterPageBreak(bool b = true)
0467     {
0468         m_afterPageBreak = b;
0469     }
0470     bool afterPageBreak() const
0471     {
0472         return m_afterPageBreak;
0473     }
0474 
0475     bool canAccommodateEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth) override;
0476     int placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool &) override;
0477 
0478     void deleteLine(RenderArena *arena) override;
0479     void extractLine() override;
0480     void attachLine() override;
0481 
0482 protected:
0483     InlineBox *m_firstChild;
0484     InlineBox *m_lastChild;
0485     bool m_includeLeftEdge : 1;
0486     bool m_includeRightEdge : 1;
0487     bool m_hasTextChildren : 1;
0488     bool m_hasTextDescendant : 1;
0489     bool m_afterPageBreak : 1;
0490 };
0491 
0492 class RootInlineBox : public InlineFlowBox
0493 {
0494 public:
0495     RootInlineBox(RenderObject *obj) : InlineFlowBox(obj), m_lineBreakObj(nullptr), m_lineBreakPos(0),
0496         m_lineBreakContext(nullptr), m_blockHeight(0), m_ellipsisBox(nullptr)
0497     {
0498         m_topOverflow = m_bottomOverflow = 0;
0499     }
0500 
0501     void detach(RenderArena *renderArena, bool noRemove = false) override;
0502     void detachEllipsisBox(RenderArena *renderArena);
0503 
0504     RootInlineBox *nextRootBox() const
0505     {
0506         return static_cast<RootInlineBox *>(m_nextLine);
0507     }
0508     RootInlineBox *prevRootBox() const
0509     {
0510         return static_cast<RootInlineBox *>(m_prevLine);
0511     }
0512 
0513     bool isRootInlineBox() const override
0514     {
0515         return true;
0516     }
0517     int topOverflow() const override
0518     {
0519         return m_topOverflow;
0520     }
0521     int bottomOverflow() const override
0522     {
0523         return m_bottomOverflow;
0524     }
0525     void setOverflowPositions(int top, int bottom) override
0526     {
0527         m_topOverflow = top;
0528         m_bottomOverflow = bottom;
0529     }
0530 
0531     bool canAccommodateEllipsis(bool ltr, int blockEdge, int lineBoxEdge, int ellipsisWidth);
0532     void placeEllipsis(const DOM::DOMString &ellipsisStr, bool ltr, int blockEdge, int ellipsisWidth, InlineBox *markupBox = nullptr);
0533     int placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool &) override;
0534 
0535     EllipsisBox *ellipsisBox() const
0536     {
0537         return m_ellipsisBox;
0538     }
0539     void paintEllipsisBox(RenderObject::PaintInfo &i, int _tx, int _ty) const;
0540     bool hitTestEllipsisBox(RenderObject::NodeInfo &info, int _x, int _y, int _tx, int _ty);
0541 
0542     void clearTruncation() override;
0543 
0544     void paint(RenderObject::PaintInfo &i, int _tx, int _ty) override;
0545     bool nodeAtPoint(RenderObject::NodeInfo &i, int x, int y, int tx, int ty) override;
0546 
0547     RenderObject *lineBreakObj() const
0548     {
0549         return m_lineBreakObj;
0550     }
0551     BidiStatus lineBreakBidiStatus() const;
0552     void setLineBreakInfo(RenderObject *, unsigned breakPos, const BidiStatus &, BidiContext *context);
0553 
0554     BidiContext *lineBreakBidiContext() const
0555     {
0556         return m_lineBreakContext;
0557     }
0558 
0559     unsigned lineBreakPos() const
0560     {
0561         return m_lineBreakPos;
0562     }
0563     void setLineBreakPos(unsigned p)
0564     {
0565         m_lineBreakPos = p;
0566     }
0567 
0568     int blockHeight() const
0569     {
0570         return m_blockHeight;
0571     }
0572     void setBlockHeight(int h)
0573     {
0574         m_blockHeight = h;
0575     }
0576 
0577     bool endsWithBreak() const
0578     {
0579         return m_endsWithBreak;
0580     }
0581     void setEndsWithBreak(bool b)
0582     {
0583         m_endsWithBreak = b;
0584     }
0585 
0586     void childRemoved(InlineBox *box);
0587 
0588 protected:
0589     int m_topOverflow;
0590     int m_bottomOverflow;
0591 
0592     // Where this line ended.  The exact object and the position within that object are stored so that
0593     // we can create a BidiIterator beginning just after the end of this line.
0594     RenderObject *m_lineBreakObj;
0595     unsigned m_lineBreakPos;
0596     BidiContext *m_lineBreakContext;
0597 
0598     // The height of the block at the end of this line.  This is where the next line starts.
0599     int m_blockHeight;
0600 
0601     KDE_BF_ENUM(QChar::Direction) m_lineBreakBidiStatusEor : 5;
0602     KDE_BF_ENUM(QChar::Direction) m_lineBreakBidiStatusLastStrong : 5;
0603     KDE_BF_ENUM(QChar::Direction) m_lineBreakBidiStatusLast : 5;
0604 
0605     // An inline text box that represents our text truncation string.
0606     EllipsisBox *m_ellipsisBox;
0607 };
0608 
0609 } //namespace
0610 
0611 #endif