| /* |
| * Copyright (C) 2000 Lars Knoll (knoll@kde.org) |
| * (C) 2000 Antti Koivisto (koivisto@kde.org) |
| * (C) 2000 Dirk Mueller (mueller@kde.org) |
| * (C) 2004 Allan Sandfeld Jensen (kde@carewolf.com) |
| * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2012 Apple Inc. All rights reserved. |
| * Copyright (C) 2009 Google Inc. All rights reserved. |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Library General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Library General Public License for more details. |
| * |
| * You should have received a copy of the GNU Library General Public License |
| * along with this library; see the file COPYING.LIB. If not, write to |
| * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| * Boston, MA 02110-1301, USA. |
| * |
| */ |
| |
| #ifndef SKY_ENGINE_CORE_RENDERING_RENDEROBJECT_H_ |
| #define SKY_ENGINE_CORE_RENDERING_RENDEROBJECT_H_ |
| |
| #include "sky/engine/core/dom/Document.h" |
| #include "sky/engine/core/dom/Element.h" |
| #include "sky/engine/core/editing/TextAffinity.h" |
| #include "sky/engine/core/html/HTMLElement.h" |
| #include "sky/engine/core/rendering/HitTestRequest.h" |
| #include "sky/engine/core/rendering/RenderObjectChildList.h" |
| #include "sky/engine/core/rendering/SubtreeLayoutScope.h" |
| #include "sky/engine/core/rendering/style/RenderStyle.h" |
| #include "sky/engine/core/rendering/style/StyleInheritedData.h" |
| #include "sky/engine/platform/geometry/FloatQuad.h" |
| #include "sky/engine/platform/geometry/LayoutRect.h" |
| #include "sky/engine/platform/transforms/TransformationMatrix.h" |
| |
| namespace blink { |
| |
| class AffineTransform; |
| class Document; |
| class HitTestLocation; |
| class HitTestResult; |
| class InlineBox; |
| class InlineFlowBox; |
| class Position; |
| class PositionWithAffinity; |
| class RenderBlock; |
| class RenderBox; |
| class RenderBoxModelObject; |
| class RenderGeometryMap; |
| class RenderLayer; |
| class RenderView; |
| class TransformState; |
| |
| struct PaintInfo; |
| |
| // Sides used when drawing borders and outlines. The values should run clockwise from top. |
| enum BoxSide { |
| BSTop, |
| BSRight, |
| BSBottom, |
| BSLeft |
| }; |
| |
| enum MarkingBehavior { |
| MarkOnlyThis, |
| MarkContainingBlockChain, |
| }; |
| |
| enum MapCoordinatesMode { |
| UseTransforms = 1 << 0, |
| // FIXME(sky): What is this for? Do we need it? |
| ApplyContainerFlip = 1 << 1, |
| // FIXME(sky): Remove |
| TraverseDocumentBoundaries = 1 << 2, |
| }; |
| typedef unsigned MapCoordinatesFlags; |
| |
| const int caretWidth = 1; |
| |
| struct AnnotatedRegionValue { |
| bool operator==(const AnnotatedRegionValue& o) const |
| { |
| return draggable == o.draggable && bounds == o.bounds; |
| } |
| |
| LayoutRect bounds; |
| bool draggable; |
| }; |
| |
| typedef WTF::HashMap<const RenderLayer*, Vector<LayoutRect> > LayerHitTestRects; |
| |
| #ifndef NDEBUG |
| const int showTreeCharacterOffset = 39; |
| #endif |
| |
| // Base class for all rendering tree objects. |
| class RenderObject { |
| friend class RenderBlock; |
| friend class RenderObjectChildList; |
| WTF_MAKE_NONCOPYABLE(RenderObject); |
| public: |
| // TODO(ojan): Pass in a reference since the node can no longer be null. |
| explicit RenderObject(Node*); |
| virtual ~RenderObject(); |
| |
| virtual const char* renderName() const = 0; |
| |
| String debugName() const; |
| |
| RenderObject* parent() const { return m_parent; } |
| bool isDescendantOf(const RenderObject*) const; |
| |
| RenderObject* previousSibling() const { return m_previous; } |
| RenderObject* nextSibling() const { return m_next; } |
| |
| RenderObject* slowFirstChild() const |
| { |
| if (const RenderObjectChildList* children = virtualChildren()) |
| return children->firstChild(); |
| return 0; |
| } |
| RenderObject* slowLastChild() const |
| { |
| if (const RenderObjectChildList* children = virtualChildren()) |
| return children->lastChild(); |
| return 0; |
| } |
| |
| virtual RenderObjectChildList* virtualChildren() { return 0; } |
| virtual const RenderObjectChildList* virtualChildren() const { return 0; } |
| |
| RenderObject* nextInPreOrder() const; |
| RenderObject* nextInPreOrder(const RenderObject* stayWithin) const; |
| RenderObject* nextInPreOrderAfterChildren() const; |
| RenderObject* nextInPreOrderAfterChildren(const RenderObject* stayWithin) const; |
| RenderObject* previousInPreOrder() const; |
| RenderObject* previousInPreOrder(const RenderObject* stayWithin) const; |
| RenderObject* childAt(unsigned) const; |
| |
| RenderObject* lastLeafChild() const; |
| |
| // The following six functions are used when the render tree hierarchy changes to make sure layers get |
| // properly added and removed. Since containership can be implemented by any subclass, and since a hierarchy |
| // can contain a mixture of boxes and other object types, these functions need to be in the base class. |
| RenderLayer* enclosingLayer() const; |
| void addLayers(RenderLayer* parentLayer); |
| void removeLayers(RenderLayer* parentLayer); |
| void moveLayers(RenderLayer* oldParent, RenderLayer* newParent); |
| RenderLayer* findNextLayer(RenderLayer* parentLayer, RenderObject* startPoint, bool checkParent = true); |
| |
| // Convenience function for getting to the nearest enclosing box of a RenderObject. |
| RenderBox* enclosingBox() const; |
| RenderBoxModelObject* enclosingBoxModelObject() const; |
| |
| #if ENABLE(ASSERT) |
| // Helper class forbidding calls to setNeedsLayout() during its lifetime. |
| class SetLayoutNeededForbiddenScope { |
| public: |
| explicit SetLayoutNeededForbiddenScope(RenderObject&); |
| ~SetLayoutNeededForbiddenScope(); |
| private: |
| RenderObject& m_renderObject; |
| bool m_preexistingForbidden; |
| }; |
| |
| void assertRendererLaidOut() const |
| { |
| #ifndef NDEBUG |
| if (needsLayout()) |
| showRenderTreeForThis(); |
| #endif |
| ASSERT_WITH_SECURITY_IMPLICATION(!needsLayout()); |
| } |
| |
| void assertSubtreeIsLaidOut() const |
| { |
| for (const RenderObject* renderer = this; renderer; renderer = renderer->nextInPreOrder()) |
| renderer->assertRendererLaidOut(); |
| } |
| #endif |
| |
| bool skipInvalidationWhenLaidOutChildren() const; |
| |
| // FIXME: This could be used when changing the size of a renderer without children to skip some invalidations. |
| bool rendererHasNoBoxEffect() const |
| { |
| return !style()->hasVisualOverflowingEffect() && !style()->hasBorder() && !style()->hasBackground(); |
| } |
| |
| // Obtains the nearest enclosing block (including this block) that contributes a first-line style to our inline |
| // children. |
| virtual RenderBlock* firstLineBlock() const; |
| |
| // RenderObject tree manipulation |
| ////////////////////////////////////////// |
| virtual bool canHaveChildren() const { return virtualChildren(); } |
| virtual bool isChildAllowed(RenderObject*, RenderStyle*) const { return true; } |
| virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0); |
| virtual void removeChild(RenderObject*); |
| ////////////////////////////////////////// |
| |
| protected: |
| ////////////////////////////////////////// |
| // Helper functions. Dangerous to use! |
| void setPreviousSibling(RenderObject* previous) { m_previous = previous; } |
| void setNextSibling(RenderObject* next) { m_next = next; } |
| void setParent(RenderObject* parent) { m_parent = parent; } |
| |
| ////////////////////////////////////////// |
| private: |
| #if ENABLE(ASSERT) |
| bool isSetNeedsLayoutForbidden() const { return m_setNeedsLayoutForbidden; } |
| void setNeedsLayoutIsForbidden(bool flag) { m_setNeedsLayoutForbidden = flag; } |
| #endif |
| |
| void addAbsoluteRectForLayer(LayoutRect& result); |
| |
| public: |
| #ifndef NDEBUG |
| void showTreeForThis() const; |
| void showRenderTreeForThis() const; |
| void showLineTreeForThis() const; |
| |
| void showRenderObject() const; |
| // We don't make printedCharacters an optional parameter so that |
| // showRenderObject can be called from gdb easily. |
| void showRenderObject(int printedCharacters) const; |
| void showRenderTreeAndMark(const RenderObject* markedObject1 = 0, const char* markedLabel1 = 0, const RenderObject* markedObject2 = 0, const char* markedLabel2 = 0, int depth = 0) const; |
| #endif |
| |
| static RenderObject* createObject(Element*, RenderStyle*); |
| static unsigned instanceCount() { return s_instanceCount; } |
| |
| #if !ENABLE(OILPAN) |
| // RenderObjects are allocated out of the rendering partition. |
| void* operator new(size_t); |
| void operator delete(void*); |
| #endif |
| |
| public: |
| virtual bool isBoxModelObject() const { return false; } |
| virtual bool isCanvas() const { return false; } |
| virtual bool isImage() const { return false; } |
| virtual bool isInlineBlock() const { return false; } |
| virtual bool isRenderBlock() const { return false; } |
| virtual bool isRenderParagraph() const { return false; } |
| virtual bool isRenderInline() const { return false; } |
| virtual bool isRenderView() const { return false; } |
| |
| bool everHadLayout() const { return m_bitfields.everHadLayout(); } |
| |
| bool alwaysCreateLineBoxesForRenderInline() const |
| { |
| ASSERT(isRenderInline()); |
| return m_bitfields.alwaysCreateLineBoxesForRenderInline(); |
| } |
| void setAlwaysCreateLineBoxesForRenderInline(bool alwaysCreateLineBoxes) |
| { |
| ASSERT(isRenderInline()); |
| m_bitfields.setAlwaysCreateLineBoxesForRenderInline(alwaysCreateLineBoxes); |
| } |
| |
| bool ancestorLineBoxDirty() const { return m_bitfields.ancestorLineBoxDirty(); } |
| void setAncestorLineBoxDirty(bool value = true) |
| { |
| m_bitfields.setAncestorLineBoxDirty(value); |
| if (value) |
| setNeedsLayout(); |
| } |
| |
| // SVG uses FloatPoint precise hit testing, and passes the point in parent |
| // coordinates instead of in paint invalidaiton container coordinates. Eventually the |
| // rest of the rendering tree will move to a similar model. |
| virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent); |
| |
| bool canHaveWhitespaceChildren() const |
| { |
| return !isFlexibleBox(); |
| } |
| |
| bool isOutOfFlowPositioned() const { return m_bitfields.isOutOfFlowPositioned(); } // absolute or fixed positioning |
| bool isPositioned() const { return m_bitfields.isPositioned(); } |
| |
| bool isText() const { return m_bitfields.isText(); } |
| bool isBox() const { return m_bitfields.isBox(); } |
| bool isInline() const { return m_bitfields.isInline(); } // inline object |
| bool isDragging() const { return m_bitfields.isDragging(); } |
| bool isReplaced() const { return m_bitfields.isReplaced(); } // a "replaced" element (see CSS) |
| |
| bool hasLayer() const { return m_bitfields.hasLayer(); } |
| |
| bool hasBoxDecorationBackground() const { return m_bitfields.hasBoxDecorationBackground(); } |
| bool hasBackground() const { return style()->hasBackground(); } |
| bool hasEntirelyFixedBackground() const; |
| |
| bool needsLayoutBecauseOfChildren() const { return needsLayout() && !selfNeedsLayout() && !needsPositionedMovementLayout() && !needsSimplifiedNormalFlowLayout(); } |
| |
| bool needsLayout() const |
| { |
| return m_bitfields.selfNeedsLayout() || m_bitfields.normalChildNeedsLayout() || m_bitfields.posChildNeedsLayout() |
| || m_bitfields.needsSimplifiedNormalFlowLayout() || m_bitfields.needsPositionedMovementLayout(); |
| } |
| |
| bool selfNeedsLayout() const { return m_bitfields.selfNeedsLayout(); } |
| bool needsPositionedMovementLayout() const { return m_bitfields.needsPositionedMovementLayout(); } |
| bool needsPositionedMovementLayoutOnly() const |
| { |
| return m_bitfields.needsPositionedMovementLayout() && !m_bitfields.selfNeedsLayout() && !m_bitfields.normalChildNeedsLayout() |
| && !m_bitfields.posChildNeedsLayout() && !m_bitfields.needsSimplifiedNormalFlowLayout(); |
| } |
| |
| bool posChildNeedsLayout() const { return m_bitfields.posChildNeedsLayout(); } |
| bool needsSimplifiedNormalFlowLayout() const { return m_bitfields.needsSimplifiedNormalFlowLayout(); } |
| bool normalChildNeedsLayout() const { return m_bitfields.normalChildNeedsLayout(); } |
| |
| bool preferredLogicalWidthsDirty() const { return m_bitfields.preferredLogicalWidthsDirty(); } |
| |
| bool needsOverflowRecalcAfterStyleChange() const { return m_bitfields.selfNeedsOverflowRecalcAfterStyleChange() || m_bitfields.childNeedsOverflowRecalcAfterStyleChange(); } |
| bool selfNeedsOverflowRecalcAfterStyleChange() const { return m_bitfields.selfNeedsOverflowRecalcAfterStyleChange(); } |
| bool childNeedsOverflowRecalcAfterStyleChange() const { return m_bitfields.childNeedsOverflowRecalcAfterStyleChange(); } |
| |
| bool isSelectionBorder() const; |
| |
| bool hasClip() const { return isOutOfFlowPositioned() && !style()->hasAutoClip(); } |
| bool hasOverflowClip() const { return m_bitfields.hasOverflowClip(); } |
| bool hasClipOrOverflowClip() const { return hasClip() || hasOverflowClip(); } |
| |
| bool hasTransform() const { return m_bitfields.hasTransform(); } |
| bool hasClipPath() const { return style() && style()->clipPath(); } |
| |
| inline bool preservesNewline() const; |
| |
| RenderView* view() const { return document().renderView(); }; |
| FrameView* frameView() const { return document().view(); }; |
| |
| bool isRooted() const; |
| |
| // TODO(ojan): Make this a reference now that it can't be null. |
| Node* node() const |
| { |
| return m_node.get(); |
| } |
| |
| Document& document() const { return m_node->document(); } |
| LocalFrame* frame() const { return document().frame(); } |
| |
| // Returns the object containing this one. Can be different from parent for positioned elements. |
| // If paintInvalidationContainer and paintInvalidationContainerSkipped are not null, on return *paintInvalidationContainerSkipped |
| // is true if the renderer returned is an ancestor of paintInvalidationContainer. |
| RenderObject* container(const RenderBox* paintInvalidationContainer = 0, bool* paintInvalidationContainerSkipped = 0) const; |
| |
| Element* offsetParent() const; |
| |
| void markContainingBlocksForLayout(bool scheduleRelayout = true, RenderObject* newRoot = 0, SubtreeLayoutScope* = 0); |
| void setNeedsLayout(MarkingBehavior = MarkContainingBlockChain, SubtreeLayoutScope* = 0); |
| void clearNeedsLayout(); |
| void setChildNeedsLayout(MarkingBehavior = MarkContainingBlockChain, SubtreeLayoutScope* = 0); |
| void setNeedsPositionedMovementLayout(); |
| void setPreferredLogicalWidthsDirty(MarkingBehavior = MarkContainingBlockChain); |
| void clearPreferredLogicalWidthsDirty(); |
| void invalidateContainerPreferredLogicalWidths(); |
| |
| void setNeedsLayoutAndPrefWidthsRecalc() |
| { |
| setNeedsLayout(); |
| setPreferredLogicalWidthsDirty(); |
| } |
| |
| void setPositionState(EPosition position) |
| { |
| ASSERT(position != AbsolutePosition || isBox()); |
| m_bitfields.setPositionedState(position); |
| } |
| void clearPositionedState() { m_bitfields.clearPositionedState(); } |
| |
| void setInline(bool isInline) { m_bitfields.setIsInline(isInline); } |
| |
| void setIsText() { m_bitfields.setIsText(true); } |
| void setIsBox() { m_bitfields.setIsBox(true); } |
| void setReplaced(bool isReplaced) { m_bitfields.setIsReplaced(isReplaced); } |
| void setHasOverflowClip(bool hasOverflowClip) { m_bitfields.setHasOverflowClip(hasOverflowClip); } |
| void setHasLayer(bool hasLayer) { m_bitfields.setHasLayer(hasLayer); } |
| void setHasTransform(bool hasTransform) { m_bitfields.setHasTransform(hasTransform); } |
| void setHasBoxDecorationBackground(bool b) { m_bitfields.setHasBoxDecorationBackground(b); } |
| |
| void scheduleRelayout(); |
| |
| void updateFillImages(const FillLayer* oldLayers, const FillLayer& newLayers); |
| void updateImage(StyleImage*, StyleImage*); |
| |
| // paintOffset is the offset from the origin of the GraphicsContext at which to paint the current object. |
| virtual void paint(PaintInfo&, const LayoutPoint& paintOffset, Vector<RenderBox*>& layers); |
| |
| // Subclasses must reimplement this method to compute the size and position |
| // of this object and all its descendants. |
| virtual void layout() = 0; |
| |
| /* This function performs a layout only if one is needed. */ |
| void layoutIfNeeded() { if (needsLayout()) layout(); } |
| |
| void forceLayout(); |
| void forceChildLayout(); |
| |
| bool hitTest(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset); |
| virtual void updateHitTestResult(HitTestResult&, const LayoutPoint&); |
| virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset); |
| |
| virtual PositionWithAffinity positionForPoint(const LayoutPoint&); |
| PositionWithAffinity createPositionWithAffinity(int offset, EAffinity); |
| PositionWithAffinity createPositionWithAffinity(const Position&); |
| |
| virtual void dirtyLinesFromChangedChild(RenderObject*); |
| |
| // Set the style of the object and update the state of the object accordingly. |
| void setStyle(PassRefPtr<RenderStyle>); |
| |
| // Updates only the local style ptr of the object. Does not update the state of the object, |
| // and so only should be called when the style is known not to have changed (or from setStyle). |
| void setStyleInternal(PassRefPtr<RenderStyle> style) { m_style = style; } |
| |
| // returns the containing block level element for this element. |
| RenderBlock* containingBlock() const; |
| |
| // Convert the given local point to absolute coordinates |
| // FIXME: Temporary. If UseTransforms is true, take transforms into account. Eventually localToAbsolute() will always be transform-aware. |
| FloatPoint localToAbsolute(const FloatPoint& localPoint = FloatPoint(), MapCoordinatesFlags = 0) const; |
| FloatPoint absoluteToLocal(const FloatPoint&, MapCoordinatesFlags = 0) const; |
| |
| // Convert a local quad to absolute coordinates, taking transforms into account. |
| FloatQuad localToAbsoluteQuad(const FloatQuad& quad, MapCoordinatesFlags mode = 0) const |
| { |
| return localToContainerQuad(quad, 0, mode); |
| } |
| // Convert an absolute quad to local coordinates. |
| FloatQuad absoluteToLocalQuad(const FloatQuad&, MapCoordinatesFlags mode = 0) const; |
| |
| // Convert a local quad into the coordinate system of container, taking transforms into account. |
| FloatQuad localToContainerQuad(const FloatQuad&, const RenderBox* paintInvalidatinoContainer, MapCoordinatesFlags = 0) const; |
| FloatPoint localToContainerPoint(const FloatPoint&, const RenderBox* paintInvalidationContainer, MapCoordinatesFlags = 0) const; |
| |
| // Return the offset from the container() renderer (excluding transforms). In multi-column layout, |
| // different offsets apply at different points, so return the offset that applies to the given point. |
| virtual LayoutSize offsetFromContainer(const RenderObject*, const LayoutPoint&, bool* offsetDependsOnPoint = 0) const; |
| // Return the offset from an object up the container() chain. Asserts that none of the intermediate objects have transforms. |
| LayoutSize offsetFromAncestorContainer(const RenderObject*) const; |
| |
| IntRect absoluteBoundingBoxRect() const; |
| |
| // Build an array of quads in absolute coords for line boxes |
| virtual void absoluteQuads(Vector<FloatQuad>&) const { } |
| |
| virtual void absoluteFocusRingQuads(Vector<FloatQuad>&); |
| |
| static FloatRect absoluteBoundingBoxRectForRange(const Range*); |
| |
| virtual LayoutUnit minPreferredLogicalWidth() const { return 0; } |
| virtual LayoutUnit maxPreferredLogicalWidth() const { return 0; } |
| |
| RenderStyle* style() const { return m_style.get(); } |
| |
| /* The two following methods are inlined in RenderObjectInlines.h */ |
| RenderStyle* firstLineStyle() const; |
| RenderStyle* style(bool firstLine) const; |
| |
| inline Color resolveColor(const RenderStyle* styleToUse, int colorProperty) const |
| { |
| return styleToUse->colorIncludingFallback(colorProperty); |
| } |
| |
| inline Color resolveColor(int colorProperty) const |
| { |
| return style()->colorIncludingFallback(colorProperty); |
| } |
| |
| struct AppliedTextDecoration { |
| Color color; |
| TextDecorationStyle style; |
| AppliedTextDecoration() : color(Color::transparent), style(TextDecorationStyleSolid) { } |
| }; |
| |
| void getTextDecorations(unsigned decorations, AppliedTextDecoration& underline, AppliedTextDecoration& overline, AppliedTextDecoration& linethrough, bool quirksMode = false, bool firstlineStyle = false); |
| |
| // Return the RenderBox in the container chain which is responsible for painting this object, or 0 |
| // if painting is root-relative. This is the container that should be passed to the 'forPaintInvalidation' |
| // methods. |
| const RenderView* containerForPaintInvalidation() const; |
| const RenderBox* adjustCompositedContainerForSpecialAncestors(const RenderBox* paintInvalidationContainer) const; |
| |
| // Overriden by RenderText for character length, used in line layout code. |
| virtual unsigned length() const { return 1; } |
| |
| // FIXME(sky): Remove |
| bool isFloatingOrOutOfFlowPositioned() const { return isOutOfFlowPositioned(); } |
| |
| bool isTransparent() const { return style()->hasOpacity(); } |
| float opacity() const { return style()->opacity(); } |
| |
| enum SelectionState { |
| SelectionNone, // The object is not selected. |
| SelectionStart, // The object either contains the start of a selection run or is the start of a run |
| SelectionInside, // The object is fully encompassed by a selection run |
| SelectionEnd, // The object either contains the end of a selection run or is the end of a run |
| SelectionBoth // The object contains an entire run or is the sole selected object in that run |
| }; |
| |
| // The current selection state for an object. For blocks, the state refers to the state of the leaf |
| // descendants (as described above in the SelectionState enum declaration). |
| SelectionState selectionState() const { return m_bitfields.selectionState(); } |
| virtual void setSelectionState(SelectionState state) { m_bitfields.setSelectionState(state); } |
| inline void setSelectionStateIfNeeded(SelectionState); |
| bool canUpdateSelectionOnRootLineBoxes(); |
| |
| virtual bool canBeSelectionLeaf() const { return false; } |
| bool hasSelectedChildren() const { return selectionState() != SelectionNone; } |
| |
| bool isSelectable() const; |
| // Obtains the selection colors that should be used when painting a selection. |
| Color selectionBackgroundColor() const; |
| Color selectionForegroundColor() const; |
| Color selectionEmphasisMarkColor() const; |
| |
| // Whether or not a given block needs to paint selection gaps. |
| virtual bool shouldPaintSelectionGaps() const { return false; } |
| |
| /** |
| * Returns the local coordinates of the caret within this render object. |
| * @param caretOffset zero-based offset determining position within the render object. |
| * @param extraWidthToEndOfLine optional out arg to give extra width to end of line - |
| * useful for character range rect computations |
| */ |
| virtual LayoutRect localCaretRect(InlineBox*, int caretOffset, LayoutUnit* extraWidthToEndOfLine = 0); |
| |
| // When performing a global document tear-down, the renderer of the document is cleared. We use this |
| // as a hook to detect the case of document destruction and don't waste time doing unnecessary work. |
| bool documentBeingDestroyed() const; |
| |
| virtual void destroy(); |
| |
| // Virtual function helper for the new FlexibleBox Layout (display: -webkit-flex). |
| virtual bool isFlexibleBox() const { return false; } |
| |
| virtual int caretMinOffset() const; |
| virtual int caretMaxOffset() const; |
| |
| virtual int previousOffset(int current) const; |
| virtual int previousOffsetForBackwardDeletion(int current) const; |
| virtual int nextOffset(int current) const; |
| |
| void selectionStartEnd(int& spos, int& epos) const; |
| |
| void remove() { if (parent()) parent()->removeChild(this); } |
| |
| bool supportsTouchAction() const; |
| |
| bool visibleToHitTestRequest(const HitTestRequest& request) const { return (request.ignorePointerEventsNone() || style()->pointerEvents() != PE_NONE); } |
| |
| bool visibleToHitTesting() const { return style()->pointerEvents() != PE_NONE; } |
| |
| // Map points and quads through elements, potentially via 3d transforms. You should never need to call these directly; use |
| // localToAbsolute/absoluteToLocal methods instead. |
| virtual void mapLocalToContainer(const RenderBox* paintInvalidationContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip) const; |
| virtual void mapAbsoluteToLocalPoint(MapCoordinatesFlags, TransformState&) const; |
| |
| // Pushes state onto RenderGeometryMap about how to map coordinates from this renderer to its container, or ancestorToStopAt (whichever is encountered first). |
| // Returns the renderer which was mapped to (container or ancestorToStopAt). |
| virtual const RenderObject* pushMappingToContainer(const RenderBox* ancestorToStopAt, RenderGeometryMap&) const; |
| |
| bool shouldUseTransformFromContainer(const RenderObject* container) const; |
| void getTransformFromContainer(const RenderObject* container, const LayoutSize& offsetInContainer, TransformationMatrix&) const; |
| |
| bool createsGroup() const { return isTransparent() || style()->hasFilter(); } |
| |
| virtual void addFocusRingRects(Vector<IntRect>&, const LayoutPoint& /* additionalOffset */, const RenderBox* /* paintContainer */ = 0) const { }; |
| |
| RespectImageOrientationEnum shouldRespectImageOrientation() const; |
| |
| bool onlyNeededPositionedMovementLayout() const { return m_bitfields.onlyNeededPositionedMovementLayout(); } |
| void setOnlyNeededPositionedMovementLayout(bool b) { m_bitfields.setOnlyNeededPositionedMovementLayout(b); } |
| |
| bool neededLayoutBecauseOfChildren() const { return m_bitfields.neededLayoutBecauseOfChildren(); } |
| void setNeededLayoutBecauseOfChildren(bool b) { m_bitfields.setNeededLayoutBecauseOfChildren(b); } |
| |
| void setNeedsOverflowRecalcAfterStyleChange(); |
| void markContainingBlocksForOverflowRecalc(); |
| |
| protected: |
| // Overrides should call the superclass at the end. m_style will be 0 the first time |
| // this function will be called. |
| virtual void styleWillChange(StyleDifference, const RenderStyle& newStyle); |
| // Overrides should call the superclass at the start. |oldStyle| will be 0 the first |
| // time this function is called. |
| virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); |
| |
| void drawLineForBoxSide(GraphicsContext*, int x1, int y1, int x2, int y2, BoxSide, |
| Color, EBorderStyle, int adjbw1, int adjbw2, bool antialias = false); |
| void drawDashedOrDottedBoxSide(GraphicsContext*, int x1, int y1, int x2, int y2, |
| BoxSide, Color, int thickness, EBorderStyle, bool antialias); |
| void drawDoubleBoxSide(GraphicsContext*, int x1, int y1, int x2, int y2, |
| int length, BoxSide, Color, int thickness, int adjacentWidth1, int adjacentWidth2, bool antialias); |
| void drawRidgeOrGrooveBoxSide(GraphicsContext*, int x1, int y1, int x2, int y2, |
| BoxSide, Color, EBorderStyle, int adjacentWidth1, int adjacentWidth2, bool antialias); |
| void drawSolidBoxSide(GraphicsContext*, int x1, int y1, int x2, int y2, |
| BoxSide, Color, int adjacentWidth1, int adjacentWidth2, bool antialias); |
| |
| void paintFocusRing(PaintInfo&, const LayoutPoint&, RenderStyle*); |
| void paintOutline(PaintInfo&, const LayoutRect&); |
| void addChildFocusRingRects(Vector<IntRect>&, const LayoutPoint& additionalOffset, const RenderBox* paintContainer) const; |
| |
| virtual LayoutRect viewRect() const; |
| |
| void clearLayoutRootIfNeeded() const; |
| virtual void willBeDestroyed(); |
| void postDestroy(); |
| |
| void insertedIntoTree(); |
| void willBeRemovedFromTree(); |
| |
| private: |
| bool hasImmediateNonWhitespaceTextChildOrPropertiesDependentOnColor() const; |
| |
| StyleDifference adjustStyleDifference(StyleDifference) const; |
| |
| Color selectionColor(int colorProperty) const; |
| |
| #if ENABLE(ASSERT) |
| void checkBlockPositionedObjectsNeedLayout(); |
| #endif |
| |
| // FIXME(sky): This method is just to avoid copy-paste. |
| // Merge container into containingBlock and then get rid of this method. |
| bool canContainAbsolutePositionObjects() const |
| { |
| return isRenderView() || (hasTransform() && isRenderBlock()); |
| } |
| |
| static bool isAllowedToModifyRenderTreeStructure(Document&); |
| |
| RefPtr<RenderStyle> m_style; |
| |
| RawPtr<Node> m_node; |
| |
| RawPtr<RenderObject> m_parent; |
| RawPtr<RenderObject> m_previous; |
| RawPtr<RenderObject> m_next; |
| |
| #if ENABLE(ASSERT) |
| unsigned m_setNeedsLayoutForbidden : 1; |
| #if ENABLE(OILPAN) |
| protected: |
| unsigned m_didCallDestroy : 1; |
| private: |
| #endif |
| #endif |
| |
| #define ADD_BOOLEAN_BITFIELD(name, Name) \ |
| private:\ |
| unsigned m_##name : 1;\ |
| public:\ |
| bool name() const { return m_##name; }\ |
| void set##Name(bool name) { m_##name = name; }\ |
| |
| class RenderObjectBitfields { |
| // FIXME(sky): Remove this enum and just use EPosition directly. |
| enum PositionedState { |
| IsStaticallyPositioned = 0, |
| IsOutOfFlowPositioned = 1, |
| }; |
| |
| public: |
| RenderObjectBitfields(Node* node) |
| : m_selfNeedsLayout(false) |
| , m_onlyNeededPositionedMovementLayout(false) |
| , m_neededLayoutBecauseOfChildren(false) |
| , m_needsPositionedMovementLayout(false) |
| , m_normalChildNeedsLayout(false) |
| , m_posChildNeedsLayout(false) |
| , m_needsSimplifiedNormalFlowLayout(false) |
| , m_preferredLogicalWidthsDirty(false) |
| , m_selfNeedsOverflowRecalcAfterStyleChange(false) |
| , m_childNeedsOverflowRecalcAfterStyleChange(false) |
| , m_isText(false) |
| , m_isBox(false) |
| , m_isInline(true) |
| , m_isReplaced(false) |
| , m_isDragging(false) |
| , m_hasLayer(false) |
| , m_hasOverflowClip(false) |
| , m_hasTransform(false) |
| , m_hasBoxDecorationBackground(false) |
| , m_everHadLayout(false) |
| , m_ancestorLineBoxDirty(false) |
| , m_alwaysCreateLineBoxesForRenderInline(false) |
| , m_positionedState(IsStaticallyPositioned) |
| , m_selectionState(SelectionNone) |
| { |
| } |
| |
| // 32 bits have been used in the first word, and 11 in the second. |
| ADD_BOOLEAN_BITFIELD(selfNeedsLayout, SelfNeedsLayout); |
| ADD_BOOLEAN_BITFIELD(onlyNeededPositionedMovementLayout, OnlyNeededPositionedMovementLayout); |
| ADD_BOOLEAN_BITFIELD(neededLayoutBecauseOfChildren, NeededLayoutBecauseOfChildren); |
| ADD_BOOLEAN_BITFIELD(needsPositionedMovementLayout, NeedsPositionedMovementLayout); |
| ADD_BOOLEAN_BITFIELD(normalChildNeedsLayout, NormalChildNeedsLayout); |
| ADD_BOOLEAN_BITFIELD(posChildNeedsLayout, PosChildNeedsLayout); |
| ADD_BOOLEAN_BITFIELD(needsSimplifiedNormalFlowLayout, NeedsSimplifiedNormalFlowLayout); |
| ADD_BOOLEAN_BITFIELD(preferredLogicalWidthsDirty, PreferredLogicalWidthsDirty); |
| ADD_BOOLEAN_BITFIELD(selfNeedsOverflowRecalcAfterStyleChange, SelfNeedsOverflowRecalcAfterStyleChange); |
| ADD_BOOLEAN_BITFIELD(childNeedsOverflowRecalcAfterStyleChange, ChildNeedsOverflowRecalcAfterStyleChange); |
| |
| ADD_BOOLEAN_BITFIELD(isText, IsText); |
| ADD_BOOLEAN_BITFIELD(isBox, IsBox); |
| ADD_BOOLEAN_BITFIELD(isInline, IsInline); |
| ADD_BOOLEAN_BITFIELD(isReplaced, IsReplaced); |
| ADD_BOOLEAN_BITFIELD(isDragging, IsDragging); |
| |
| ADD_BOOLEAN_BITFIELD(hasLayer, HasLayer); |
| ADD_BOOLEAN_BITFIELD(hasOverflowClip, HasOverflowClip); // Set in the case of overflow:auto/scroll/hidden |
| ADD_BOOLEAN_BITFIELD(hasTransform, HasTransform); |
| ADD_BOOLEAN_BITFIELD(hasBoxDecorationBackground, HasBoxDecorationBackground); |
| |
| ADD_BOOLEAN_BITFIELD(everHadLayout, EverHadLayout); |
| ADD_BOOLEAN_BITFIELD(ancestorLineBoxDirty, AncestorLineBoxDirty); |
| |
| // from RenderInline |
| ADD_BOOLEAN_BITFIELD(alwaysCreateLineBoxesForRenderInline, AlwaysCreateLineBoxesForRenderInline); |
| |
| private: |
| unsigned m_positionedState : 1; // PositionedState |
| unsigned m_selectionState : 3; // SelectionState |
| |
| public: |
| bool isOutOfFlowPositioned() const { return m_positionedState == IsOutOfFlowPositioned; } |
| bool isPositioned() const { return m_positionedState != IsStaticallyPositioned; } |
| |
| void setPositionedState(int positionState) |
| { |
| m_positionedState = static_cast<PositionedState>(positionState); |
| } |
| void clearPositionedState() { m_positionedState = StaticPosition; } |
| |
| ALWAYS_INLINE SelectionState selectionState() const { return static_cast<SelectionState>(m_selectionState); } |
| ALWAYS_INLINE void setSelectionState(SelectionState selectionState) { m_selectionState = selectionState; } |
| }; |
| |
| #undef ADD_BOOLEAN_BITFIELD |
| |
| RenderObjectBitfields m_bitfields; |
| |
| void setSelfNeedsLayout(bool b) { m_bitfields.setSelfNeedsLayout(b); } |
| void setNeedsPositionedMovementLayout(bool b) { m_bitfields.setNeedsPositionedMovementLayout(b); } |
| void setNormalChildNeedsLayout(bool b) { m_bitfields.setNormalChildNeedsLayout(b); } |
| void setPosChildNeedsLayout(bool b) { m_bitfields.setPosChildNeedsLayout(b); } |
| void setNeedsSimplifiedNormalFlowLayout(bool b) { m_bitfields.setNeedsSimplifiedNormalFlowLayout(b); } |
| void setIsDragging(bool b) { m_bitfields.setIsDragging(b); } |
| void setEverHadLayout(bool b) { m_bitfields.setEverHadLayout(b); } |
| void setSelfNeedsOverflowRecalcAfterStyleChange(bool b) { m_bitfields.setSelfNeedsOverflowRecalcAfterStyleChange(b); } |
| void setChildNeedsOverflowRecalcAfterStyleChange(bool b) { m_bitfields.setChildNeedsOverflowRecalcAfterStyleChange(b); } |
| |
| private: |
| // Store state between styleWillChange and styleDidChange |
| static bool s_affectsParentBlock; |
| |
| static unsigned s_instanceCount; |
| }; |
| |
| // Allow equality comparisons of RenderObjects by reference or pointer, interchangeably. |
| DEFINE_COMPARISON_OPERATORS_WITH_REFERENCES(RenderObject) |
| |
| inline bool RenderObject::documentBeingDestroyed() const |
| { |
| return !document().isActive(); |
| } |
| |
| // setNeedsLayout() won't cause full paint invalidations as |
| // setNeedsLayout() does. Otherwise the two methods are identical. |
| inline void RenderObject::setNeedsLayout(MarkingBehavior markParents, SubtreeLayoutScope* layouter) |
| { |
| ASSERT(!isSetNeedsLayoutForbidden()); |
| bool alreadyNeededLayout = m_bitfields.selfNeedsLayout(); |
| setSelfNeedsLayout(true); |
| if (!alreadyNeededLayout) { |
| if (markParents == MarkContainingBlockChain && (!layouter || layouter->root() != this)) |
| markContainingBlocksForLayout(true, 0, layouter); |
| } |
| } |
| |
| inline void RenderObject::clearNeedsLayout() |
| { |
| setOnlyNeededPositionedMovementLayout(needsPositionedMovementLayoutOnly()); |
| setNeededLayoutBecauseOfChildren(needsLayoutBecauseOfChildren()); |
| setSelfNeedsLayout(false); |
| setEverHadLayout(true); |
| setPosChildNeedsLayout(false); |
| setNeedsSimplifiedNormalFlowLayout(false); |
| setNormalChildNeedsLayout(false); |
| setNeedsPositionedMovementLayout(false); |
| setAncestorLineBoxDirty(false); |
| #if ENABLE(ASSERT) |
| checkBlockPositionedObjectsNeedLayout(); |
| #endif |
| } |
| |
| inline void RenderObject::setChildNeedsLayout(MarkingBehavior markParents, SubtreeLayoutScope* layouter) |
| { |
| ASSERT(!isSetNeedsLayoutForbidden()); |
| bool alreadyNeededLayout = normalChildNeedsLayout(); |
| setNormalChildNeedsLayout(true); |
| // FIXME: Replace MarkOnlyThis with the SubtreeLayoutScope code path and remove the MarkingBehavior argument entirely. |
| if (!alreadyNeededLayout && markParents == MarkContainingBlockChain && (!layouter || layouter->root() != this)) |
| markContainingBlocksForLayout(true, 0, layouter); |
| } |
| |
| inline void RenderObject::setNeedsPositionedMovementLayout() |
| { |
| bool alreadyNeededLayout = needsPositionedMovementLayout(); |
| setNeedsPositionedMovementLayout(true); |
| ASSERT(!isSetNeedsLayoutForbidden()); |
| if (!alreadyNeededLayout) |
| markContainingBlocksForLayout(); |
| } |
| |
| inline bool RenderObject::preservesNewline() const |
| { |
| return style()->preserveNewline(); |
| } |
| |
| inline void RenderObject::setSelectionStateIfNeeded(SelectionState state) |
| { |
| if (selectionState() == state) |
| return; |
| |
| setSelectionState(state); |
| } |
| |
| #define DEFINE_RENDER_OBJECT_TYPE_CASTS(thisType, predicate) \ |
| DEFINE_TYPE_CASTS(thisType, RenderObject, object, object->predicate, object.predicate) |
| |
| } // namespace blink |
| |
| #ifndef NDEBUG |
| // Outside the WebCore namespace for ease of invocation from gdb. |
| void showTree(const blink::RenderObject*); |
| void showLineTree(const blink::RenderObject*); |
| void showRenderTree(const blink::RenderObject* object1); |
| // We don't make object2 an optional parameter so that showRenderTree |
| // can be called from gdb easily. |
| void showRenderTree(const blink::RenderObject* object1, const blink::RenderObject* object2); |
| |
| #endif |
| |
| #endif // SKY_ENGINE_CORE_RENDERING_RENDEROBJECT_H_ |