summaryrefslogtreecommitdiff
path: root/Source/WebCore/rendering/RenderObject.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2016-04-10 09:28:39 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2016-04-10 09:28:39 +0000
commit32761a6cee1d0dee366b885b7b9c777e67885688 (patch)
treed6bec92bebfb216f4126356e55518842c2f476a1 /Source/WebCore/rendering/RenderObject.cpp
parenta4e969f4965059196ca948db781e52f7cfebf19e (diff)
downloadWebKitGtk-tarball-32761a6cee1d0dee366b885b7b9c777e67885688.tar.gz
webkitgtk-2.4.11webkitgtk-2.4.11
Diffstat (limited to 'Source/WebCore/rendering/RenderObject.cpp')
-rw-r--r--Source/WebCore/rendering/RenderObject.cpp1651
1 files changed, 917 insertions, 734 deletions
diff --git a/Source/WebCore/rendering/RenderObject.cpp b/Source/WebCore/rendering/RenderObject.cpp
index edb4f3398..fa99f248c 100644
--- a/Source/WebCore/rendering/RenderObject.cpp
+++ b/Source/WebCore/rendering/RenderObject.cpp
@@ -32,20 +32,17 @@
#include "EventHandler.h"
#include "FloatQuad.h"
#include "FlowThreadController.h"
+#include "Frame.h"
#include "FrameSelection.h"
#include "FrameView.h"
-#include "GeometryUtilities.h"
#include "GraphicsContext.h"
#include "HTMLAnchorElement.h"
#include "HTMLElement.h"
#include "HTMLImageElement.h"
#include "HTMLNames.h"
-#include "HTMLTableCellElement.h"
#include "HTMLTableElement.h"
#include "HitTestResult.h"
-#include "Logging.h"
#include "LogicalSelectionOffsetCaches.h"
-#include "MainFrame.h"
#include "Page.h"
#include "PseudoElement.h"
#include "RenderCounter.h"
@@ -55,26 +52,22 @@
#include "RenderIterator.h"
#include "RenderLayer.h"
#include "RenderLayerBacking.h"
-#include "RenderMultiColumnFlowThread.h"
-#include "RenderNamedFlowFragment.h"
-#include "RenderNamedFlowThread.h"
-#include "RenderRuby.h"
-#include "RenderSVGResourceContainer.h"
+#include "RenderNamedFlowThread.h"
#include "RenderScrollbarPart.h"
-#include "RenderTableRow.h"
-#include "RenderTableSection.h"
#include "RenderTheme.h"
#include "RenderView.h"
-#include "RenderWidget.h"
-#include "SVGRenderSupport.h"
#include "Settings.h"
#include "StyleResolver.h"
#include "TransformState.h"
#include "htmlediting.h"
#include <algorithm>
-#include <stdio.h>
#include <wtf/RefCountedLeakCounter.h>
+#if ENABLE(SVG)
+#include "RenderSVGResourceContainer.h"
+#include "SVGRenderSupport.h"
+#endif
+
#if PLATFORM(IOS)
#include "SelectionRect.h"
#endif
@@ -84,8 +77,6 @@ namespace WebCore {
using namespace HTMLNames;
#ifndef NDEBUG
-void printRenderTreeForLiveDocuments();
-
RenderObject::SetLayoutNeededForbiddenScope::SetLayoutNeededForbiddenScope(RenderObject* renderObject, bool isForbidden)
: m_renderObject(renderObject)
, m_preexistingForbidden(m_renderObject->isSetNeedsLayoutForbidden())
@@ -115,34 +106,29 @@ DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, renderObjectCounter, ("Rend
RenderObject::RenderObject(Node& node)
: CachedImageClient()
, m_node(node)
- , m_parent(nullptr)
- , m_previous(nullptr)
- , m_next(nullptr)
+ , m_parent(0)
+ , m_previous(0)
+ , m_next(0)
#ifndef NDEBUG
, m_hasAXObject(false)
, m_setNeedsLayoutForbidden(false)
#endif
, m_bitfields(node)
{
- if (RenderView* renderView = node.document().renderView())
- renderView->didCreateRenderer();
+ if (!node.isDocumentNode())
+ view().didCreateRenderer();
#ifndef NDEBUG
renderObjectCounter.increment();
- static std::once_flag onceFlag;
- std::call_once(onceFlag, [] {
- registerNotifyCallback("com.apple.WebKit.showRenderTree", printRenderTreeForLiveDocuments);
- });
#endif
}
RenderObject::~RenderObject()
{
- view().didDestroyRenderer();
#ifndef NDEBUG
ASSERT(!m_hasAXObject);
renderObjectCounter.decrement();
#endif
- ASSERT(!hasRareData());
+ view().didDestroyRenderer();
}
RenderTheme& RenderObject::theme() const
@@ -151,10 +137,10 @@ RenderTheme& RenderObject::theme() const
return document().page()->theme();
}
-bool RenderObject::isDescendantOf(const RenderObject* ancestor) const
+bool RenderObject::isDescendantOf(const RenderObject* obj) const
{
- for (const RenderObject* renderer = this; renderer; renderer = renderer->m_parent) {
- if (renderer == ancestor)
+ for (const RenderObject* r = this; r; r = r->m_parent) {
+ if (r == obj)
return true;
}
return false;
@@ -234,14 +220,14 @@ RenderObject* RenderObject::nextInPreOrder(const RenderObject* stayWithin) const
RenderObject* RenderObject::nextInPreOrderAfterChildren(const RenderObject* stayWithin) const
{
if (this == stayWithin)
- return nullptr;
+ return 0;
const RenderObject* current = this;
RenderObject* next;
while (!(next = current->nextSibling())) {
current = current->parent();
if (!current || current == stayWithin)
- return nullptr;
+ return 0;
}
return next;
}
@@ -260,7 +246,7 @@ RenderObject* RenderObject::previousInPreOrder() const
RenderObject* RenderObject::previousInPreOrder(const RenderObject* stayWithin) const
{
if (this == stayWithin)
- return nullptr;
+ return 0;
return previousInPreOrder();
}
@@ -277,7 +263,7 @@ RenderObject* RenderObject::firstLeafChild() const
{
RenderObject* r = firstChildSlow();
while (r) {
- RenderObject* n = nullptr;
+ RenderObject* n = 0;
n = r->firstChildSlow();
if (!n)
break;
@@ -290,7 +276,7 @@ RenderObject* RenderObject::lastLeafChild() const
{
RenderObject* r = lastChildSlow();
while (r) {
- RenderObject* n = nullptr;
+ RenderObject* n = 0;
n = r->lastChildSlow();
if (!n)
break;
@@ -309,7 +295,7 @@ RenderObject* RenderObject::traverseNext(const RenderObject* stayWithin) const
return child;
}
if (this == stayWithin)
- return nullptr;
+ return 0;
if (nextSibling()) {
ASSERT(!stayWithin || nextSibling()->isDescendantOf(stayWithin));
return nextSibling();
@@ -321,7 +307,7 @@ RenderObject* RenderObject::traverseNext(const RenderObject* stayWithin) const
ASSERT(!stayWithin || !n->nextSibling() || n->nextSibling()->isDescendantOf(stayWithin));
return n->nextSibling();
}
- return nullptr;
+ return 0;
}
// Non-recursive version of the DFS search.
@@ -342,7 +328,7 @@ RenderObject* RenderObject::traverseNext(const RenderObject* stayWithin, HeightT
}
if (this == stayWithin)
- return nullptr;
+ return 0;
// Now we traverse other nodes if they exist, otherwise
// we go to the parent node and try doing the same.
@@ -353,7 +339,7 @@ RenderObject* RenderObject::traverseNext(const RenderObject* stayWithin, HeightT
currentDepth--;
}
if (!n)
- return nullptr;
+ return 0;
for (RenderObject* sibling = n->nextSibling(); sibling; sibling = sibling->nextSibling()) {
overflowType = inclusionFunction(sibling);
if (overflowType != FixedHeight) {
@@ -367,9 +353,9 @@ RenderObject* RenderObject::traverseNext(const RenderObject* stayWithin, HeightT
n = n->parent();
currentDepth--;
} else
- return nullptr;
+ return 0;
}
- return nullptr;
+ return 0;
}
RenderObject* RenderObject::traverseNext(const RenderObject* stayWithin, TraverseNextInclusionFunction inclusionFunction) const
@@ -382,7 +368,7 @@ RenderObject* RenderObject::traverseNext(const RenderObject* stayWithin, Travers
}
if (this == stayWithin)
- return nullptr;
+ return 0;
for (RenderObject* sibling = nextSibling(); sibling; sibling = sibling->nextSibling()) {
if (inclusionFunction(sibling)) {
@@ -405,21 +391,21 @@ RenderObject* RenderObject::traverseNext(const RenderObject* stayWithin, Travers
if ((!stayWithin || n->parent() != stayWithin))
n = n->parent();
else
- return nullptr;
+ return 0;
}
}
- return nullptr;
+ return 0;
}
-static RenderObject::BlockContentHeightType includeNonFixedHeight(const RenderObject* renderer)
+static RenderObject::BlockContentHeightType includeNonFixedHeight(const RenderObject* render)
{
- const RenderStyle& style = renderer->style();
+ const RenderStyle& style = render->style();
if (style.height().type() == Fixed) {
- if (is<RenderBlock>(*renderer)) {
+ if (render->isRenderBlock()) {
+ const RenderBlock* block = toRenderBlock(render);
// For fixed height styles, if the overflow size of the element spills out of the specified
// height, assume we can apply text auto-sizing.
- if (style.overflowY() == OVISIBLE
- && style.height().value() < downcast<RenderBlock>(renderer)->layoutOverflowRect().maxY())
+ if (style.overflowY() == OVISIBLE && style.height().value() < block->layoutOverflowRect().maxY())
return RenderObject::OverflowHeight;
}
return RenderObject::FixedHeight;
@@ -449,8 +435,8 @@ void RenderObject::adjustComputedFontSizesOnBlocks(float size, float visibleWidt
depthStack.append(newFixedDepth);
int stackSize = depthStack.size();
- if (is<RenderBlockFlow>(*descendent) && !descendent->isListItem() && (!stackSize || currentDepth - depthStack[stackSize - 1] > TextAutoSizingFixedHeightDepth))
- downcast<RenderBlockFlow>(*descendent).adjustComputedFontSizes(size, visibleWidth);
+ if (descendent->isRenderBlockFlow() && !descendent->isListItem() && (!stackSize || currentDepth - depthStack[stackSize - 1] > TextAutoSizingFixedHeightDepth))
+ toRenderBlockFlow(descendent)->adjustComputedFontSizes(size, visibleWidth);
newFixedDepth = 0;
}
@@ -477,8 +463,8 @@ void RenderObject::resetTextAutosizing()
depthStack.append(newFixedDepth);
int stackSize = depthStack.size();
- if (is<RenderBlockFlow>(*descendent) && !descendent->isListItem() && (!stackSize || currentDepth - depthStack[stackSize - 1] > TextAutoSizingFixedHeightDepth))
- downcast<RenderBlockFlow>(*descendent).resetComputedFontSize();
+ if (descendent->isRenderBlockFlow() && !descendent->isListItem() && (!stackSize || currentDepth - depthStack[stackSize - 1] > TextAutoSizingFixedHeightDepth))
+ toRenderBlockFlow(descendent)->resetComputedFontSize();
newFixedDepth = 0;
}
}
@@ -503,14 +489,16 @@ bool RenderObject::scrollRectToVisible(const LayoutRect& rect, const ScrollAlign
return true;
}
-RenderBox& RenderObject::enclosingBox() const
+RenderBox* RenderObject::enclosingBox() const
{
- return *lineageOfType<RenderBox>(const_cast<RenderObject&>(*this)).first();
+ // FIXME: This should return a reference; it can always find the root RenderView.
+ return lineageOfType<RenderBox>(const_cast<RenderObject&>(*this)).first();
}
-RenderBoxModelObject& RenderObject::enclosingBoxModelObject() const
+RenderBoxModelObject* RenderObject::enclosingBoxModelObject() const
{
- return *lineageOfType<RenderBoxModelObject>(const_cast<RenderObject&>(*this)).first();
+ // FIXME: This should return a reference; it can always find the root RenderView.
+ return lineageOfType<RenderBoxModelObject>(const_cast<RenderObject&>(*this)).first();
}
bool RenderObject::fixedPositionedWithNamedFlowContainingBlock() const
@@ -525,7 +513,7 @@ static bool hasFixedPosInNamedFlowContainingBlock(const RenderObject* renderer)
ASSERT(renderer->flowThreadState() != RenderObject::NotInsideFlowThread);
RenderObject* curr = const_cast<RenderObject*>(renderer);
- while (curr && !is<RenderView>(*curr)) {
+ while (curr) {
if (curr->fixedPositionedWithNamedFlowContainingBlock())
return true;
curr = curr->containingBlock();
@@ -534,9 +522,37 @@ static bool hasFixedPosInNamedFlowContainingBlock(const RenderObject* renderer)
return false;
}
+RenderFlowThread* RenderObject::locateFlowThreadContainingBlock() const
+{
+ ASSERT(flowThreadState() != NotInsideFlowThread);
+
+ // See if we have the thread cached because we're in the middle of layout.
+ RenderFlowThread* flowThread = view().flowThreadController().currentRenderFlowThread();
+ if (flowThread)
+ return flowThread;
+
+ // Not in the middle of layout so have to find the thread the slow way.
+ RenderObject* curr = const_cast<RenderObject*>(this);
+ while (curr) {
+ if (curr->isRenderFlowThread())
+ return toRenderFlowThread(curr);
+ curr = curr->containingBlock();
+ }
+ return 0;
+}
+
+RenderNamedFlowThread* RenderObject::renderNamedFlowThreadWrapper() const
+{
+ RenderObject* object = const_cast<RenderObject*>(this);
+ while (object && object->isAnonymousBlock() && !object->isRenderNamedFlowThread())
+ object = object->parent();
+
+ return object && object->isRenderNamedFlowThread() ? toRenderNamedFlowThread(object) : 0;
+}
+
RenderBlock* RenderObject::firstLineBlock() const
{
- return nullptr;
+ return 0;
}
static inline bool objectIsRelayoutBoundary(const RenderElement* object)
@@ -548,13 +564,15 @@ static inline bool objectIsRelayoutBoundary(const RenderElement* object)
if (object->isTextControl())
return true;
+#if ENABLE(SVG)
if (object->isSVGRoot())
return true;
+#endif
if (!object->hasOverflowClip())
return false;
- if (object->style().width().isIntrinsicOrAuto() || object->style().height().isIntrinsicOrAuto() || object->style().height().isPercentOrCalculated())
+ if (object->style().width().isIntrinsicOrAuto() || object->style().height().isIntrinsicOrAuto() || object->style().height().isPercent())
return false;
// Table parts can't be relayout roots since the table is responsible for layouting all the parts.
@@ -572,8 +590,8 @@ void RenderObject::clearNeedsLayout()
setNeedsSimplifiedNormalFlowLayoutBit(false);
setNormalChildNeedsLayoutBit(false);
setNeedsPositionedMovementLayoutBit(false);
- if (is<RenderElement>(*this))
- downcast<RenderElement>(*this).setAncestorLineBoxDirty(false);
+ if (isRenderElement())
+ toRenderElement(this)->setAncestorLineBoxDirty(false);
#ifndef NDEBUG
checkBlockPositionedObjectsNeedLayout();
#endif
@@ -581,18 +599,18 @@ void RenderObject::clearNeedsLayout()
static void scheduleRelayoutForSubtree(RenderElement& renderer)
{
- if (is<RenderView>(renderer)) {
- downcast<RenderView>(renderer).frameView().scheduleRelayout();
+ if (!renderer.isRenderView()) {
+ if (!renderer.isRooted())
+ return;
+ renderer.view().frameView().scheduleRelayoutOfSubtree(renderer);
return;
}
-
- if (renderer.isRooted())
- renderer.view().frameView().scheduleRelayoutOfSubtree(renderer);
+ toRenderView(renderer).frameView().scheduleRelayout();
}
-void RenderObject::markContainingBlocksForLayout(ScheduleRelayout scheduleRelayout, RenderElement* newRoot)
+void RenderObject::markContainingBlocksForLayout(bool scheduleRelayout, RenderElement* newRoot)
{
- ASSERT(scheduleRelayout == ScheduleRelayout::No || !newRoot);
+ ASSERT(!scheduleRelayout || !newRoot);
ASSERT(!isSetNeedsLayoutForbidden());
auto ancestor = container();
@@ -636,14 +654,14 @@ void RenderObject::markContainingBlocksForLayout(ScheduleRelayout scheduleRelayo
if (ancestor == newRoot)
return;
- if (scheduleRelayout == ScheduleRelayout::Yes && objectIsRelayoutBoundary(ancestor))
+ if (scheduleRelayout && objectIsRelayoutBoundary(ancestor))
break;
hasOutOfFlowPosition = ancestor->style().hasOutOfFlowPosition();
ancestor = container;
}
- if (scheduleRelayout == ScheduleRelayout::Yes && ancestor)
+ if (scheduleRelayout && ancestor)
scheduleRelayoutForSubtree(*ancestor);
}
@@ -652,8 +670,8 @@ void RenderObject::checkBlockPositionedObjectsNeedLayout()
{
ASSERT(!needsLayout());
- if (is<RenderBlock>(*this))
- downcast<RenderBlock>(*this).checkPositionedObjectsNeedLayout();
+ if (isRenderBlock())
+ toRenderBlock(this)->checkPositionedObjectsNeedLayout();
}
#endif
@@ -689,50 +707,371 @@ void RenderObject::invalidateContainerPreferredLogicalWidths()
void RenderObject::setLayerNeedsFullRepaint()
{
ASSERT(hasLayer());
- downcast<RenderLayerModelObject>(*this).layer()->setRepaintStatus(NeedsFullRepaint);
+ toRenderLayerModelObject(this)->layer()->setRepaintStatus(NeedsFullRepaint);
}
void RenderObject::setLayerNeedsFullRepaintForPositionedMovementLayout()
{
ASSERT(hasLayer());
- downcast<RenderLayerModelObject>(*this).layer()->setRepaintStatus(NeedsFullRepaintForPositionedMovementLayout);
+ toRenderLayerModelObject(this)->layer()->setRepaintStatus(NeedsFullRepaintForPositionedMovementLayout);
}
RenderBlock* RenderObject::containingBlock() const
{
- auto parent = this->parent();
- if (!parent && is<RenderScrollbarPart>(*this))
- parent = downcast<RenderScrollbarPart>(*this).rendererOwningScrollbar();
+ auto o = parent();
+ if (!o && isRenderScrollbarPart())
+ o = toRenderScrollbarPart(this)->rendererOwningScrollbar();
const RenderStyle& style = this->style();
- if (!is<RenderText>(*this) && style.position() == FixedPosition)
- parent = containingBlockForFixedPosition(parent);
- else if (!is<RenderText>(*this) && style.position() == AbsolutePosition)
- parent = containingBlockForAbsolutePosition(parent);
+ if (!isText() && style.position() == FixedPosition)
+ o = containingBlockForFixedPosition(o);
+ else if (!isText() && style.position() == AbsolutePosition)
+ o = containingBlockForAbsolutePosition(o);
else
- parent = containingBlockForObjectInFlow(parent);
+ o = containingBlockForObjectInFlow(o);
+
+ if (!o || !o->isRenderBlock())
+ return 0; // This can still happen in case of an orphaned tree
- // This can still happen in case of an detached tree
- if (!parent)
- return nullptr;
- return downcast<RenderBlock>(parent);
+ return toRenderBlock(o);
}
-void RenderObject::addPDFURLRect(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
+void RenderObject::drawLineForBoxSide(GraphicsContext* graphicsContext, int x1, int y1, int x2, int y2,
+ BoxSide side, Color color, EBorderStyle borderStyle, int adjacentWidth1, int adjacentWidth2, bool antialias)
{
- Vector<LayoutRect> focusRingRects;
+ int thickness;
+ int length;
+ if (side == BSTop || side == BSBottom) {
+ thickness = y2 - y1;
+ length = x2 - x1;
+ } else {
+ thickness = x2 - x1;
+ length = y2 - y1;
+ }
+
+ // FIXME: We really would like this check to be an ASSERT as we don't want to draw empty borders. However
+ // nothing guarantees that the following recursive calls to drawLineForBoxSide will have non-null dimensions.
+ if (!thickness || !length)
+ return;
+
+ if (borderStyle == DOUBLE && thickness < 3)
+ borderStyle = SOLID;
+
+ const RenderStyle& style = this->style();
+ switch (borderStyle) {
+ case BNONE:
+ case BHIDDEN:
+ return;
+ case DOTTED:
+ case DASHED: {
+ if (thickness > 0) {
+ bool wasAntialiased = graphicsContext->shouldAntialias();
+ StrokeStyle oldStrokeStyle = graphicsContext->strokeStyle();
+ graphicsContext->setShouldAntialias(antialias);
+ graphicsContext->setStrokeColor(color, style.colorSpace());
+ graphicsContext->setStrokeThickness(thickness);
+ graphicsContext->setStrokeStyle(borderStyle == DASHED ? DashedStroke : DottedStroke);
+
+ switch (side) {
+ case BSBottom:
+ case BSTop:
+ graphicsContext->drawLine(IntPoint(x1, (y1 + y2) / 2), IntPoint(x2, (y1 + y2) / 2));
+ break;
+ case BSRight:
+ case BSLeft:
+ graphicsContext->drawLine(IntPoint((x1 + x2) / 2, y1), IntPoint((x1 + x2) / 2, y2));
+ break;
+ }
+ graphicsContext->setShouldAntialias(wasAntialiased);
+ graphicsContext->setStrokeStyle(oldStrokeStyle);
+ }
+ break;
+ }
+ case DOUBLE: {
+ int thirdOfThickness = (thickness + 1) / 3;
+ ASSERT(thirdOfThickness);
+
+ if (adjacentWidth1 == 0 && adjacentWidth2 == 0) {
+ StrokeStyle oldStrokeStyle = graphicsContext->strokeStyle();
+ graphicsContext->setStrokeStyle(NoStroke);
+ graphicsContext->setFillColor(color, style.colorSpace());
+
+ bool wasAntialiased = graphicsContext->shouldAntialias();
+ graphicsContext->setShouldAntialias(antialias);
+
+ switch (side) {
+ case BSTop:
+ case BSBottom:
+ graphicsContext->drawRect(IntRect(x1, y1, length, thirdOfThickness));
+ graphicsContext->drawRect(IntRect(x1, y2 - thirdOfThickness, length, thirdOfThickness));
+ break;
+ case BSLeft:
+ case BSRight:
+ // FIXME: Why do we offset the border by 1 in this case but not the other one?
+ if (length > 1) {
+ graphicsContext->drawRect(IntRect(x1, y1 + 1, thirdOfThickness, length - 1));
+ graphicsContext->drawRect(IntRect(x2 - thirdOfThickness, y1 + 1, thirdOfThickness, length - 1));
+ }
+ break;
+ }
+
+ graphicsContext->setShouldAntialias(wasAntialiased);
+ graphicsContext->setStrokeStyle(oldStrokeStyle);
+ } else {
+ int adjacent1BigThird = ((adjacentWidth1 > 0) ? adjacentWidth1 + 1 : adjacentWidth1 - 1) / 3;
+ int adjacent2BigThird = ((adjacentWidth2 > 0) ? adjacentWidth2 + 1 : adjacentWidth2 - 1) / 3;
+
+ switch (side) {
+ case BSTop:
+ drawLineForBoxSide(graphicsContext, x1 + std::max((-adjacentWidth1 * 2 + 1) / 3, 0),
+ y1, x2 - std::max((-adjacentWidth2 * 2 + 1) / 3, 0), y1 + thirdOfThickness,
+ side, color, SOLID, adjacent1BigThird, adjacent2BigThird, antialias);
+ drawLineForBoxSide(graphicsContext, x1 + std::max((adjacentWidth1 * 2 + 1) / 3, 0),
+ y2 - thirdOfThickness, x2 - std::max((adjacentWidth2 * 2 + 1) / 3, 0), y2,
+ side, color, SOLID, adjacent1BigThird, adjacent2BigThird, antialias);
+ break;
+ case BSLeft:
+ drawLineForBoxSide(graphicsContext, x1, y1 + std::max((-adjacentWidth1 * 2 + 1) / 3, 0),
+ x1 + thirdOfThickness, y2 - std::max((-adjacentWidth2 * 2 + 1) / 3, 0),
+ side, color, SOLID, adjacent1BigThird, adjacent2BigThird, antialias);
+ drawLineForBoxSide(graphicsContext, x2 - thirdOfThickness, y1 + std::max((adjacentWidth1 * 2 + 1) / 3, 0),
+ x2, y2 - std::max((adjacentWidth2 * 2 + 1) / 3, 0),
+ side, color, SOLID, adjacent1BigThird, adjacent2BigThird, antialias);
+ break;
+ case BSBottom:
+ drawLineForBoxSide(graphicsContext, x1 + std::max((adjacentWidth1 * 2 + 1) / 3, 0),
+ y1, x2 - std::max((adjacentWidth2 * 2 + 1) / 3, 0), y1 + thirdOfThickness,
+ side, color, SOLID, adjacent1BigThird, adjacent2BigThird, antialias);
+ drawLineForBoxSide(graphicsContext, x1 + std::max((-adjacentWidth1 * 2 + 1) / 3, 0),
+ y2 - thirdOfThickness, x2 - std::max((-adjacentWidth2 * 2 + 1) / 3, 0), y2,
+ side, color, SOLID, adjacent1BigThird, adjacent2BigThird, antialias);
+ break;
+ case BSRight:
+ drawLineForBoxSide(graphicsContext, x1, y1 + std::max((adjacentWidth1 * 2 + 1) / 3, 0),
+ x1 + thirdOfThickness, y2 - std::max((adjacentWidth2 * 2 + 1) / 3, 0),
+ side, color, SOLID, adjacent1BigThird, adjacent2BigThird, antialias);
+ drawLineForBoxSide(graphicsContext, x2 - thirdOfThickness, y1 + std::max((-adjacentWidth1 * 2 + 1) / 3, 0),
+ x2, y2 - std::max((-adjacentWidth2 * 2 + 1) / 3, 0),
+ side, color, SOLID, adjacent1BigThird, adjacent2BigThird, antialias);
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ }
+ case RIDGE:
+ case GROOVE: {
+ EBorderStyle s1;
+ EBorderStyle s2;
+ if (borderStyle == GROOVE) {
+ s1 = INSET;
+ s2 = OUTSET;
+ } else {
+ s1 = OUTSET;
+ s2 = INSET;
+ }
+
+ int adjacent1BigHalf = ((adjacentWidth1 > 0) ? adjacentWidth1 + 1 : adjacentWidth1 - 1) / 2;
+ int adjacent2BigHalf = ((adjacentWidth2 > 0) ? adjacentWidth2 + 1 : adjacentWidth2 - 1) / 2;
+
+ switch (side) {
+ case BSTop:
+ drawLineForBoxSide(graphicsContext, x1 + std::max(-adjacentWidth1, 0) / 2, y1, x2 - std::max(-adjacentWidth2, 0) / 2, (y1 + y2 + 1) / 2,
+ side, color, s1, adjacent1BigHalf, adjacent2BigHalf, antialias);
+ drawLineForBoxSide(graphicsContext, x1 + std::max(adjacentWidth1 + 1, 0) / 2, (y1 + y2 + 1) / 2, x2 - std::max(adjacentWidth2 + 1, 0) / 2, y2,
+ side, color, s2, adjacentWidth1 / 2, adjacentWidth2 / 2, antialias);
+ break;
+ case BSLeft:
+ drawLineForBoxSide(graphicsContext, x1, y1 + std::max(-adjacentWidth1, 0) / 2, (x1 + x2 + 1) / 2, y2 - std::max(-adjacentWidth2, 0) / 2,
+ side, color, s1, adjacent1BigHalf, adjacent2BigHalf, antialias);
+ drawLineForBoxSide(graphicsContext, (x1 + x2 + 1) / 2, y1 + std::max(adjacentWidth1 + 1, 0) / 2, x2, y2 - std::max(adjacentWidth2 + 1, 0) / 2,
+ side, color, s2, adjacentWidth1 / 2, adjacentWidth2 / 2, antialias);
+ break;
+ case BSBottom:
+ drawLineForBoxSide(graphicsContext, x1 + std::max(adjacentWidth1, 0) / 2, y1, x2 - std::max(adjacentWidth2, 0) / 2, (y1 + y2 + 1) / 2,
+ side, color, s2, adjacent1BigHalf, adjacent2BigHalf, antialias);
+ drawLineForBoxSide(graphicsContext, x1 + std::max(-adjacentWidth1 + 1, 0) / 2, (y1 + y2 + 1) / 2, x2 - std::max(-adjacentWidth2 + 1, 0) / 2, y2,
+ side, color, s1, adjacentWidth1 / 2, adjacentWidth2 / 2, antialias);
+ break;
+ case BSRight:
+ drawLineForBoxSide(graphicsContext, x1, y1 + std::max(adjacentWidth1, 0) / 2, (x1 + x2 + 1) / 2, y2 - std::max(adjacentWidth2, 0) / 2,
+ side, color, s2, adjacent1BigHalf, adjacent2BigHalf, antialias);
+ drawLineForBoxSide(graphicsContext, (x1 + x2 + 1) / 2, y1 + std::max(-adjacentWidth1 + 1, 0) / 2, x2, y2 - std::max(-adjacentWidth2 + 1, 0) / 2,
+ side, color, s1, adjacentWidth1 / 2, adjacentWidth2 / 2, antialias);
+ break;
+ }
+ break;
+ }
+ case INSET:
+ // FIXME: Maybe we should lighten the colors on one side like Firefox.
+ // https://bugs.webkit.org/show_bug.cgi?id=58608
+ if (side == BSTop || side == BSLeft)
+ color = color.dark();
+ FALLTHROUGH;
+ case OUTSET:
+ if (borderStyle == OUTSET && (side == BSBottom || side == BSRight))
+ color = color.dark();
+ FALLTHROUGH;
+ case SOLID: {
+ StrokeStyle oldStrokeStyle = graphicsContext->strokeStyle();
+ graphicsContext->setStrokeStyle(NoStroke);
+ graphicsContext->setFillColor(color, style.colorSpace());
+ ASSERT(x2 >= x1);
+ ASSERT(y2 >= y1);
+ if (!adjacentWidth1 && !adjacentWidth2) {
+ // Turn off antialiasing to match the behavior of drawConvexPolygon();
+ // this matters for rects in transformed contexts.
+ bool wasAntialiased = graphicsContext->shouldAntialias();
+ graphicsContext->setShouldAntialias(antialias);
+ graphicsContext->drawRect(IntRect(x1, y1, x2 - x1, y2 - y1));
+ graphicsContext->setShouldAntialias(wasAntialiased);
+ graphicsContext->setStrokeStyle(oldStrokeStyle);
+ return;
+ }
+ FloatPoint quad[4];
+ switch (side) {
+ case BSTop:
+ quad[0] = FloatPoint(x1 + std::max(-adjacentWidth1, 0), y1);
+ quad[1] = FloatPoint(x1 + std::max(adjacentWidth1, 0), y2);
+ quad[2] = FloatPoint(x2 - std::max(adjacentWidth2, 0), y2);
+ quad[3] = FloatPoint(x2 - std::max(-adjacentWidth2, 0), y1);
+ break;
+ case BSBottom:
+ quad[0] = FloatPoint(x1 + std::max(adjacentWidth1, 0), y1);
+ quad[1] = FloatPoint(x1 + std::max(-adjacentWidth1, 0), y2);
+ quad[2] = FloatPoint(x2 - std::max(-adjacentWidth2, 0), y2);
+ quad[3] = FloatPoint(x2 - std::max(adjacentWidth2, 0), y1);
+ break;
+ case BSLeft:
+ quad[0] = FloatPoint(x1, y1 + std::max(-adjacentWidth1, 0));
+ quad[1] = FloatPoint(x1, y2 - std::max(-adjacentWidth2, 0));
+ quad[2] = FloatPoint(x2, y2 - std::max(adjacentWidth2, 0));
+ quad[3] = FloatPoint(x2, y1 + std::max(adjacentWidth1, 0));
+ break;
+ case BSRight:
+ quad[0] = FloatPoint(x1, y1 + std::max(adjacentWidth1, 0));
+ quad[1] = FloatPoint(x1, y2 - std::max(adjacentWidth2, 0));
+ quad[2] = FloatPoint(x2, y2 - std::max(-adjacentWidth2, 0));
+ quad[3] = FloatPoint(x2, y1 + std::max(-adjacentWidth1, 0));
+ break;
+ }
+
+ graphicsContext->drawConvexPolygon(4, quad, antialias);
+ graphicsContext->setStrokeStyle(oldStrokeStyle);
+ break;
+ }
+ }
+}
+
+void RenderObject::paintFocusRing(PaintInfo& paintInfo, const LayoutPoint& paintOffset, RenderStyle* style)
+{
+ Vector<IntRect> focusRingRects;
addFocusRingRects(focusRingRects, paintOffset, paintInfo.paintContainer);
- LayoutRect urlRect = unionRect(focusRingRects);
+ if (style->outlineStyleIsAuto())
+ paintInfo.context->drawFocusRing(focusRingRects, style->outlineWidth(), style->outlineOffset(), style->visitedDependentColor(CSSPropertyOutlineColor));
+ else
+ addPDFURLRect(paintInfo.context, unionRect(focusRingRects));
+}
- if (urlRect.isEmpty())
+void RenderObject::addPDFURLRect(GraphicsContext* context, const LayoutRect& rect)
+{
+ if (rect.isEmpty())
return;
- Node* node = this->node();
- if (!is<Element>(node) || !node->isLink())
+ Node* n = node();
+ if (!n || !n->isLink() || !n->isElementNode())
return;
- const AtomicString& href = downcast<Element>(*node).getAttribute(hrefAttr);
+ const AtomicString& href = toElement(n)->getAttribute(hrefAttr);
if (href.isNull())
return;
- paintInfo.context().setURLForRect(node->document().completeURL(href), snappedIntRect(urlRect));
+ context->setURLForRect(n->document().completeURL(href), pixelSnappedIntRect(rect));
+}
+
+void RenderObject::paintOutline(PaintInfo& paintInfo, const LayoutRect& paintRect)
+{
+ if (!hasOutline())
+ return;
+
+ RenderStyle& styleToUse = style();
+ LayoutUnit outlineWidth = styleToUse.outlineWidth();
+
+ int outlineOffset = styleToUse.outlineOffset();
+
+ if (styleToUse.outlineStyleIsAuto() || hasOutlineAnnotation()) {
+ if (!theme().supportsFocusRing(&styleToUse)) {
+ // Only paint the focus ring by hand if the theme isn't able to draw the focus ring.
+ paintFocusRing(paintInfo, paintRect.location(), &styleToUse);
+ }
+ }
+
+ if (styleToUse.outlineStyleIsAuto() || styleToUse.outlineStyle() == BNONE)
+ return;
+
+ IntRect inner = pixelSnappedIntRect(paintRect);
+ inner.inflate(outlineOffset);
+
+ IntRect outer = pixelSnappedIntRect(inner);
+ outer.inflate(outlineWidth);
+
+ // FIXME: This prevents outlines from painting inside the object. See bug 12042
+ if (outer.isEmpty())
+ return;
+
+ EBorderStyle outlineStyle = styleToUse.outlineStyle();
+ Color outlineColor = styleToUse.visitedDependentColor(CSSPropertyOutlineColor);
+
+ GraphicsContext* graphicsContext = paintInfo.context;
+ bool useTransparencyLayer = outlineColor.hasAlpha();
+ if (useTransparencyLayer) {
+ if (outlineStyle == SOLID) {
+ Path path;
+ path.addRect(outer);
+ path.addRect(inner);
+ graphicsContext->setFillRule(RULE_EVENODD);
+ graphicsContext->setFillColor(outlineColor, styleToUse.colorSpace());
+ graphicsContext->fillPath(path);
+ return;
+ }
+ graphicsContext->beginTransparencyLayer(static_cast<float>(outlineColor.alpha()) / 255);
+ outlineColor = Color(outlineColor.red(), outlineColor.green(), outlineColor.blue());
+ }
+
+ int leftOuter = outer.x();
+ int leftInner = inner.x();
+ int rightOuter = outer.maxX();
+ int rightInner = inner.maxX();
+ int topOuter = outer.y();
+ int topInner = inner.y();
+ int bottomOuter = outer.maxY();
+ int bottomInner = inner.maxY();
+
+ drawLineForBoxSide(graphicsContext, leftOuter, topOuter, leftInner, bottomOuter, BSLeft, outlineColor, outlineStyle, outlineWidth, outlineWidth);
+ drawLineForBoxSide(graphicsContext, leftOuter, topOuter, rightOuter, topInner, BSTop, outlineColor, outlineStyle, outlineWidth, outlineWidth);
+ drawLineForBoxSide(graphicsContext, rightInner, topOuter, rightOuter, bottomOuter, BSRight, outlineColor, outlineStyle, outlineWidth, outlineWidth);
+ drawLineForBoxSide(graphicsContext, leftOuter, bottomInner, rightOuter, bottomOuter, BSBottom, outlineColor, outlineStyle, outlineWidth, outlineWidth);
+
+ if (useTransparencyLayer)
+ graphicsContext->endTransparencyLayer();
+}
+
+// FIXME: Make this return an unsigned integer?
+int RenderObject::columnNumberForOffset(int offset)
+{
+ int columnNumber = 0;
+ RenderBlock* containingBlock = this->containingBlock();
+ RenderView& view = containingBlock->view();
+ const Pagination& pagination = view.frameView().frame().page()->pagination();
+ if (pagination.mode == Pagination::Unpaginated)
+ return columnNumber;
+
+ ColumnInfo* columnInfo = view.columnInfo();
+ if (columnInfo && !columnInfo->progressionIsInline()) {
+ if (!columnInfo->progressionIsReversed())
+ columnNumber = (pagination.pageLength + pagination.gap - offset) / (pagination.pageLength + pagination.gap);
+ else
+ columnNumber = offset / (pagination.pageLength + pagination.gap);
+ }
+ return columnNumber;
}
#if PLATFORM(IOS)
@@ -762,15 +1101,15 @@ void RenderObject::collectSelectionRects(Vector<SelectionRect>& rects, unsigned
unsigned numberOfQuads = quads.size();
for (unsigned i = 0; i < numberOfQuads; ++i)
- rects.append(SelectionRect(quads[i].enclosingBoundingBox(), isHorizontalWritingMode(), view().pageNumberForBlockProgressionOffset(quads[i].enclosingBoundingBox().x())));
+ rects.append(SelectionRect(quads[i].enclosingBoundingBox(), isHorizontalWritingMode(), columnNumberForOffset(quads[i].enclosingBoundingBox().x())));
}
#endif
-IntRect RenderObject::absoluteBoundingBoxRect(bool useTransforms, bool* wasFixed) const
+IntRect RenderObject::absoluteBoundingBoxRect(bool useTransforms) const
{
if (useTransforms) {
Vector<FloatQuad> quads;
- absoluteQuads(quads, wasFixed);
+ absoluteQuads(quads);
size_t n = quads.size();
if (!n)
@@ -782,7 +1121,7 @@ IntRect RenderObject::absoluteBoundingBoxRect(bool useTransforms, bool* wasFixed
return result;
}
- FloatPoint absPos = localToAbsolute(FloatPoint(), 0 /* ignore transforms */, wasFixed);
+ FloatPoint absPos = localToAbsolute();
Vector<IntRect> rects;
absoluteRects(rects, flooredLayoutPoint(absPos));
@@ -793,34 +1132,35 @@ IntRect RenderObject::absoluteBoundingBoxRect(bool useTransforms, bool* wasFixed
LayoutRect result = rects[0];
for (size_t i = 1; i < n; ++i)
result.unite(rects[i]);
- return snappedIntRect(result);
+ return pixelSnappedIntRect(result);
}
void RenderObject::absoluteFocusRingQuads(Vector<FloatQuad>& quads)
{
- Vector<LayoutRect> rects;
+ Vector<IntRect> rects;
// FIXME: addFocusRingRects() needs to be passed this transform-unaware
// localToAbsolute() offset here because RenderInline::addFocusRingRects()
// implicitly assumes that. This doesn't work correctly with transformed
// descendants.
FloatPoint absolutePoint = localToAbsolute();
addFocusRingRects(rects, flooredLayoutPoint(absolutePoint));
- float deviceScaleFactor = document().deviceScaleFactor();
- for (auto rect : rects) {
- rect.moveBy(LayoutPoint(-absolutePoint));
- quads.append(localToAbsoluteQuad(FloatQuad(snapRectToDevicePixels(rect, deviceScaleFactor))));
+ size_t count = rects.size();
+ for (size_t i = 0; i < count; ++i) {
+ IntRect rect = rects[i];
+ rect.move(-absolutePoint.x(), -absolutePoint.y());
+ quads.append(localToAbsoluteQuad(FloatQuad(rect)));
}
}
FloatRect RenderObject::absoluteBoundingBoxRectForRange(const Range* range)
{
- if (!range)
+ if (!range || !range->startContainer())
return FloatRect();
range->ownerDocument().updateLayout();
Vector<FloatQuad> quads;
- range->absoluteTextQuads(quads);
+ range->textQuads(quads);
if (quads.isEmpty())
return FloatRect();
@@ -852,8 +1192,9 @@ LayoutRect RenderObject::paintingRootRect(LayoutRect& topLevelRect)
RenderLayerModelObject* RenderObject::containerForRepaint() const
{
- RenderLayerModelObject* repaintContainer = nullptr;
+ RenderLayerModelObject* repaintContainer = 0;
+#if USE(ACCELERATED_COMPOSITING)
if (view().usesCompositing()) {
if (RenderLayer* parentLayer = enclosingLayer()) {
RenderLayer* compLayer = parentLayer->enclosingCompositingLayerForRepaint();
@@ -861,6 +1202,9 @@ RenderLayerModelObject* RenderObject::containerForRepaint() const
repaintContainer = &compLayer->renderer();
}
}
+#endif
+
+#if ENABLE(CSS_FILTERS)
if (view().hasSoftwareFilters()) {
if (RenderLayer* parentLayer = enclosingLayer()) {
RenderLayer* enclosingFilterLayer = parentLayer->enclosingFilterLayer();
@@ -868,6 +1212,7 @@ RenderLayerModelObject* RenderObject::containerForRepaint() const
return &enclosingFilterLayer->renderer();
}
}
+#endif
// If we have a flow thread, then we need to do individual repaints within the RenderRegions instead.
// Return the flow thread as a repaint container in order to create a chokepoint that allows us to change
@@ -878,149 +1223,97 @@ RenderLayerModelObject* RenderObject::containerForRepaint() const
// then the repaint container is not the flow thread.
if (hasFixedPosInNamedFlowContainingBlock(this))
return repaintContainer;
+ // The ancestor document will do the reparenting when the repaint propagates further up.
+ // We're just a seamless child document, and we don't need to do the hacking.
+ if (parentRenderFlowThread && &parentRenderFlowThread->document() != &document())
+ return repaintContainer;
// If we have already found a repaint container then we will repaint into that container only if it is part of the same
// flow thread. Otherwise we will need to catch the repaint call and send it to the flow thread.
- RenderFlowThread* repaintContainerFlowThread = repaintContainer ? repaintContainer->flowThreadContainingBlock() : nullptr;
+ RenderFlowThread* repaintContainerFlowThread = repaintContainer ? repaintContainer->flowThreadContainingBlock() : 0;
if (!repaintContainerFlowThread || repaintContainerFlowThread != parentRenderFlowThread)
repaintContainer = parentRenderFlowThread;
}
return repaintContainer;
}
-void RenderObject::propagateRepaintToParentWithOutlineAutoIfNeeded(const RenderLayerModelObject& repaintContainer, const LayoutRect& repaintRect) const
+void RenderObject::repaintUsingContainer(const RenderLayerModelObject* repaintContainer, const IntRect& r, bool immediate, bool shouldClipToLayer) const
{
- if (!hasOutlineAutoAncestor())
- return;
-
- // FIXME: We should really propagate only when the the child renderer sticks out.
- bool repaintRectNeedsConverting = false;
- // Issue repaint on the renderer with outline: auto.
- for (const auto* renderer = this; renderer; renderer = renderer->parent()) {
- bool rendererHasOutlineAutoAncestor = renderer->hasOutlineAutoAncestor();
- ASSERT(rendererHasOutlineAutoAncestor
- || renderer->outlineStyleForRepaint().outlineStyleIsAuto()
- || (is<RenderElement>(*renderer) && downcast<RenderElement>(*renderer).hasContinuation()));
- if (renderer == &repaintContainer && rendererHasOutlineAutoAncestor)
- repaintRectNeedsConverting = true;
- if (rendererHasOutlineAutoAncestor)
- continue;
- // Issue repaint on the correct repaint container.
- LayoutRect adjustedRepaintRect = repaintRect;
- adjustedRepaintRect.inflate(renderer->outlineStyleForRepaint().outlineSize());
- if (!repaintRectNeedsConverting)
- repaintContainer.repaintRectangle(adjustedRepaintRect);
- else if (is<RenderLayerModelObject>(renderer)) {
- const auto& rendererWithOutline = downcast<RenderLayerModelObject>(*renderer);
- adjustedRepaintRect = LayoutRect(repaintContainer.localToContainerQuad(FloatRect(adjustedRepaintRect), &rendererWithOutline).boundingBox());
- rendererWithOutline.repaintRectangle(adjustedRepaintRect);
- }
+ if (!repaintContainer) {
+ view().repaintViewRectangle(r, immediate);
return;
}
- ASSERT_NOT_REACHED();
-}
-
-void RenderObject::repaintUsingContainer(const RenderLayerModelObject* repaintContainer, const LayoutRect& r, bool shouldClipToLayer) const
-{
- if (r.isEmpty())
- return;
- if (!repaintContainer)
- repaintContainer = &view();
-
- if (is<RenderFlowThread>(*repaintContainer)) {
- downcast<RenderFlowThread>(*repaintContainer).repaintRectangleInRegions(r);
+ if (repaintContainer->isRenderFlowThread()) {
+ toRenderFlowThread(repaintContainer)->repaintRectangleInRegions(r, immediate);
return;
}
- propagateRepaintToParentWithOutlineAutoIfNeeded(*repaintContainer, r);
-
+#if ENABLE(CSS_FILTERS)
if (repaintContainer->hasFilter() && repaintContainer->layer() && repaintContainer->layer()->requiresFullLayerImageForFilters()) {
- repaintContainer->layer()->setFilterBackendNeedsRepaintingInRect(r);
+ repaintContainer->layer()->setFilterBackendNeedsRepaintingInRect(r, immediate);
return;
}
+#endif
+#if USE(ACCELERATED_COMPOSITING)
+ RenderView& v = view();
if (repaintContainer->isRenderView()) {
- RenderView& view = this->view();
- ASSERT(repaintContainer == &view);
- bool viewHasCompositedLayer = view.isComposited();
- if (!viewHasCompositedLayer || view.layer()->backing()->paintsIntoWindow()) {
- LayoutRect rect = r;
- if (viewHasCompositedLayer && view.layer()->transform())
- rect = LayoutRect(view.layer()->transform()->mapRect(snapRectToDevicePixels(rect, document().deviceScaleFactor())));
- view.repaintViewRectangle(rect);
+ ASSERT(repaintContainer == &v);
+ bool viewHasCompositedLayer = v.hasLayer() && v.layer()->isComposited();
+ if (!viewHasCompositedLayer || v.layer()->backing()->paintsIntoWindow()) {
+ v.repaintViewRectangle(viewHasCompositedLayer && v.layer()->transform() ? v.layer()->transform()->mapRect(r) : r, immediate);
return;
}
}
-
- if (view().usesCompositing()) {
- ASSERT(repaintContainer->isComposited());
+
+ if (v.usesCompositing()) {
+ ASSERT(repaintContainer->hasLayer() && repaintContainer->layer()->isComposited());
repaintContainer->layer()->setBackingNeedsRepaintInRect(r, shouldClipToLayer ? GraphicsLayer::ClipToLayer : GraphicsLayer::DoNotClipToLayer);
}
+#else
+ if (repaintContainer->isRenderView())
+ toRenderView(*repaintContainer).repaintViewRectangle(r, immediate);
+#endif
}
-void RenderObject::repaint() const
+void RenderObject::repaint(bool immediate) const
{
// Don't repaint if we're unrooted (note that view() still returns the view when unrooted)
- if (!isRooted())
+ RenderView* view;
+ if (!isRooted(&view))
return;
- const RenderView& view = this->view();
- if (view.printing())
- return;
+ if (view->printing())
+ return; // Don't repaint if we're printing.
RenderLayerModelObject* repaintContainer = containerForRepaint();
- repaintUsingContainer(repaintContainer, clippedOverflowRectForRepaint(repaintContainer));
+ repaintUsingContainer(repaintContainer ? repaintContainer : view, pixelSnappedIntRect(clippedOverflowRectForRepaint(repaintContainer)), immediate);
}
-void RenderObject::repaintRectangle(const LayoutRect& r, bool shouldClipToLayer) const
+void RenderObject::repaintRectangle(const LayoutRect& r, bool immediate, bool shouldClipToLayer) const
{
// Don't repaint if we're unrooted (note that view() still returns the view when unrooted)
- if (!isRooted())
+ RenderView* view;
+ if (!isRooted(&view))
return;
- const RenderView& view = this->view();
- if (view.printing())
- return;
+ if (view->printing())
+ return; // Don't repaint if we're printing.
LayoutRect dirtyRect(r);
+
// FIXME: layoutDelta needs to be applied in parts before/after transforms and
// repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308
- dirtyRect.move(view.layoutDelta());
+ dirtyRect.move(view->layoutDelta());
RenderLayerModelObject* repaintContainer = containerForRepaint();
- repaintUsingContainer(repaintContainer, computeRectForRepaint(dirtyRect, repaintContainer), shouldClipToLayer);
-}
-
-void RenderObject::repaintSlowRepaintObject() const
-{
- // Don't repaint if we're unrooted (note that view() still returns the view when unrooted)
- if (!isRooted())
- return;
-
- const RenderView& view = this->view();
- if (view.printing())
- return;
-
- const RenderLayerModelObject* repaintContainer = containerForRepaint();
- if (!repaintContainer)
- repaintContainer = &view;
-
- bool shouldClipToLayer = true;
- IntRect repaintRect;
- // If this is the root background, we need to check if there is an extended background rect. If
- // there is, then we should not allow painting to clip to the layer size.
- if (isDocumentElementRenderer() || isBody()) {
- shouldClipToLayer = !view.frameView().hasExtendedBackgroundRectForPainting();
- repaintRect = snappedIntRect(view.backgroundRect());
- } else
- repaintRect = snappedIntRect(clippedOverflowRectForRepaint(repaintContainer));
-
- repaintUsingContainer(repaintContainer, repaintRect, shouldClipToLayer);
+ computeRectForRepaint(repaintContainer, dirtyRect);
+ repaintUsingContainer(repaintContainer ? repaintContainer : view, pixelSnappedIntRect(dirtyRect), immediate, shouldClipToLayer);
}
IntRect RenderObject::pixelSnappedAbsoluteClippedOverflowRect() const
{
- return snappedIntRect(absoluteClippedOverflowRect());
+ return pixelSnappedIntRect(absoluteClippedOverflowRect());
}
bool RenderObject::checkForRepaintDuringLayout() const
@@ -1041,251 +1334,201 @@ LayoutRect RenderObject::clippedOverflowRectForRepaint(const RenderLayerModelObj
return LayoutRect();
}
-LayoutRect RenderObject::computeRectForRepaint(const LayoutRect& rect, const RenderLayerModelObject* repaintContainer, bool fixed) const
+void RenderObject::computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect& rect, bool fixed) const
{
if (repaintContainer == this)
- return rect;
+ return;
- auto* parent = this->parent();
- if (!parent)
- return rect;
+ if (auto o = parent()) {
+ if (o->isRenderBlockFlow()) {
+ RenderBlock* cb = toRenderBlock(o);
+ if (cb->hasColumns())
+ cb->adjustRectForColumns(rect);
+ }
- LayoutRect adjustedRect = rect;
- if (parent->hasOverflowClip()) {
- downcast<RenderBox>(*parent).applyCachedClipAndScrollOffsetForRepaint(adjustedRect);
- if (adjustedRect.isEmpty())
- return adjustedRect;
+ if (o->hasOverflowClip()) {
+ RenderBox* boxParent = toRenderBox(o);
+ boxParent->applyCachedClipAndScrollOffsetForRepaint(rect);
+ if (rect.isEmpty())
+ return;
+ }
+
+ o->computeRectForRepaint(repaintContainer, rect, fixed);
}
- return parent->computeRectForRepaint(adjustedRect, repaintContainer, fixed);
}
-FloatRect RenderObject::computeFloatRectForRepaint(const FloatRect&, const RenderLayerModelObject*, bool) const
+void RenderObject::computeFloatRectForRepaint(const RenderLayerModelObject*, FloatRect&, bool) const
{
ASSERT_NOT_REACHED();
- return FloatRect();
}
-#if ENABLE(TREE_DEBUGGING)
-
-static void showRenderTreeLegend()
-{
- fprintf(stderr, "\n(B)lock/(I)nline/I(N)line-block, (R)elative/A(B)solute/Fi(X)ed/Stick(Y) positioned, (O)verflow clipping, (A)nonymous, (G)enerated, (F)loating, has(L)ayer, (C)omposited, (D)irty layout, Dirty (S)tyle\n");
-}
+#ifndef NDEBUG
-void RenderObject::showNodeTreeForThis() const
+void RenderObject::showTreeForThis() const
{
- if (!node())
- return;
- node()->showTreeForThis();
+ if (node())
+ node()->showTreeForThis();
}
void RenderObject::showRenderTreeForThis() const
{
- const WebCore::RenderObject* root = this;
- while (root->parent())
- root = root->parent();
- showRenderTreeLegend();
- root->showRenderSubTreeAndMark(this, 1);
+ showRenderTree(this, 0);
}
void RenderObject::showLineTreeForThis() const
{
- if (!is<RenderBlockFlow>(*this))
- return;
- showRenderTreeLegend();
- showRenderObject(false, 1);
- downcast<RenderBlockFlow>(*this).showLineTreeAndMark(nullptr, 2);
+ if (containingBlock())
+ containingBlock()->showLineTreeAndMark(0, 0, 0, 0, this);
}
-static const RenderFlowThread* flowThreadContainingBlockFromRenderer(const RenderObject* renderer)
+void RenderObject::showRenderObject() const
{
- if (!renderer)
- return nullptr;
-
- if (renderer->flowThreadState() == RenderObject::NotInsideFlowThread)
- return nullptr;
-
- if (is<RenderFlowThread>(*renderer))
- return downcast<RenderFlowThread>(renderer);
-
- if (is<RenderBlock>(*renderer))
- return downcast<RenderBlock>(*renderer).cachedFlowThreadContainingBlock();
-
- return nullptr;
+ showRenderObject(0);
}
-void RenderObject::showRegionsInformation() const
+void RenderObject::showRenderObject(int printedCharacters) const
{
- const RenderFlowThread* ftcb = flowThreadContainingBlockFromRenderer(this);
-
- if (!ftcb) {
- // Only the boxes have region range information.
- // Try to get the flow thread containing block information
- // from the containing block of this box.
- if (is<RenderBox>(*this))
- ftcb = flowThreadContainingBlockFromRenderer(containingBlock());
+ // As this function is intended to be used when debugging, the
+ // this pointer may be 0.
+ if (!this) {
+ fputs("(null)\n", stderr);
+ return;
}
- if (!ftcb)
- return;
+ printedCharacters += fprintf(stderr, "%s %p", renderName(), this);
- RenderRegion* startRegion = nullptr;
- RenderRegion* endRegion = nullptr;
- ftcb->getRegionRangeForBox(downcast<RenderBox>(this), startRegion, endRegion);
- fprintf(stderr, " [Rs:%p Re:%p]", startRegion, endRegion);
+ if (node()) {
+ if (printedCharacters)
+ for (; printedCharacters < showTreeCharacterOffset; printedCharacters++)
+ fputc(' ', stderr);
+ fputc('\t', stderr);
+ node()->showNode();
+ } else
+ fputc('\n', stderr);
}
-void RenderObject::showRenderObject(bool mark, int depth) const
+void RenderObject::showRenderTreeAndMark(const RenderObject* markedObject1, const char* markedLabel1, const RenderObject* markedObject2, const char* markedLabel2, int depth) const
{
- if (isInlineBlockOrInlineTable())
- fputc('N', stderr);
- else if (isInline())
- fputc('I', stderr);
- else
- fputc('B', stderr);
-
- if (isPositioned()) {
- if (isRelPositioned())
- fputc('R', stderr);
- else if (isStickyPositioned())
- fputc('Y', stderr);
- else if (isOutOfFlowPositioned()) {
- if (style().position() == AbsolutePosition)
- fputc('B', stderr);
- else
- fputc('X', stderr);
- }
- } else
- fputc('-', stderr);
-
- if (hasOverflowClip())
- fputc('O', stderr);
- else
- fputc('-', stderr);
-
- if (isAnonymous())
- fputc('A', stderr);
- else
- fputc('-', stderr);
-
- if (isPseudoElement() || isAnonymous())
- fputc('G', stderr);
- else
- fputc('-', stderr);
-
- if (isFloating())
- fputc('F', stderr);
- else
- fputc('-', stderr);
-
- if (hasLayer())
- fputc('L', stderr);
- else
- fputc('-', stderr);
-
- if (isComposited())
- fputc('C', stderr);
- else
- fputc('-', stderr);
-
- fputc(' ', stderr);
-
- if (needsLayout())
- fputc('D', stderr);
- else
- fputc('-', stderr);
-
- if (node() && node()->needsStyleRecalc())
- fputc('S', stderr);
- else
- fputc('-', stderr);
-
int printedCharacters = 0;
- if (mark) {
- fprintf(stderr, "*");
- ++printedCharacters;
- }
-
- while (++printedCharacters <= depth * 2)
+ if (markedObject1 == this && markedLabel1)
+ printedCharacters += fprintf(stderr, "%s", markedLabel1);
+ if (markedObject2 == this && markedLabel2)
+ printedCharacters += fprintf(stderr, "%s", markedLabel2);
+ for (; printedCharacters < depth * 2; printedCharacters++)
fputc(' ', stderr);
- if (node())
- fprintf(stderr, "%s ", node()->nodeName().utf8().data());
+ showRenderObject(printedCharacters);
+ if (!this)
+ return;
- String name = renderName();
- // FIXME: Renderer's name should not include property value listing.
- int pos = name.find('(');
- if (pos > 0)
- fprintf(stderr, "%s", name.left(pos - 1).utf8().data());
- else
- fprintf(stderr, "%s", name.utf8().data());
+ for (const RenderObject* child = firstChildSlow(); child; child = child->nextSibling())
+ child->showRenderTreeAndMark(markedObject1, markedLabel1, markedObject2, markedLabel2, depth + 1);
+}
- if (is<RenderBox>(*this)) {
- const auto& box = downcast<RenderBox>(*this);
- fprintf(stderr, " (%.2f, %.2f) (%.2f, %.2f)", box.x().toFloat(), box.y().toFloat(), box.width().toFloat(), box.height().toFloat());
- }
+#endif // NDEBUG
- fprintf(stderr, " renderer->(%p)", this);
- if (node()) {
- fprintf(stderr, " node->(%p)", node());
- if (node()->isTextNode()) {
- String value = node()->nodeValue();
- fprintf(stderr, " length->(%u)", value.length());
-
- value.replaceWithLiteral('\\', "\\\\");
- value.replaceWithLiteral('\n', "\\n");
-
- const int maxPrintedLength = 80;
- if (value.length() > maxPrintedLength) {
- String substring = value.substring(0, maxPrintedLength);
- fprintf(stderr, " \"%s\"...", substring.utf8().data());
- } else
- fprintf(stderr, " \"%s\"", value.utf8().data());
+Color RenderObject::selectionBackgroundColor() const
+{
+ Color color;
+ if (style().userSelect() != SELECT_NONE) {
+ if (frame().selection().shouldShowBlockCursor() && frame().selection().isCaret())
+ color = style().visitedDependentColor(CSSPropertyColor).blendWithWhite();
+ else {
+ RefPtr<RenderStyle> pseudoStyle = getUncachedPseudoStyle(PseudoStyleRequest(SELECTION));
+ if (pseudoStyle && pseudoStyle->visitedDependentColor(CSSPropertyBackgroundColor).isValid())
+ color = pseudoStyle->visitedDependentColor(CSSPropertyBackgroundColor).blendWithWhite();
+ else
+ color = frame().selection().isFocusedAndActive() ? theme().activeSelectionBackgroundColor() : theme().inactiveSelectionBackgroundColor();
}
}
- showRegionsInformation();
- fprintf(stderr, "\n");
+ return color;
}
-void RenderObject::showRenderSubTreeAndMark(const RenderObject* markedObject, int depth) const
+Color RenderObject::selectionColor(int colorProperty) const
{
- showRenderObject(markedObject == this, depth);
- if (is<RenderBlockFlow>(*this))
- downcast<RenderBlockFlow>(*this).showLineTreeAndMark(nullptr, depth + 1);
+ Color color;
+ // If the element is unselectable, or we are only painting the selection,
+ // don't override the foreground color with the selection foreground color.
+ if (style().userSelect() == SELECT_NONE
+ || (view().frameView().paintBehavior() & PaintBehaviorSelectionOnly))
+ return color;
- for (const RenderObject* child = firstChildSlow(); child; child = child->nextSibling())
- child->showRenderSubTreeAndMark(markedObject, depth + 1);
+ if (RefPtr<RenderStyle> pseudoStyle = getUncachedPseudoStyle(PseudoStyleRequest(SELECTION))) {
+ color = pseudoStyle->visitedDependentColor(colorProperty);
+ if (!color.isValid())
+ color = pseudoStyle->visitedDependentColor(CSSPropertyColor);
+ } else
+ color = frame().selection().isFocusedAndActive() ? theme().activeSelectionForegroundColor() : theme().inactiveSelectionForegroundColor();
+
+ return color;
}
-#endif // NDEBUG
+Color RenderObject::selectionForegroundColor() const
+{
+ return selectionColor(CSSPropertyWebkitTextFillColor);
+}
-SelectionSubtreeRoot& RenderObject::selectionRoot() const
+Color RenderObject::selectionEmphasisMarkColor() const
{
- RenderFlowThread* flowThread = flowThreadContainingBlock();
- if (!flowThread)
- return view();
+ return selectionColor(CSSPropertyWebkitTextEmphasisColor);
+}
- if (is<RenderNamedFlowThread>(*flowThread))
- return downcast<RenderNamedFlowThread>(*flowThread);
- if (is<RenderMultiColumnFlowThread>(*flowThread)) {
- if (!flowThread->containingBlock())
- return view();
- return flowThread->containingBlock()->selectionRoot();
+void RenderObject::selectionStartEnd(int& spos, int& epos) const
+{
+ view().selectionStartEnd(spos, epos);
+}
+
+void RenderObject::handleDynamicFloatPositionChange()
+{
+ // We have gone from not affecting the inline status of the parent flow to suddenly
+ // having an impact. See if there is a mismatch between the parent flow's
+ // childrenInline() state and our state.
+ setInline(style().isDisplayInlineType());
+ if (isInline() != parent()->childrenInline()) {
+ if (!isInline())
+ toRenderBoxModelObject(parent())->childBecameNonInline(this);
+ else {
+ // An anonymous block must be made to wrap this inline.
+ RenderBlock* block = toRenderBlock(parent())->createAnonymousBlock();
+ parent()->insertChildInternal(block, this, RenderElement::NotifyChildren);
+ parent()->removeChildInternal(*this, RenderElement::NotifyChildren);
+ block->insertChildInternal(this, nullptr, RenderElement::NotifyChildren);
+ }
}
- ASSERT_NOT_REACHED();
- return view();
}
-void RenderObject::selectionStartEnd(int& spos, int& epos) const
+void RenderObject::removeAnonymousWrappersForInlinesIfNecessary()
{
- selectionRoot().selectionData().selectionStartEndPositions(spos, epos);
+ RenderBlock* parentBlock = toRenderBlock(parent());
+ if (!parentBlock->canCollapseAnonymousBlockChild())
+ return;
+
+ // We have changed to floated or out-of-flow positioning so maybe all our parent's
+ // children can be inline now. Bail if there are any block children left on the line,
+ // otherwise we can proceed to stripping solitary anonymous wrappers from the inlines.
+ // FIXME: We should also handle split inlines here - we exclude them at the moment by returning
+ // if we find a continuation.
+ RenderObject* curr = parent()->firstChild();
+ while (curr && ((curr->isAnonymousBlock() && !toRenderBlock(curr)->isAnonymousBlockContinuation()) || curr->style().isFloating() || curr->style().hasOutOfFlowPosition()))
+ curr = curr->nextSibling();
+
+ if (curr)
+ return;
+
+ curr = parent()->firstChild();
+ while (curr) {
+ RenderObject* next = curr->nextSibling();
+ if (curr->isAnonymousBlock())
+ parentBlock->collapseAnonymousBoxChild(parentBlock, toRenderBlock(curr));
+ curr = next;
+ }
}
-FloatPoint RenderObject::localToAbsolute(const FloatPoint& localPoint, MapCoordinatesFlags mode, bool* wasFixed) const
+FloatPoint RenderObject::localToAbsolute(const FloatPoint& localPoint, MapCoordinatesFlags mode) const
{
TransformState transformState(TransformState::ApplyTransformDirection, localPoint);
- mapLocalToContainer(nullptr, transformState, mode | ApplyContainerFlip, wasFixed);
+ mapLocalToContainer(0, transformState, mode | ApplyContainerFlip);
transformState.flatten();
return transformState.lastPlanarPoint();
@@ -1313,55 +1556,63 @@ void RenderObject::mapLocalToContainer(const RenderLayerModelObject* repaintCont
if (repaintContainer == this)
return;
- auto* parent = this->parent();
- if (!parent)
+ auto o = parent();
+ if (!o)
return;
// FIXME: this should call offsetFromContainer to share code, but I'm not sure it's ever called.
- LayoutPoint centerPoint(transformState.mappedPoint());
- if (mode & ApplyContainerFlip && is<RenderBox>(*parent)) {
- if (parent->style().isFlippedBlocksWritingMode())
- transformState.move(downcast<RenderBox>(parent)->flipForWritingMode(LayoutPoint(transformState.mappedPoint())) - centerPoint);
+ LayoutPoint centerPoint = roundedLayoutPoint(transformState.mappedPoint());
+ if (mode & ApplyContainerFlip && o->isBox()) {
+ if (o->style().isFlippedBlocksWritingMode())
+ transformState.move(toRenderBox(o)->flipForWritingModeIncludingColumns(roundedLayoutPoint(transformState.mappedPoint())) - centerPoint);
mode &= ~ApplyContainerFlip;
}
- if (is<RenderBox>(*parent))
- transformState.move(-downcast<RenderBox>(*parent).scrolledContentOffset());
+ LayoutSize columnOffset;
+ o->adjustForColumns(columnOffset, roundedLayoutPoint(transformState.mappedPoint()));
+ if (!columnOffset.isZero())
+ transformState.move(columnOffset);
- parent->mapLocalToContainer(repaintContainer, transformState, mode, wasFixed);
+ if (o->hasOverflowClip())
+ transformState.move(-toRenderBox(o)->scrolledContentOffset());
+
+ o->mapLocalToContainer(repaintContainer, transformState, mode, wasFixed);
}
const RenderObject* RenderObject::pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const
{
ASSERT_UNUSED(ancestorToStopAt, ancestorToStopAt != this);
- auto* container = parent();
+ auto container = parent();
if (!container)
- return nullptr;
+ return 0;
// FIXME: this should call offsetFromContainer to share code, but I'm not sure it's ever called.
LayoutSize offset;
- if (is<RenderBox>(*container))
- offset = -downcast<RenderBox>(*container).scrolledContentOffset();
+ if (container->hasOverflowClip())
+ offset = -toRenderBox(container)->scrolledContentOffset();
- geometryMap.push(this, offset, false);
+ geometryMap.push(this, offset, hasColumns());
return container;
}
void RenderObject::mapAbsoluteToLocalPoint(MapCoordinatesFlags mode, TransformState& transformState) const
{
- if (auto* parent = this->parent()) {
- parent->mapAbsoluteToLocalPoint(mode, transformState);
- if (is<RenderBox>(*parent))
- transformState.move(downcast<RenderBox>(*parent).scrolledContentOffset());
+ auto o = parent();
+ if (o) {
+ o->mapAbsoluteToLocalPoint(mode, transformState);
+ if (o->hasOverflowClip())
+ transformState.move(toRenderBox(o)->scrolledContentOffset());
}
}
bool RenderObject::shouldUseTransformFromContainer(const RenderObject* containerObject) const
{
-#if ENABLE(3D_TRANSFORMS)
- return hasTransform() || (containerObject && containerObject->style().hasPerspective());
+#if ENABLE(3D_RENDERING)
+ // hasTransform() indicates whether the object has transform, transform-style or perspective. We just care about transform,
+ // so check the layer's transform directly.
+ return (hasLayer() && toRenderLayerModelObject(this)->layer()->transform()) || (containerObject && containerObject->style().hasPerspective());
#else
UNUSED_PARAM(containerObject);
return hasTransform();
@@ -1373,14 +1624,14 @@ void RenderObject::getTransformFromContainer(const RenderObject* containerObject
transform.makeIdentity();
transform.translate(offsetInContainer.width(), offsetInContainer.height());
RenderLayer* layer;
- if (hasLayer() && (layer = downcast<RenderLayerModelObject>(*this).layer()) && layer->transform())
+ if (hasLayer() && (layer = toRenderLayerModelObject(this)->layer()) && layer->transform())
transform.multiply(layer->currentTransform());
-#if ENABLE(3D_TRANSFORMS)
+#if ENABLE(3D_RENDERING)
if (containerObject && containerObject->hasLayer() && containerObject->style().hasPerspective()) {
// Perpsective on the container affects us, so we have to factor it in here.
ASSERT(containerObject->hasLayer());
- FloatPoint perspectiveOrigin = downcast<RenderLayerModelObject>(*containerObject).layer()->perspectiveOrigin();
+ FloatPoint perspectiveOrigin = toRenderLayerModelObject(containerObject)->layer()->perspectiveOrigin();
TransformationMatrix perspectiveMatrix;
perspectiveMatrix.applyPerspective(containerObject->style().perspective());
@@ -1399,7 +1650,7 @@ FloatQuad RenderObject::localToContainerQuad(const FloatQuad& localQuad, const R
// Track the point at the center of the quad's bounding box. As mapLocalToContainer() calls offsetFromContainer(),
// it will use that point as the reference point to decide which column's transform to apply in multiple-column blocks.
TransformState transformState(TransformState::ApplyTransformDirection, localQuad.boundingBox().center(), localQuad);
- mapLocalToContainer(repaintContainer, transformState, mode | ApplyContainerFlip, wasFixed);
+ mapLocalToContainer(repaintContainer, transformState, mode | ApplyContainerFlip | UseTransforms, wasFixed);
transformState.flatten();
return transformState.lastPlanarQuad();
@@ -1408,42 +1659,45 @@ FloatQuad RenderObject::localToContainerQuad(const FloatQuad& localQuad, const R
FloatPoint RenderObject::localToContainerPoint(const FloatPoint& localPoint, const RenderLayerModelObject* repaintContainer, MapCoordinatesFlags mode, bool* wasFixed) const
{
TransformState transformState(TransformState::ApplyTransformDirection, localPoint);
- mapLocalToContainer(repaintContainer, transformState, mode | ApplyContainerFlip, wasFixed);
+ mapLocalToContainer(repaintContainer, transformState, mode | ApplyContainerFlip | UseTransforms, wasFixed);
transformState.flatten();
return transformState.lastPlanarPoint();
}
-LayoutSize RenderObject::offsetFromContainer(RenderElement& container, const LayoutPoint&, bool* offsetDependsOnPoint) const
+LayoutSize RenderObject::offsetFromContainer(RenderObject* o, const LayoutPoint& point, bool* offsetDependsOnPoint) const
{
- ASSERT(&container == this->container());
+ ASSERT(o == container());
LayoutSize offset;
- if (is<RenderBox>(container))
- offset -= downcast<RenderBox>(container).scrolledContentOffset();
+
+ o->adjustForColumns(offset, point);
+
+ if (o->hasOverflowClip())
+ offset -= toRenderBox(o)->scrolledContentOffset();
if (offsetDependsOnPoint)
- *offsetDependsOnPoint = is<RenderFlowThread>(container);
+ *offsetDependsOnPoint = hasColumns() || o->isRenderFlowThread();
return offset;
}
-LayoutSize RenderObject::offsetFromAncestorContainer(RenderElement& container) const
+LayoutSize RenderObject::offsetFromAncestorContainer(RenderObject* container) const
{
LayoutSize offset;
LayoutPoint referencePoint;
const RenderObject* currContainer = this;
do {
- RenderElement* nextContainer = currContainer->container();
+ auto nextContainer = currContainer->container();
ASSERT(nextContainer); // This means we reached the top without finding container.
if (!nextContainer)
break;
ASSERT(!currContainer->hasTransform());
- LayoutSize currentOffset = currContainer->offsetFromContainer(*nextContainer, referencePoint);
+ LayoutSize currentOffset = currContainer->offsetFromContainer(nextContainer, referencePoint);
offset += currentOffset;
referencePoint.move(currentOffset);
currContainer = nextContainer;
- } while (currContainer != &container);
+ } while (currContainer != container);
return offset;
}
@@ -1456,9 +1710,19 @@ LayoutRect RenderObject::localCaretRect(InlineBox*, int, LayoutUnit* extraWidthT
return LayoutRect();
}
-bool RenderObject::isRooted() const
+bool RenderObject::isRooted(RenderView** view) const
{
- return isDescendantOf(&view());
+ const RenderObject* o = this;
+ while (o->parent())
+ o = o->parent();
+
+ if (!o->isRenderView())
+ return false;
+
+ if (view)
+ *view = &const_cast<RenderView&>(toRenderView(*o));
+
+ return true;
}
RespectImageOrientationEnum RenderObject::shouldRespectImageOrientation() const
@@ -1470,7 +1734,7 @@ RespectImageOrientationEnum RenderObject::shouldRespectImageOrientation() const
#endif
// Respect the image's orientation if it's being used as a full-page image or it's
// an <img> and the setting to respect it everywhere is set.
- return (frame().settings().shouldRespectImageOrientation() && is<HTMLImageElement>(node())) ? RespectImageOrientation : DoNotRespectImageOrientation;
+ return (frame().settings().shouldRespectImageOrientation() && node() && isHTMLImageElement(node())) ? RespectImageOrientation : DoNotRespectImageOrientation;
}
bool RenderObject::hasOutlineAnnotation() const
@@ -1509,15 +1773,15 @@ RenderElement* RenderObject::container(const RenderLayerModelObject* repaintCont
// can't get back to the canvas. Instead we just walk as high up
// as we can. If we're in the tree, we'll get the root. If we
// aren't we'll get the root of our little subtree (most likely
- // we'll just return nullptr).
+ // we'll just return 0).
// FIXME: The definition of view() has changed to not crawl up the render tree. It might
// be safe now to use it.
- // FIXME: share code with containingBlockForFixedPosition().
while (o && o->parent() && !(o->hasTransform() && o->isRenderBlock())) {
+#if ENABLE(SVG)
// foreignObject is the containing block for its contents.
if (o->isSVGForeignObject())
break;
-
+#endif
// The render flow thread is the top most containing block
// for the fixed positioned elements.
if (o->isOutOfFlowRenderFlowThread())
@@ -1532,12 +1796,11 @@ RenderElement* RenderObject::container(const RenderLayerModelObject* repaintCont
// Same goes here. We technically just want our containing block, but
// we may not have one if we're part of an uninstalled subtree. We'll
// climb as high as we can though.
- // FIXME: share code with isContainingBlockCandidateForAbsolutelyPositionedObject().
- // FIXME: hasTransformRelatedProperty() includes preserves3D() check, but this may need to change: https://www.w3.org/Bugs/Public/show_bug.cgi?id=27566
- while (o && o->style().position() == StaticPosition && !o->isRenderView() && !(o->hasTransformRelatedProperty() && o->isRenderBlock())) {
+ while (o && o->style().position() == StaticPosition && !o->isRenderView() && !(o->hasTransform() && o->isRenderBlock())) {
+#if ENABLE(SVG)
if (o->isSVGForeignObject()) // foreignObject is the containing block for contents inside it
break;
-
+#endif
if (repaintContainerSkipped && o == repaintContainer)
*repaintContainerSkipped = true;
@@ -1551,11 +1814,21 @@ RenderElement* RenderObject::container(const RenderLayerModelObject* repaintCont
bool RenderObject::isSelectionBorder() const
{
SelectionState st = selectionState();
- return st == SelectionStart
- || st == SelectionEnd
- || st == SelectionBoth
- || view().selectionUnsplitStart() == this
- || view().selectionUnsplitEnd() == this;
+ return st == SelectionStart || st == SelectionEnd || st == SelectionBoth;
+}
+
+inline void RenderObject::clearLayoutRootIfNeeded() const
+{
+ if (documentBeingDestroyed())
+ return;
+
+ if (view().frameView().layoutRoot() == this) {
+ ASSERT_NOT_REACHED();
+ // This indicates a failure to layout the child, which is why
+ // the layout root is still set to |this|. Make sure to clear it
+ // since we are getting destroyed.
+ view().frameView().clearLayoutRoot();
+ }
}
void RenderObject::willBeDestroyed()
@@ -1567,21 +1840,41 @@ void RenderObject::willBeDestroyed()
removeFromParent();
- ASSERT(documentBeingDestroyed() || !is<RenderElement>(*this) || !view().frameView().hasSlowRepaintObject(downcast<RenderElement>(*this)));
+ ASSERT(documentBeingDestroyed() || !isRenderElement() || !view().frameView().hasSlowRepaintObject(toRenderElement(this)));
// The remove() call above may invoke axObjectCache()->childrenChanged() on the parent, which may require the AX render
// object for this renderer. So we remove the AX render object now, after the renderer is removed.
if (AXObjectCache* cache = document().existingAXObjectCache())
cache->remove(this);
+#ifndef NDEBUG
+ if (!documentBeingDestroyed() && view().hasRenderNamedFlowThreads()) {
+ // After remove, the object and the associated information should not be in any flow thread.
+ const RenderNamedFlowThreadList* flowThreadList = view().flowThreadController().renderNamedFlowThreadList();
+ for (RenderNamedFlowThreadList::const_iterator iter = flowThreadList->begin(); iter != flowThreadList->end(); ++iter) {
+ const RenderNamedFlowThread* renderFlowThread = *iter;
+ ASSERT(!renderFlowThread->hasChild(this));
+ ASSERT(!renderFlowThread->hasChildInfo(this));
+ }
+ }
+#endif
+
+ // If this renderer had a parent, remove should have destroyed any counters
+ // attached to this renderer and marked the affected other counters for
+ // reevaluation. This apparently redundant check is here for the case when
+ // this renderer had no parent at the time remove() was called.
+
+ if (hasCounterNodeMap())
+ RenderCounter::destroyCounterNodes(this);
+
// FIXME: Would like to do this in RenderBoxModelObject, but the timing is so complicated that this can't easily
// be moved into RenderBoxModelObject::destroy.
if (hasLayer()) {
setHasLayer(false);
- downcast<RenderLayerModelObject>(*this).destroyLayer();
+ toRenderLayerModelObject(this)->destroyLayer();
}
- removeRareData();
+ clearLayoutRootIfNeeded();
}
void RenderObject::insertedIntoTree()
@@ -1589,10 +1882,10 @@ void RenderObject::insertedIntoTree()
// FIXME: We should ASSERT(isRooted()) here but generated content makes some out-of-order insertion.
if (!isFloating() && parent()->childrenInline())
- parent()->dirtyLinesFromChangedChild(*this);
+ parent()->dirtyLinesFromChangedChild(this);
- if (RenderFlowThread* flowThread = flowThreadContainingBlock())
- flowThread->flowThreadDescendantInserted(this);
+ if (RenderNamedFlowThread* containerFlowThread = parent()->renderNamedFlowThreadWrapper())
+ containerFlowThread->addFlowChild(this);
}
void RenderObject::willBeRemovedFromTree()
@@ -1601,109 +1894,38 @@ void RenderObject::willBeRemovedFromTree()
removeFromRenderFlowThread();
+ if (RenderNamedFlowThread* containerFlowThread = parent()->renderNamedFlowThreadWrapper())
+ containerFlowThread->removeFlowChild(this);
+
+#if ENABLE(SVG)
// Update cached boundaries in SVG renderers, if a child is removed.
parent()->setNeedsBoundariesUpdate();
+#endif
}
void RenderObject::removeFromRenderFlowThread()
{
if (flowThreadState() == NotInsideFlowThread)
return;
-
+
// Sometimes we remove the element from the flow, but it's not destroyed at that time.
- // It's only until later when we actually destroy it and remove all the children from it.
+ // It's only until later when we actually destroy it and remove all the children from it.
// Currently, that happens for firstLetter elements and list markers.
// Pass in the flow thread so that we don't have to look it up for all the children.
- removeFromRenderFlowThreadIncludingDescendants(true);
+ removeFromRenderFlowThreadRecursive(flowThreadContainingBlock());
}
-void RenderObject::removeFromRenderFlowThreadIncludingDescendants(bool shouldUpdateState)
+void RenderObject::removeFromRenderFlowThreadRecursive(RenderFlowThread* renderFlowThread)
{
- // Once we reach another flow thread we don't need to update the flow thread state
- // but we have to continue cleanup the flow thread info.
- if (isRenderFlowThread())
- shouldUpdateState = false;
-
for (RenderObject* child = firstChildSlow(); child; child = child->nextSibling())
- child->removeFromRenderFlowThreadIncludingDescendants(shouldUpdateState);
+ child->removeFromRenderFlowThreadRecursive(renderFlowThread);
- // We have to ask for our containing flow thread as it may be above the removed sub-tree.
- RenderFlowThread* flowThreadContainingBlock = this->flowThreadContainingBlock();
- while (flowThreadContainingBlock) {
- flowThreadContainingBlock->removeFlowChildInfo(this);
- if (flowThreadContainingBlock->flowThreadState() == NotInsideFlowThread)
- break;
- RenderObject* parent = flowThreadContainingBlock->parent();
- if (!parent)
- break;
- flowThreadContainingBlock = parent->flowThreadContainingBlock();
- }
- if (is<RenderBlock>(*this))
- downcast<RenderBlock>(*this).setCachedFlowThreadContainingBlockNeedsUpdate();
-
- if (shouldUpdateState)
- setFlowThreadState(NotInsideFlowThread);
-}
-
-void RenderObject::invalidateFlowThreadContainingBlockIncludingDescendants(RenderFlowThread* flowThread)
-{
- if (flowThreadState() == NotInsideFlowThread)
- return;
-
- if (is<RenderBlock>(*this)) {
- RenderBlock& block = downcast<RenderBlock>(*this);
-
- if (block.cachedFlowThreadContainingBlockNeedsUpdate())
- return;
-
- flowThread = block.cachedFlowThreadContainingBlock();
- block.setCachedFlowThreadContainingBlockNeedsUpdate();
- }
-
- if (flowThread)
- flowThread->removeFlowChildInfo(this);
-
- for (RenderObject* child = firstChildSlow(); child; child = child->nextSibling())
- child->invalidateFlowThreadContainingBlockIncludingDescendants(flowThread);
-}
-
-static void collapseAnonymousTableRowsIfNeeded(const RenderObject& rendererToBeDestroyed)
-{
- if (!is<RenderTableRow>(rendererToBeDestroyed))
- return;
-
- auto& rowToBeDestroyed = downcast<RenderTableRow>(rendererToBeDestroyed);
- auto* section = downcast<RenderTableSection>(rowToBeDestroyed.parent());
- if (!section)
- return;
-
- // All siblings generated?
- for (auto* current = section->firstRow(); current; current = current->nextRow()) {
- if (current == &rendererToBeDestroyed)
- continue;
- if (!current->isAnonymous())
- return;
- }
-
- RenderTableRow* rowToInsertInto = nullptr;
- auto* currentRow = section->firstRow();
- while (currentRow) {
- if (currentRow == &rendererToBeDestroyed) {
- currentRow = currentRow->nextRow();
- continue;
- }
- if (!rowToInsertInto) {
- rowToInsertInto = currentRow;
- currentRow = currentRow->nextRow();
- continue;
- }
- currentRow->moveAllChildrenTo(rowToInsertInto);
- auto* destroyThis = currentRow;
- currentRow = currentRow->nextRow();
- destroyThis->destroy();
- }
- if (rowToInsertInto)
- rowToInsertInto->setNeedsLayout();
+ RenderFlowThread* localFlowThread = renderFlowThread;
+ if (flowThreadState() == InsideInFlowThread)
+ localFlowThread = flowThreadContainingBlock(); // We have to ask. We can't just assume we are in the same flow thread.
+ if (localFlowThread)
+ localFlowThread->removeFlowChildInfo(this);
+ setFlowThreadState(NotInsideFlowThread);
}
void RenderObject::destroyAndCleanupAnonymousWrappers()
@@ -1714,41 +1936,34 @@ void RenderObject::destroyAndCleanupAnonymousWrappers()
return;
}
- auto* destroyRoot = this;
- auto* destroyRootParent = destroyRoot->parent();
- while (destroyRootParent && destroyRootParent->isAnonymous()) {
- if (!destroyRootParent->isTableCell() && !destroyRootParent->isTableRow()
- && !destroyRootParent->isTableCaption() && !destroyRootParent->isTableSection() && !destroyRootParent->isTable())
+ RenderObject* destroyRoot = this;
+ for (auto destroyRootParent = destroyRoot->parent(); destroyRootParent && destroyRootParent->isAnonymous(); destroyRoot = destroyRootParent, destroyRootParent = destroyRootParent->parent()) {
+ // Currently we only remove anonymous cells' and table sections' wrappers but we should remove all unneeded
+ // wrappers. See http://webkit.org/b/52123 as an example where this is needed.
+ if (!destroyRootParent->isTableCell() && !destroyRootParent->isTableSection())
break;
- // single child?
- if (!(destroyRootParent->firstChild() == destroyRoot && destroyRootParent->lastChild() == destroyRoot))
+
+ if (destroyRootParent->firstChild() != this || destroyRootParent->lastChild() != this)
break;
- destroyRoot = destroyRootParent;
- destroyRootParent = destroyRootParent->parent();
}
- collapseAnonymousTableRowsIfNeeded(*destroyRoot);
+
destroyRoot->destroy();
+
// WARNING: |this| is deleted here.
}
void RenderObject::destroy()
{
- m_bitfields.setBeingDestroyed(true);
-
#if PLATFORM(IOS)
if (hasLayer())
- downcast<RenderBoxModelObject>(*this).layer()->willBeDestroyed();
+ toRenderBoxModelObject(this)->layer()->willBeDestroyed();
#endif
willBeDestroyed();
- if (is<RenderWidget>(*this)) {
- downcast<RenderWidget>(*this).deref();
- return;
- }
delete this;
}
-VisiblePosition RenderObject::positionForPoint(const LayoutPoint&, const RenderRegion*)
+VisiblePosition RenderObject::positionForPoint(const LayoutPoint&)
{
return createVisiblePosition(caretMinOffset(), DOWNSTREAM);
}
@@ -1757,7 +1972,7 @@ void RenderObject::updateDragState(bool dragOn)
{
bool valueChanged = (dragOn != isDragging());
setIsDragging(dragOn);
- if (valueChanged && node() && (style().affectedByDrag() || (is<Element>(*node()) && downcast<Element>(*node()).childrenAffectedByDrag())))
+ if (valueChanged && node() && (style().affectedByDrag() || (node()->isElementNode() && toElement(node())->childrenAffectedByDrag())))
node()->setNeedsStyleRecalc();
for (RenderObject* curr = firstChildSlow(); curr; curr = curr->nextSibling())
curr->updateDragState(dragOn);
@@ -1765,12 +1980,7 @@ void RenderObject::updateDragState(bool dragOn)
bool RenderObject::isComposited() const
{
- return hasLayer() && downcast<RenderLayerModelObject>(*this).layer()->isComposited();
-}
-
-bool RenderObject::isAnonymousInlineBlock() const
-{
- return isAnonymous() && style().display() == INLINE_BLOCK && style().styleType() == NOPSEUDO && isRenderBlockFlow() && !isRubyRun() && !isRubyBase() && !isRuby(parent());
+ return hasLayer() && toRenderLayerModelObject(this)->layer()->isComposited();
}
bool RenderObject::hitTest(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestFilter hitTestFilter)
@@ -1806,7 +2016,7 @@ void RenderObject::updateHitTestResult(HitTestResult& result, const LayoutPoint&
// If we hit the anonymous renderers inside generated content we should
// actually hit the generated content so walk up to the PseudoElement.
if (!node && parent() && parent()->isBeforeOrAfterContent()) {
- for (auto* renderer = parent(); renderer && !node; renderer = renderer->parent())
+ for (auto renderer = parent(); renderer && !node; renderer = renderer->parent())
node = renderer->element();
}
@@ -1828,6 +2038,48 @@ int RenderObject::innerLineHeight() const
return style().computedLineHeight();
}
+RenderStyle* RenderObject::getCachedPseudoStyle(PseudoId pseudo, RenderStyle* parentStyle) const
+{
+ if (pseudo < FIRST_INTERNAL_PSEUDOID && !style().hasPseudoStyle(pseudo))
+ return 0;
+
+ RenderStyle* cachedStyle = style().getCachedPseudoStyle(pseudo);
+ if (cachedStyle)
+ return cachedStyle;
+
+ RefPtr<RenderStyle> result = getUncachedPseudoStyle(PseudoStyleRequest(pseudo), parentStyle);
+ if (result)
+ return style().addCachedPseudoStyle(result.release());
+ return 0;
+}
+
+PassRefPtr<RenderStyle> RenderObject::getUncachedPseudoStyle(const PseudoStyleRequest& pseudoStyleRequest, RenderStyle* parentStyle, RenderStyle* ownStyle) const
+{
+ if (pseudoStyleRequest.pseudoId < FIRST_INTERNAL_PSEUDOID && !ownStyle && !style().hasPseudoStyle(pseudoStyleRequest.pseudoId))
+ return 0;
+
+ if (!parentStyle) {
+ ASSERT(!ownStyle);
+ parentStyle = &style();
+ }
+
+ // FIXME: This "find nearest element parent" should be a helper function.
+ Node* n = node();
+ while (n && !n->isElementNode())
+ n = n->parentNode();
+ if (!n)
+ return 0;
+ Element* element = toElement(n);
+
+ if (pseudoStyleRequest.pseudoId == FIRST_LINE_INHERITED) {
+ RefPtr<RenderStyle> result = document().ensureStyleResolver().styleForElement(element, parentStyle, DisallowStyleSharing);
+ result->setStyleType(FIRST_LINE_INHERITED);
+ return result.release();
+ }
+
+ return document().ensureStyleResolver().pseudoStyleForElement(element, pseudoStyleRequest, parentStyle);
+}
+
static Color decorationColor(RenderStyle* style)
{
Color result;
@@ -1846,58 +2098,49 @@ static Color decorationColor(RenderStyle* style)
return result;
}
-void RenderObject::getTextDecorationColorsAndStyles(int decorations, Color& underlineColor, Color& overlineColor, Color& linethroughColor,
- TextDecorationStyle& underlineStyle, TextDecorationStyle& overlineStyle, TextDecorationStyle& linethroughStyle, bool firstlineStyle) const
+void RenderObject::getTextDecorationColors(int decorations, Color& underline, Color& overline,
+ Color& linethrough, bool quirksMode, bool firstlineStyle)
{
- const RenderObject* current = this;
- RenderStyle* styleToUse = nullptr;
+ RenderObject* curr = this;
+ RenderStyle* styleToUse = 0;
TextDecoration currDecs = TextDecorationNone;
Color resultColor;
do {
- styleToUse = firstlineStyle ? &current->firstLineStyle() : &current->style();
+ styleToUse = firstlineStyle ? &curr->firstLineStyle() : &curr->style();
currDecs = styleToUse->textDecoration();
resultColor = decorationColor(styleToUse);
// Parameter 'decorations' is cast as an int to enable the bitwise operations below.
if (currDecs) {
if (currDecs & TextDecorationUnderline) {
decorations &= ~TextDecorationUnderline;
- underlineColor = resultColor;
- underlineStyle = styleToUse->textDecorationStyle();
+ underline = resultColor;
}
if (currDecs & TextDecorationOverline) {
decorations &= ~TextDecorationOverline;
- overlineColor = resultColor;
- overlineStyle = styleToUse->textDecorationStyle();
+ overline = resultColor;
}
if (currDecs & TextDecorationLineThrough) {
decorations &= ~TextDecorationLineThrough;
- linethroughColor = resultColor;
- linethroughStyle = styleToUse->textDecorationStyle();
+ linethrough = resultColor;
}
}
- if (current->isRubyText())
+ if (curr->isRubyText())
return;
- current = current->parent();
- if (current && current->isAnonymousBlock() && downcast<RenderBlock>(*current).continuation())
- current = downcast<RenderBlock>(*current).continuation();
- } while (current && decorations && (!current->node() || (!is<HTMLAnchorElement>(*current->node()) && !current->node()->hasTagName(fontTag))));
+ curr = curr->parent();
+ if (curr && curr->isAnonymousBlock() && toRenderBlock(curr)->continuation())
+ curr = toRenderBlock(curr)->continuation();
+ } while (curr && decorations && (!quirksMode || !curr->node() || (!isHTMLAnchorElement(curr->node()) && !curr->node()->hasTagName(fontTag))));
// If we bailed out, use the element we bailed out at (typically a <font> or <a> element).
- if (decorations && current) {
- styleToUse = firstlineStyle ? &current->firstLineStyle() : &current->style();
+ if (decorations && curr) {
+ styleToUse = firstlineStyle ? &curr->firstLineStyle() : &curr->style();
resultColor = decorationColor(styleToUse);
- if (decorations & TextDecorationUnderline) {
- underlineColor = resultColor;
- underlineStyle = styleToUse->textDecorationStyle();
- }
- if (decorations & TextDecorationOverline) {
- overlineColor = resultColor;
- overlineStyle = styleToUse->textDecorationStyle();
- }
- if (decorations & TextDecorationLineThrough) {
- linethroughColor = resultColor;
- linethroughStyle = styleToUse->textDecorationStyle();
- }
+ if (decorations & TextDecorationUnderline)
+ underline = resultColor;
+ if (decorations & TextDecorationOverline)
+ overline = resultColor;
+ if (decorations & TextDecorationLineThrough)
+ linethrough = resultColor;
}
}
@@ -1905,16 +2148,19 @@ void RenderObject::getTextDecorationColorsAndStyles(int decorations, Color& unde
void RenderObject::addAnnotatedRegions(Vector<AnnotatedRegionValue>& regions)
{
// Convert the style regions to absolute coordinates.
- if (style().visibility() != VISIBLE || !is<RenderBox>(*this))
+ if (style().visibility() != VISIBLE || !isBox())
return;
- auto& box = downcast<RenderBox>(*this);
+ RenderBox* box = toRenderBox(this);
FloatPoint absPos = localToAbsolute();
const Vector<StyleDashboardRegion>& styleRegions = style().dashboardRegions();
- for (const auto& styleRegion : styleRegions) {
- LayoutUnit w = box.width();
- LayoutUnit h = box.height();
+ unsigned i, count = styleRegions.size();
+ for (i = 0; i < count; i++) {
+ StyleDashboardRegion styleRegion = styleRegions[i];
+
+ LayoutUnit w = box->width();
+ LayoutUnit h = box->height();
AnnotatedRegionValue region;
region.label = styleRegion.label;
@@ -1942,15 +2188,42 @@ void RenderObject::collectAnnotatedRegions(Vector<AnnotatedRegionValue>& regions
{
// RenderTexts don't have their own style, they just use their parent's style,
// so we don't want to include them.
- if (is<RenderText>(*this))
+ if (isText())
return;
addAnnotatedRegions(regions);
- for (RenderObject* current = downcast<RenderElement>(*this).firstChild(); current; current = current->nextSibling())
- current->collectAnnotatedRegions(regions);
+ for (RenderObject* curr = toRenderElement(this)->firstChild(); curr; curr = curr->nextSibling())
+ curr->collectAnnotatedRegions(regions);
}
#endif
+bool RenderObject::willRenderImage(CachedImage*)
+{
+ // Without visibility we won't render (and therefore don't care about animation).
+ if (style().visibility() != VISIBLE)
+ return false;
+
+#if PLATFORM(IOS)
+ if (document().frame()->timersPaused())
+ return false;
+#else
+ // We will not render a new image when Active DOM is suspended
+ if (document().activeDOMObjectsAreSuspended())
+ return false;
+#endif
+
+ // If we're not in a window (i.e., we're dormant from being put in the b/f cache or in a background tab)
+ // then we don't want to render either.
+ return !document().inPageCache() && !document().view()->isOffscreen();
+}
+
+int RenderObject::maximalOutlineSize(PaintPhase p) const
+{
+ if (p != PaintPhaseOutline && p != PaintPhaseSelfOutline && p != PaintPhaseChildOutlines)
+ return 0;
+ return view().maximalOutlineSize();
+}
+
int RenderObject::caretMinOffset() const
{
return 0;
@@ -1959,7 +2232,7 @@ int RenderObject::caretMinOffset() const
int RenderObject::caretMaxOffset() const
{
if (isReplaced())
- return node() ? std::max(1U, node()->countChildNodes()) : 1;
+ return node() ? std::max(1U, node()->childNodeCount()) : 1;
if (isHR())
return 1;
return 0;
@@ -1982,14 +2255,20 @@ int RenderObject::nextOffset(int current) const
void RenderObject::adjustRectForOutlineAndShadow(LayoutRect& rect) const
{
- LayoutUnit outlineSize = outlineStyleForRepaint().outlineSize();
+ int outlineSize = outlineStyleForRepaint().outlineSize();
if (const ShadowData* boxShadow = style().boxShadow()) {
boxShadow->adjustRectForShadow(rect, outlineSize);
return;
}
+
rect.inflate(outlineSize);
}
+AnimationController& RenderObject::animation() const
+{
+ return frame().animation();
+}
+
void RenderObject::imageChanged(CachedImage* image, const IntRect* rect)
{
imageChanged(static_cast<WrappedImagePtr>(image), rect);
@@ -2001,8 +2280,8 @@ RenderBoxModelObject* RenderObject::offsetParent() const
// A is the root element.
// A is the HTML body element.
// The computed value of the position property for element A is fixed.
- if (isDocumentElementRenderer() || isBody() || (isOutOfFlowPositioned() && style().position() == FixedPosition))
- return nullptr;
+ if (isRoot() || isBody() || (isOutOfFlowPositioned() && style().position() == FixedPosition))
+ return 0;
// If A is an area HTML element which has a map HTML element somewhere in the ancestor
// chain return the nearest ancestor map HTML element and stop this algorithm.
@@ -2018,26 +2297,24 @@ RenderBoxModelObject* RenderObject::offsetParent() const
bool skipTables = isPositioned();
float currZoom = style().effectiveZoom();
- auto current = parent();
- while (current && (!current->element() || (!current->isPositioned() && !current->isBody())) && !is<RenderNamedFlowThread>(*current)) {
- Element* element = current->element();
- if (!skipTables && element && (is<HTMLTableElement>(*element) || is<HTMLTableCellElement>(*element)))
+ auto curr = parent();
+ while (curr && (!curr->element() || (!curr->isPositioned() && !curr->isBody())) && !curr->isRenderNamedFlowThread()) {
+ Element* element = curr->element();
+ if (!skipTables && element && (isHTMLTableElement(element) || element->hasTagName(tdTag) || element->hasTagName(thTag)))
break;
- float newZoom = current->style().effectiveZoom();
+ float newZoom = curr->style().effectiveZoom();
if (currZoom != newZoom)
break;
currZoom = newZoom;
- current = current->parent();
+ curr = curr->parent();
}
// CSS regions specification says that region flows should return the body element as their offsetParent.
- if (is<RenderNamedFlowThread>(current)) {
- auto* body = document().bodyOrFrameset();
- current = body ? body->renderer() : nullptr;
- }
+ if (curr && curr->isRenderNamedFlowThread())
+ curr = document().body() ? document().body()->renderer() : 0;
- return is<RenderBoxModelObject>(current) ? downcast<RenderBoxModelObject>(current) : nullptr;
+ return curr && curr->isBoxModelObject() ? toRenderBoxModelObject(curr) : 0;
}
VisiblePosition RenderObject::createVisiblePosition(int offset, EAffinity affinity) const
@@ -2128,7 +2405,20 @@ bool RenderObject::canHaveGeneratedChildren() const
Node* RenderObject::generatingPseudoHostElement() const
{
- return downcast<PseudoElement>(*node()).hostElement();
+ return toPseudoElement(node())->hostElement();
+}
+
+bool RenderObject::canBeReplacedWithInlineRunIn() const
+{
+ return true;
+}
+
+#if ENABLE(SVG)
+
+RenderSVGResourceContainer* RenderObject::toRenderSVGResourceContainer()
+{
+ ASSERT_NOT_REACHED();
+ return 0;
}
void RenderObject::setNeedsBoundariesUpdate()
@@ -2175,144 +2465,37 @@ bool RenderObject::nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const
return false;
}
-RenderNamedFlowFragment* RenderObject::currentRenderNamedFlowFragment() const
-{
- RenderFlowThread* flowThread = flowThreadContainingBlock();
- if (!is<RenderNamedFlowThread>(flowThread))
- return nullptr;
-
- // FIXME: Once regions are fully integrated with the compositing system we should uncomment this assert.
- // This assert needs to be disabled because it's possible to ask for the ancestor clipping rectangle of
- // a layer without knowing the containing region in advance.
- // ASSERT(flowThread->currentRegion() && flowThread->currentRegion()->isRenderNamedFlowFragment());
-
- return downcast<RenderNamedFlowFragment>(flowThread->currentRegion());
-}
-
-RenderFlowThread* RenderObject::locateFlowThreadContainingBlock() const
-{
- RenderBlock* containingBlock = this->containingBlock();
- return containingBlock ? containingBlock->flowThreadContainingBlock() : nullptr;
-}
-
-void RenderObject::calculateBorderStyleColor(const EBorderStyle& style, const BoxSide& side, Color& color)
-{
- ASSERT(style == INSET || style == OUTSET);
- // This values were derived empirically.
- const RGBA32 baseDarkColor = 0xFF202020;
- const RGBA32 baseLightColor = 0xFFEBEBEB;
- enum Operation { Darken, Lighten };
+#endif // ENABLE(SVG)
- Operation operation = (side == BSTop || side == BSLeft) == (style == INSET) ? Darken : Lighten;
-
- // Here we will darken the border decoration color when needed. This will yield a similar behavior as in FF.
- if (operation == Darken) {
- if (differenceSquared(color, Color::black) > differenceSquared(baseDarkColor, Color::black))
- color = color.dark();
- } else {
- if (differenceSquared(color, Color::white) > differenceSquared(baseLightColor, Color::white))
- color = color.light();
- }
-}
-
-void RenderObject::setIsDragging(bool isDragging)
-{
- if (isDragging || hasRareData())
- ensureRareData().setIsDragging(isDragging);
-}
-
-void RenderObject::setHasReflection(bool hasReflection)
-{
- if (hasReflection || hasRareData())
- ensureRareData().setHasReflection(hasReflection);
-}
-
-void RenderObject::setIsRenderFlowThread(bool isFlowThread)
-{
- if (isFlowThread || hasRareData())
- ensureRareData().setIsRenderFlowThread(isFlowThread);
-}
-
-void RenderObject::setHasOutlineAutoAncestor(bool hasOutlineAutoAncestor)
-{
- if (hasOutlineAutoAncestor || hasRareData())
- ensureRareData().setHasOutlineAutoAncestor(hasOutlineAutoAncestor);
-}
-
-void RenderObject::setIsRegisteredForVisibleInViewportCallback(bool registered)
-{
- if (registered || hasRareData())
- ensureRareData().setIsRegisteredForVisibleInViewportCallback(registered);
-}
-
-void RenderObject::setVisibleInViewportState(VisibleInViewportState visible)
-{
- if (visible != VisibilityUnknown || hasRareData())
- ensureRareData().setVisibleInViewportState(visible);
-}
+} // namespace WebCore
-RenderObject::RareDataHash& RenderObject::rareDataMap()
-{
- static NeverDestroyed<RareDataHash> map;
- return map;
-}
+#ifndef NDEBUG
-RenderObject::RenderObjectRareData RenderObject::rareData() const
+void showTree(const WebCore::RenderObject* object)
{
- if (!hasRareData())
- return RenderObjectRareData();
-
- return rareDataMap().get(this);
+ if (object)
+ object->showTreeForThis();
}
-RenderObject::RenderObjectRareData& RenderObject::ensureRareData()
+void showLineTree(const WebCore::RenderObject* object)
{
- setHasRareData(true);
- return rareDataMap().add(this, RenderObjectRareData()).iterator->value;
+ if (object)
+ object->showLineTreeForThis();
}
-void RenderObject::removeRareData()
+void showRenderTree(const WebCore::RenderObject* object1)
{
- rareDataMap().remove(this);
- setHasRareData(false);
+ showRenderTree(object1, 0);
}
-#ifndef NDEBUG
-void printRenderTreeForLiveDocuments()
+void showRenderTree(const WebCore::RenderObject* object1, const WebCore::RenderObject* object2)
{
- for (const auto* document : Document::allDocuments()) {
- if (!document->renderView() || document->inPageCache())
- continue;
- if (document->frame() && document->frame()->isMainFrame())
- fprintf(stderr, "----------------------main frame--------------------------\n");
- fprintf(stderr, "%s", document->url().string().utf8().data());
- showRenderTree(document->renderView());
+ if (object1) {
+ const WebCore::RenderObject* root = object1;
+ while (root->parent())
+ root = root->parent();
+ root->showRenderTreeAndMark(object1, "*", object2, "-", 0);
}
}
-#endif
-} // namespace WebCore
-
-#if ENABLE(TREE_DEBUGGING)
-
-void showNodeTree(const WebCore::RenderObject* object)
-{
- if (!object)
- return;
- object->showNodeTreeForThis();
-}
-
-void showLineTree(const WebCore::RenderObject* object)
-{
- if (!object)
- return;
- object->showLineTreeForThis();
-}
-
-void showRenderTree(const WebCore::RenderObject* object)
-{
- if (!object)
- return;
- object->showRenderTreeForThis();
-}
#endif