diff options
Diffstat (limited to 'Source/WebCore/rendering/InlineFlowBox.cpp')
| -rw-r--r-- | Source/WebCore/rendering/InlineFlowBox.cpp | 172 |
1 files changed, 94 insertions, 78 deletions
diff --git a/Source/WebCore/rendering/InlineFlowBox.cpp b/Source/WebCore/rendering/InlineFlowBox.cpp index aa9fcb5..e146dd9 100644 --- a/Source/WebCore/rendering/InlineFlowBox.cpp +++ b/Source/WebCore/rendering/InlineFlowBox.cpp @@ -67,6 +67,18 @@ int InlineFlowBox::getFlowSpacingLogicalWidth() return totWidth; } +IntRect InlineFlowBox::roundedFrameRect() const +{ + // Begin by snapping the x and y coordinates to the nearest pixel. + int snappedX = lroundf(x()); + int snappedY = lroundf(y()); + + int snappedMaxX = lroundf(x() + width()); + int snappedMaxY = lroundf(y() + height()); + + return IntRect(snappedX, snappedY, snappedMaxX - snappedX, snappedMaxY - snappedY); +} + void InlineFlowBox::addToLine(InlineBox* child) { ASSERT(!child->parent()); @@ -167,13 +179,13 @@ void InlineFlowBox::attachLineBoxToRenderObject() toRenderInline(renderer())->lineBoxes()->attachLineBox(this); } -void InlineFlowBox::adjustPosition(int dx, int dy) +void InlineFlowBox::adjustPosition(float dx, float dy) { InlineBox::adjustPosition(dx, dy); for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) child->adjustPosition(dx, dy); if (m_overflow) - m_overflow->move(dx, dy); + m_overflow->move(dx, dy); // FIXME: Rounding error here since overflow was pixel snapped, but nobody other than list markers passes non-integral values here. } RenderLineBoxList* InlineFlowBox::rendererLineBoxes() const @@ -255,12 +267,12 @@ void InlineFlowBox::determineSpacingForFlowBoxes(bool lastLine, RenderObject* en } } -int InlineFlowBox::placeBoxesInInlineDirection(int logicalLeft, bool& needsWordSpacing, GlyphOverflowAndFallbackFontsMap& textBoxDataMap) +float InlineFlowBox::placeBoxesInInlineDirection(float logicalLeft, bool& needsWordSpacing, GlyphOverflowAndFallbackFontsMap& textBoxDataMap) { // Set our x position. setLogicalLeft(logicalLeft); - int startLogicalLeft = logicalLeft; + float startLogicalLeft = logicalLeft; logicalLeft += borderLogicalLeft() + paddingLogicalLeft(); for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { @@ -345,17 +357,16 @@ bool InlineFlowBox::requiresIdeographicBaseline(const GlyphOverflowAndFallbackFo return false; } -void InlineFlowBox::adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent, - int maxPositionTop, int maxPositionBottom) +void InlineFlowBox::adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent, int maxPositionTop, int maxPositionBottom) { for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { // The computed lineheight needs to be extended for the // positioned elements if (curr->renderer()->isPositioned()) continue; // Positioned placeholders don't affect calculations. - if (curr->logicalTop() == PositionTop || curr->logicalTop() == PositionBottom) { + if (curr->verticalAlign() == TOP || curr->verticalAlign() == BOTTOM) { int lineHeight = curr->lineHeight(); - if (curr->logicalTop() == PositionTop) { + if (curr->verticalAlign() == TOP) { if (maxAscent + maxDescent < lineHeight) maxDescent = lineHeight - maxAscent; } @@ -397,40 +408,37 @@ static int verticalPositionForBox(InlineBox* box, FontBaseline baselineType, boo int verticalPosition = 0; EVerticalAlign verticalAlign = renderer->style()->verticalAlign(); - if (verticalAlign == TOP) - verticalPosition = PositionTop; - else if (verticalAlign == BOTTOM) - verticalPosition = PositionBottom; - else { - RenderObject* parent = renderer->parent(); - if (parent->isRenderInline() && parent->style()->verticalAlign() != TOP && parent->style()->verticalAlign() != BOTTOM) - verticalPosition = box->parent()->logicalTop(); - - if (verticalAlign != BASELINE) { - const Font& font = parent->style(firstLine)->font(); - const FontMetrics& fontMetrics = font.fontMetrics(); - int fontSize = font.pixelSize(); - - LineDirectionMode lineDirection = parent->style()->isHorizontalWritingMode() ? HorizontalLine : VerticalLine; - - if (verticalAlign == SUB) - verticalPosition += fontSize / 5 + 1; - else if (verticalAlign == SUPER) - verticalPosition -= fontSize / 3 + 1; - else if (verticalAlign == TEXT_TOP) - verticalPosition += renderer->baselinePosition(baselineType, firstLine, lineDirection) - fontMetrics.ascent(baselineType); - else if (verticalAlign == MIDDLE) - verticalPosition += -static_cast<int>(fontMetrics.xHeight() / 2) - renderer->lineHeight(firstLine, lineDirection) / 2 + renderer->baselinePosition(baselineType, firstLine, lineDirection); - else if (verticalAlign == TEXT_BOTTOM) { - verticalPosition += fontMetrics.descent(baselineType); - // lineHeight - baselinePosition is always 0 for replaced elements (except inline blocks), so don't bother wasting time in that case. - if (!renderer->isReplaced() || renderer->isInlineBlockOrInlineTable()) - verticalPosition -= (renderer->lineHeight(firstLine, lineDirection) - renderer->baselinePosition(baselineType, firstLine, lineDirection)); - } else if (verticalAlign == BASELINE_MIDDLE) - verticalPosition += -renderer->lineHeight(firstLine, lineDirection) / 2 + renderer->baselinePosition(baselineType, firstLine, lineDirection); - else if (verticalAlign == LENGTH) - verticalPosition -= renderer->style()->verticalAlignLength().calcValue(renderer->lineHeight(firstLine, lineDirection)); - } + if (verticalAlign == TOP || verticalAlign == BOTTOM) + return 0; + + RenderObject* parent = renderer->parent(); + if (parent->isRenderInline() && parent->style()->verticalAlign() != TOP && parent->style()->verticalAlign() != BOTTOM) + verticalPosition = box->parent()->logicalTop(); + + if (verticalAlign != BASELINE) { + const Font& font = parent->style(firstLine)->font(); + const FontMetrics& fontMetrics = font.fontMetrics(); + int fontSize = font.pixelSize(); + + LineDirectionMode lineDirection = parent->style()->isHorizontalWritingMode() ? HorizontalLine : VerticalLine; + + if (verticalAlign == SUB) + verticalPosition += fontSize / 5 + 1; + else if (verticalAlign == SUPER) + verticalPosition -= fontSize / 3 + 1; + else if (verticalAlign == TEXT_TOP) + verticalPosition += renderer->baselinePosition(baselineType, firstLine, lineDirection) - fontMetrics.ascent(baselineType); + else if (verticalAlign == MIDDLE) + verticalPosition += -static_cast<int>(fontMetrics.xHeight() / 2) - renderer->lineHeight(firstLine, lineDirection) / 2 + renderer->baselinePosition(baselineType, firstLine, lineDirection); + else if (verticalAlign == TEXT_BOTTOM) { + verticalPosition += fontMetrics.descent(baselineType); + // lineHeight - baselinePosition is always 0 for replaced elements (except inline blocks), so don't bother wasting time in that case. + if (!renderer->isReplaced() || renderer->isInlineBlockOrInlineTable()) + verticalPosition -= (renderer->lineHeight(firstLine, lineDirection) - renderer->baselinePosition(baselineType, firstLine, lineDirection)); + } else if (verticalAlign == BASELINE_MIDDLE) + verticalPosition += -renderer->lineHeight(firstLine, lineDirection) / 2 + renderer->baselinePosition(baselineType, firstLine, lineDirection); + else if (verticalAlign == LENGTH) + verticalPosition -= renderer->style()->verticalAlignLength().calcValue(renderer->lineHeight(firstLine, lineDirection)); } // Store the cached value. @@ -542,10 +550,10 @@ void InlineFlowBox::computeLogicalBoxHeights(int& maxPositionTop, int& maxPositi } } - if (curr->logicalTop() == PositionTop) { + if (curr->verticalAlign() == TOP) { if (maxPositionTop < lineHeight) maxPositionTop = lineHeight; - } else if (curr->logicalTop() == PositionBottom) { + } else if (curr->verticalAlign() == BOTTOM) { if (maxPositionBottom < lineHeight) maxPositionBottom = lineHeight; } else if ((!isInlineFlow || static_cast<InlineFlowBox*>(curr)->hasTextChildren()) || curr->boxModelObject()->hasInlineDirectionBordersOrPadding() || strictMode) { @@ -592,9 +600,9 @@ void InlineFlowBox::placeBoxesInBlockDirection(int top, int maxHeight, int maxAs lineTopIncludingMargins, lineBottomIncludingMargins, hasAnnotationsBefore, hasAnnotationsAfter, baselineType); bool childAffectsTopBottomPos = true; - if (curr->logicalTop() == PositionTop) + if (curr->verticalAlign() == TOP) curr->setLogicalTop(top); - else if (curr->logicalTop() == PositionBottom) + else if (curr->verticalAlign() == BOTTOM) curr->setLogicalTop(top + maxHeight - curr->lineHeight()); else { if ((isInlineFlow && !static_cast<InlineFlowBox*>(curr)->hasTextChildren()) && !curr->boxModelObject()->hasInlineDirectionBordersOrPadding() && !strictMode) @@ -724,8 +732,8 @@ void InlineFlowBox::addBoxShadowVisualOverflow(IntRect& logicalVisualOverflow) int boxShadowLogicalRight; renderer()->style(m_firstLine)->getBoxShadowInlineDirectionExtent(boxShadowLogicalLeft, boxShadowLogicalRight); - int logicalLeftVisualOverflow = min(logicalLeft() + boxShadowLogicalLeft, logicalVisualOverflow.x()); - int logicalRightVisualOverflow = max(logicalRight() + boxShadowLogicalRight, logicalVisualOverflow.maxX()); + int logicalLeftVisualOverflow = min(pixelSnappedLogicalLeft() + boxShadowLogicalLeft, logicalVisualOverflow.x()); + int logicalRightVisualOverflow = max(pixelSnappedLogicalRight() + boxShadowLogicalRight, logicalVisualOverflow.maxX()); logicalVisualOverflow = IntRect(logicalLeftVisualOverflow, logicalTopVisualOverflow, logicalRightVisualOverflow - logicalLeftVisualOverflow, logicalBottomVisualOverflow - logicalTopVisualOverflow); @@ -781,8 +789,8 @@ void InlineFlowBox::addTextBoxVisualOverflow(const InlineTextBox* textBox, Glyph int logicalTopVisualOverflow = min(textBox->logicalTop() + childOverflowLogicalTop, logicalVisualOverflow.y()); int logicalBottomVisualOverflow = max(textBox->logicalBottom() + childOverflowLogicalBottom, logicalVisualOverflow.maxY()); - int logicalLeftVisualOverflow = min(textBox->logicalLeft() + childOverflowLogicalLeft, logicalVisualOverflow.x()); - int logicalRightVisualOverflow = max(textBox->logicalRight() + childOverflowLogicalRight, logicalVisualOverflow.maxX()); + int logicalLeftVisualOverflow = min(textBox->pixelSnappedLogicalLeft() + childOverflowLogicalLeft, logicalVisualOverflow.x()); + int logicalRightVisualOverflow = max(textBox->pixelSnappedLogicalRight() + childOverflowLogicalRight, logicalVisualOverflow.maxX()); logicalVisualOverflow = IntRect(logicalLeftVisualOverflow, logicalTopVisualOverflow, logicalRightVisualOverflow - logicalLeftVisualOverflow, logicalBottomVisualOverflow - logicalTopVisualOverflow); @@ -819,7 +827,7 @@ void InlineFlowBox::computeOverflow(int lineTop, int lineBottom, bool strictMode // Visual overflow just includes overflow for stuff we need to repaint ourselves. Self-painting layers are ignored. // Layout overflow is used to determine scrolling extent, so it still includes child layers and also factors in // transforms, relative positioning, etc. - IntRect logicalLayoutOverflow(logicalLeft(), topOverflow, logicalWidth(), bottomOverflow - topOverflow); + IntRect logicalLayoutOverflow(enclosingIntRect(FloatRect(logicalLeft(), topOverflow, logicalWidth(), bottomOverflow - topOverflow))); IntRect logicalVisualOverflow(logicalLayoutOverflow); // box-shadow on root line boxes is applying to the block and not to the lines. @@ -864,7 +872,7 @@ void InlineFlowBox::computeOverflow(int lineTop, int lineBottom, bool strictMode // all functions that query overflow. void InlineFlowBox::setLayoutOverflow(const IntRect& rect) { - IntRect frameBox = frameRect(); + IntRect frameBox = enclosingIntRect(FloatRect(x(), y(), width(), height())); if (frameBox == rect || rect.isEmpty()) return; @@ -876,7 +884,7 @@ void InlineFlowBox::setLayoutOverflow(const IntRect& rect) void InlineFlowBox::setVisualOverflow(const IntRect& rect) { - IntRect frameBox = frameRect(); + IntRect frameBox = enclosingIntRect(FloatRect(x(), y(), width(), height())); if (frameBox == rect || rect.isEmpty()) return; @@ -912,9 +920,9 @@ bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re } // Now check ourselves. - IntPoint boxOrigin = locationIncludingFlipping(); + FloatPoint boxOrigin = locationIncludingFlipping(); boxOrigin.move(tx, ty); - IntRect rect(boxOrigin, IntSize(width(), height())); + FloatRect rect(boxOrigin, IntSize(width(), height())); if (visibleToHitTesting() && rect.intersects(result.rectForPoint(x, y))) { renderer()->updateHitTestResult(result, flipForWritingMode(IntPoint(x - tx, y - ty))); // Don't add in m_x or m_y here, we want coords in the containing block's space. if (!result.addNodeToRectBasedTestResult(renderer()->node(), x, y, rect)) @@ -943,13 +951,20 @@ void InlineFlowBox::paint(PaintInfo& paintInfo, int tx, int ty) RenderBlock* cb = 0; bool containingBlockPaintsContinuationOutline = inlineFlow->continuation() || inlineFlow->isInlineElementContinuation(); - if (containingBlockPaintsContinuationOutline) { - cb = renderer()->containingBlock()->containingBlock(); - - for (RenderBoxModelObject* box = boxModelObject(); box != cb; box = box->parent()->enclosingBoxModelObject()) { - if (box->hasSelfPaintingLayer()) { - containingBlockPaintsContinuationOutline = false; - break; + if (containingBlockPaintsContinuationOutline) { + // FIXME: See https://bugs.webkit.org/show_bug.cgi?id=54690. We currently don't reconnect inline continuations + // after a child removal. As a result, those merged inlines do not get seperated and hence not get enclosed by + // anonymous blocks. In this case, it is better to bail out and paint it ourself. + RenderBlock* enclosingAnonymousBlock = renderer()->containingBlock(); + if (!enclosingAnonymousBlock->isAnonymousBlock()) + containingBlockPaintsContinuationOutline = false; + else { + cb = enclosingAnonymousBlock->containingBlock(); + for (RenderBoxModelObject* box = boxModelObject(); box != cb; box = box->parent()->enclosingBoxModelObject()) { + if (box->hasSelfPaintingLayer()) { + containingBlockPaintsContinuationOutline = false; + break; + } } } } @@ -1050,10 +1065,12 @@ void InlineFlowBox::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty) if (!paintInfo.shouldPaintWithinRoot(renderer()) || renderer()->style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseForeground) return; - int x = m_x; - int y = m_y; - int w = width(); - int h = height(); + // Pixel snap background/border painting. + IntRect frameRect = roundedFrameRect(); + int x = frameRect.x(); + int y = frameRect.y(); + int w = frameRect.width(); + int h = frameRect.height(); // Constrain our background/border painting to the line top and bottom if necessary. bool noQuirksMode = renderer()->document()->inNoQuirksMode(); @@ -1079,14 +1096,11 @@ void InlineFlowBox::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty) RenderStyle* styleToUse = renderer()->style(m_firstLine); if ((!parent() && m_firstLine && styleToUse != renderer()->style()) || (parent() && renderer()->hasBoxDecorations())) { // Shadow comes first and is behind the background and border. - if (styleToUse->boxShadow()) - paintBoxShadow(context, styleToUse, Normal, tx, ty, w, h); + paintBoxShadow(context, styleToUse, Normal, tx, ty, w, h); Color c = styleToUse->visitedDependentColor(CSSPropertyBackgroundColor); paintFillLayers(paintInfo, c, styleToUse->backgroundLayers(), tx, ty, w, h); - - if (styleToUse->boxShadow()) - paintBoxShadow(context, styleToUse, Inset, tx, ty, w, h); + paintBoxShadow(context, styleToUse, Inset, tx, ty, w, h); // :first-line cannot be used to put borders on a line. Always paint borders with our // non-first-line style. @@ -1133,10 +1147,12 @@ void InlineFlowBox::paintMask(PaintInfo& paintInfo, int tx, int ty) if (!paintInfo.shouldPaintWithinRoot(renderer()) || renderer()->style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask) return; - int x = m_x; - int y = m_y; - int w = width(); - int h = height(); + // Pixel snap mask painting. + IntRect frameRect = roundedFrameRect(); + int x = frameRect.x(); + int y = frameRect.y(); + int w = frameRect.width(); + int h = frameRect.height(); // Constrain our background/border painting to the line top and bottom if necessary. bool noQuirksMode = renderer()->document()->inNoQuirksMode(); @@ -1237,14 +1253,14 @@ bool InlineFlowBox::canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsis return true; } -int InlineFlowBox::placeEllipsisBox(bool ltr, int blockLeftEdge, int blockRightEdge, int ellipsisWidth, bool& foundBox) +float InlineFlowBox::placeEllipsisBox(bool ltr, float blockLeftEdge, float blockRightEdge, float ellipsisWidth, bool& foundBox) { - int result = -1; + float result = -1; // We iterate over all children, the foundBox variable tells us when we've found the // box containing the ellipsis. All boxes after that one in the flow are hidden. // If our flow is ltr then iterate over the boxes from left to right, otherwise iterate // from right to left. Varying the order allows us to correctly hide the boxes following the ellipsis. - InlineBox *box = ltr ? firstChild() : lastChild(); + InlineBox* box = ltr ? firstChild() : lastChild(); // NOTE: these will cross after foundBox = true. int visibleLeftEdge = blockLeftEdge; |
