diff options
Diffstat (limited to 'WebCore/rendering/InlineFlowBox.cpp')
-rw-r--r-- | WebCore/rendering/InlineFlowBox.cpp | 252 |
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); |