summaryrefslogtreecommitdiffstats
path: root/WebCore/rendering/InlineFlowBox.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/rendering/InlineFlowBox.cpp')
-rw-r--r--WebCore/rendering/InlineFlowBox.cpp252
1 files changed, 145 insertions, 107 deletions
diff --git a/WebCore/rendering/InlineFlowBox.cpp b/WebCore/rendering/InlineFlowBox.cpp
index 543c190..143d3d8 100644
--- a/WebCore/rendering/InlineFlowBox.cpp
+++ b/WebCore/rendering/InlineFlowBox.cpp
@@ -29,6 +29,7 @@
#include "RootInlineBox.h"
#include "RenderBlock.h"
#include "RenderInline.h"
+#include "RenderLayer.h"
#include "RenderListMarker.h"
#include "RenderTableCell.h"
#include "RootInlineBox.h"
@@ -167,6 +168,8 @@ void InlineFlowBox::adjustPosition(int dx, int dy)
InlineRunBox::adjustPosition(dx, dy);
for (InlineBox* child = firstChild(); child; child = child->nextOnLine())
child->adjustPosition(dx, dy);
+ if (m_overflow)
+ m_overflow->move(dx, dy);
}
RenderLineBoxList* InlineFlowBox::rendererLineBoxes() const
@@ -248,16 +251,21 @@ void InlineFlowBox::determineSpacingForFlowBoxes(bool lastLine, RenderObject* en
}
}
-int InlineFlowBox::placeBoxesHorizontally(int xPos, int& leftPosition, int& rightPosition, bool& needsWordSpacing)
+int InlineFlowBox::placeBoxesHorizontally(int xPos, bool& needsWordSpacing)
{
// Set our x position.
setX(xPos);
+ int leftLayoutOverflow = xPos;
+ int rightLayoutOverflow = xPos;
+ int leftVisualOverflow = xPos;
+ int rightVisualOverflow = xPos;
+
int boxShadowLeft;
int boxShadowRight;
renderer()->style(m_firstLine)->getBoxShadowHorizontalExtent(boxShadowLeft, boxShadowRight);
- leftPosition = min(xPos + boxShadowLeft, leftPosition);
+ leftVisualOverflow = min(xPos + boxShadowLeft, leftVisualOverflow);
int startX = xPos;
xPos += borderLeft() + paddingLeft();
@@ -275,23 +283,24 @@ int InlineFlowBox::placeBoxesHorizontally(int xPos, int& leftPosition, int& righ
int strokeOverflow = static_cast<int>(ceilf(rt->style()->textStrokeWidth() / 2.0f));
- // If letter-spacing is negative, we should factor that into right overflow. (Even in RTL, letter-spacing is
+ // If letter-spacing is negative, we should factor that into right layout overflow. (Even in RTL, letter-spacing is
// applied to the right, so this is not an issue with left overflow.
int letterSpacing = min(0, (int)rt->style(m_firstLine)->font().letterSpacing());
-
+ rightLayoutOverflow = max(xPos + text->width() - letterSpacing, rightLayoutOverflow);
+
int leftGlyphOverflow = -strokeOverflow;
int rightGlyphOverflow = strokeOverflow - letterSpacing;
- int visualOverflowLeft = leftGlyphOverflow;
- int visualOverflowRight = rightGlyphOverflow;
+ int childOverflowLeft = leftGlyphOverflow;
+ int childOverflowRight = rightGlyphOverflow;
for (ShadowData* shadow = rt->style()->textShadow(); shadow; shadow = shadow->next) {
- visualOverflowLeft = min(visualOverflowLeft, shadow->x - shadow->blur + leftGlyphOverflow);
- visualOverflowRight = max(visualOverflowRight, shadow->x + shadow->blur + rightGlyphOverflow);
+ childOverflowLeft = min(childOverflowLeft, shadow->x - shadow->blur + leftGlyphOverflow);
+ childOverflowRight = max(childOverflowRight, shadow->x + shadow->blur + rightGlyphOverflow);
}
- leftPosition = min(xPos + visualOverflowLeft, leftPosition);
- rightPosition = max(xPos + text->width() + visualOverflowRight, rightPosition);
- m_maxHorizontalVisualOverflow = max(max(visualOverflowRight, -visualOverflowLeft), (int)m_maxHorizontalVisualOverflow);
+ leftVisualOverflow = min(xPos + childOverflowLeft, leftVisualOverflow);
+ rightVisualOverflow = max(xPos + text->width() + childOverflowRight, rightVisualOverflow);
+
xPos += text->width();
} else {
if (curr->renderer()->isPositioned()) {
@@ -307,13 +316,26 @@ int InlineFlowBox::placeBoxesHorizontally(int xPos, int& leftPosition, int& righ
if (curr->renderer()->isRenderInline()) {
InlineFlowBox* flow = static_cast<InlineFlowBox*>(curr);
xPos += flow->marginLeft();
- xPos = flow->placeBoxesHorizontally(xPos, leftPosition, rightPosition, needsWordSpacing);
+ xPos = flow->placeBoxesHorizontally(xPos, needsWordSpacing);
xPos += flow->marginRight();
+ leftLayoutOverflow = min(leftLayoutOverflow, flow->leftLayoutOverflow());
+ rightLayoutOverflow = max(rightLayoutOverflow, flow->rightLayoutOverflow());
+ leftVisualOverflow = min(leftVisualOverflow, flow->leftVisualOverflow());
+ rightVisualOverflow = max(rightVisualOverflow, flow->rightVisualOverflow());
} else if (!curr->renderer()->isListMarker() || toRenderListMarker(curr->renderer())->isInside()) {
xPos += curr->boxModelObject()->marginLeft();
curr->setX(xPos);
- leftPosition = min(xPos + toRenderBox(curr->renderer())->overflowLeft(false), leftPosition);
- rightPosition = max(xPos + toRenderBox(curr->renderer())->overflowWidth(false), rightPosition);
+
+ RenderBox* box = toRenderBox(curr->renderer());
+ int childLeftOverflow = box->hasOverflowClip() ? 0 : box->leftLayoutOverflow();
+ int childRightOverflow = box->hasOverflowClip() ? curr->width() : box->rightLayoutOverflow();
+
+ leftLayoutOverflow = min(xPos + childLeftOverflow, leftLayoutOverflow);
+ rightLayoutOverflow = max(xPos + childRightOverflow, rightLayoutOverflow);
+
+ leftVisualOverflow = min(xPos + box->leftVisualOverflow(), leftVisualOverflow);
+ rightVisualOverflow = max(xPos + box->rightVisualOverflow(), rightVisualOverflow);
+
xPos += curr->width() + curr->boxModelObject()->marginRight();
}
}
@@ -321,45 +343,13 @@ int InlineFlowBox::placeBoxesHorizontally(int xPos, int& leftPosition, int& righ
xPos += borderRight() + paddingRight();
setWidth(xPos - startX);
- rightPosition = max(x() + width() + boxShadowRight, rightPosition);
+ rightVisualOverflow = max(x() + width() + boxShadowRight, rightVisualOverflow);
+ rightLayoutOverflow = max(x() + width(), rightLayoutOverflow);
+ setHorizontalOverflowPositions(leftLayoutOverflow, rightLayoutOverflow, leftVisualOverflow, rightVisualOverflow);
return xPos;
}
-int InlineFlowBox::verticallyAlignBoxes(int heightOfBlock)
-{
- int maxPositionTop = 0;
- int maxPositionBottom = 0;
- int maxAscent = 0;
- int maxDescent = 0;
-
- // Figure out if we're in strict mode. Note that we can't simply use !style()->htmlHacks(),
- // because that would match almost strict mode as well.
- RenderObject* curr = renderer();
- while (curr && !curr->node())
- curr = curr->container();
- bool strictMode = (curr && curr->document()->inStrictMode());
-
- computeLogicalBoxHeights(maxPositionTop, maxPositionBottom, maxAscent, maxDescent, strictMode);
-
- if (maxAscent + maxDescent < max(maxPositionTop, maxPositionBottom))
- adjustMaxAscentAndDescent(maxAscent, maxDescent, maxPositionTop, maxPositionBottom);
-
- int maxHeight = maxAscent + maxDescent;
- int topPosition = heightOfBlock;
- int bottomPosition = heightOfBlock;
- int selectionTop = heightOfBlock;
- int selectionBottom = heightOfBlock;
- placeBoxesVertically(heightOfBlock, maxHeight, maxAscent, strictMode, topPosition, bottomPosition, selectionTop, selectionBottom);
-
- setVerticalOverflowPositions(topPosition, bottomPosition);
- setVerticalSelectionPositions(selectionTop, selectionBottom);
-
- heightOfBlock += maxHeight;
-
- return heightOfBlock;
-}
-
void InlineFlowBox::adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent,
int maxPositionTop, int maxPositionBottom)
{
@@ -479,11 +469,10 @@ void InlineFlowBox::computeLogicalBoxHeights(int& maxPositionTop, int& maxPositi
}
}
-void InlineFlowBox::placeBoxesVertically(int yPos, int maxHeight, int maxAscent, bool strictMode,
- int& topPosition, int& bottomPosition, int& selectionTop, int& selectionBottom)
+void InlineFlowBox::placeBoxesVertically(int yPos, int maxHeight, int maxAscent, bool strictMode, int& selectionTop, int& selectionBottom)
{
if (isRootInlineBox())
- setY(yPos + max(0, maxAscent - baselinePosition(true))); // Place our root box.
+ setY(yPos + maxAscent - baselinePosition(true)); // Place our root box.
for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
if (curr->renderer()->isPositioned())
@@ -493,7 +482,7 @@ void InlineFlowBox::placeBoxesVertically(int yPos, int maxHeight, int maxAscent,
// line-height).
bool isInlineFlow = curr->isInlineFlowBox();
if (isInlineFlow)
- static_cast<InlineFlowBox*>(curr)->placeBoxesVertically(yPos, maxHeight, maxAscent, strictMode, topPosition, bottomPosition, selectionTop, selectionBottom);
+ static_cast<InlineFlowBox*>(curr)->placeBoxesVertically(yPos, maxHeight, maxAscent, strictMode, selectionTop, selectionBottom);
bool childAffectsTopBottomPos = true;
if (curr->y() == PositionTop)
@@ -504,43 +493,18 @@ void InlineFlowBox::placeBoxesVertically(int yPos, int maxHeight, int maxAscent,
if ((isInlineFlow && !static_cast<InlineFlowBox*>(curr)->hasTextChildren()) && !curr->boxModelObject()->hasHorizontalBordersOrPadding() && !strictMode)
childAffectsTopBottomPos = false;
int posAdjust = maxAscent - curr->baselinePosition(false);
- if (!childAffectsTopBottomPos)
- posAdjust = max(0, posAdjust);
curr->setY(curr->y() + yPos + posAdjust);
}
- // FIXME: By only considering overflow as part of the root line box, we can't get an accurate picture regarding what the line
- // actually needs to paint. A line box that is part of a self-painting layer technically shouldn't contribute to the overflow
- // of the line, but in order to not do this and paint accurately, we have to track the overflow somewhere else (either by storing overflow
- // in each InlineFlowBox up the chain or in the layer itself). Relative positioned objects on a line will cause scrollbars
- // to appear when they shouldn't until we fix this issue.
int newY = curr->y();
- int overflowTop = 0;
- int overflowBottom = 0;
if (curr->isText() || curr->isInlineFlowBox()) {
const Font& font = curr->renderer()->style(m_firstLine)->font();
newY += curr->baselinePosition(false) - font.ascent();
-
- curr->renderer()->style(m_firstLine)->getBoxShadowVerticalExtent(overflowTop, overflowBottom);
-
- for (ShadowData* textShadow = curr->renderer()->style(m_firstLine)->textShadow(); textShadow; textShadow = textShadow->next) {
- overflowTop = min(overflowTop, textShadow->y - textShadow->blur);
- overflowBottom = max(overflowBottom, textShadow->y + textShadow->blur);
- }
-
- if (curr->renderer()->hasReflection()) {
- RenderBox* box = toRenderBox(curr->renderer());
- overflowTop = min(overflowTop, box->reflectionBox().y());
- overflowBottom = max(overflowBottom, box->reflectionBox().bottom());
- }
-
if (curr->isInlineFlowBox())
newY -= curr->boxModelObject()->borderTop() + curr->boxModelObject()->paddingTop();
} else if (!curr->renderer()->isBR()) {
RenderBox* box = toRenderBox(curr->renderer());
newY += box->marginTop();
- overflowTop = box->overflowTop(false);
- overflowBottom = box->overflowHeight(false) - box->height();
}
curr->setY(newY);
@@ -549,8 +513,6 @@ void InlineFlowBox::placeBoxesVertically(int yPos, int maxHeight, int maxAscent,
int boxHeight = curr->height();
selectionTop = min(selectionTop, newY);
selectionBottom = max(selectionBottom, newY + boxHeight);
- topPosition = min(topPosition, newY + overflowTop);
- bottomPosition = max(bottomPosition, newY + boxHeight + overflowBottom);
}
}
@@ -564,8 +526,88 @@ void InlineFlowBox::placeBoxesVertically(int yPos, int maxHeight, int maxAscent,
}
}
+void InlineFlowBox::computeVerticalOverflow(int lineTop, int lineBottom, bool strictMode)
+{
+ int boxHeight = height();
+
+ // Any spillage outside of the line top and bottom is not considered overflow. We just ignore this, since it only happens
+ // from the "your ascent/descent don't affect the line" quirk.
+ // FIXME: Technically this means there can be repaint errors in the case where a line box has a shadow or background that spills
+ // outside of the block. We should consider making any line box that has anything to render just stop respecting the quirk or making
+ // boxes that render something set visual overflow.
+ int topOverflow = max(y(), lineTop);
+ int bottomOverflow = min(y() + boxHeight, lineBottom);
+
+ int topLayoutOverflow = topOverflow;
+ int bottomLayoutOverflow = bottomOverflow;
+
+ int topVisualOverflow = topOverflow;
+ int bottomVisualOverflow = bottomOverflow;
+
+ // box-shadow on root line boxes is applying to the block and not to the lines.
+ if (parent()) {
+ int boxShadowTop;
+ int boxShadowBottom;
+ renderer()->style(m_firstLine)->getBoxShadowVerticalExtent(boxShadowTop, boxShadowBottom);
+
+ topVisualOverflow = min(y() + boxShadowTop, topVisualOverflow);
+ bottomVisualOverflow = max(y() + boxHeight + boxShadowBottom, bottomVisualOverflow);
+ }
+
+ for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
+ if (curr->renderer()->isPositioned())
+ continue; // Positioned placeholders don't affect calculations.
+
+ if (curr->renderer()->isText()) {
+ InlineTextBox* text = static_cast<InlineTextBox*>(curr);
+ RenderText* rt = toRenderText(text->renderer());
+ if (rt->isBR())
+ continue;
+
+ int strokeOverflow = static_cast<int>(ceilf(rt->style()->textStrokeWidth() / 2.0f));
+
+ int topGlyphOverflow = -strokeOverflow;
+ int bottomGlyphOverflow = strokeOverflow;
+
+ int childOverflowTop = topGlyphOverflow;
+ int childOverflowBottom = bottomGlyphOverflow;
+ for (ShadowData* shadow = rt->style()->textShadow(); shadow; shadow = shadow->next) {
+ childOverflowTop = min(childOverflowTop, shadow->y - shadow->blur + topGlyphOverflow);
+ childOverflowBottom = max(childOverflowBottom, shadow->y + shadow->blur + bottomGlyphOverflow);
+ }
+
+ topVisualOverflow = min(curr->y() + childOverflowTop, topVisualOverflow);
+ bottomVisualOverflow = max(curr->y() + text->height() + childOverflowBottom, bottomVisualOverflow);
+ } else if (curr->renderer()->isRenderInline()) {
+ InlineFlowBox* flow = static_cast<InlineFlowBox*>(curr);
+ flow->computeVerticalOverflow(lineTop, lineBottom, strictMode);
+ topLayoutOverflow = min(topLayoutOverflow, flow->topLayoutOverflow());
+ bottomLayoutOverflow = max(bottomLayoutOverflow, flow->bottomLayoutOverflow());
+ topVisualOverflow = min(topVisualOverflow, flow->topVisualOverflow());
+ bottomVisualOverflow = max(bottomVisualOverflow, flow->bottomVisualOverflow());
+ } else if (!curr->boxModelObject()->hasSelfPaintingLayer()){
+ // Only include overflow from replaced inlines if they do not paint themselves.
+ RenderBox* box = toRenderBox(curr->renderer());
+ int boxY = curr->y();
+ int childTopOverflow = box->hasOverflowClip() ? 0 : box->topLayoutOverflow();
+ int childBottomOverflow = box->hasOverflowClip() ? curr->height() : box->bottomLayoutOverflow();
+ topLayoutOverflow = min(boxY + childTopOverflow, topLayoutOverflow);
+ bottomLayoutOverflow = max(boxY + childBottomOverflow, bottomLayoutOverflow);
+ topVisualOverflow = min(boxY + box->topVisualOverflow(), topVisualOverflow);
+ bottomVisualOverflow = max(boxY + box->bottomVisualOverflow(), bottomVisualOverflow);
+ }
+ }
+
+ setVerticalOverflowPositions(topLayoutOverflow, bottomLayoutOverflow, topVisualOverflow, bottomVisualOverflow, boxHeight);
+}
+
bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty)
{
+ IntRect overflowRect(visibleOverflowRect());
+ overflowRect.move(tx, ty);
+ if (!overflowRect.contains(x, y))
+ return false;
+
// Check children first.
for (InlineBox* curr = lastChild(); curr; curr = curr->prevOnLine()) {
if ((curr->renderer()->isText() || !curr->boxModelObject()->hasSelfPaintingLayer()) && curr->nodeAtPoint(request, result, x, y, tx, ty)) {
@@ -586,23 +628,14 @@ bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re
void InlineFlowBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
{
- int xPos = tx + m_x - renderer()->maximalOutlineSize(paintInfo.phase);
- int w = width() + 2 * renderer()->maximalOutlineSize(paintInfo.phase);
- int shadowLeft;
- int shadowRight;
-
- renderer()->style(m_firstLine)->getBoxShadowHorizontalExtent(shadowLeft, shadowRight);
-
- for (ShadowData* textShadow = renderer()->style(m_firstLine)->textShadow(); textShadow; textShadow = textShadow->next) {
- shadowLeft = min(textShadow->x - textShadow->blur, shadowLeft);
- shadowRight = max(textShadow->x + textShadow->blur, shadowRight);
- }
-
- xPos += shadowLeft;
- w += -shadowLeft + shadowRight;
- bool intersectsDamageRect = xPos < paintInfo.rect.right() && xPos + w > paintInfo.rect.x();
+ IntRect overflowRect(visibleOverflowRect());
+ overflowRect.inflate(renderer()->maximalOutlineSize(paintInfo.phase));
+ overflowRect.move(tx, ty);
+
+ if (!paintInfo.rect.intersects(overflowRect))
+ return;
- if (intersectsDamageRect && paintInfo.phase != PaintPhaseChildOutlines) {
+ if (paintInfo.phase != PaintPhaseChildOutlines) {
if (paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) {
// Add ourselves to the paint info struct's list of inlines that need to paint their
// outlines.
@@ -645,7 +678,7 @@ void InlineFlowBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
}
// 4. Paint our strike-through
- if (intersectsDamageRect && (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection))
+ if (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection)
paintTextDecorations(paintInfo, tx, ty, true);
}
@@ -774,18 +807,23 @@ void InlineFlowBox::paintMask(RenderObject::PaintInfo& paintInfo, int tx, int ty
int w = width();
int h = height();
- // Figure out if we need to push a transparency layer to render our mask.
- bool pushTransparencyLayer = false;
const NinePieceImage& maskNinePieceImage = renderer()->style()->maskBoxImage();
StyleImage* maskBoxImage = renderer()->style()->maskBoxImage().image();
- if ((maskBoxImage && renderer()->style()->maskLayers()->hasImage()) || renderer()->style()->maskLayers()->next())
- pushTransparencyLayer = true;
-
- CompositeOperator compositeOp = CompositeDestinationIn;
- if (pushTransparencyLayer) {
- paintInfo.context->setCompositeOperation(CompositeDestinationIn);
- paintInfo.context->beginTransparencyLayer(1.0f);
- compositeOp = CompositeSourceOver;
+
+ // Figure out if we need to push a transparency layer to render our mask.
+ bool pushTransparencyLayer = false;
+ bool compositedMask = renderer()->hasLayer() && boxModelObject()->layer()->hasCompositedMask();
+ CompositeOperator compositeOp = CompositeSourceOver;
+ if (!compositedMask) {
+ if ((maskBoxImage && renderer()->style()->maskLayers()->hasImage()) || renderer()->style()->maskLayers()->next())
+ pushTransparencyLayer = true;
+
+ compositeOp = CompositeDestinationIn;
+ if (pushTransparencyLayer) {
+ paintInfo.context->setCompositeOperation(CompositeDestinationIn);
+ paintInfo.context->beginTransparencyLayer(1.0f);
+ compositeOp = CompositeSourceOver;
+ }
}
paintFillLayers(paintInfo, Color(), renderer()->style()->maskLayers(), tx, ty, w, h, compositeOp);