Commit 3ab7ef3a authored by antti@apple.com's avatar antti@apple.com
Browse files

Tighten typing in inline rendering

https://bugs.webkit.org/show_bug.cgi?id=122076

Reviewed by Andreas Kling.
        
More RenderElement, const, &, etc.

* dom/Position.cpp:
(WebCore::Position::hasRenderedNonAnonymousDescendantsWithHeight):
* rendering/InlineFlowBox.cpp:
(WebCore::isLastChildForRenderer):
(WebCore::isAncestorAndWithinBlock):
(WebCore::InlineFlowBox::determineSpacingForFlowBoxes):
(WebCore::InlineFlowBox::nodeAtPoint):
* rendering/InlineIterator.h:
(WebCore::InlineIterator::InlineIterator):
(WebCore::InlineIterator::root):
(WebCore::isEmptyInline):
(WebCore::bidiNextShared):
(WebCore::bidiNextSkippingEmptyInlines):
(WebCore::bidiNextIncludingEmptyInlines):
(WebCore::bidiFirstSkippingEmptyInlines):
* rendering/RenderBlockLineLayout.cpp:
(WebCore::inlineLogicalWidth):
(WebCore::alwaysRequiresLineBox):
(WebCore::requiresLineBox):
(WebCore::canBreakAtThisPosition):
(WebCore::LineBreaker::nextSegmentBreak):
* rendering/shapes/ShapeInsideInfo.h:
(WebCore::LineSegmentIterator::LineSegmentIterator):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@156618 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent f73a79e3
2013-09-29 Antti Koivisto <antti@apple.com>
Tighten typing in inline rendering
https://bugs.webkit.org/show_bug.cgi?id=122076
Reviewed by Andreas Kling.
More RenderElement, const, &, etc.
* dom/Position.cpp:
(WebCore::Position::hasRenderedNonAnonymousDescendantsWithHeight):
* rendering/InlineFlowBox.cpp:
(WebCore::isLastChildForRenderer):
(WebCore::isAncestorAndWithinBlock):
(WebCore::InlineFlowBox::determineSpacingForFlowBoxes):
(WebCore::InlineFlowBox::nodeAtPoint):
* rendering/InlineIterator.h:
(WebCore::InlineIterator::InlineIterator):
(WebCore::InlineIterator::root):
(WebCore::isEmptyInline):
(WebCore::bidiNextShared):
(WebCore::bidiNextSkippingEmptyInlines):
(WebCore::bidiNextIncludingEmptyInlines):
(WebCore::bidiFirstSkippingEmptyInlines):
* rendering/RenderBlockLineLayout.cpp:
(WebCore::inlineLogicalWidth):
(WebCore::alwaysRequiresLineBox):
(WebCore::requiresLineBox):
(WebCore::canBreakAtThisPosition):
(WebCore::LineBreaker::nextSegmentBreak):
* rendering/shapes/ShapeInsideInfo.h:
(WebCore::LineSegmentIterator::LineSegmentIterator):
2013-09-28 Sam Weinig <sam@webkit.org>
 
Merge ScriptControllerBase into ScriptController
......@@ -854,14 +854,31 @@ static int boundingBoxLogicalHeight(RenderObject *o, const IntRect &rect)
bool Position::hasRenderedNonAnonymousDescendantsWithHeight(const RenderElement& renderer)
{
RenderObject* stop = renderer.nextInPreOrderAfterChildren();
for (RenderObject* o = renderer.firstChild(); o && o != stop; o = o->nextInPreOrder())
if (o->nonPseudoNode()) {
if ((o->isText() && boundingBoxLogicalHeight(o, toRenderText(o)->linesBoundingBox()))
|| (o->isLineBreak() && boundingBoxLogicalHeight(o, toRenderLineBreak(o)->linesBoundingBox()))
|| (o->isBox() && toRenderBox(o)->pixelSnappedLogicalHeight())
|| (o->isRenderInline() && isEmptyInline(o) && boundingBoxLogicalHeight(o, toRenderInline(o)->linesBoundingBox())))
for (RenderObject* o = renderer.firstChild(); o && o != stop; o = o->nextInPreOrder()) {
if (!o->nonPseudoNode())
continue;
if (o->isText()) {
if (boundingBoxLogicalHeight(o, toRenderText(o)->linesBoundingBox()))
return true;
continue;
}
if (o->isLineBreak()) {
if (boundingBoxLogicalHeight(o, toRenderLineBreak(o)->linesBoundingBox()))
return true;
continue;
}
if (o->isBox()) {
if (toRenderBox(o)->pixelSnappedLogicalHeight())
return true;
continue;
}
if (o->isRenderInline()) {
const RenderInline& renderInline = toRenderInline(*o);
if (isEmptyInline(renderInline) && boundingBoxLogicalHeight(o, renderInline.linesBoundingBox()))
return true;
continue;
}
}
return false;
}
......
......@@ -269,20 +269,20 @@ RenderLineBoxList& InlineFlowBox::rendererLineBoxes() const
return toRenderInline(renderer()).lineBoxes();
}
static inline bool isLastChildForRenderer(RenderElement* ancestor, RenderObject* child)
static inline bool isLastChildForRenderer(const RenderElement& ancestor, const RenderObject* child)
{
if (!child)
return false;
if (child == ancestor)
if (child == &ancestor)
return true;
RenderObject* curr = child;
RenderElement* parent = curr->parent();
const RenderObject* curr = child;
const RenderElement* parent = curr->parent();
while (parent && (!parent->isRenderBlock() || parent->isInline())) {
if (parent->lastChild() != curr)
return false;
if (parent == ancestor)
if (parent == &ancestor)
return true;
curr = parent;
......@@ -292,9 +292,9 @@ static inline bool isLastChildForRenderer(RenderElement* ancestor, RenderObject*
return true;
}
static bool isAncestorAndWithinBlock(RenderObject& ancestor, RenderObject* child)
static bool isAncestorAndWithinBlock(const RenderInline& ancestor, const RenderObject* child)
{
RenderObject* object = child;
const RenderObject* object = child;
while (object && (!object->isRenderBlock() || object->isInline())) {
if (object == &ancestor)
return true;
......@@ -331,7 +331,7 @@ void InlineFlowBox::determineSpacingForFlowBoxes(bool lastLine, bool isLogically
if (!lineBoxList.lastLineBox()->isConstructed()) {
RenderInline& inlineFlow = toRenderInline(renderer());
bool isLastObjectOnLine = !isAncestorAndWithinBlock(renderer(), logicallyLastRunRenderer) || (isLastChildForRenderer(&renderer(), logicallyLastRunRenderer) && !isLogicallyLastRunWrapped);
bool isLastObjectOnLine = !isAncestorAndWithinBlock(inlineFlow, logicallyLastRunRenderer) || (isLastChildForRenderer(renderer(), logicallyLastRunRenderer) && !isLogicallyLastRunWrapped);
// We include the border under these conditions:
// (1) The next line was not created, or it is constructed. We check the previous line for rtl.
......@@ -1018,10 +1018,10 @@ bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re
// Check children first.
// We need to account for culled inline parents of the hit-tested nodes, so that they may also get included in area-based hit-tests.
RenderObject* culledParent = 0;
RenderElement* culledParent = 0;
for (InlineBox* curr = lastChild(); curr; curr = curr->prevOnLine()) {
if (curr->renderer().isText() || !curr->boxModelObject()->hasSelfPaintingLayer()) {
RenderObject* newParent = 0;
RenderElement* newParent = 0;
// Culled parents are only relevant for area-based hit-tests, so ignore it in point-based ones.
if (locationInContainer.isRectBasedTest()) {
newParent = curr->renderer().parent();
......
......@@ -25,6 +25,7 @@
#include "BidiRun.h"
#include "RenderBlock.h"
#include "RenderInline.h"
#include "RenderText.h"
#include <wtf/StdLibExtras.h>
......@@ -43,7 +44,7 @@ public:
{
}
InlineIterator(RenderObject* root, RenderObject* o, unsigned p)
InlineIterator(RenderElement* root, RenderObject* o, unsigned p)
: m_root(root)
, m_obj(o)
, m_pos(p)
......@@ -67,7 +68,7 @@ public:
RenderObject* object() const { return m_obj; }
unsigned offset() const { return m_pos; }
RenderObject* root() const { return m_root; }
RenderElement* root() const { return m_root; }
void fastIncrementInTextNode();
void increment(InlineBidiResolver* = 0);
......@@ -90,7 +91,7 @@ public:
ALWAYS_INLINE WTF::Unicode::Direction direction() const;
private:
RenderObject* m_root;
RenderElement* m_root;
// FIXME: These should be private.
public:
......@@ -175,18 +176,17 @@ enum EmptyInlineBehavior {
IncludeEmptyInlines,
};
static bool isEmptyInline(RenderObject* object)
static bool isEmptyInline(const RenderInline& renderer)
{
if (!object->isRenderInline())
return false;
for (RenderObject* curr = toRenderElement(object)->firstChild(); curr; curr = curr->nextSibling()) {
for (RenderObject* curr = renderer.firstChild(); curr; curr = curr->nextSibling()) {
if (curr->isFloatingOrOutOfFlowPositioned())
continue;
if (curr->isText() && toRenderText(curr)->isAllCollapsibleWhitespace())
if (curr->isText()) {
if (!toRenderText(curr)->isAllCollapsibleWhitespace())
return false;
continue;
if (!isEmptyInline(curr))
}
if (!curr->isRenderInline() || !isEmptyInline(toRenderInline(*curr)))
return false;
}
return true;
......@@ -196,7 +196,7 @@ static bool isEmptyInline(RenderObject* object)
// This function will iterate over inlines within a block, optionally notifying
// a bidi resolver as it enters/exits inlines (so it can push/pop embedding levels).
template <class Observer>
static inline RenderObject* bidiNextShared(RenderObject* root, RenderObject* current, Observer* observer = 0, EmptyInlineBehavior emptyInlineBehavior = SkipEmptyInlines, bool* endOfInlinePtr = 0)
static inline RenderObject* bidiNextShared(RenderElement* root, RenderObject* current, Observer* observer = 0, EmptyInlineBehavior emptyInlineBehavior = SkipEmptyInlines, bool* endOfInlinePtr = 0)
{
RenderObject* next = 0;
// oldEndOfInline denotes if when we last stopped iterating if we were at the end of an inline.
......@@ -241,8 +241,7 @@ static inline RenderObject* bidiNextShared(RenderObject* root, RenderObject* cur
break;
if (isIteratorTarget(next)
|| ((emptyInlineBehavior == IncludeEmptyInlines || isEmptyInline(next)) // Always return EMPTY inlines.
&& next->isRenderInline()))
|| (next->isRenderInline() && (emptyInlineBehavior == IncludeEmptyInlines || isEmptyInline(toRenderInline(*next)))))
break;
current = next;
}
......@@ -254,20 +253,20 @@ static inline RenderObject* bidiNextShared(RenderObject* root, RenderObject* cur
}
template <class Observer>
static inline RenderObject* bidiNextSkippingEmptyInlines(RenderObject* root, RenderObject* current, Observer* observer)
static inline RenderObject* bidiNextSkippingEmptyInlines(RenderElement* root, RenderObject* current, Observer* observer)
{
// The SkipEmptyInlines callers never care about endOfInlinePtr.
return bidiNextShared(root, current, observer, SkipEmptyInlines);
}
// This makes callers cleaner as they don't have to specify a type for the observer when not providing one.
static inline RenderObject* bidiNextSkippingEmptyInlines(RenderObject* root, RenderObject* current)
static inline RenderObject* bidiNextSkippingEmptyInlines(RenderElement* root, RenderObject* current)
{
InlineBidiResolver* observer = 0;
return bidiNextSkippingEmptyInlines(root, current, observer);
}
static inline RenderObject* bidiNextIncludingEmptyInlines(RenderObject* root, RenderObject* current, bool* endOfInlinePtr = 0)
static inline RenderObject* bidiNextIncludingEmptyInlines(RenderElement* root, RenderObject* current, bool* endOfInlinePtr = 0)
{
InlineBidiResolver* observer = 0; // Callers who include empty inlines, never use an observer.
return bidiNextShared(root, current, observer, IncludeEmptyInlines, endOfInlinePtr);
......@@ -281,7 +280,7 @@ static inline RenderObject* bidiFirstSkippingEmptyInlines(RenderElement* root, I
if (o->isRenderInline()) {
notifyObserverEnteredObject(resolver, o);
if (!isEmptyInline(o))
if (!isEmptyInline(toRenderInline(*o)))
o = bidiNextSkippingEmptyInlines(root, o, resolver);
else {
// Never skip empty inlines.
......
......@@ -124,14 +124,14 @@ ShapeInsideInfo* RenderBlock::layoutShapeInsideInfo() const
}
#endif
static inline LayoutUnit borderPaddingMarginStart(RenderInline* child)
static inline LayoutUnit borderPaddingMarginStart(const RenderInline& child)
{
return child->marginStart() + child->paddingStart() + child->borderStart();
return child.marginStart() + child.paddingStart() + child.borderStart();
}
static inline LayoutUnit borderPaddingMarginEnd(RenderInline* child)
static inline LayoutUnit borderPaddingMarginEnd(const RenderInline& child)
{
return child->marginEnd() + child->paddingEnd() + child->borderEnd();
return child.marginEnd() + child.paddingEnd() + child.borderEnd();
}
static inline bool shouldAddBorderPaddingMargin(RenderObject* child)
......@@ -152,9 +152,9 @@ static LayoutUnit inlineLogicalWidth(RenderObject* child, bool checkStartEdge =
{
unsigned lineDepth = 1;
LayoutUnit extraWidth = 0;
RenderObject* parent = child->parent();
RenderElement* parent = child->parent();
while (parent->isRenderInline() && lineDepth++ < cMaxLineDepth) {
RenderInline* parentAsRenderInline = toRenderInline(parent);
const RenderInline& parentAsRenderInline = toRenderInline(*parent);
if (!isEmptyInline(parentAsRenderInline)) {
checkStartEdge = checkStartEdge && shouldAddBorderPaddingMargin(previousInFlowSibling(child));
if (checkStartEdge)
......@@ -622,7 +622,7 @@ public:
HashSet<const SimpleFontData*> fallbackFonts;
};
static inline const RenderStyle& lineStyle(RenderElement& renderer, const LineInfo& lineInfo)
static inline const RenderStyle& lineStyle(const RenderElement& renderer, const LineInfo& lineInfo)
{
return lineInfo.isFirstLine() ? *renderer.firstLineStyle() : *renderer.style();
}
......@@ -2216,11 +2216,11 @@ static inline bool shouldCollapseWhiteSpace(const RenderStyle* style, const Line
|| (whitespacePosition == TrailingWhitespace && style->whiteSpace() == PRE_WRAP && (!lineInfo.isEmpty() || !lineInfo.previousLineBrokeCleanly()));
}
static bool requiresLineBoxForContent(RenderInline* flow, const LineInfo& lineInfo)
static bool requiresLineBoxForContent(const RenderInline& flow, const LineInfo& lineInfo)
{
RenderElement* parent = flow->parent();
if (flow->document().inNoQuirksMode()) {
const RenderStyle& flowStyle = lineStyle(*flow, lineInfo);
RenderElement* parent = flow.parent();
if (flow.document().inNoQuirksMode()) {
const RenderStyle& flowStyle = lineStyle(flow, lineInfo);
const RenderStyle& parentStyle = lineStyle(*parent, lineInfo);
if (flowStyle.lineHeight() != parentStyle.lineHeight()
|| flowStyle.verticalAlign() != parentStyle.verticalAlign()
......@@ -2230,24 +2230,24 @@ static bool requiresLineBoxForContent(RenderInline* flow, const LineInfo& lineIn
return false;
}
static bool hasInlineDirectionBordersPaddingOrMargin(RenderInline* flow)
static bool hasInlineDirectionBordersPaddingOrMargin(const RenderInline& flow)
{
// Where an empty inline is split across anonymous blocks we should only give lineboxes to the 'sides' of the
// inline that have borders, padding or margin.
bool shouldApplyStartBorderPaddingOrMargin = !flow->parent()->isAnonymousBlock() || !flow->isInlineElementContinuation();
if (shouldApplyStartBorderPaddingOrMargin && (flow->borderStart() || flow->marginStart() || flow->paddingStart()))
bool shouldApplyStartBorderPaddingOrMargin = !flow.parent()->isAnonymousBlock() || !flow.isInlineElementContinuation();
if (shouldApplyStartBorderPaddingOrMargin && (flow.borderStart() || flow.marginStart() || flow.paddingStart()))
return true;
bool shouldApplyEndBorderPaddingOrMargin = !flow->parent()->isAnonymousBlock() || flow->isInlineElementContinuation() || !flow->inlineElementContinuation();
return shouldApplyEndBorderPaddingOrMargin && (flow->borderEnd() || flow->marginEnd() || flow->paddingEnd());
bool shouldApplyEndBorderPaddingOrMargin = !flow.parent()->isAnonymousBlock() || flow.isInlineElementContinuation() || !flow.inlineElementContinuation();
return shouldApplyEndBorderPaddingOrMargin && (flow.borderEnd() || flow.marginEnd() || flow.paddingEnd());
}
static bool alwaysRequiresLineBox(RenderObject* flow)
static bool alwaysRequiresLineBox(const RenderInline& flow)
{
// FIXME: Right now, we only allow line boxes for inlines that are truly empty.
// We need to fix this, though, because at the very least, inlines containing only
// ignorable whitespace should should also have line boxes.
return isEmptyInline(flow) && hasInlineDirectionBordersPaddingOrMargin(toRenderInline(flow));
return isEmptyInline(flow) && hasInlineDirectionBordersPaddingOrMargin(flow);
}
static bool requiresLineBox(const InlineIterator& it, const LineInfo& lineInfo = LineInfo(), WhitespacePosition whitespacePosition = LeadingWhitespace)
......@@ -2258,15 +2258,20 @@ static bool requiresLineBox(const InlineIterator& it, const LineInfo& lineInfo =
if (it.m_obj->isBR())
return true;
if (it.m_obj->isRenderInline() && !alwaysRequiresLineBox(it.m_obj) && !requiresLineBoxForContent(toRenderInline(it.m_obj), lineInfo))
return false;
bool rendererIsEmptyInline = false;
if (it.m_obj->isRenderInline()) {
const RenderInline& inlineRenderer = toRenderInline(*it.m_obj);
if (!alwaysRequiresLineBox(inlineRenderer) && !requiresLineBoxForContent(inlineRenderer, lineInfo))
return false;
rendererIsEmptyInline = isEmptyInline(inlineRenderer);
}
if (!shouldCollapseWhiteSpace(it.m_obj->style(), lineInfo, whitespacePosition))
return true;
UChar current = it.current();
bool notJustWhitespace = current != ' ' && current != '\t' && current != softHyphen && (current != '\n' || it.m_obj->preservesNewline()) && !skipNonBreakingSpace(it, lineInfo);
return notJustWhitespace || isEmptyInline(it.m_obj);
return notJustWhitespace || rendererIsEmptyInline;
}
bool RenderBlock::generatesLineBoxesForInlineChild(RenderObject* inlineObj)
......@@ -2607,7 +2612,7 @@ static bool canBreakAtThisPosition(bool autoWrap, LineWidth& width, InlineIterat
return true;
// Avoid breaking before empty inlines.
if (next && isEmptyInline(next))
if (next && next->isRenderInline() && isEmptyInline(toRenderInline(*next)))
return false;
// Return early if we autowrap and the current character is a space as we will always want to break at such a position.
......@@ -2617,8 +2622,11 @@ static bool canBreakAtThisPosition(bool autoWrap, LineWidth& width, InlineIterat
if (next && next->isLineBreakOpportunity())
return autoWrap;
bool nextIsText = (next && (current.m_obj->isText() || isEmptyInline(current.m_obj)) && next->isText() && (autoWrap || next->style()->autoWrap()));
if (!nextIsText)
bool nextIsAutoWrappingText = (next && next->isText() && (autoWrap || next->style()->autoWrap()));
if (!nextIsAutoWrappingText)
return autoWrap;
bool currentIsTextOrEmptyInline = current.m_obj->isText() || (current.m_obj->isRenderInline() && isEmptyInline(toRenderInline(*current.m_obj)));
if (!currentIsTextOrEmptyInline)
return autoWrap;
bool canBreakHere = !currentCharacterIsSpace && textBeginsWithBreakablePosition(next);
......@@ -2820,16 +2828,14 @@ InlineIterator LineBreaker::nextSegmentBreak(InlineBidiResolver& resolver, LineI
// Update prior line break context characters, using U+FFFD (OBJECT REPLACEMENT CHARACTER) for floating element.
renderTextInfo.m_lineBreakIterator.updatePriorContext(replacementCharacter);
} else if (current.m_obj->isRenderInline()) {
RenderInline& flowBox = toRenderInline(*current.m_obj);
// Right now, we should only encounter empty inlines here.
ASSERT(isEmptyInline(current.m_obj));
RenderInline* flowBox = toRenderInline(current.m_obj);
ASSERT(isEmptyInline(flowBox));
// Now that some inline flows have line boxes, if we are already ignoring spaces, we need
// to make sure that we stop to include this object and then start ignoring spaces again.
// If this object is at the start of the line, we need to behave like list markers and
// start ignoring spaces.
bool requiresLineBox = alwaysRequiresLineBox(current.m_obj);
bool requiresLineBox = alwaysRequiresLineBox(flowBox);
if (requiresLineBox || requiresLineBoxForContent(flowBox, lineInfo)) {
// An empty inline that only has line-height, vertical-align or font-metrics will only get a
// line box to affect the height of the line if the rest of the line is not empty.
......@@ -2846,7 +2852,7 @@ InlineIterator LineBreaker::nextSegmentBreak(InlineBidiResolver& resolver, LineI
currentCharacterIsWS = true;
ignoringSpaces = true;
} else {
trailingObjects.appendBoxIfNeeded(flowBox);
trailingObjects.appendBoxIfNeeded(&flowBox);
}
}
......
......@@ -40,13 +40,14 @@ namespace WebCore {
class InlineIterator;
class RenderBlock;
class RenderElement;
class RenderObject;
struct LineSegmentIterator {
RenderObject* root;
RenderElement* root;
RenderObject* object;
unsigned offset;
LineSegmentIterator(RenderObject* root, RenderObject* object, unsigned offset)
LineSegmentIterator(RenderElement* root, RenderObject* object, unsigned offset)
: root(root)
, object(object)
, offset(offset)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment