File indexing completed on 2025-02-02 14:13:15
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