1 /*
2  * This file is part of the html renderer for KDE.
3  *
4  * Copyright (C) 2000-2003 Lars Knoll (knoll@kde.org)
5  *           (C) 2000 Antti Koivisto (koivisto@kde.org)
6  *           (C) 2000-2003 Dirk Mueller (mueller@kde.org)
7  *           (C) 2002-2003 Apple Computer, Inc.
8  *           (C) 2004 Allan Sandfeld Jensen
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public License
21  * along with this library; see the file COPYING.LIB.  If not, write to
22  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23  * Boston, MA 02110-1301, USA.
24  *
25  */
26 #ifndef render_object_h
27 #define render_object_h
28 
29 #include <QColor>
30 #include <QRect>
31 #include <assert.h>
32 #include <QList>
33 
34 #include <QDebug>
35 
36 #include "xml/dom_docimpl.h"
37 #include "misc/khtmllayout.h"
38 #include "misc/loader_client.h"
39 #include "misc/helper.h"
40 #include "rendering/render_style.h"
41 #include "rendering/render_position.h"
42 #include <QTextStream>
43 
44 // svg
45 #include "FloatRect.h"
46 #include "AffineTransform.h"
47 
48 using WebCore::FloatRect;
49 using WebCore::AffineTransform;
50 
51 class QPainter;
52 class QTextStream;
53 template<class Key, class T> class QCache;
54 
55 #ifndef NDEBUG
56 #define KHTMLAssert( x ) if( !(x) ) { \
57         const RenderObject *o = this; while( o->parent() ) o = o->parent(); \
58         o->printTree(); \
59         qDebug(" this object = %p", (void*) this); \
60         assert( x ); \
61     }
62 #else
63 #define KHTMLAssert( x )
64 #endif
65 
66 /*
67  *  The painting of a layer occurs in three distinct phases.  Each phase involves
68  *  a recursive descent into the layer's render objects. The first phase is the background phase.
69  *  The backgrounds and borders of all blocks are painted.  Inlines are not painted at all.
70  *  Floats must paint above block backgrounds but entirely below inline content that can overlap them.
71  *  In the foreground phase, all inlines are fully painted.  Inline replaced elements will get all
72  *  three phases invoked on them during this phase.
73  */
74 
75 typedef enum {
76     PaintActionElementBackground = 0,
77     PaintActionChildBackground,
78     PaintActionChildBackgrounds,
79     PaintActionFloat,
80     PaintActionForeground,
81     PaintActionOutline,
82     PaintActionSelection,
83     PaintActionCollapsedTableBorders
84 } PaintAction;
85 
86 typedef enum {
87     HitTestAll = 0,
88     HitTestSelfOnly = 1,
89     HitTestChildrenOnly = 2
90 } HitTestAction;
91 
92 typedef enum {
93     PageBreakNormal = 0, // all rules apply
94     PageBreakHarder = 1, // page-break-inside: avoid is ignored
95     PageBreakForced = 2  // page-break-after/before: avoid, orphans and widows ignored
96 } PageBreakLevel;
97 
98 typedef enum {
99     LowPriority = 0,
100     NormalPriority = 1,
101     HighPriority = 2,
102     RealtimePriority = 3
103 } Priority;
104 
105 inline PageBreakLevel operator| (PageBreakLevel a, PageBreakLevel b)
106 {
107     if (a == PageBreakForced || b == PageBreakForced) {
108         return PageBreakForced;
109     }
110     if (a == PageBreakHarder || b == PageBreakHarder) {
111         return PageBreakHarder;
112     }
113     return PageBreakNormal;
114 }
115 
116 namespace DOM
117 {
118 class HTMLAreaElementImpl;
119 class NodeImpl;
120 class DocumentImpl;
121 class ElementImpl;
122 class EventImpl;
123 class Selection;
124 }
125 
126 namespace khtml
127 {
128 class RenderFlow;
129 class RenderStyle;
130 class CachedObject;
131 class RenderObject;
132 class RenderCanvas;
133 class RenderText;
134 class RenderFrameSet;
135 class RenderArena;
136 class RenderLayer;
137 class RenderBlock;
138 class InlineBox;
139 class InlineFlowBox;
140 class CounterNode;
141 class RenderPosition;
142 
143 /**
144  * Base Class for all rendering tree objects.
145  */
146 class RenderObject : public CachedObjectClient
147 {
148     RenderObject(const RenderObject &);
149     RenderObject &operator=(const RenderObject &);
150 public:
151     KHTML_EXPORT static void cleanup();
152 
153     RenderObject(DOM::NodeImpl *node);
154     virtual ~RenderObject();
155 
parent()156     RenderObject *parent() const
157     {
158         return m_parent;
159     }
160 
previousSibling()161     RenderObject *previousSibling() const
162     {
163         return m_previous;
164     }
nextSibling()165     RenderObject *nextSibling() const
166     {
167         return m_next;
168     }
169 
firstChild()170     virtual RenderObject *firstChild() const
171     {
172         return nullptr;
173     }
lastChild()174     virtual RenderObject *lastChild() const
175     {
176         return nullptr;
177     }
178 
179     RenderObject *nextRenderer() const;
180     RenderObject *previousRenderer() const;
181 
182     RenderObject *nextEditable() const;
183     RenderObject *previousEditable() const;
184 
185     RenderObject *firstLeafChild() const;
186     RenderObject *lastLeafChild() const;
187 
childAllowed()188     virtual bool childAllowed() const
189     {
190         return false;
191     }
borderTopExtra()192     virtual int borderTopExtra() const
193     {
194         return 0;
195     }
borderBottomExtra()196     virtual int borderBottomExtra() const
197     {
198         return 0;
199     }
200 
layer()201     virtual RenderLayer *layer() const
202     {
203         return nullptr;
204     }
205     RenderLayer *enclosingLayer() const;
206     RenderLayer *enclosingStackingContext() const;
207     void addLayers(RenderLayer *parentLayer, RenderObject *newObject);
208     void removeLayers(RenderLayer *parentLayer);
209     void moveLayers(RenderLayer *oldParent, RenderLayer *newParent);
210     RenderLayer *findNextLayer(RenderLayer *parentLayer, RenderObject *startPoint,
211                                bool checkParent = true);
positionChildLayers()212     virtual void positionChildLayers() { }
requiresLayer()213     virtual bool requiresLayer() const
214     {
215         return isRoot()/* ### */ || isPositioned() || isRelPositioned() || hasOverflowClip() || style()->opacity() < 1.0f;
216     }
217 
overflowClipRect(int,int)218     virtual QRect overflowClipRect(int /*tx*/, int /*ty*/)
219     {
220         return QRect(0, 0, 0, 0);
221     }
clipRect(int,int)222     virtual QRect clipRect(int /*tx*/, int /*ty*/)
223     {
224         return QRect(0, 0, 0, 0);
225     }
hasClip()226     bool hasClip() const
227     {
228         return isPositioned() &&  style()->hasClip();
229     }
hasOverflowClip()230     bool hasOverflowClip() const
231     {
232         return m_hasOverflowClip;
233     }
234 
scrollsOverflow()235     bool scrollsOverflow() const
236     {
237         return scrollsOverflowX() || scrollsOverflowY();
238     }
scrollsOverflowX()239     bool scrollsOverflowX() const
240     {
241         return  hasOverflowClip() && (style()->overflowX() == OSCROLL || style()->overflowX() == OAUTO);
242     }
scrollsOverflowY()243     bool scrollsOverflowY() const
244     {
245         return  hasOverflowClip() && (style()->overflowY() == OSCROLL || style()->overflowY() == OAUTO);
246     }
247 
getBaselineOfFirstLineBox()248     virtual int getBaselineOfFirstLineBox()
249     {
250         return -1;    // Tables and blocks implement this.
251     }
getFirstLineBox()252     virtual InlineFlowBox *getFirstLineBox()
253     {
254         return nullptr;    // Tables and blocks implement this.
255     }
256 
257     // Whether or not a positioned element requires normal flow x/y to be computed
258     // to determine its position.
hasStaticX()259     bool hasStaticX() const
260     {
261         return style()->left().isAuto() && style()->right().isAuto();
262     }
hasStaticY()263     bool hasStaticY() const
264     {
265         return style()->top().isAuto() && style()->bottom().isAuto();
266     }
isPosWithStaticDim()267     bool isPosWithStaticDim()   const
268     {
269         return isPositioned() && (hasStaticX() || hasStaticY());
270     }
271 
272     // Linear tree traversal
273     RenderObject *objectBelow() const;
274     RenderObject *objectAbove() const;
275 
276     // Returns if an object has counter-increment or counter-reset
277     bool hasCounter(const DOMString &counter) const;
278     // Calculates the value of the counter
279     CounterNode *getCounter(const DOMString &counter, bool view = false, bool counters = false);
280     // Detaches all counterNodes
281     void detachCounters();
282 
283 protected:
284     // Helper functions for counter-cache
285     void insertCounter(const DOMString &counter, CounterNode *value);
286     CounterNode *lookupCounter(const DOMString &counter) const;
287 
288 public:
289     //////////////////////////////////////////
290     // RenderObject tree manipulation
291     virtual void addChild(RenderObject *newChild, RenderObject *beforeChild = nullptr);
292     virtual void removeChild(RenderObject *oldChild);
293 
294     // raw tree manipulation
295     virtual RenderObject *removeChildNode(RenderObject *child);
296     virtual void appendChildNode(RenderObject *child);
297     virtual void insertChildNode(RenderObject *child, RenderObject *before);
298     //////////////////////////////////////////
299 
300     //////////////////////////////////////////
301     // Helper functions. Dangerous to use!
setPreviousSibling(RenderObject * previous)302     void setPreviousSibling(RenderObject *previous)
303     {
304         m_previous = previous;
305     }
setNextSibling(RenderObject * next)306     void setNextSibling(RenderObject *next)
307     {
308         m_next = next;
309     }
setParent(RenderObject * parent)310     void setParent(RenderObject *parent)
311     {
312         m_parent = parent;
313     }
314     //////////////////////////////////////////
315 
316 public:
renderName()317     virtual const char *renderName() const
318     {
319         return "RenderObject";
320     }
321 #ifdef ENABLE_DUMP
322     QString information() const;
323     virtual void printTree(int indent = 0) const;
324     virtual void dump(QTextStream &stream, const QString &ind = QString()) const;
325     void printLineBoxTree() const;
326 #endif
327 
328     static RenderObject *createObject(DOM::NodeImpl *node, RenderStyle *style);
329 
330     // Overloaded new operator.  Derived classes must override operator new
331     // in order to allocate out of the RenderArena.
332     void *operator new(size_t sz, RenderArena *renderArena) throw();
333 
334     // Overridden to prevent the normal delete from being called.
335     void operator delete(void *ptr, size_t sz);
336 
337 private:
338     // The normal operator new is disallowed on all render objects.
339     void *operator new(size_t sz);
340 
341 public:
342     RenderArena *renderArena() const;
continuation()343     virtual RenderFlow *continuation() const
344     {
345         return nullptr;
346     }
isInlineContinuation()347     virtual bool isInlineContinuation() const
348     {
349         return false;
350     }
351 
isRoot()352     bool isRoot() const
353     {
354         return m_isRoot && !m_isAnonymous;
355     }
setIsRoot(bool b)356     void setIsRoot(bool b)
357     {
358         m_isRoot = b;
359     }
360     bool isHR() const;
361     // some helper functions...
isRenderBlock()362     virtual bool isRenderBlock() const
363     {
364         return false;
365     }
isRenderInline()366     virtual bool isRenderInline() const
367     {
368         return false;
369     }
isInlineFlow()370     virtual bool isInlineFlow() const
371     {
372         return false;
373     }
isBlockFlow()374     virtual bool isBlockFlow() const
375     {
376         return false;
377     }
isInlineBlockOrInlineTable()378     virtual bool isInlineBlockOrInlineTable() const
379     {
380         return false;
381     }
childrenInline()382     virtual bool childrenInline() const
383     {
384         return false;
385     }
isBox()386     virtual bool isBox() const
387     {
388         return false;
389     }
isRenderReplaced()390     virtual bool isRenderReplaced() const
391     {
392         return false;
393     }
394 
isGlyph()395     virtual bool isGlyph() const
396     {
397         return false;
398     }
isCounter()399     virtual bool isCounter() const
400     {
401         return false;
402     }
isQuote()403     virtual bool isQuote() const
404     {
405         return false;
406     }
isListItem()407     virtual bool isListItem() const
408     {
409         return false;
410     }
isListMarker()411     virtual bool isListMarker() const
412     {
413         return false;
414     }
isCanvas()415     virtual bool isCanvas() const
416     {
417         return false;
418     }
isBR()419     virtual bool isBR() const
420     {
421         return false;
422     }
isTableCell()423     virtual bool isTableCell() const
424     {
425         return false;
426     }
isTableRow()427     virtual bool isTableRow() const
428     {
429         return false;
430     }
isTableSection()431     virtual bool isTableSection() const
432     {
433         return false;
434     }
isTableCol()435     virtual bool isTableCol() const
436     {
437         return false;
438     }
isTable()439     virtual bool isTable() const
440     {
441         return false;
442     }
isWidget()443     virtual bool isWidget() const
444     {
445         return false;
446     }
isBody()447     virtual bool isBody() const
448     {
449         return false;
450     }
isFormElement()451     virtual bool isFormElement() const
452     {
453         return false;
454     }
isFrameSet()455     virtual bool isFrameSet() const
456     {
457         return false;
458     }
isApplet()459     virtual bool isApplet() const
460     {
461         return false;
462     }
isMedia()463     virtual bool isMedia() const
464     {
465         return false;
466     }
467 
468     virtual bool isEditable() const;
469 
470     // svg
isSVGRoot()471     virtual bool isSVGRoot() const
472     {
473         return false;
474     }
isRenderPath()475     virtual bool isRenderPath() const
476     {
477         return false;
478     }
isSVGContainer()479     virtual bool isSVGContainer() const
480     {
481         return false;
482     }
isSVGText()483     virtual bool isSVGText() const
484     {
485         return false;
486     }
isSVGHiddenContainer()487     virtual bool isSVGHiddenContainer() const
488     {
489         return false;
490     }
491 
492     virtual FloatRect relativeBBox(bool includeStroke = false) const;
493 
494     virtual AffineTransform localTransform() const;
495     virtual AffineTransform absoluteTransform() const;
496     // end svg
497 
498     bool isHTMLMarquee() const;
499     bool isWordBreak() const;
500 
isAnonymous()501     bool isAnonymous() const
502     {
503         return m_isAnonymous;
504     }
setIsAnonymous(bool b)505     void setIsAnonymous(bool b)
506     {
507         m_isAnonymous = b;
508     }
isAnonymousBlock()509     bool isAnonymousBlock() const
510     {
511         return isAnonymous() && style()->display() == BLOCK && node()->isDocumentNode();
512     }
isPseudoAnonymous()513     bool isPseudoAnonymous() const
514     {
515         return isAnonymous() && !node()->isDocumentNode();
516     }
517 
isFloating()518     bool isFloating() const
519     {
520         return m_floating;
521     }
isPositioned()522     bool isPositioned() const
523     {
524         return m_positioned;
525     }
isRelPositioned()526     bool isRelPositioned() const
527     {
528         return m_relPositioned;
529     }
isText()530     bool isText() const
531     {
532         return m_isText;
533     }
isInline()534     bool isInline() const
535     {
536         return m_inline;
537     }
isCompact()538     bool isCompact() const
539     {
540         return style()->display() == COMPACT;    // compact
541     }
isRunIn()542     bool isRunIn() const
543     {
544         return style()->display() == RUN_IN;    // run-in object
545     }
546     bool mouseInside() const;
547     bool isDragging() const;
isReplaced()548     bool isReplaced() const
549     {
550         return m_replaced;
551     }
isReplacedBlock()552     bool isReplacedBlock() const
553     {
554         return isInline() && isReplaced() && isRenderBlock();
555     }
shouldPaintBackgroundOrBorder()556     bool shouldPaintBackgroundOrBorder() const
557     {
558         return m_paintBackground;
559     }
needsLayout()560     bool needsLayout() const
561     {
562         return m_needsLayout || m_normalChildNeedsLayout || m_posChildNeedsLayout;
563     }
markedForRepaint()564     bool markedForRepaint() const
565     {
566         return m_markedForRepaint;
567     }
setMarkedForRepaint(bool m)568     void setMarkedForRepaint(bool m)
569     {
570         m_markedForRepaint = m;
571     }
selfNeedsLayout()572     bool selfNeedsLayout() const
573     {
574         return m_needsLayout;
575     }
posChildNeedsLayout()576     bool posChildNeedsLayout() const
577     {
578         return m_posChildNeedsLayout;
579     }
normalChildNeedsLayout()580     bool normalChildNeedsLayout() const
581     {
582         return m_normalChildNeedsLayout;
583     }
minMaxKnown()584     bool minMaxKnown() const
585     {
586         return m_minMaxKnown;
587     }
hasFirstLine()588     bool hasFirstLine() const
589     {
590         return m_hasFirstLine;
591     }
isSelectionBorder()592     bool isSelectionBorder() const
593     {
594         return m_isSelectionBorder;
595     }
recalcMinMax()596     bool recalcMinMax() const
597     {
598         return m_recalcMinMax;
599     }
600 
601     RenderCanvas *canvas() const;
602     // don't even think about making this method virtual!
603     DOM::DocumentImpl *document() const;
element()604     DOM::NodeImpl *element() const
605     {
606         return isAnonymous() ? nullptr : m_node;
607     }
node()608     DOM::NodeImpl *node() const
609     {
610         return m_node;
611     }
612 
handleEvent(const DOM::EventImpl &)613     virtual bool handleEvent(const DOM::EventImpl &)
614     {
615         return false;
616     }
617 
618     /**
619       * returns the object containing this one. can be different from parent for
620       * positioned elements
621       */
622     RenderObject *container() const;
623 
624     void markContainingBlocksForLayout();
625     void dirtyFormattingContext(bool checkContainer);
626     void repaintDuringLayout();
627     void setNeedsLayout(bool b, bool markParents = true);
628     void setChildNeedsLayout(bool b, bool markParents = true);
629     void setMinMaxKnown(bool b = true)
630     {
631         m_minMaxKnown = b;
632         if (!b) {
633             RenderObject *o = this;
634             while (o) {  // ### && !o->m_recalcMinMax ) {
635                 o->m_recalcMinMax = true;
636                 o = o->m_parent;
637             }
638         }
639     }
setNeedsLayoutAndMinMaxRecalc()640     void setNeedsLayoutAndMinMaxRecalc()
641     {
642         setMinMaxKnown(false);
643         setNeedsLayout(true);
644     }
645     void setPositioned(bool b = true)
646     {
647         m_positioned = b;
648     }
649     void setRelPositioned(bool b = true)
650     {
651         m_relPositioned = b;
652     }
653     void setFloating(bool b = true)
654     {
655         m_floating = b;
656     }
657     void setInline(bool b = true)
658     {
659         m_inline = b;
660     }
661     void setMouseInside(bool b = true)
662     {
663         m_mouseInside = b;
664     }
665     void setShouldPaintBackgroundOrBorder(bool b = true)
666     {
667         m_paintBackground = b;
668     }
setRenderText()669     void setRenderText()
670     {
671         m_isText = true;
672     }
673     void setReplaced(bool b = true)
674     {
675         m_replaced = b;
676     }
677     void setHasOverflowClip(bool b = true)
678     {
679         m_hasOverflowClip = b;
680     }
681     void setIsSelectionBorder(bool b = true)
682     {
683         m_isSelectionBorder = b;
684     }
685 
686     void scheduleRelayout(RenderObject *clippedObj = nullptr);
687 
688     void updateBackgroundImages(RenderStyle *oldStyle);
689 
690     virtual InlineBox *createInlineBox(bool makePlaceHolderBox, bool isRootLineBox);
removeInlineBox(InlineBox *)691     virtual void removeInlineBox(InlineBox * /*box*/) {}
692 
693     virtual InlineBox *inlineBox(long offset = 0);
694     virtual short lineHeight(bool firstLine) const;
695     virtual short verticalPositionHint(bool firstLine) const;
696     virtual short baselinePosition(bool firstLine) const;
697     short getVerticalPosition(bool firstLine, RenderObject *ref = nullptr) const;
698 
699     /*
700      * Print the object and its children, clipped by (x|y|w|h).
701      * (tx|ty) is the calculated position of the parent
702      */
703     struct PaintInfo {
PaintInfoPaintInfo704         PaintInfo(QPainter *_p, const QRect &_r, PaintAction _phase)
705             : p(_p), r(_r), phase(_phase), outlineObjects(nullptr) {}
~PaintInfoPaintInfo706         ~PaintInfo()
707         {
708             delete outlineObjects;
709         }
710         QPainter *p;
711         QRect     r;
712         PaintAction phase;
713         QList<RenderFlow *> *outlineObjects; // used to list which outlines should be painted by a block with inline children
714     };
715     virtual void paint(PaintInfo &i, int tx, int ty);
716 
717     void calcBorderRadii(QPoint &topLeftRadii, QPoint &topRightRadii, QPoint &bottomLeftRadii, QPoint &bottomRightRadii, int w, int h) const;
718 
719     void drawBorderArc(QPainter *p, int x, int y, float horThickness, float vertThickness,
720                        const QPoint &radius, int angleStart, int angleSpan, const QBrush &brush,
721                        const QColor &textColor, EBorderStyle style, qreal *dashOffset = nullptr) const;
722 
723     void paintBorder(QPainter *p, int _tx, int _ty, int w, int h, const RenderStyle *style, bool begin = true, bool end = true);
724     void paintOutline(QPainter *p, int _tx, int _ty, int w, int h, const RenderStyle *style);
725 
paintBoxDecorations(PaintInfo &,int,int)726     virtual void paintBoxDecorations(PaintInfo &, int /*_tx*/, int /*_ty*/) {}
727 
paintBackgroundExtended(QPainter *,const QColor &,const BackgroundLayer *,QRect,int,int,int,int,int,int,int,int,int,int,int,int)728     virtual void paintBackgroundExtended(QPainter * /*p*/, const QColor & /*c*/, const BackgroundLayer * /*bgLayer*/,
729                                          QRect /*clipr*/, int /*_tx*/, int /*_ty*/,
730                                          int /*w*/, int /*height*/, int /*bleft*/, int /*bright*/, int /*pleft*/, int /*pright*/,
731                                          int /*btop*/, int /*bbottom*/, int /*ptop*/, int /*pbottom*/) {}
732 
733     /*
734      * This function calculates the minimum & maximum width that the object
735      * can be set to.
736      *
737      * when the Element calls setMinMaxKnown(true), calcMinMaxWidth() will
738      * be no longer called.
739      *
740      * when a element has a fixed size, m_minWidth and m_maxWidth should be
741      * set to the same value. This has the special meaning that m_width,
742      * contains the actual value.
743      *
744      * assumes calcMinMaxWidth has already been called for all children.
745      */
calcMinMaxWidth()746     virtual void calcMinMaxWidth() { }
747 
748     /*
749      * Does the min max width recalculations after changes.
750      */
751     void recalcMinMaxWidths();
752 
753     /*
754      * Calculates the actual width of the object (only for non inline
755      * objects)
756      */
calcWidth()757     virtual void calcWidth() {}
758 
759     /*
760      * Calculates the actual width of the object (only for non inline
761      * objects)
762      */
calcHeight()763     virtual void calcHeight() {}
764 
765     /*
766      * This function should cause the Element to calculate its
767      * width and height and the layout of its content
768      *
769      * when the Element calls setNeedsLayout(false), layout() is no
770      * longer called during relayouts, as long as there is no
771      * style sheet change. When that occurs, m_needsLayout will be
772      * set to true and the Element receives layout() calls
773      * again.
774      */
775     virtual void layout() = 0;
776 
777     /* This function performs a layout only if one is needed. */
layoutIfNeeded()778     void layoutIfNeeded()
779     {
780         if (needsLayout()) {
781             layout();
782         }
783     }
784 
785     // used for element state updates that can not be fixed with a
786     // repaint and do not need a relayout
updateFromElement()787     virtual void updateFromElement() {}
788 
789     // Called immediately after render-object is inserted
attach()790     virtual void attach()
791     {
792         m_attached = true;
793     }
attached()794     bool attached()
795     {
796         return m_attached;
797     }
798     // The corresponding closing element has been parsed. ### remove me
close()799     virtual void close() { }
800 
availableHeight()801     virtual int availableHeight() const
802     {
803         return 0;
804     }
805 
806     // Whether or not the element shrinks to its max width (rather than filling the width
807     // of a containing block).  HTML4 buttons, legends, and floating/compact elements do this.
808     bool sizesToMaxWidth() const;
809 
810     /*
811      * NeesPageClear indicates the object crossed a page-break but could not break itself and now
812      * needs to be moved clear by its parent.
813      */
814     void setNeedsPageClear(bool b = true)
815     {
816         m_needsPageClear = b;
817     }
needsPageClear()818     virtual bool needsPageClear() const
819     {
820         return m_needsPageClear;
821     }
822 
823     /*
824      * ContainsPageBreak indicates the object contains a clean page-break.
825      * ### should be removed and replaced with (crossesPageBreak && !needsPageClear)
826      */
827     void setContainsPageBreak(bool b = true)
828     {
829         m_containsPageBreak = b;
830     }
containsPageBreak()831     virtual bool containsPageBreak() const
832     {
833         return m_containsPageBreak;
834     }
835 
pageTopAfter(int y)836     virtual int pageTopAfter(int y) const
837     {
838         if (parent()) {
839             return parent()->pageTopAfter(y);
840         } else {
841             return 0;
842         }
843     }
844 
crossesPageBreak(int top,int bottom)845     virtual int crossesPageBreak(int top, int bottom) const
846     {
847         if (parent()) {
848             return parent()->crossesPageBreak(top, bottom);
849         } else {
850             return 0;
851         }
852     }
853 
854     // Checks if a page-break before child is possible at the given page-break level
855     // false means the child should attempt the break self.
canClear(RenderObject *,PageBreakLevel level)856     virtual bool canClear(RenderObject * /*child*/, PageBreakLevel level)
857     {
858         if (parent()) {
859             return parent()->canClear(this, level);
860         } else {
861             return false;
862         }
863     }
864 
865     void setAfterPageBreak(bool b = true)
866     {
867         m_afterPageBreak = b;
868     }
869     void setBeforePageBreak(bool b = true)
870     {
871         m_beforePageBreak = b;
872     }
afterPageBreak()873     virtual bool afterPageBreak() const
874     {
875         return m_afterPageBreak;
876     }
beforePageBreak()877     virtual bool beforePageBreak() const
878     {
879         return m_beforePageBreak;
880     }
881 
882     // does a query on the rendertree and finds the innernode
883     // and overURL for the given position
884     // if readonly == false, it will recalc hover styles accordingly
885     class NodeInfo
886     {
887         friend class RenderImage;
888         friend class RenderFlow;
889         friend class RenderInline;
890         friend class RenderText;
891         friend class RenderWidget;
892         friend class RenderObject;
893         friend class RenderFrameSet;
894         friend class RenderLayer;
895         friend class DOM::HTMLAreaElementImpl;
896     public:
NodeInfo(bool readonly,bool active)897         NodeInfo(bool readonly, bool active)
898             : m_innerNode(nullptr), m_innerNonSharedNode(nullptr), m_innerURLElement(nullptr), m_readonly(readonly), m_active(active)
899         { }
900 
innerNode()901         DOM::NodeImpl *innerNode() const
902         {
903             return m_innerNode;
904         }
innerNonSharedNode()905         DOM::NodeImpl *innerNonSharedNode() const
906         {
907             return m_innerNonSharedNode;
908         }
URLElement()909         DOM::NodeImpl *URLElement() const
910         {
911             return m_innerURLElement;
912         }
readonly()913         bool readonly() const
914         {
915             return m_readonly;
916         }
active()917         bool active() const
918         {
919             return m_active;
920         }
921 
922     private:
setInnerNode(DOM::NodeImpl * n)923         void setInnerNode(DOM::NodeImpl *n)
924         {
925             m_innerNode = n;
926         }
setInnerNonSharedNode(DOM::NodeImpl * n)927         void setInnerNonSharedNode(DOM::NodeImpl *n)
928         {
929             m_innerNonSharedNode = n;
930         }
setURLElement(DOM::NodeImpl * n)931         void setURLElement(DOM::NodeImpl *n)
932         {
933             m_innerURLElement = n;
934         }
935 
936         DOM::NodeImpl *m_innerNode;
937         DOM::NodeImpl *m_innerNonSharedNode;
938         DOM::NodeImpl *m_innerURLElement;
939         bool m_readonly;
940         bool m_active;
941     };
942 
943     /** contains stateful information for a checkSelectionPoint call
944      */
945     struct SelPointState {
946         /** last node that was before the current position */
947         DOM::NodeImpl *m_lastNode;
948         /** offset of last node */
949         long m_lastOffset;
950         /** true when the last node had the result SelectionAfterInLine */
951         bool m_afterInLine;
952 
SelPointStateSelPointState953         SelPointState() : m_lastNode(nullptr), m_lastOffset(0), m_afterInLine(false)
954         {}
955     };
956 
957 #if 0
958     virtual FindSelectionResult checkSelectionPoint(int _x, int _y, int _tx, int _ty,
959             DOM::NodeImpl *&, int &offset,
960             SelPointState &);
961 #endif
962     virtual bool nodeAtPoint(NodeInfo &info, int x, int y, int tx, int ty, HitTestAction, bool inside = false);
963     void setInnerNode(NodeInfo &info);
964 
965     // Position/Selection stuff
966     virtual RenderPosition positionForCoordinates(int x, int y);
967 
968     // set the style of the object.
969     virtual void setStyle(RenderStyle *style);
970 
971     // returns the containing block level element for this element.
972     RenderBlock *containingBlock() const;
973 
974     // return just the width of the containing block
975     virtual short containingBlockWidth(RenderObject *providedCB = nullptr) const;
976     // return just the height of the containing block
977     virtual int containingBlockHeight(RenderObject *providedCB = nullptr) const;
978 
979     // size of the content area (box size minus padding/border)
contentWidth()980     virtual short contentWidth() const
981     {
982         return 0;
983     }
contentHeight()984     virtual int contentHeight() const
985     {
986         return 0;
987     }
988 
989     // intrinsic extend of replaced elements. undefined otherwise
intrinsicWidth()990     virtual short intrinsicWidth() const
991     {
992         return 0;
993     }
intrinsicHeight()994     virtual int intrinsicHeight() const
995     {
996         return 0;
997     }
998 
999     // relative to parent node
setPos(int,int)1000     virtual void setPos(int /*xPos*/, int /*yPos*/) { }
setWidth(int)1001     virtual void setWidth(int /*width*/) { }
setHeight(int)1002     virtual void setHeight(int /*height*/) { }
1003 
xPos()1004     virtual int xPos() const
1005     {
1006         return 0;
1007     }
yPos()1008     virtual int yPos() const
1009     {
1010         return 0;
1011     }
1012 
1013     /** the position of the object from where it begins drawing, including
1014      * its negative overflow
1015      */
effectiveXPos()1016     int effectiveXPos() const
1017     {
1018         return xPos() + (hasOverflowClip() ? 0 : overflowLeft());
1019     }
1020 
1021     /** the position of the object from where it begins drawing, including
1022      * its negative overflow
1023      */
effectiveYPos()1024     int effectiveYPos() const
1025     {
1026         return yPos() + (hasOverflowClip() ? -borderTopExtra() : qMin(overflowTop(), -borderTopExtra()));
1027     }
1028 
1029     /** Leftmost coordinate of this inline element relative to containing
1030      * block. Always zero for non-inline elements.
1031      */
inlineXPos()1032     virtual int inlineXPos() const
1033     {
1034         return 0;
1035     }
1036     /** Topmost coordinate of this inline element relative to containing
1037      * block. Always zero for non-inline elements.
1038      */
inlineYPos()1039     virtual int inlineYPos() const
1040     {
1041         return 0;
1042     }
1043 
1044     // calculate client position of box
1045     virtual bool absolutePosition(int &/*xPos*/, int &/*yPos*/, bool fixed = false) const;
1046 
1047     // width and height are without margins but include paddings and borders
width()1048     virtual short width() const
1049     {
1050         return 0;
1051     }
height()1052     virtual int height() const
1053     {
1054         return 0;
1055     }
1056 
1057     // The height of a block when you include overflow spillage out of
1058     // the bottom of the block (e.g., a <div style="height:25px"> that
1059     // has a 100px tall image inside it would have an overflow height
1060     // of borderTop() + paddingTop() + 100px.
overflowHeight()1061     virtual int overflowHeight() const
1062     {
1063         return height();
1064     }
overflowWidth()1065     virtual int overflowWidth() const
1066     {
1067         return width();
1068     }
1069     // how much goes over the left hand side (0 or a negative number)
overflowTop()1070     virtual int overflowTop() const
1071     {
1072         return 0;
1073     }
overflowLeft()1074     virtual int overflowLeft() const
1075     {
1076         return 0;
1077     }
1078 
1079     /**
1080      * Returns the height that is effectively considered when contemplating the
1081      * object as a whole -- usually the overflow height, or the height if clipped.
1082      */
effectiveHeight()1083     int effectiveHeight() const
1084     {
1085         return hasOverflowClip() ? height() + borderTopExtra() + borderBottomExtra() :
1086                qMax(overflowHeight() - overflowTop(),  height() + borderTopExtra() + borderBottomExtra());
1087     }
1088     /**
1089      * Returns the width that is effectively considered when contemplating the
1090      * object as a whole -- usually the overflow width, or the width if clipped.
1091      */
effectiveWidth()1092     int effectiveWidth() const
1093     {
1094         return hasOverflowClip() ? width() : overflowWidth() - overflowLeft();
1095     }
1096 
1097     QRectF clientRectToViewport(const QRectF &rect);
1098     virtual QList< QRectF > getClientRects();
1099 
1100     // IE extensions, heavily used in ECMA
offsetWidth()1101     virtual short offsetWidth() const
1102     {
1103         return width();
1104     }
offsetHeight()1105     virtual int offsetHeight() const
1106     {
1107         return height() + borderTopExtra() + borderBottomExtra();
1108     }
1109     virtual int offsetLeft() const;
1110     virtual int offsetTop() const;
1111     virtual RenderObject *offsetParent() const;
1112     int clientLeft() const;
1113     int clientTop() const;
1114     short clientWidth() const;
1115     int clientHeight() const;
1116     virtual short scrollWidth() const;
1117     virtual int scrollHeight() const;
1118 
isSelfCollapsingBlock()1119     virtual bool isSelfCollapsingBlock() const
1120     {
1121         return false;
1122     }
collapsedMarginTop()1123     short collapsedMarginTop() const
1124     {
1125         return maxTopMargin(true) - maxTopMargin(false);
1126     }
collapsedMarginBottom()1127     short collapsedMarginBottom() const
1128     {
1129         return maxBottomMargin(true) - maxBottomMargin(false);
1130     }
1131 
isTopMarginQuirk()1132     virtual bool isTopMarginQuirk() const
1133     {
1134         return false;
1135     }
isBottomMarginQuirk()1136     virtual bool isBottomMarginQuirk() const
1137     {
1138         return false;
1139     }
maxTopMargin(bool positive)1140     virtual short maxTopMargin(bool positive) const
1141     {
1142         return positive ? qMax(int(marginTop()), 0) : - qMin(int(marginTop()), 0);
1143     }
maxBottomMargin(bool positive)1144     virtual short maxBottomMargin(bool positive) const
1145     {
1146         return positive ? qMax(int(marginBottom()), 0) : - qMin(int(marginBottom()), 0);
1147     }
1148 
marginTop()1149     virtual short marginTop() const
1150     {
1151         return 0;
1152     }
marginBottom()1153     virtual short marginBottom() const
1154     {
1155         return 0;
1156     }
marginLeft()1157     virtual short marginLeft() const
1158     {
1159         return 0;
1160     }
marginRight()1161     virtual short marginRight() const
1162     {
1163         return 0;
1164     }
1165 
1166     virtual int paddingTop() const;
1167     virtual int paddingBottom() const;
1168     virtual int paddingLeft() const;
1169     virtual int paddingRight() const;
1170 
borderTop()1171     virtual int borderTop() const
1172     {
1173         return style()->borderTopWidth();
1174     }
borderBottom()1175     virtual int borderBottom() const
1176     {
1177         return style()->borderBottomWidth();
1178     }
borderLeft()1179     virtual int borderLeft() const
1180     {
1181         return style()->borderLeftWidth();
1182     }
borderRight()1183     virtual int borderRight() const
1184     {
1185         return style()->borderRightWidth();
1186     }
1187 
minWidth()1188     virtual short minWidth() const
1189     {
1190         return 0;
1191     }
maxWidth()1192     virtual int maxWidth() const
1193     {
1194         return 0;
1195     }
1196 
style()1197     RenderStyle *style() const
1198     {
1199         return m_style;
1200     }
style(bool firstLine)1201     RenderStyle *style(bool firstLine) const
1202     {
1203         RenderStyle *s = m_style;
1204         if (firstLine && hasFirstLine()) {
1205             RenderStyle *pseudoStyle  = style()->getPseudoStyle(RenderStyle::FIRST_LINE);
1206             if (pseudoStyle) {
1207                 s = pseudoStyle;
1208             }
1209         }
1210         return s;
1211     }
1212 
1213     void getTextDecorationColors(int decorations, QColor &underline, QColor &overline,
1214                                  QColor &linethrough, bool quirksMode = false);
1215 
1216     enum BorderSide {
1217         BSTop, BSBottom, BSLeft, BSRight
1218     };
1219     void drawBorder(QPainter *p, int x1, int y1, int x2, int y2, BorderSide s,
1220                     QColor c, const QColor &textcolor, EBorderStyle style,
1221                     int adjbw1, int adjbw2, bool invalidisInvert = false, qreal *dashOffset = nullptr);
1222 
1223     // Used by collapsed border tables.
1224     virtual void collectBorders(QList<CollapsedBorderValue> &borderStyles);
1225 
1226     // force a complete repaint
1227     virtual void repaint(Priority p = NormalPriority)
1228     {
1229         if (m_parent) {
1230             m_parent->repaint(p);
1231         }
1232     }
1233     virtual void repaintRectangle(int x, int y, int w, int h, Priority p = NormalPriority, bool f = false);
1234 
length()1235     virtual unsigned int length() const
1236     {
1237         return 1;
1238     }
1239 
isHidden()1240     virtual bool isHidden() const
1241     {
1242         return isFloating() || isPositioned();
1243     }
1244 
1245     // Special objects are objects that are neither really inline nor blocklevel
isFloatingOrPositioned()1246     bool isFloatingOrPositioned() const
1247     {
1248         return (isFloating() || isPositioned());
1249     }
hasOverhangingFloats()1250     virtual bool hasOverhangingFloats() const
1251     {
1252         return false;
1253     }
hasFloats()1254     virtual bool hasFloats() const
1255     {
1256         return false;
1257     }
containsFloat(RenderObject *)1258     virtual bool containsFloat(RenderObject * /*o*/) const
1259     {
1260         return false;
1261     }
1262     virtual void markAllDescendantsWithFloatsForLayout(RenderObject * /*floatToRemove*/ = nullptr) {}
1263 
1264     bool flowAroundFloats() const;
1265     bool usesLineWidth() const;
1266 
1267     // positioning of inline children (bidi)
position(InlineBox *,int,int,bool)1268     virtual void position(InlineBox *, int, int, bool) {}
1269 //    virtual void position(int, int, int, int, int, bool, bool, int) {}
1270 
1271     // Applied as a "slop" to dirty rect checks during the outline painting phase's dirty-rect checks.
1272     int maximalOutlineSize(PaintAction p) const;
1273 
1274     enum SelectionState {
1275         SelectionNone,
1276         SelectionStart,
1277         SelectionInside,
1278         SelectionEnd,
1279         SelectionBoth
1280     };
1281 
selectionState()1282     virtual SelectionState selectionState() const
1283     {
1284         return SelectionNone;
1285     }
setSelectionState(SelectionState)1286     virtual void setSelectionState(SelectionState) {}
1287     bool shouldSelect() const;
1288     virtual bool isPointInsideSelection(int x, int y, const DOM::Selection &) const;
1289 
1290     DOM::NodeImpl *draggableNode(bool dhtmlOK, bool uaOK, bool &dhtmlWillDrag) const;
1291 
1292     /**
1293      * Flags which influence the appearance and position
1294      * @param CFOverride input overrides existing character, caret should be
1295      *      cover the whole character
1296      * @param CFOutside coordinates are to be interpreted outside of the
1297      *      render object
1298      * @param CFOutsideEnd coordinates are to be interpreted at the outside
1299      *      end of the render object (only valid if CFOutside is also set)
1300      */
1301     enum CaretFlags { CFOverride = 0x01, CFOutside = 0x02, CFOutsideEnd = 0x04 };
1302 
1303     /**
1304      * Returns the content coordinates of the caret within this render object.
1305      * @param offset zero-based offset determining position within the render object.
1306      * @param flags combination of enum CaretFlags
1307      * @param _x returns the left coordinate
1308      * @param _y returns the top coordinate
1309      * @param width returns the caret's width
1310      * @param height returns the caret's height
1311      */
1312     virtual void caretPos(int offset, int flags, int &_x, int &_y, int &width, int &height) const;
1313 
1314     // returns the lowest position of the lowest object in that particular object.
1315     // This 'height' is relative to the topleft of the margin box of the object.
1316     // Implemented in RenderFlow.
1317     virtual int lowestPosition(bool /*includeOverflowInterior*/ = true, bool /*includeSelf*/ = true) const
1318     {
1319         return 0;
1320     }
1321     virtual int rightmostPosition(bool /*includeOverflowInterior*/ = true, bool /*includeSelf*/ = true) const
1322     {
1323         return 0;
1324     }
1325     virtual int leftmostPosition(bool /*includeOverflowInterior*/ = true, bool /*includeSelf*/ = true) const
1326     {
1327         return 0;
1328     }
1329     virtual int highestPosition(bool /*includeOverflowInterior*/ = true, bool /*includeSelf*/ = true) const
1330     {
1331         return 0;
1332     }
1333 
1334     // recursively invalidate current layout
1335     // unused: void invalidateLayout();
1336 
calcVerticalMargins()1337     virtual void calcVerticalMargins() {}
1338     void removeFromObjectLists();
1339     void setInPosObjectList(bool b = true)
1340     {
1341         m_inPosObjectList = b;
1342     }
inPosObjectList()1343     bool inPosObjectList() const
1344     {
1345         return m_inPosObjectList;
1346     }
1347 
1348     virtual void deleteInlineBoxes(RenderArena *arena = nullptr)
1349     {
1350         (void)arena;
1351     }
1352     virtual void dirtyInlineBoxes(bool /*fullLayout*/, bool /*isRootLineBox*/ = false) {}
dirtyLinesFromChangedChild(RenderObject *)1353     virtual void dirtyLinesFromChangedChild(RenderObject *) {}
1354     virtual void detach();
1355 
documentBeingDestroyed()1356     bool documentBeingDestroyed() const
1357     {
1358         return !document()->renderer();
1359     }
1360 
setDoNotDelete(bool b)1361     void setDoNotDelete(bool b)
1362     {
1363         m_doNotDelete = b;
1364     }
doNotDelete()1365     bool doNotDelete() const
1366     {
1367         return m_doNotDelete;
1368     }
1369 
font(bool firstLine)1370     const QFont &font(bool firstLine) const
1371     {
1372         return style(firstLine)->font();
1373     }
1374 
fontMetrics(bool firstLine)1375     const QFontMetrics &fontMetrics(bool firstLine) const
1376     {
1377         return style(firstLine)->fontMetrics();
1378     }
1379 
1380     /** returns the lowest possible value the caret offset may have to
1381      * still point to a valid position.
1382      *
1383      * Returns 0 by default.
1384      */
1385     virtual long caretMinOffset() const;
1386     /** returns the highest possible value the caret offset may have to
1387      * still point to a valid position.
1388      *
1389      * Returns 0 by default, as generic elements are considered to have no
1390      * width.
1391      */
1392     virtual long caretMaxOffset() const;
1393     virtual unsigned long caretMaxRenderedOffset() const;
1394 
1395     void updatePixmap(const QRect &, CachedImage *) override;
1396 
1397     QRegion visibleFlowRegion(int x, int y) const;
1398 
removeSuperfluousAnonymousBlockChild(RenderObject *)1399     virtual void removeSuperfluousAnonymousBlockChild(RenderObject *) {}
1400 
1401     // Unregisters from parent but does not destroy
1402     void remove();
1403 protected:
1404     virtual void selectionStartEnd(int &spos, int &epos);
1405 
1406     virtual QRect viewRect() const;
setDetached()1407     void setDetached()
1408     {
1409         m_attached = false;
1410     }
1411     void invalidateVerticalPosition();
1412     bool attemptDirectLayerTranslation();
1413     void updateWidgetMasks();
1414 
1415     void arenaDelete(RenderArena *arena);
1416 
1417 private:
1418     RenderStyle *m_style;
1419     DOM::NodeImpl *m_node;
1420     RenderObject *m_parent;
1421     RenderObject *m_previous;
1422     RenderObject *m_next;
1423 
1424     short m_verticalPosition;
1425 
1426     bool m_needsLayout               : 1;
1427     bool m_normalChildNeedsLayout    : 1;
1428     bool m_markedForRepaint          : 1;
1429     bool m_posChildNeedsLayout       : 1;
1430 
1431     bool m_minMaxKnown               : 1;
1432     bool m_floating                  : 1;
1433 
1434     bool m_positioned                : 1;
1435     bool m_relPositioned             : 1;
1436     bool m_paintBackground           : 1; // if the box has something to paint in the
1437     // background painting phase (background, border, etc)
1438 
1439     bool m_isAnonymous               : 1;
1440     bool m_recalcMinMax          : 1;
1441     bool m_isText                    : 1;
1442     bool m_inline                    : 1;
1443     bool m_attached                  : 1;
1444 
1445     bool m_replaced                  : 1;
1446     bool m_mouseInside               : 1;
1447     bool m_hasFirstLine              : 1;
1448     bool m_isSelectionBorder         : 1;
1449 
1450     bool m_isRoot                    : 1;
1451 
1452     bool m_beforePageBreak           : 1;
1453     bool m_afterPageBreak            : 1;
1454 
1455     bool m_needsPageClear            : 1;
1456     bool m_containsPageBreak         : 1;
1457 
1458     bool m_hasOverflowClip           : 1;
1459     bool m_inPosObjectList           : 1;
1460 
1461     bool m_doNotDelete               : 1; // This object should not be auto-deleted
1462 
1463     // ### we have 16 + 26 bits.
1464 
1465     static QCache<quint64, QPixmap> *s_dashedLineCache;
1466 
1467     void arenaDelete(RenderArena *arena, void *objectBase);
1468 
1469     friend class RenderLayer;
1470     friend class RenderListItem;
1471     friend class RenderContainer;
1472     friend class RenderCanvas;
1473 };
1474 
1475 enum VerticalPositionHint {
1476     PositionTop = -0x4000,
1477     PositionBottom = 0x4000,
1478     PositionUndefined = 0x3fff
1479 };
1480 
1481 } //namespace
1482 #endif
1483