summaryrefslogtreecommitdiff
path: root/Source/WebCore/rendering/RenderObject.cpp
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@digia.com>2013-09-13 12:51:20 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-09-19 20:50:05 +0200
commitd441d6f39bb846989d95bcf5caf387b42414718d (patch)
treee367e64a75991c554930278175d403c072de6bb8 /Source/WebCore/rendering/RenderObject.cpp
parent0060b2994c07842f4c59de64b5e3e430525c4b90 (diff)
downloadqtwebkit-d441d6f39bb846989d95bcf5caf387b42414718d.tar.gz
Import Qt5x2 branch of QtWebkit for Qt 5.2
Importing a new snapshot of webkit. Change-Id: I2d01ad12cdc8af8cb015387641120a9d7ea5f10c Reviewed-by: Allan Sandfeld Jensen <allan.jensen@digia.com>
Diffstat (limited to 'Source/WebCore/rendering/RenderObject.cpp')
-rw-r--r--Source/WebCore/rendering/RenderObject.cpp608
1 files changed, 387 insertions, 221 deletions
diff --git a/Source/WebCore/rendering/RenderObject.cpp b/Source/WebCore/rendering/RenderObject.cpp
index 17bdafb54..b93764828 100644
--- a/Source/WebCore/rendering/RenderObject.cpp
+++ b/Source/WebCore/rendering/RenderObject.cpp
@@ -28,19 +28,23 @@
#include "RenderObject.h"
#include "AXObjectCache.h"
-#include "Chrome.h"
+#include "AnimationController.h"
#include "ContentData.h"
#include "CursorList.h"
-#include "DashArray.h"
-#include "EditingBoundary.h"
+#include "EventHandler.h"
#include "FloatQuad.h"
#include "FlowThreadController.h"
#include "Frame.h"
+#include "FrameSelection.h"
#include "FrameView.h"
#include "GraphicsContext.h"
+#include "HTMLAnchorElement.h"
#include "HTMLElement.h"
+#include "HTMLImageElement.h"
#include "HTMLNames.h"
+#include "HTMLTableElement.h"
#include "HitTestResult.h"
+#include "LogicalSelectionOffsetCaches.h"
#include "Page.h"
#include "RenderArena.h"
#include "RenderCounter.h"
@@ -52,6 +56,7 @@
#include "RenderImageResourceStyleImage.h"
#include "RenderInline.h"
#include "RenderLayer.h"
+#include "RenderLayerBacking.h"
#include "RenderListItem.h"
#include "RenderMultiColumnBlock.h"
#include "RenderNamedFlowThread.h"
@@ -70,9 +75,8 @@
#include "TransformState.h"
#include "htmlediting.h"
#include <algorithm>
-#include <stdio.h>
#include <wtf/RefCountedLeakCounter.h>
-#include <wtf/UnusedParam.h>
+#include <wtf/StackStats.h>
#if USE(ACCELERATED_COMPOSITING)
#include "RenderLayerCompositor.h"
@@ -92,11 +96,11 @@ using namespace HTMLNames;
#ifndef NDEBUG
static void* baseOfRenderObjectBeingDeleted;
-RenderObject::SetLayoutNeededForbiddenScope::SetLayoutNeededForbiddenScope(RenderObject* renderObject)
+RenderObject::SetLayoutNeededForbiddenScope::SetLayoutNeededForbiddenScope(RenderObject* renderObject, bool isForbidden)
: m_renderObject(renderObject)
, m_preexistingForbidden(m_renderObject->isSetNeedsLayoutForbidden())
{
- m_renderObject->setNeedsLayoutIsForbidden(true);
+ m_renderObject->setNeedsLayoutIsForbidden(isForbidden);
}
RenderObject::SetLayoutNeededForbiddenScope::~SetLayoutNeededForbiddenScope()
@@ -116,7 +120,30 @@ struct SameSizeAsRenderObject {
COMPILE_ASSERT(sizeof(RenderObject) == sizeof(SameSizeAsRenderObject), RenderObject_should_stay_small);
+// On low-powered/mobile devices, preventing blitting on a scroll can cause noticeable delays
+// when scrolling a page with a fixed background image. As an optimization, assuming there are
+// no fixed positoned elements on the page, we can acclerate scrolling (via blitting) if we
+// ignore the CSS property "background-attachment: fixed".
+static bool shouldRepaintFixedBackgroundsOnScroll(FrameView* frameView)
+{
+#if !ENABLE(FAST_MOBILE_SCROLLING) && !PLATFORM(QT)
+ UNUSED_PARAM(frameView);
+#endif
+
+ bool repaintFixedBackgroundsOnScroll = true;
+#if ENABLE(FAST_MOBILE_SCROLLING)
+#if PLATFORM(QT)
+ if (frameView->delegatesScrolling())
+ repaintFixedBackgroundsOnScroll = false;
+#else
+ repaintFixedBackgroundsOnScroll = false;
+#endif
+#endif
+ return repaintFixedBackgroundsOnScroll;
+}
+
bool RenderObject::s_affectsParentBlock = false;
+bool RenderObject::s_noLongerAffectsParentBlock = false;
RenderObjectAncestorLineboxDirtySet* RenderObject::s_ancestorLineboxDirtySet = 0;
@@ -133,17 +160,17 @@ void RenderObject::operator delete(void* ptr, size_t sz)
*(size_t *)ptr = sz;
}
-RenderObject* RenderObject::createObject(Node* node, RenderStyle* style)
+RenderObject* RenderObject::createObject(Element* element, RenderStyle* style)
{
- Document* doc = node->document();
+ Document* doc = element->document();
RenderArena* arena = doc->renderArena();
// Minimal support for content properties replacing an entire element.
// Works only if we have exactly one piece of content and it's a URL.
// Otherwise acts as if we didn't support this feature.
const ContentData* contentData = style->contentData();
- if (contentData && !contentData->next() && contentData->isImage() && doc != node) {
- RenderImage* image = new (arena) RenderImage(node);
+ if (contentData && !contentData->next() && contentData->isImage() && !element->isPseudoElement()) {
+ RenderImage* image = new (arena) RenderImage(element);
// RenderImageResourceStyleImage requires a style being present on the image but we don't want to
// trigger a style change now as the node is not fully attached. Moving this code to style change
// doesn't make sense as it should be run once at renderer creation.
@@ -157,56 +184,56 @@ RenderObject* RenderObject::createObject(Node* node, RenderStyle* style)
return image;
}
- if (node->hasTagName(rubyTag)) {
+ if (element->hasTagName(rubyTag)) {
if (style->display() == INLINE)
- return new (arena) RenderRubyAsInline(node);
+ return new (arena) RenderRubyAsInline(element);
else if (style->display() == BLOCK)
- return new (arena) RenderRubyAsBlock(node);
+ return new (arena) RenderRubyAsBlock(element);
}
// treat <rt> as ruby text ONLY if it still has its default treatment of block
- if (node->hasTagName(rtTag) && style->display() == BLOCK)
- return new (arena) RenderRubyText(node);
+ if (element->hasTagName(rtTag) && style->display() == BLOCK)
+ return new (arena) RenderRubyText(element);
if (doc->cssRegionsEnabled() && style->isDisplayRegionType() && !style->regionThread().isEmpty() && doc->renderView())
- return new (arena) RenderRegion(node, 0);
+ return new (arena) RenderRegion(element, 0);
switch (style->display()) {
case NONE:
return 0;
case INLINE:
- return new (arena) RenderInline(node);
+ return new (arena) RenderInline(element);
case BLOCK:
case INLINE_BLOCK:
case RUN_IN:
case COMPACT:
if ((!style->hasAutoColumnCount() || !style->hasAutoColumnWidth()) && doc->regionBasedColumnsEnabled())
- return new (arena) RenderMultiColumnBlock(node);
- return new (arena) RenderBlock(node);
+ return new (arena) RenderMultiColumnBlock(element);
+ return new (arena) RenderBlock(element);
case LIST_ITEM:
- return new (arena) RenderListItem(node);
+ return new (arena) RenderListItem(element);
case TABLE:
case INLINE_TABLE:
- return new (arena) RenderTable(node);
+ return new (arena) RenderTable(element);
case TABLE_ROW_GROUP:
case TABLE_HEADER_GROUP:
case TABLE_FOOTER_GROUP:
- return new (arena) RenderTableSection(node);
+ return new (arena) RenderTableSection(element);
case TABLE_ROW:
- return new (arena) RenderTableRow(node);
+ return new (arena) RenderTableRow(element);
case TABLE_COLUMN_GROUP:
case TABLE_COLUMN:
- return new (arena) RenderTableCol(node);
+ return new (arena) RenderTableCol(element);
case TABLE_CELL:
- return new (arena) RenderTableCell(node);
+ return new (arena) RenderTableCell(element);
case TABLE_CAPTION:
- return new (arena) RenderTableCaption(node);
+ return new (arena) RenderTableCaption(element);
case BOX:
case INLINE_BOX:
- return new (arena) RenderDeprecatedFlexibleBox(node);
+ return new (arena) RenderDeprecatedFlexibleBox(element);
case FLEX:
case INLINE_FLEX:
- return new (arena) RenderFlexibleBox(node);
+ return new (arena) RenderFlexibleBox(element);
case GRID:
case INLINE_GRID:
- return new (arena) RenderGrid(node);
+ return new (arena) RenderGrid(element);
}
return 0;
@@ -230,7 +257,6 @@ RenderObject::RenderObject(Node* node)
#ifndef NDEBUG
renderObjectCounter.increment();
#endif
- ASSERT(node);
}
RenderObject::~RenderObject()
@@ -277,6 +303,19 @@ bool RenderObject::isHTMLMarquee() const
return node() && node()->renderer() == this && node()->hasTagName(marqueeTag);
}
+void RenderObject::setFlowThreadStateIncludingDescendants(FlowThreadState state)
+{
+ setFlowThreadState(state);
+
+ for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
+ // If the child is a fragmentation context it already updated the descendants flag accordingly.
+ if (child->isRenderFlowThread())
+ continue;
+ ASSERT(state != child->flowThreadState());
+ child->setFlowThreadStateIncludingDescendants(state);
+ }
+}
+
void RenderObject::addChild(RenderObject* newChild, RenderObject* beforeChild)
{
RenderObjectChildList* children = virtualChildren();
@@ -444,7 +483,7 @@ static void addLayers(RenderObject* obj, RenderLayer* parentLayer, RenderObject*
{
if (obj->hasLayer()) {
if (!beforeChild && newObject) {
- // We need to figure out the layer that follows newObject. We only do
+ // We need to figure out the layer that follows newObject. We only do
// this the first time we find a child layer, and then we update the
// pointer values for newObject and beforeChild used by everyone else.
beforeChild = newObject->parent()->findNextLayer(parentLayer, newObject);
@@ -503,7 +542,7 @@ void RenderObject::moveLayers(RenderLayer* oldParent, RenderLayer* newParent)
RenderLayer* RenderObject::findNextLayer(RenderLayer* parentLayer, RenderObject* startPoint,
bool checkParent)
{
- // Error check the parent layer passed in. If it's null, we can't find anything.
+ // Error check the parent layer passed in. If it's null, we can't find anything.
if (!parentLayer)
return 0;
@@ -523,7 +562,7 @@ RenderLayer* RenderObject::findNextLayer(RenderLayer* parentLayer, RenderObject*
}
}
- // Step 3: If our layer is the desired parent layer, then we're finished. We didn't
+ // Step 3: If our layer is the desired parent layer, then we're finished. We didn't
// find anything.
if (parentLayer == ourLayer)
return 0;
@@ -584,11 +623,10 @@ RenderBoxModelObject* RenderObject::enclosingBoxModelObject() const
return 0;
}
-RenderFlowThread* RenderObject::enclosingRenderFlowThread() const
-{
- if (!inRenderFlowThread())
- return 0;
-
+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)
@@ -599,7 +637,7 @@ RenderFlowThread* RenderObject::enclosingRenderFlowThread() const
while (curr) {
if (curr->isRenderFlowThread())
return toRenderFlowThread(curr);
- curr = curr->parent();
+ curr = curr->containingBlock();
}
return 0;
}
@@ -645,6 +683,7 @@ static inline bool objectIsRelayoutBoundary(const RenderObject* object)
void RenderObject::markContainingBlocksForLayout(bool scheduleRelayout, RenderObject* newRoot)
{
ASSERT(!scheduleRelayout || !newRoot);
+ ASSERT(!isSetNeedsLayoutForbidden());
RenderObject* object = container();
RenderObject* last = this;
@@ -652,6 +691,11 @@ void RenderObject::markContainingBlocksForLayout(bool scheduleRelayout, RenderOb
bool simplifiedNormalFlowLayout = needsSimplifiedNormalFlowLayout() && !selfNeedsLayout() && !normalChildNeedsLayout();
while (object) {
+#ifndef NDEBUG
+ // FIXME: Remove this once we remove the special cases for counters, quotes and mathml
+ // calling setNeedsLayout during preferred width computation.
+ SetLayoutNeededForbiddenScope layoutForbiddenScope(object, isSetNeedsLayoutForbidden());
+#endif
// Don't mark the outermost object of an unrooted subtree. That object will be
// marked when the subtree is added to the document.
RenderObject* container = object->container();
@@ -750,56 +794,13 @@ RenderBlock* RenderObject::containingBlock() const
RenderObject* o = parent();
if (!o && isRenderScrollbarPart())
o = toRenderScrollbarPart(this)->rendererOwningScrollbar();
- if (!isText() && m_style->position() == FixedPosition) {
- while (o) {
- if (o->isRenderView())
- break;
- if (o->hasTransform() && o->isRenderBlock())
- break;
- // The render flow thread is the top most containing block
- // for the fixed positioned elements.
- if (o->isRenderFlowThread())
- break;
-#if ENABLE(SVG)
- // foreignObject is the containing block for its contents.
- if (o->isSVGForeignObject())
- break;
-#endif
- o = o->parent();
- }
- ASSERT(!o->isAnonymousBlock());
- } else if (!isText() && m_style->position() == AbsolutePosition) {
- while (o) {
- // For relpositioned inlines, we return the nearest non-anonymous enclosing block. We don't try
- // to return the inline itself. This allows us to avoid having a positioned objects
- // list in all RenderInlines and lets us return a strongly-typed RenderBlock* result
- // from this method. The container() method can actually be used to obtain the
- // inline directly.
- if (!o->style()->position() == StaticPosition && !(o->isInline() && !o->isReplaced()))
- break;
- if (o->isRenderView())
- break;
- if (o->hasTransform() && o->isRenderBlock())
- break;
- if (o->style()->hasInFlowPosition() && o->isInline() && !o->isReplaced()) {
- o = o->containingBlock();
- break;
- }
-#if ENABLE(SVG)
- if (o->isSVGForeignObject()) //foreignObject is the containing block for contents inside it
- break;
-#endif
-
- o = o->parent();
- }
-
- while (o && o->isAnonymousBlock())
- o = o->containingBlock();
- } else {
- while (o && ((o->isInline() && !o->isReplaced()) || !o->isRenderBlock()))
- o = o->parent();
- }
+ if (!isText() && m_style->position() == FixedPosition)
+ o = containingBlockForFixedPosition(o);
+ else if (!isText() && m_style->position() == AbsolutePosition)
+ o = containingBlockForAbsolutePosition(o);
+ else
+ o = containingBlockForObjectInFlow(o);
if (!o || !o->isRenderBlock())
return 0; // This can still happen in case of an orphaned tree
@@ -821,10 +822,19 @@ static bool mustRepaintFillLayers(const RenderObject* renderer, const FillLayer*
if (!layer->xPosition().isZero() || !layer->yPosition().isZero())
return true;
- if (layer->size().type == SizeLength) {
- if (layer->size().size.width().isPercent() || layer->size().size.height().isPercent())
+ EFillSizeType sizeType = layer->sizeType();
+
+ if (sizeType == Contain || sizeType == Cover)
+ return true;
+
+ if (sizeType == SizeLength) {
+ LengthSize size = layer->sizeLength();
+ if (size.width().isPercent() || size.height().isPercent())
return true;
- } else if (layer->size().type == Contain || layer->size().type == Cover || img->usesImageContainerSize())
+ // If the image has neither an intrinsic width nor an intrinsic height, its size is determined as for 'contain'.
+ if ((size.width().isAuto() || size.height().isAuto()) && img->isGeneratedImage())
+ return true;
+ } else if (img->usesImageContainerSize())
return true;
return false;
@@ -885,14 +895,13 @@ void RenderObject::drawLineForBoxSide(GraphicsContext* graphicsContext, int x1,
return;
case DOTTED:
case DASHED: {
- graphicsContext->setStrokeColor(color, m_style->colorSpace());
- graphicsContext->setStrokeThickness(thickness);
- StrokeStyle oldStrokeStyle = graphicsContext->strokeStyle();
- graphicsContext->setStrokeStyle(style == DASHED ? DashedStroke : DottedStroke);
-
if (thickness > 0) {
bool wasAntialiased = graphicsContext->shouldAntialias();
+ StrokeStyle oldStrokeStyle = graphicsContext->strokeStyle();
graphicsContext->setShouldAntialias(antialias);
+ graphicsContext->setStrokeColor(color, m_style->colorSpace());
+ graphicsContext->setStrokeThickness(thickness);
+ graphicsContext->setStrokeStyle(style == DASHED ? DashedStroke : DottedStroke);
switch (side) {
case BSBottom:
@@ -1086,14 +1095,14 @@ void RenderObject::drawLineForBoxSide(GraphicsContext* graphicsContext, int x1,
}
}
-void RenderObject::paintFocusRing(GraphicsContext* context, const LayoutPoint& paintOffset, RenderStyle* style)
+void RenderObject::paintFocusRing(PaintInfo& paintInfo, const LayoutPoint& paintOffset, RenderStyle* style)
{
Vector<IntRect> focusRingRects;
- addFocusRingRects(focusRingRects, paintOffset);
+ addFocusRingRects(focusRingRects, paintOffset, paintInfo.paintContainer);
if (style->outlineStyleIsAuto())
- context->drawFocusRing(focusRingRects, style->outlineWidth(), style->outlineOffset(), style->visitedDependentColor(CSSPropertyOutlineColor));
+ paintInfo.context->drawFocusRing(focusRingRects, style->outlineWidth(), style->outlineOffset(), style->visitedDependentColor(CSSPropertyOutlineColor));
else
- addPDFURLRect(context, unionRect(focusRingRects));
+ addPDFURLRect(paintInfo.context, unionRect(focusRingRects));
}
void RenderObject::addPDFURLRect(GraphicsContext* context, const LayoutRect& rect)
@@ -1103,29 +1112,26 @@ void RenderObject::addPDFURLRect(GraphicsContext* context, const LayoutRect& rec
Node* n = node();
if (!n || !n->isLink() || !n->isElementNode())
return;
- const AtomicString& href = static_cast<Element*>(n)->getAttribute(hrefAttr);
+ const AtomicString& href = toElement(n)->getAttribute(hrefAttr);
if (href.isNull())
return;
context->setURLForRect(n->document()->completeURL(href), pixelSnappedIntRect(rect));
}
-void RenderObject::paintOutline(GraphicsContext* graphicsContext, const LayoutRect& paintRect)
+void RenderObject::paintOutline(PaintInfo& paintInfo, const LayoutRect& paintRect)
{
if (!hasOutline())
return;
RenderStyle* styleToUse = style();
LayoutUnit outlineWidth = styleToUse->outlineWidth();
- EBorderStyle outlineStyle = styleToUse->outlineStyle();
-
- Color outlineColor = styleToUse->visitedDependentColor(CSSPropertyOutlineColor);
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(graphicsContext, paintRect.location(), styleToUse);
+ paintFocusRing(paintInfo, paintRect.location(), styleToUse);
}
}
@@ -1142,6 +1148,10 @@ void RenderObject::paintOutline(GraphicsContext* graphicsContext, const LayoutRe
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) {
@@ -1214,11 +1224,11 @@ void RenderObject::absoluteFocusRingQuads(Vector<FloatQuad>& quads)
// descendants.
FloatPoint absolutePoint = localToAbsolute();
addFocusRingRects(rects, flooredLayoutPoint(absolutePoint));
- size_t count = rects.size();
+ 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), SnapOffsetForTransforms));
+ quads.append(localToAbsoluteQuad(FloatQuad(rect)));
}
}
@@ -1233,9 +1243,12 @@ FloatRect RenderObject::absoluteBoundingBoxRectForRange(const Range* range)
Vector<FloatQuad> quads;
range->textQuads(quads);
- FloatRect result;
- for (size_t i = 0; i < quads.size(); ++i)
- result.unite(quads[i].boundingBox());
+ if (quads.isEmpty())
+ return FloatRect();
+
+ FloatRect result = quads[0].boundingBox();
+ for (size_t i = 1; i < quads.size(); ++i)
+ result.uniteEvenIfEmpty(quads[i].boundingBox());
return result;
}
@@ -1248,6 +1261,7 @@ void RenderObject::addAbsoluteRectForLayer(LayoutRect& result)
current->addAbsoluteRectForLayer(result);
}
+// FIXME: change this to use the subtreePaint terminology
LayoutRect RenderObject::paintingRootRect(LayoutRect& topLevelRect)
{
LayoutRect result = absoluteBoundingBoxRectIgnoringTransforms();
@@ -1292,11 +1306,16 @@ RenderLayerModelObject* RenderObject::containerForRepaint() const
// 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
// repainting to do individual region repaints.
- if (inRenderFlowThread()) {
- RenderFlowThread* parentRenderFlowThread = enclosingRenderFlowThread();
+ RenderFlowThread* parentRenderFlowThread = flowThreadContainingBlock();
+ if (parentRenderFlowThread) {
+ // 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.
- if (!(repaintContainer && repaintContainer->inRenderFlowThread() && repaintContainer->enclosingRenderFlowThread() == parentRenderFlowThread))
+ RenderFlowThread* repaintContainerFlowThread = repaintContainer ? repaintContainer->flowThreadContainingBlock() : 0;
+ if (!repaintContainerFlowThread || repaintContainerFlowThread != parentRenderFlowThread)
repaintContainer = parentRenderFlowThread;
}
return repaintContainer;
@@ -1327,10 +1346,7 @@ void RenderObject::repaintUsingContainer(const RenderLayerModelObject* repaintCo
ASSERT(repaintContainer == v);
bool viewHasCompositedLayer = v->hasLayer() && v->layer()->isComposited();
if (!viewHasCompositedLayer || v->layer()->backing()->paintsIntoWindow()) {
- LayoutRect repaintRectangle = r;
- if (viewHasCompositedLayer && v->layer()->transform())
- repaintRectangle = enclosingIntRect(v->layer()->transform()->mapRect(r));
- v->repaintViewRectangle(repaintRectangle, immediate);
+ v->repaintViewRectangle(viewHasCompositedLayer && v->layer()->transform() ? v->layer()->transform()->mapRect(r) : r, immediate);
return;
}
}
@@ -1496,14 +1512,6 @@ bool RenderObject::repaintAfterLayoutIfNeeded(const RenderLayerModelObject* repa
return false;
}
-void RenderObject::repaintDuringLayoutIfMoved(const LayoutRect&)
-{
-}
-
-void RenderObject::repaintOverhangingFloats(bool)
-{
-}
-
bool RenderObject::checkForRepaintDuringLayout() const
{
return !document()->view()->needsFullRepaint() && !hasLayer() && everHadLayout();
@@ -1623,13 +1631,15 @@ Color RenderObject::selectionBackgroundColor() const
{
Color color;
if (style()->userSelect() != SELECT_NONE) {
- RefPtr<RenderStyle> pseudoStyle = getUncachedPseudoStyle(SELECTION);
- if (pseudoStyle && pseudoStyle->visitedDependentColor(CSSPropertyBackgroundColor).isValid())
- color = pseudoStyle->visitedDependentColor(CSSPropertyBackgroundColor).blendWithWhite();
- else
- color = frame()->selection()->isFocusedAndActive() ?
- theme()->activeSelectionBackgroundColor() :
- theme()->inactiveSelectionBackgroundColor();
+ 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();
+ }
}
return color;
@@ -1644,7 +1654,7 @@ Color RenderObject::selectionColor(int colorProperty) const
|| (frame()->view()->paintBehavior() & PaintBehaviorSelectionOnly))
return color;
- if (RefPtr<RenderStyle> pseudoStyle = getUncachedPseudoStyle(SELECTION)) {
+ if (RefPtr<RenderStyle> pseudoStyle = getUncachedPseudoStyle(PseudoStyleRequest(SELECTION))) {
color = pseudoStyle->visitedDependentColor(colorProperty);
if (!color.isValid())
color = pseudoStyle->visitedDependentColor(CSSPropertyColor);
@@ -1690,6 +1700,30 @@ void RenderObject::handleDynamicFloatPositionChange()
}
}
+void RenderObject::removeAnonymousWrappersForInlinesIfNecessary()
+{
+ // 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();
+ RenderBlock* parentBlock = toRenderBlock(parent());
+ while (curr) {
+ RenderObject* next = curr->nextSibling();
+ if (curr->isAnonymousBlock())
+ parentBlock->collapseAnonymousBoxChild(parentBlock, toRenderBlock(curr));
+ curr = next;
+ }
+}
+
void RenderObject::setAnimatableStyle(PassRefPtr<RenderStyle> style)
{
if (!isText() && style)
@@ -1756,6 +1790,37 @@ StyleDifference RenderObject::adjustStyleDifference(StyleDifference diff, unsign
return diff;
}
+void RenderObject::setPseudoStyle(PassRefPtr<RenderStyle> pseudoStyle)
+{
+ ASSERT(pseudoStyle->styleType() == BEFORE || pseudoStyle->styleType() == AFTER);
+
+ // Images are special and must inherit the pseudoStyle so the width and height of
+ // the pseudo element doesn't change the size of the image. In all other cases we
+ // can just share the style.
+ if (isImage()) {
+ RefPtr<RenderStyle> style = RenderStyle::create();
+ style->inheritFrom(pseudoStyle.get());
+ setStyle(style.release());
+ return;
+ }
+
+ setStyle(pseudoStyle);
+}
+
+inline bool RenderObject::hasImmediateNonWhitespaceTextChild() const
+{
+ for (const RenderObject* r = firstChild(); r; r = r->nextSibling()) {
+ if (r->isText() && !toRenderText(r)->isAllCollapsibleWhitespace())
+ return true;
+ }
+ return false;
+}
+
+inline bool RenderObject::shouldRepaintForStyleDifference(StyleDifference diff) const
+{
+ return diff == StyleDifferenceRepaint || (diff == StyleDifferenceRepaintIfText && hasImmediateNonWhitespaceTextChild());
+}
+
void RenderObject::setStyle(PassRefPtr<RenderStyle> style)
{
if (m_style == style) {
@@ -1809,21 +1874,26 @@ void RenderObject::setStyle(PassRefPtr<RenderStyle> style)
if (updatedDiff == StyleDifferenceLayout)
setNeedsLayoutAndPrefWidthsRecalc();
else if (updatedDiff == StyleDifferenceLayoutPositionedMovementOnly)
- setNeedsPositionedMovementLayout();
+ setNeedsPositionedMovementLayout(oldStyle.get());
else if (updatedDiff == StyleDifferenceSimplifiedLayoutAndPositionedMovement) {
- setNeedsPositionedMovementLayout();
+ setNeedsPositionedMovementLayout(oldStyle.get());
setNeedsSimplifiedNormalFlowLayout();
} else if (updatedDiff == StyleDifferenceSimplifiedLayout)
setNeedsSimplifiedNormalFlowLayout();
}
-
- if (updatedDiff == StyleDifferenceRepaintLayer || updatedDiff == StyleDifferenceRepaint) {
+
+ if (updatedDiff == StyleDifferenceRepaintLayer || shouldRepaintForStyleDifference(updatedDiff)) {
// Do a repaint with the new style now, e.g., for example if we go from
// not having an outline to having an outline.
repaint();
}
}
+static inline bool rendererHasBackground(const RenderObject* renderer)
+{
+ return renderer && renderer->hasBackground();
+}
+
void RenderObject::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
{
if (m_style) {
@@ -1837,8 +1907,10 @@ void RenderObject::styleWillChange(StyleDifference diff, const RenderStyle* newS
if (visibilityChanged)
document()->setAnnotatedRegionsDirty(true);
#endif
- if (visibilityChanged && AXObjectCache::accessibilityEnabled())
- document()->axObjectCache()->childrenChanged(parent());
+ if (visibilityChanged) {
+ if (AXObjectCache* cache = document()->existingAXObjectCache())
+ cache->childrenChanged(parent());
+ }
// Keep layer hierarchy visibility bits up to date if visibility changes.
if (m_style->visibility() != newStyle->visibility()) {
@@ -1854,7 +1926,7 @@ void RenderObject::styleWillChange(StyleDifference diff, const RenderStyle* newS
}
}
- if (m_parent && (diff == StyleDifferenceRepaint || newStyle->outlineSize() < m_style->outlineSize()))
+ if (m_parent && (newStyle->outlineSize() < m_style->outlineSize() || shouldRepaintForStyleDifference(diff)))
repaint();
if (isFloating() && (m_style->floating() != newStyle->floating()))
// For changes in float styles, we need to conceivably remove ourselves
@@ -1869,41 +1941,48 @@ void RenderObject::styleWillChange(StyleDifference diff, const RenderStyle* newS
&& (!newStyle->isFloating() && !newStyle->hasOutOfFlowPosition())
&& parent() && (parent()->isBlockFlow() || parent()->isRenderInline());
+ s_noLongerAffectsParentBlock = ((!isFloating() && newStyle->isFloating()) || (!isOutOfFlowPositioned() && newStyle->hasOutOfFlowPosition()))
+ && parent() && parent()->isRenderBlock();
+
// reset style flags
if (diff == StyleDifferenceLayout || diff == StyleDifferenceLayoutPositionedMovementOnly) {
setFloating(false);
- setPositioned(false);
- setRelPositioned(false);
- setStickyPositioned(false);
+ clearPositionedState();
}
setHorizontalWritingMode(true);
- setPaintBackground(false);
+ setHasBoxDecorations(false);
setHasOverflowClip(false);
setHasTransform(false);
setHasReflection(false);
- } else
+ } else {
s_affectsParentBlock = false;
+ s_noLongerAffectsParentBlock = false;
+ }
- if (view()->frameView()) {
- bool shouldBlitOnFixedBackgroundImage = false;
-#if ENABLE(FAST_MOBILE_SCROLLING)
- // On low-powered/mobile devices, preventing blitting on a scroll can cause noticeable delays
- // when scrolling a page with a fixed background image. As an optimization, assuming there are
- // no fixed positoned elements on the page, we can acclerate scrolling (via blitting) if we
- // ignore the CSS property "background-attachment: fixed".
-#if PLATFORM(QT)
- if (view()->frameView()->delegatesScrolling())
-#endif
- shouldBlitOnFixedBackgroundImage = true;
-#endif
+ if (FrameView* frameView = view()->frameView()) {
+ bool repaintFixedBackgroundsOnScroll = shouldRepaintFixedBackgroundsOnScroll(frameView);
- bool newStyleSlowScroll = newStyle && !shouldBlitOnFixedBackgroundImage && newStyle->hasFixedBackgroundImage();
- bool oldStyleSlowScroll = m_style && !shouldBlitOnFixedBackgroundImage && m_style->hasFixedBackgroundImage();
+ bool newStyleSlowScroll = newStyle && repaintFixedBackgroundsOnScroll && newStyle->hasFixedBackgroundImage();
+ bool oldStyleSlowScroll = m_style && repaintFixedBackgroundsOnScroll && m_style->hasFixedBackgroundImage();
+
+#if USE(ACCELERATED_COMPOSITING)
+ bool drawsRootBackground = isRoot() || (isBody() && !rendererHasBackground(document()->documentElement()->renderer()));
+ if (drawsRootBackground && repaintFixedBackgroundsOnScroll) {
+ if (view()->compositor()->supportsFixedRootBackgroundCompositing()) {
+ if (newStyleSlowScroll && newStyle->hasEntirelyFixedBackground())
+ newStyleSlowScroll = false;
+
+ if (oldStyleSlowScroll && m_style->hasEntirelyFixedBackground())
+ oldStyleSlowScroll = false;
+ }
+ }
+#endif
if (oldStyleSlowScroll != newStyleSlowScroll) {
if (oldStyleSlowScroll)
- view()->frameView()->removeSlowRepaintObject();
+ frameView->removeSlowRepaintObject(this);
+
if (newStyleSlowScroll)
- view()->frameView()->addSlowRepaintObject();
+ frameView->addSlowRepaintObject(this);
}
}
}
@@ -1924,6 +2003,8 @@ void RenderObject::styleDidChange(StyleDifference diff, const RenderStyle* oldSt
if (s_affectsParentBlock)
handleDynamicFloatPositionChange();
+ if (s_noLongerAffectsParentBlock)
+ removeAnonymousWrappersForInlinesIfNecessary();
#if ENABLE(SVG)
SVGRenderSupport::styleChanged(this);
#endif
@@ -1947,17 +2028,17 @@ void RenderObject::styleDidChange(StyleDifference diff, const RenderStyle* oldSt
else
setNeedsSimplifiedNormalFlowLayout();
} else if (diff == StyleDifferenceSimplifiedLayoutAndPositionedMovement) {
- setNeedsPositionedMovementLayout();
+ setNeedsPositionedMovementLayout(oldStyle);
setNeedsSimplifiedNormalFlowLayout();
} else if (diff == StyleDifferenceLayoutPositionedMovementOnly)
- setNeedsPositionedMovementLayout();
+ setNeedsPositionedMovementLayout(oldStyle);
// Don't check for repaint here; we need to wait until the layer has been
// updated by subclasses before we know if we have to repaint (in setStyle()).
if (oldStyle && !areCursorsEqual(oldStyle, style())) {
if (Frame* frame = this->frame())
- frame->eventHandler()->dispatchFakeMouseMoveEventSoon();
+ frame->eventHandler()->scheduleCursorUpdate();
}
}
@@ -2044,6 +2125,14 @@ FloatPoint RenderObject::absoluteToLocal(const FloatPoint& containerPoint, MapCo
return transformState.lastPlanarPoint();
}
+FloatQuad RenderObject::absoluteToLocalQuad(const FloatQuad& quad, MapCoordinatesFlags mode) const
+{
+ TransformState transformState(TransformState::UnapplyInverseTransformDirection, quad.boundingBox().center(), quad);
+ mapAbsoluteToLocalPoint(mode, transformState);
+ transformState.flatten();
+ return transformState.lastPlanarQuad();
+}
+
void RenderObject::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed) const
{
if (repaintContainer == this)
@@ -2170,7 +2259,7 @@ LayoutSize RenderObject::offsetFromContainer(RenderObject* o, const LayoutPoint&
offset -= toRenderBox(o)->scrolledContentOffset();
if (offsetDependsOnPoint)
- *offsetDependsOnPoint = hasColumns();
+ *offsetDependsOnPoint = hasColumns() || o->isRenderFlowThread();
return offset;
}
@@ -2240,11 +2329,11 @@ RespectImageOrientationEnum RenderObject::shouldRespectImageOrientation() const
// 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
-#if USE(CG) || PLATFORM(CHROMIUM) || USE(CAIRO)
+#if USE(CG) || USE(CAIRO) || PLATFORM(BLACKBERRY)
// This can only be enabled for ports which honor the orientation flag in their drawing code.
document()->isImageDocument() ||
#endif
- (document()->settings() && document()->settings()->shouldRespectImageOrientation() && node() && (node()->hasTagName(HTMLNames::imgTag) || node()->hasTagName(HTMLNames::webkitInnerImageTag))) ? RespectImageOrientation : DoNotRespectImageOrientation;
+ (document()->settings() && document()->settings()->shouldRespectImageOrientation() && node() && isHTMLImageElement(node())) ? RespectImageOrientation : DoNotRespectImageOrientation;
}
bool RenderObject::hasOutlineAnnotation() const
@@ -2252,6 +2341,11 @@ bool RenderObject::hasOutlineAnnotation() const
return node() && node()->isLink() && document()->printing();
}
+bool RenderObject::hasEntirelyFixedBackground() const
+{
+ return m_style->hasEntirelyFixedBackground();
+}
+
RenderObject* RenderObject::container(const RenderLayerModelObject* repaintContainer, bool* repaintContainerSkipped) const
{
if (repaintContainerSkipped)
@@ -2289,7 +2383,7 @@ RenderObject* RenderObject::container(const RenderLayerModelObject* repaintConta
#endif
// The render flow thread is the top most containing block
// for the fixed positioned elements.
- if (o->isRenderFlowThread())
+ if (o->isOutOfFlowRenderFlowThread())
break;
if (repaintContainerSkipped && o == repaintContainer)
@@ -2353,14 +2447,22 @@ void RenderObject::willBeDestroyed()
if (frame() && frame()->eventHandler()->autoscrollRenderer() == this)
frame()->eventHandler()->stopAutoscrollTimer(true);
- if (AXObjectCache::accessibilityEnabled()) {
- document()->axObjectCache()->childrenChanged(this->parent());
- document()->axObjectCache()->remove(this);
- }
animation()->cancelAnimations(this);
+ // For accessibility management, notify the parent of the imminent change to its child set.
+ // We do it now, before remove(), while the parent pointer is still available.
+ if (AXObjectCache* cache = document()->existingAXObjectCache())
+ cache->childrenChanged(this->parent());
+
remove();
+ ASSERT(documentBeingDestroyed() || !frame()->view()->hasSlowRepaintObject(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() && view()->hasRenderNamedFlowThreads()) {
// After remove, the object and the associated information should not be in any flow thread.
@@ -2425,6 +2527,14 @@ void RenderObject::willBeRemovedFromTree()
{
// FIXME: We should ASSERT(isRooted()) but we have some out-of-order removals which would need to be fixed first.
+ if (!isText()) {
+ if (FrameView* frameView = view()->frameView()) {
+ bool repaintFixedBackgroundsOnScroll = shouldRepaintFixedBackgroundsOnScroll(frameView);
+ if (repaintFixedBackgroundsOnScroll && m_style && m_style->hasFixedBackgroundImage())
+ frameView->removeSlowRepaintObject(this);
+ }
+ }
+
// If we remove a visible child from an invisible parent, we don't know the layer visibility any more.
RenderLayer* layer = 0;
if (parent()->style()->visibility() != VISIBLE && style()->visibility() == VISIBLE && !hasLayer()) {
@@ -2442,8 +2552,7 @@ void RenderObject::willBeRemovedFromTree()
if (isOutOfFlowPositioned() && parent()->childrenInline())
parent()->dirtyLinesFromChangedChild(this);
- if (inRenderFlowThread())
- removeFromRenderFlowThread();
+ removeFromRenderFlowThread();
if (RenderNamedFlowThread* containerFlowThread = parent()->renderNamedFlowThreadWrapper())
containerFlowThread->removeFlowChild(this);
@@ -2456,13 +2565,14 @@ void RenderObject::willBeRemovedFromTree()
void RenderObject::removeFromRenderFlowThread()
{
- RenderFlowThread* renderFlowThread = enclosingRenderFlowThread();
- ASSERT(renderFlowThread);
- // Sometimes we remove the element from the flow, but it's not destroyed at that time.
+ 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.
// 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.
- removeFromRenderFlowThreadRecursive(renderFlowThread);
+ removeFromRenderFlowThreadRecursive(flowThreadContainingBlock());
}
void RenderObject::removeFromRenderFlowThreadRecursive(RenderFlowThread* renderFlowThread)
@@ -2471,8 +2581,13 @@ void RenderObject::removeFromRenderFlowThreadRecursive(RenderFlowThread* renderF
for (RenderObject* child = children->firstChild(); child; child = child->nextSibling())
child->removeFromRenderFlowThreadRecursive(renderFlowThread);
}
- renderFlowThread->removeFlowChildInfo(this);
- setInRenderFlowThread(false);
+
+ 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()
@@ -2485,9 +2600,9 @@ void RenderObject::destroyAndCleanupAnonymousWrappers()
RenderObject* destroyRoot = this;
for (RenderObject* destroyRootParent = destroyRoot->parent(); destroyRootParent && destroyRootParent->isAnonymous(); destroyRoot = destroyRootParent, destroyRootParent = destroyRootParent->parent()) {
- // Currently we only remove anonymous cells' wrapper but we should remove all unneeded
+ // 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())
+ if (!destroyRootParent->isTableCell() && !destroyRootParent->isTableSection())
break;
if (destroyRootParent->firstChild() != this || destroyRootParent->lastChild() != this)
@@ -2586,11 +2701,19 @@ void RenderObject::updateHitTestResult(HitTestResult& result, const LayoutPoint&
if (result.innerNode())
return;
- Node* n = node();
- if (n) {
- result.setInnerNode(n);
+ Node* node = this->node();
+
+ // 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 (RenderObject* renderer = parent(); renderer && !node; renderer = renderer->parent())
+ node = renderer->node();
+ }
+
+ if (node) {
+ result.setInnerNode(node);
if (!result.innerNonSharedNode())
- result.setInnerNonSharedNode(n);
+ result.setInnerNonSharedNode(node);
result.setLocalPoint(point);
}
}
@@ -2644,7 +2767,7 @@ static PassRefPtr<RenderStyle> firstLineStyleForCachedUncachedType(StyleCacheSta
if (RenderBlock* firstLineBlock = rendererForFirstLineStyle->firstLineBlock()) {
if (type == Cached)
return firstLineBlock->getCachedPseudoStyle(FIRST_LINE, style);
- return firstLineBlock->getUncachedPseudoStyle(FIRST_LINE, style, firstLineBlock == renderer ? style : 0);
+ return firstLineBlock->getUncachedPseudoStyle(PseudoStyleRequest(FIRST_LINE), style, firstLineBlock == renderer ? style : 0);
}
} else if (!rendererForFirstLineStyle->isAnonymous() && rendererForFirstLineStyle->isRenderInline()) {
RenderStyle* parentStyle = rendererForFirstLineStyle->parent()->firstLineStyle();
@@ -2654,7 +2777,7 @@ static PassRefPtr<RenderStyle> firstLineStyleForCachedUncachedType(StyleCacheSta
rendererForFirstLineStyle->style()->setHasPseudoStyle(FIRST_LINE_INHERITED);
return rendererForFirstLineStyle->getCachedPseudoStyle(FIRST_LINE_INHERITED, parentStyle);
}
- return rendererForFirstLineStyle->getUncachedPseudoStyle(FIRST_LINE_INHERITED, parentStyle, style);
+ return rendererForFirstLineStyle->getUncachedPseudoStyle(PseudoStyleRequest(FIRST_LINE_INHERITED), parentStyle, style);
}
}
return 0;
@@ -2689,15 +2812,15 @@ RenderStyle* RenderObject::getCachedPseudoStyle(PseudoId pseudo, RenderStyle* pa
if (cachedStyle)
return cachedStyle;
- RefPtr<RenderStyle> result = getUncachedPseudoStyle(pseudo, parentStyle);
+ RefPtr<RenderStyle> result = getUncachedPseudoStyle(PseudoStyleRequest(pseudo), parentStyle);
if (result)
return style()->addCachedPseudoStyle(result.release());
return 0;
}
-PassRefPtr<RenderStyle> RenderObject::getUncachedPseudoStyle(PseudoId pseudo, RenderStyle* parentStyle, RenderStyle* ownStyle) const
+PassRefPtr<RenderStyle> RenderObject::getUncachedPseudoStyle(const PseudoStyleRequest& pseudoStyleRequest, RenderStyle* parentStyle, RenderStyle* ownStyle) const
{
- if (pseudo < FIRST_INTERNAL_PSEUDOID && !ownStyle && !style()->hasPseudoStyle(pseudo))
+ if (pseudoStyleRequest.pseudoId < FIRST_INTERNAL_PSEUDOID && !ownStyle && !style()->hasPseudoStyle(pseudoStyleRequest.pseudoId))
return 0;
if (!parentStyle) {
@@ -2713,17 +2836,24 @@ PassRefPtr<RenderStyle> RenderObject::getUncachedPseudoStyle(PseudoId pseudo, Re
return 0;
Element* element = toElement(n);
- if (pseudo == FIRST_LINE_INHERITED) {
- RefPtr<RenderStyle> result = document()->styleResolver()->styleForElement(element, parentStyle, DisallowStyleSharing);
+ 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()->styleResolver()->pseudoStyleForElement(pseudo, element, parentStyle);
+
+ return document()->ensureStyleResolver()->pseudoStyleForElement(element, pseudoStyleRequest, parentStyle);
}
static Color decorationColor(RenderStyle* style)
{
Color result;
+#if ENABLE(CSS3_TEXT)
+ // Check for text decoration color first.
+ result = style->visitedDependentColor(CSSPropertyWebkitTextDecorationColor);
+ if (result.isValid())
+ return result;
+#endif // CSS3_TEXT
if (style->textStrokeWidth() > 0) {
// Prefer stroke color if possible but not if it's fully transparent.
result = style->visitedDependentColor(CSSPropertyWebkitTextStrokeColor);
@@ -2740,21 +2870,25 @@ void RenderObject::getTextDecorationColors(int decorations, Color& underline, Co
{
RenderObject* curr = this;
RenderStyle* styleToUse = 0;
+ TextDecoration currDecs = TextDecorationNone;
+ Color resultColor;
do {
styleToUse = curr->style(firstlineStyle);
- int currDecs = styleToUse->textDecoration();
+ currDecs = styleToUse->textDecoration();
+ resultColor = decorationColor(styleToUse);
+ // Parameter 'decorations' is cast as an int to enable the bitwise operations below.
if (currDecs) {
- if (currDecs & UNDERLINE) {
- decorations &= ~UNDERLINE;
- underline = decorationColor(styleToUse);
+ if (currDecs & TextDecorationUnderline) {
+ decorations &= ~TextDecorationUnderline;
+ underline = resultColor;
}
- if (currDecs & OVERLINE) {
- decorations &= ~OVERLINE;
- overline = decorationColor(styleToUse);
+ if (currDecs & TextDecorationOverline) {
+ decorations &= ~TextDecorationOverline;
+ overline = resultColor;
}
- if (currDecs & LINE_THROUGH) {
- decorations &= ~LINE_THROUGH;
- linethrough = decorationColor(styleToUse);
+ if (currDecs & TextDecorationLineThrough) {
+ decorations &= ~TextDecorationLineThrough;
+ linethrough = resultColor;
}
}
if (curr->isRubyText())
@@ -2762,18 +2896,18 @@ void RenderObject::getTextDecorationColors(int decorations, Color& underline, Co
curr = curr->parent();
if (curr && curr->isAnonymousBlock() && toRenderBlock(curr)->continuation())
curr = toRenderBlock(curr)->continuation();
- } while (curr && decorations && (!quirksMode || !curr->node() ||
- (!curr->node()->hasTagName(aTag) && !curr->node()->hasTagName(fontTag))));
+ } 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 && curr) {
styleToUse = curr->style(firstlineStyle);
- if (decorations & UNDERLINE)
- underline = decorationColor(styleToUse);
- if (decorations & OVERLINE)
- overline = decorationColor(styleToUse);
- if (decorations & LINE_THROUGH)
- linethrough = decorationColor(styleToUse);
+ resultColor = decorationColor(styleToUse);
+ if (decorations & TextDecorationUnderline)
+ underline = resultColor;
+ if (decorations & TextDecorationOverline)
+ overline = resultColor;
+ if (decorations & TextDecorationLineThrough)
+ linethrough = resultColor;
}
}
@@ -2910,6 +3044,33 @@ void RenderObject::imageChanged(CachedImage* image, const IntRect* rect)
{
imageChanged(static_cast<WrappedImagePtr>(image), rect);
}
+
+RenderObject* RenderObject::hoverAncestor() const
+{
+ // When searching for the hover ancestor and encountering a named flow thread,
+ // the search will continue with the DOM ancestor of the top-most element
+ // in the named flow thread.
+ // See https://bugs.webkit.org/show_bug.cgi?id=111749
+ RenderObject* hoverAncestor = parent();
+
+ // Skip anonymous blocks directly flowed into flow threads as it would
+ // prevent us from continuing the search on the DOM tree when reaching the named flow thread.
+ if (hoverAncestor && hoverAncestor->isAnonymousBlock() && hoverAncestor->parent() && hoverAncestor->parent()->isRenderNamedFlowThread())
+ hoverAncestor = hoverAncestor->parent();
+
+ if (hoverAncestor && hoverAncestor->isRenderNamedFlowThread()) {
+ hoverAncestor = 0;
+
+ Node* node = this->node();
+ if (node) {
+ Node* domAncestorNode = node->parentNode();
+ if (domAncestorNode)
+ hoverAncestor = domAncestorNode->renderer();
+ }
+ }
+
+ return hoverAncestor;
+}
RenderBoxModelObject* RenderObject::offsetParent() const
{
@@ -2935,24 +3096,29 @@ RenderBoxModelObject* RenderObject::offsetParent() const
bool skipTables = isPositioned();
float currZoom = style()->effectiveZoom();
RenderObject* curr = parent();
- while (curr && (!curr->node() || (!curr->isPositioned() && !curr->isBody()))) {
+ while (curr && (!curr->node() || (!curr->isPositioned() && !curr->isBody())) && !curr->isRenderNamedFlowThread()) {
Node* element = curr->node();
- if (!skipTables && element && (element->hasTagName(tableTag) || element->hasTagName(tdTag) || element->hasTagName(thTag)))
+ if (!skipTables && element && (isHTMLTableElement(element) || element->hasTagName(tdTag) || element->hasTagName(thTag)))
break;
-
+
float newZoom = curr->style()->effectiveZoom();
if (currZoom != newZoom)
break;
currZoom = newZoom;
curr = curr->parent();
}
+
+ // CSS regions specification says that region flows should return the body element as their offsetParent.
+ if (curr && curr->isRenderNamedFlowThread())
+ curr = document()->body() ? document()->body()->renderer() : 0;
+
return curr && curr->isBoxModelObject() ? toRenderBoxModelObject(curr) : 0;
}
VisiblePosition RenderObject::createVisiblePosition(int offset, EAffinity affinity)
{
// If this is a non-anonymous renderer in an editable area, then it's simple.
- if (Node* node = this->node()) {
+ if (Node* node = nonPseudoNode()) {
if (!node->rendererIsEditable()) {
// If it can be found, we prefer a visually equivalent position that is editable.
Position position = createLegacyEditingPosition(node, offset);
@@ -2978,7 +3144,7 @@ VisiblePosition RenderObject::createVisiblePosition(int offset, EAffinity affini
// Find non-anonymous content after.
RenderObject* renderer = child;
while ((renderer = renderer->nextInPreOrder(parent))) {
- if (Node* node = renderer->node())
+ if (Node* node = renderer->nonPseudoNode())
return VisiblePosition(firstPositionInOrBeforeNode(node), DOWNSTREAM);
}
@@ -2987,12 +3153,12 @@ VisiblePosition RenderObject::createVisiblePosition(int offset, EAffinity affini
while ((renderer = renderer->previousInPreOrder())) {
if (renderer == parent)
break;
- if (Node* node = renderer->node())
+ if (Node* node = renderer->nonPseudoNode())
return VisiblePosition(lastPositionInOrAfterNode(node), DOWNSTREAM);
}
// Use the parent itself unless it too is anonymous.
- if (Node* node = parent->node())
+ if (Node* node = parent->nonPseudoNode())
return VisiblePosition(firstPositionInOrBeforeNode(node), DOWNSTREAM);
// Repeat at the next level up.