diff options
| author | Ben Murdoch <benm@google.com> | 2011-05-24 11:24:40 +0100 |
|---|---|---|
| committer | Ben Murdoch <benm@google.com> | 2011-06-02 09:53:15 +0100 |
| commit | 81bc750723a18f21cd17d1b173cd2a4dda9cea6e (patch) | |
| tree | 7a9e5ed86ff429fd347a25153107221543909b19 /Source/WebCore/rendering | |
| parent | 94088a6d336c1dd80a1e734af51e96abcbb689a7 (diff) | |
| download | external_webkit-81bc750723a18f21cd17d1b173cd2a4dda9cea6e.zip external_webkit-81bc750723a18f21cd17d1b173cd2a4dda9cea6e.tar.gz external_webkit-81bc750723a18f21cd17d1b173cd2a4dda9cea6e.tar.bz2 | |
Merge WebKit at r80534: Intial merge by Git
Change-Id: Ia7a83357124c9e1cdb1debf55d9661ec0bd09a61
Diffstat (limited to 'Source/WebCore/rendering')
104 files changed, 2555 insertions, 2117 deletions
diff --git a/Source/WebCore/rendering/AutoTableLayout.cpp b/Source/WebCore/rendering/AutoTableLayout.cpp index bb0df0b..9775ec5 100644 --- a/Source/WebCore/rendering/AutoTableLayout.cpp +++ b/Source/WebCore/rendering/AutoTableLayout.cpp @@ -519,7 +519,6 @@ void AutoTableLayout::layout() // fall through break; case Auto: - case Static: if (m_layoutStruct[i].emptyCellsOnly) numAutoEmptyCellsOnly++; else { diff --git a/Source/WebCore/rendering/HitTestResult.cpp b/Source/WebCore/rendering/HitTestResult.cpp index 5d9b3df..ba98eff 100644 --- a/Source/WebCore/rendering/HitTestResult.cpp +++ b/Source/WebCore/rendering/HitTestResult.cpp @@ -545,6 +545,23 @@ bool HitTestResult::addNodeToRectBasedTestResult(Node* node, int x, int y, const return !rect.contains(rectForPoint(x, y)); } +bool HitTestResult::addNodeToRectBasedTestResult(Node* node, int x, int y, const FloatRect& rect) +{ + // If it is not a rect-based hit test, this method has to be no-op. + // Return false, so the hit test stops. + if (!isRectBasedTest()) + return false; + + // If node is null, return true so the hit test can continue. + if (!node) + return true; + + node = node->shadowAncestorNode(); + m_rectBasedTestResult.add(node); + + return !rect.contains(rectForPoint(x, y)); +} + void HitTestResult::append(const HitTestResult& other) { ASSERT(isRectBasedTest() && other.isRectBasedTest()); diff --git a/Source/WebCore/rendering/HitTestResult.h b/Source/WebCore/rendering/HitTestResult.h index 1545da9..3aa17e3 100644 --- a/Source/WebCore/rendering/HitTestResult.h +++ b/Source/WebCore/rendering/HitTestResult.h @@ -20,6 +20,7 @@ #ifndef HitTestResult_h #define HitTestResult_h +#include "FloatRect.h" #include "IntPoint.h" #include "IntRect.h" #include "IntSize.h" @@ -109,7 +110,8 @@ public: // Returns true if it is rect-based hit test and needs to continue until the rect is fully // enclosed by the boundaries of a node. - bool addNodeToRectBasedTestResult(Node*, int x, int y, const IntRect& rect = IntRect()); + bool addNodeToRectBasedTestResult(Node*, int x, int y, const IntRect& = IntRect()); + bool addNodeToRectBasedTestResult(Node*, int x, int y, const FloatRect&); const ListHashSet<RefPtr<Node> >& rectBasedTestResult() const { return m_rectBasedTestResult; } void append(const HitTestResult&); diff --git a/Source/WebCore/rendering/InlineBox.cpp b/Source/WebCore/rendering/InlineBox.cpp index 4fcbe2d..1f4e244 100644 --- a/Source/WebCore/rendering/InlineBox.cpp +++ b/Source/WebCore/rendering/InlineBox.cpp @@ -150,14 +150,12 @@ void InlineBox::attachLine() toRenderBox(m_renderer)->setInlineBoxWrapper(this); } -void InlineBox::adjustPosition(int dx, int dy) +void InlineBox::adjustPosition(float dx, float dy) { m_x += dx; m_y += dy; - if (m_renderer->isReplaced()) { - RenderBox* box = toRenderBox(m_renderer); - box->move(dx, dy); - } + if (m_renderer->isReplaced()) + toRenderBox(m_renderer)->positionLineBox(this); } void InlineBox::paint(PaintInfo& paintInfo, int tx, int ty) @@ -278,21 +276,35 @@ bool InlineBox::canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidt return !(boxRect.intersects(ellipsisRect)); } -int InlineBox::placeEllipsisBox(bool, int, int, int, bool&) +float InlineBox::placeEllipsisBox(bool, float, float, float, bool&) { // Use -1 to mean "we didn't set the position." return -1; } -IntPoint InlineBox::locationIncludingFlipping() +FloatPoint InlineBox::locationIncludingFlipping() { if (!renderer()->style()->isFlippedBlocksWritingMode()) - return IntPoint(x(), y()); + return FloatPoint(x(), y()); RenderBlock* block = root()->block(); if (block->style()->isHorizontalWritingMode()) - return IntPoint(x(), block->height() - height() - y()); + return FloatPoint(x(), block->height() - height() - y()); else - return IntPoint(block->width() - width() - x(), y()); + return FloatPoint(block->width() - width() - x(), y()); +} + +void InlineBox::flipForWritingMode(FloatRect& rect) +{ + if (!renderer()->style()->isFlippedBlocksWritingMode()) + return; + root()->block()->flipForWritingMode(rect); +} + +FloatPoint InlineBox::flipForWritingMode(const FloatPoint& point) +{ + if (!renderer()->style()->isFlippedBlocksWritingMode()) + return point; + return root()->block()->flipForWritingMode(point); } void InlineBox::flipForWritingMode(IntRect& rect) diff --git a/Source/WebCore/rendering/InlineBox.h b/Source/WebCore/rendering/InlineBox.h index d486ec0..de7b224 100644 --- a/Source/WebCore/rendering/InlineBox.h +++ b/Source/WebCore/rendering/InlineBox.h @@ -68,7 +68,7 @@ public: { } - InlineBox(RenderObject* obj, int x, int y, int logicalWidth, bool firstLine, bool constructed, + InlineBox(RenderObject* obj, float x, float y, float logicalWidth, bool firstLine, bool constructed, bool dirty, bool extracted, bool isHorizontal, InlineBox* next, InlineBox* prev, InlineFlowBox* parent) : m_next(next) , m_prev(prev) @@ -112,15 +112,15 @@ public: virtual bool isLineBreak() const { return false; } - virtual void adjustPosition(int dx, int dy); - void adjustLineDirectionPosition(int delta) + virtual void adjustPosition(float dx, float dy); + void adjustLineDirectionPosition(float delta) { if (isHorizontal()) adjustPosition(delta, 0); else adjustPosition(0, delta); } - void adjustBlockDirectionPosition(int delta) + void adjustBlockDirectionPosition(float delta) { if (isHorizontal()) adjustPosition(0, delta); @@ -220,28 +220,28 @@ public: RootInlineBox* root(); // x() is the left side of the box in the containing block's coordinate system. - void setX(int x) { m_x = x; } - int x() const { return m_x; } + void setX(float x) { m_x = x; } + float x() const { return m_x; } // y() is the top side of the box in the containing block's coordinate system. - void setY(int y) { m_y = y; } - int y() const { return m_y; } + void setY(float y) { m_y = y; } + float y() const { return m_y; } - int width() const { return isHorizontal() ? logicalWidth() : logicalHeight(); } - int height() const { return isHorizontal() ? logicalHeight() : logicalWidth(); } - - IntRect frameRect() const { return IntRect(x(), y(), width(), height()); } + float width() const { return isHorizontal() ? logicalWidth() : logicalHeight(); } + float height() const { return isHorizontal() ? logicalHeight() : logicalWidth(); } // The logicalLeft position is the left edge of the line box in a horizontal line and the top edge in a vertical line. - int logicalLeft() const { return isHorizontal() ? m_x : m_y; } - int logicalRight() const { return logicalLeft() + logicalWidth(); } - void setLogicalLeft(int left) + float logicalLeft() const { return isHorizontal() ? m_x : m_y; } + float logicalRight() const { return logicalLeft() + logicalWidth(); } + void setLogicalLeft(float left) { if (isHorizontal()) m_x = left; else m_y = left; } + int pixelSnappedLogicalLeft() const { return logicalLeft(); } + int pixelSnappedLogicalRight() const { return ceilf(logicalRight()); } // The logicalTop[ position is the top edge of the line box in a horizontal line and the left edge in a vertical line. int logicalTop() const { return isHorizontal() ? m_y : m_x; } @@ -255,8 +255,8 @@ public: } // The logical width is our extent in the line's overall inline direction, i.e., width for horizontal text and height for vertical text. - void setLogicalWidth(int w) { m_logicalWidth = w; } - int logicalWidth() const { return m_logicalWidth; } + void setLogicalWidth(float w) { m_logicalWidth = w; } + float logicalWidth() const { return m_logicalWidth; } // The logical height is our extent in the block flow direction, i.e., height for horizontal text and width for vertical text. int logicalHeight() const; @@ -286,7 +286,7 @@ public: virtual bool canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth); // visibleLeftEdge, visibleRightEdge are in the parent's coordinate system. - virtual int placeEllipsisBox(bool ltr, int visibleLeftEdge, int visibleRightEdge, int ellipsisWidth, bool&); + virtual float placeEllipsisBox(bool ltr, float visibleLeftEdge, float visibleRightEdge, float ellipsisWidth, bool&); void setHasBadParent(); @@ -294,6 +294,8 @@ public: bool visibleToHitTesting() const { return renderer()->style()->visibility() == VISIBLE && renderer()->style()->pointerEvents() != PE_NONE; } + EVerticalAlign verticalAlign() const { return renderer()->style(m_firstLine)->verticalAlign(); } + // Use with caution! The type is not checked! RenderBoxModelObject* boxModelObject() const { @@ -302,7 +304,9 @@ public: return 0; } - IntPoint locationIncludingFlipping(); + FloatPoint locationIncludingFlipping(); + void flipForWritingMode(FloatRect&); + FloatPoint flipForWritingMode(const FloatPoint&); void flipForWritingMode(IntRect&); IntPoint flipForWritingMode(const IntPoint&); @@ -315,9 +319,9 @@ private: public: RenderObject* m_renderer; - int m_x; - int m_y; - int m_logicalWidth; + float m_x; + float m_y; + float m_logicalWidth; // Some of these bits are actually for subclasses and moved here to compact the structures. 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; diff --git a/Source/WebCore/rendering/InlineFlowBox.h b/Source/WebCore/rendering/InlineFlowBox.h index d47111f8..918cf5d 100644 --- a/Source/WebCore/rendering/InlineFlowBox.h +++ b/Source/WebCore/rendering/InlineFlowBox.h @@ -85,7 +85,7 @@ public: virtual void deleteLine(RenderArena*); virtual void extractLine(); virtual void attachLine(); - virtual void adjustPosition(int dx, int dy); + virtual void adjustPosition(float dx, float dy); virtual void extractLineBoxFromRenderObject(); virtual void attachLineBoxToRenderObject(); @@ -93,6 +93,8 @@ public: virtual void clearTruncation(); + IntRect roundedFrameRect() const; + virtual void paintBoxDecorations(PaintInfo&, int tx, int ty); virtual void paintMask(PaintInfo&, int tx, int ty); void paintFillLayers(const PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int w, int h, CompositeOperator = CompositeSourceOver); @@ -155,7 +157,7 @@ public: void determineSpacingForFlowBoxes(bool lastLine, RenderObject* endObject); int getFlowSpacingLogicalWidth(); bool onEndChain(RenderObject* endObject); - int placeBoxesInInlineDirection(int logicalLeft, bool& needsWordSpacing, GlyphOverflowAndFallbackFontsMap&); + float placeBoxesInInlineDirection(float logicalLeft, bool& needsWordSpacing, GlyphOverflowAndFallbackFontsMap&); void computeLogicalBoxHeights(int& maxPositionTop, int& maxPositionBottom, int& maxAscent, int& maxDescent, bool& setMaxAscent, bool& setMaxDescent, bool strictMode, GlyphOverflowAndFallbackFontsMap&, FontBaseline, VerticalPositionCache&); @@ -176,7 +178,7 @@ public: virtual RenderObject::SelectionState selectionState(); virtual bool canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth); - virtual int placeEllipsisBox(bool ltr, int blockLeftEdge, int blockRightEdge, int ellipsisWidth, bool&); + virtual float placeEllipsisBox(bool ltr, float blockLeftEdge, float blockRightEdge, float ellipsisWidth, bool&); bool hasTextChildren() const { return m_hasTextChildren; } @@ -187,10 +189,10 @@ public: // For horizontal-tb and vertical-lr they will match physical directions, but for horizontal-bt and vertical-rl, the top/bottom and left/right // respectively are flipped when compared to their physical counterparts. For example minX is on the left in vertical-lr, but it is on the right in vertical-rl. int minYLayoutOverflow() const { return m_overflow ? m_overflow->minYLayoutOverflow() : m_y; } - int maxYLayoutOverflow() const { return m_overflow ? m_overflow->maxYLayoutOverflow() : m_y + height(); } + int maxYLayoutOverflow() const { return m_overflow ? m_overflow->maxYLayoutOverflow() : ceilf(m_y + height()); } int minXLayoutOverflow() const { return m_overflow ? m_overflow->minXLayoutOverflow() : m_x; } - int maxXLayoutOverflow() const { return m_overflow ? m_overflow->maxXLayoutOverflow() : m_x + width(); } - IntRect layoutOverflowRect() const { return m_overflow ? m_overflow->layoutOverflowRect() : IntRect(m_x, m_y, width(), height()); } + int maxXLayoutOverflow() const { return m_overflow ? m_overflow->maxXLayoutOverflow() : ceilf(m_x + width()); } + IntRect layoutOverflowRect() const { return m_overflow ? m_overflow->layoutOverflowRect() : enclosingIntRect(FloatRect(m_x, m_y, width(), height())); } int logicalLeftLayoutOverflow() const { return renderer()->style()->isHorizontalWritingMode() ? minXLayoutOverflow() : minYLayoutOverflow(); } int logicalRightLayoutOverflow() const { return renderer()->style()->isHorizontalWritingMode() ? maxXLayoutOverflow() : maxYLayoutOverflow(); } int logicalTopLayoutOverflow() const { return renderer()->style()->isHorizontalWritingMode() ? minYVisualOverflow() : minXVisualOverflow(); } @@ -204,10 +206,10 @@ public: } int minYVisualOverflow() const { return m_overflow ? m_overflow->minYVisualOverflow() : m_y; } - int maxYVisualOverflow() const { return m_overflow ? m_overflow->maxYVisualOverflow() : m_y + height(); } + int maxYVisualOverflow() const { return m_overflow ? m_overflow->maxYVisualOverflow() : ceilf(m_y + height()); } int minXVisualOverflow() const { return m_overflow ? m_overflow->minXVisualOverflow() : m_x; } - int maxXVisualOverflow() const { return m_overflow ? m_overflow->maxXVisualOverflow() : m_x + width(); } - IntRect visualOverflowRect() const { return m_overflow ? m_overflow->visualOverflowRect() : IntRect(m_x, m_y, width(), height()); } + int maxXVisualOverflow() const { return m_overflow ? m_overflow->maxXVisualOverflow() : ceilf(m_x + width()); } + IntRect visualOverflowRect() const { return m_overflow ? m_overflow->visualOverflowRect() : enclosingIntRect(FloatRect(m_x, m_y, width(), height())); } int logicalLeftVisualOverflow() const { return renderer()->style()->isHorizontalWritingMode() ? minXVisualOverflow() : minYVisualOverflow(); } int logicalRightVisualOverflow() const { return renderer()->style()->isHorizontalWritingMode() ? maxXVisualOverflow() : maxYVisualOverflow(); } int logicalTopVisualOverflow() const { return renderer()->style()->isHorizontalWritingMode() ? minYVisualOverflow() : minXVisualOverflow(); } diff --git a/Source/WebCore/rendering/InlineTextBox.cpp b/Source/WebCore/rendering/InlineTextBox.cpp index 4802f02..6d6ca4d 100644 --- a/Source/WebCore/rendering/InlineTextBox.cpp +++ b/Source/WebCore/rendering/InlineTextBox.cpp @@ -208,7 +208,7 @@ void InlineTextBox::attachLine() toRenderText(renderer())->attachTextBox(this); } -int InlineTextBox::placeEllipsisBox(bool flowIsLTR, int visibleLeftEdge, int visibleRightEdge, int ellipsisWidth, bool& foundBox) +float InlineTextBox::placeEllipsisBox(bool flowIsLTR, float visibleLeftEdge, float visibleRightEdge, float ellipsisWidth, bool& foundBox) { if (foundBox) { m_truncation = cFullTruncation; @@ -216,7 +216,7 @@ int InlineTextBox::placeEllipsisBox(bool flowIsLTR, int visibleLeftEdge, int vis } // For LTR this is the left edge of the box, for RTL, the right edge in parent coordinates. - int ellipsisX = flowIsLTR ? visibleRightEdge - ellipsisWidth : visibleLeftEdge + ellipsisWidth; + float ellipsisX = flowIsLTR ? visibleRightEdge - ellipsisWidth : visibleLeftEdge + ellipsisWidth; // Criteria for full truncation: // LTR: the left edge of the ellipsis is to the left of our text run. @@ -258,7 +258,7 @@ int InlineTextBox::placeEllipsisBox(bool flowIsLTR, int visibleLeftEdge, int vis // If we got here that means that we were only partially truncated and we need to return the pixel offset at which // to place the ellipsis. - int widthOfVisibleText = toRenderText(renderer())->width(m_start, offset, textPos(), m_firstLine); + float widthOfVisibleText = toRenderText(renderer())->width(m_start, offset, textPos(), m_firstLine); // The ellipsis needs to be placed just after the last visible character. // Where "after" is defined by the flow directionality, not the inline @@ -326,9 +326,9 @@ bool InlineTextBox::nodeAtPoint(const HitTestRequest&, HitTestResult& result, in if (isLineBreak()) return false; - IntPoint boxOrigin = locationIncludingFlipping(); + FloatPoint boxOrigin = locationIncludingFlipping(); boxOrigin.move(tx, ty); - IntRect rect(boxOrigin, IntSize(width(), height())); + FloatRect rect(boxOrigin, IntSize(width(), height())); if (m_truncation != cFullTruncation && visibleToHitTesting() && rect.intersects(result.rectForPoint(x, y))) { renderer()->updateHitTestResult(result, flipForWritingMode(IntPoint(x - tx, y - ty))); if (!result.addNodeToRectBasedTestResult(renderer()->node(), x, y, rect)) @@ -364,8 +364,8 @@ FloatSize InlineTextBox::applyShadowToGraphicsContext(GraphicsContext* context, return extraOffset; } -static void paintTextWithShadows(GraphicsContext* context, const Font& font, const TextRun& textRun, const AtomicString& emphasisMark, int emphasisMarkOffset, int startOffset, int endOffset, int truncationPoint, const IntPoint& textOrigin, - const IntRect& boxRect, const ShadowData* shadow, bool stroked, bool horizontal) +static void paintTextWithShadows(GraphicsContext* context, const Font& font, const TextRun& textRun, const AtomicString& emphasisMark, int emphasisMarkOffset, int startOffset, int endOffset, int truncationPoint, const FloatPoint& textOrigin, + const FloatRect& boxRect, const ShadowData* shadow, bool stroked, bool horizontal) { Color fillColor = context->fillColor(); ColorSpace fillColorSpace = context->fillColorSpace(); @@ -489,10 +489,10 @@ void InlineTextBox::paint(PaintInfo& paintInfo, int tx, int ty) ty -= styleToUse->isHorizontalWritingMode() ? 0 : logicalHeight(); - IntPoint boxOrigin = locationIncludingFlipping(); + FloatPoint boxOrigin = locationIncludingFlipping(); boxOrigin.move(tx, ty); - IntRect boxRect(boxOrigin, IntSize(logicalWidth(), logicalHeight())); - IntPoint textOrigin = IntPoint(boxOrigin.x(), boxOrigin.y() + styleToUse->fontMetrics().ascent()); + FloatRect boxRect(boxOrigin, IntSize(logicalWidth(), logicalHeight())); + FloatPoint textOrigin = FloatPoint(boxOrigin.x(), boxOrigin.y() + styleToUse->fontMetrics().ascent()); RenderCombineText* combinedText = styleToUse->hasTextCombine() ? toRenderCombineText(textRenderer()) : 0; bool shouldRotate = !isHorizontal() && (!combinedText || !combinedText->isCombined()); @@ -747,7 +747,7 @@ void InlineTextBox::selectionStartEnd(int& sPos, int& ePos) ePos = min(endPos - m_start, (int)m_len); } -void InlineTextBox::paintSelection(GraphicsContext* context, const IntPoint& boxOrigin, RenderStyle* style, const Font& font) +void InlineTextBox::paintSelection(GraphicsContext* context, const FloatPoint& boxOrigin, RenderStyle* style, const Font& font) { // See if we have a selection to paint at all. int sPos, ePos; @@ -781,6 +781,7 @@ void InlineTextBox::paintSelection(GraphicsContext* context, const IntPoint& box int deltaY = renderer()->style()->isFlippedLinesWritingMode() ? selectionBottom() - logicalBottom() : logicalTop() - selectionTop(); int selHeight = selectionHeight(); +<<<<<<< HEAD IntPoint localOrigin(boxOrigin.x(), boxOrigin.y() - deltaY); context->clip(IntRect(localOrigin, IntSize(m_logicalWidth, selHeight))); #ifdef ANDROID_DISABLE_ROUNDING_HACKS @@ -790,6 +791,10 @@ void InlineTextBox::paintSelection(GraphicsContext* context, const IntPoint& box textRun.disableRoundingHacks(); context->drawHighlightForText(font, textRun, localOrigin, selHeight, c, style->colorSpace(), sPos, ePos); #else +======= + FloatPoint localOrigin(boxOrigin.x(), boxOrigin.y() - deltaY); + context->clip(FloatRect(localOrigin, FloatSize(m_logicalWidth, selHeight))); +>>>>>>> WebKit at r80534 context->drawHighlightForText(font, TextRun(characters, length, textRenderer()->allowTabs(), textPos(), m_expansion, trailingExpansionBehavior(), !isLeftToRightDirection(), m_dirOverride || style->visuallyOrdered()), localOrigin, selHeight, c, style->colorSpace(), sPos, ePos); @@ -797,7 +802,7 @@ void InlineTextBox::paintSelection(GraphicsContext* context, const IntPoint& box context->restore(); } -void InlineTextBox::paintCompositionBackground(GraphicsContext* context, const IntPoint& boxOrigin, RenderStyle* style, const Font& font, int startPos, int endPos) +void InlineTextBox::paintCompositionBackground(GraphicsContext* context, const FloatPoint& boxOrigin, RenderStyle* style, const Font& font, int startPos, int endPos) { int offset = m_start; int sPos = max(startPos - offset, 0); @@ -814,6 +819,7 @@ void InlineTextBox::paintCompositionBackground(GraphicsContext* context, const I int deltaY = renderer()->style()->isFlippedLinesWritingMode() ? selectionBottom() - logicalBottom() : logicalTop() - selectionTop(); int selHeight = selectionHeight(); +<<<<<<< HEAD IntPoint localOrigin(boxOrigin.x(), boxOrigin.y() - deltaY); #ifdef ANDROID_DISABLE_ROUNDING_HACKS TextRun textRun = TextRun(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_expansion, trailingExpansionBehavior(), @@ -822,6 +828,9 @@ void InlineTextBox::paintCompositionBackground(GraphicsContext* context, const I textRun.disableRoundingHacks(); context->drawHighlightForText(font, textRun, localOrigin, selHeight, c, style->colorSpace(), sPos, ePos); #else +======= + FloatPoint localOrigin(boxOrigin.x(), boxOrigin.y() - deltaY); +>>>>>>> WebKit at r80534 context->drawHighlightForText(font, TextRun(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_expansion, trailingExpansionBehavior(), !isLeftToRightDirection(), m_dirOverride || style->visuallyOrdered()), localOrigin, selHeight, c, style->colorSpace(), sPos, ePos); @@ -849,14 +858,14 @@ void InlineTextBox::paintCustomHighlight(int tx, int ty, const AtomicString& typ #endif -void InlineTextBox::paintDecoration(GraphicsContext* context, const IntPoint& boxOrigin, int deco, const ShadowData* shadow) +void InlineTextBox::paintDecoration(GraphicsContext* context, const FloatPoint& boxOrigin, int deco, const ShadowData* shadow) { if (m_truncation == cFullTruncation) return; - IntPoint localOrigin = boxOrigin; + FloatPoint localOrigin = boxOrigin; - int width = m_logicalWidth; + float width = m_logicalWidth; if (m_truncation != cNoTruncation) { width = toRenderText(renderer())->width(m_start, m_truncation, textPos(), m_firstLine); if (!isLeftToRightDirection()) @@ -880,9 +889,9 @@ void InlineTextBox::paintDecoration(GraphicsContext* context, const IntPoint& bo int extraOffset = 0; if (!linesAreOpaque && shadow && shadow->next()) { context->save(); - IntRect clipRect(localOrigin, IntSize(width, baseline + 2)); + FloatRect clipRect(localOrigin, FloatSize(width, baseline + 2)); for (const ShadowData* s = shadow; s; s = s->next()) { - IntRect shadowRect(localOrigin, IntSize(width, baseline + 2)); + FloatRect shadowRect(localOrigin, FloatSize(width, baseline + 2)); shadowRect.inflate(s->blur()); int shadowX = isHorizontal() ? s->x() : s->y(); int shadowY = isHorizontal() ? s->y() : -s->x(); @@ -909,7 +918,7 @@ void InlineTextBox::paintDecoration(GraphicsContext* context, const IntPoint& bo } int shadowX = isHorizontal() ? shadow->x() : shadow->y(); int shadowY = isHorizontal() ? shadow->y() : -shadow->x(); - context->setShadow(IntSize(shadowX, shadowY - extraOffset), shadow->blur(), shadow->color(), colorSpace); + context->setShadow(FloatSize(shadowX, shadowY - extraOffset), shadow->blur(), shadow->color(), colorSpace); setShadow = true; shadow = shadow->next(); } @@ -918,7 +927,7 @@ void InlineTextBox::paintDecoration(GraphicsContext* context, const IntPoint& bo context->setStrokeColor(underline, colorSpace); context->setStrokeStyle(SolidStroke); // Leave one pixel of white between the baseline and the underline. - context->drawLineForText(IntPoint(localOrigin.x(), localOrigin.y() + baseline + 1), width, isPrinting); + context->drawLineForText(FloatPoint(localOrigin.x(), localOrigin.y() + baseline + 1), width, isPrinting); } if (deco & OVERLINE) { context->setStrokeColor(overline, colorSpace); @@ -928,7 +937,7 @@ void InlineTextBox::paintDecoration(GraphicsContext* context, const IntPoint& bo if (deco & LINE_THROUGH) { context->setStrokeColor(linethrough, colorSpace); context->setStrokeStyle(SolidStroke); - context->drawLineForText(IntPoint(localOrigin.x(), localOrigin.y() + 2 * baseline / 3), width, isPrinting); + context->drawLineForText(FloatPoint(localOrigin.x(), localOrigin.y() + 2 * baseline / 3), width, isPrinting); } } while (shadow); @@ -953,7 +962,7 @@ static GraphicsContext::TextCheckingLineStyle textCheckingLineStyleForMarkerType } } -void InlineTextBox::paintSpellingOrGrammarMarker(GraphicsContext* pt, const IntPoint& boxOrigin, const DocumentMarker& marker, RenderStyle* style, const Font& font, bool grammar) +void InlineTextBox::paintSpellingOrGrammarMarker(GraphicsContext* pt, const FloatPoint& boxOrigin, const DocumentMarker& marker, RenderStyle* style, const Font& font, bool grammar) { // Never print spelling/grammar markers (5327887) if (textRenderer()->document()->printing()) @@ -962,8 +971,8 @@ void InlineTextBox::paintSpellingOrGrammarMarker(GraphicsContext* pt, const IntP if (m_truncation == cFullTruncation) return; - int start = 0; // start of line to draw, relative to tx - int width = m_logicalWidth; // how much line to draw + float start = 0; // start of line to draw, relative to tx + float width = m_logicalWidth; // how much line to draw // Determine whether we need to measure text bool markerSpansWholeBox = true; @@ -984,13 +993,18 @@ void InlineTextBox::paintSpellingOrGrammarMarker(GraphicsContext* pt, const IntP // Calculate start & width int deltaY = renderer()->style()->isFlippedLinesWritingMode() ? selectionBottom() - logicalBottom() : logicalTop() - selectionTop(); int selHeight = selectionHeight(); - IntPoint startPoint(boxOrigin.x(), boxOrigin.y() - deltaY); + FloatPoint startPoint(boxOrigin.x(), boxOrigin.y() - deltaY); TextRun run(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_expansion, trailingExpansionBehavior(), !isLeftToRightDirection(), m_dirOverride || style->visuallyOrdered()); +<<<<<<< HEAD #ifdef ANDROID_DISABLE_ROUNDING_HACKS if (m_disableRoundingHacks) run.disableRoundingHacks(); #endif +======= + + // FIXME: Convert the document markers to float rects. +>>>>>>> WebKit at r80534 IntRect markerRect = enclosingIntRect(font.selectionRectForText(run, startPoint, selHeight, startPosition, endPosition)); start = markerRect.x() - startPoint.x(); width = markerRect.width(); @@ -1021,10 +1035,10 @@ void InlineTextBox::paintSpellingOrGrammarMarker(GraphicsContext* pt, const IntP // In larger fonts, though, place the underline up near the baseline to prevent a big gap. underlineOffset = baseline + 2; } - pt->drawLineForTextChecking(IntPoint(boxOrigin.x() + start, boxOrigin.y() + underlineOffset), width, textCheckingLineStyleForMarkerType(marker.type)); + pt->drawLineForTextChecking(FloatPoint(boxOrigin.x() + start, boxOrigin.y() + underlineOffset), width, textCheckingLineStyleForMarkerType(marker.type)); } -void InlineTextBox::paintTextMatchMarker(GraphicsContext* pt, const IntPoint& boxOrigin, const DocumentMarker& marker, RenderStyle* style, const Font& font) +void InlineTextBox::paintTextMatchMarker(GraphicsContext* pt, const FloatPoint& boxOrigin, const DocumentMarker& marker, RenderStyle* style, const Font& font) { // Use same y positioning and height as for selection, so that when the selection and this highlight are on // the same word there are no pieces sticking out. @@ -1051,8 +1065,8 @@ void InlineTextBox::paintTextMatchMarker(GraphicsContext* pt, const IntPoint& bo renderer()->theme()->platformInactiveTextSearchHighlightColor(); pt->save(); updateGraphicsContext(pt, color, color, 0, style->colorSpace()); // Don't draw text at all! - pt->clip(IntRect(boxOrigin.x(), boxOrigin.y() - deltaY, m_logicalWidth, selHeight)); - pt->drawHighlightForText(font, run, IntPoint(boxOrigin.x(), boxOrigin.y() - deltaY), selHeight, color, style->colorSpace(), sPos, ePos); + pt->clip(FloatRect(boxOrigin.x(), boxOrigin.y() - deltaY, m_logicalWidth, selHeight)); + pt->drawHighlightForText(font, run, FloatPoint(boxOrigin.x(), boxOrigin.y() - deltaY), selHeight, color, style->colorSpace(), sPos, ePos); pt->restore(); } } @@ -1078,7 +1092,7 @@ void InlineTextBox::computeRectForReplacementMarker(const DocumentMarker& marker renderer()->document()->markers()->setRenderedRectForMarker(renderer()->node(), marker, markerRect); } -void InlineTextBox::paintDocumentMarkers(GraphicsContext* pt, const IntPoint& boxOrigin, RenderStyle* style, const Font& font, bool background) +void InlineTextBox::paintDocumentMarkers(GraphicsContext* pt, const FloatPoint& boxOrigin, RenderStyle* style, const Font& font, bool background) { if (!renderer()->node()) return; @@ -1096,6 +1110,7 @@ void InlineTextBox::paintDocumentMarkers(GraphicsContext* pt, const IntPoint& bo case DocumentMarker::Grammar: case DocumentMarker::Spelling: case DocumentMarker::CorrectionIndicator: + case DocumentMarker::Replacement: if (background) continue; break; @@ -1128,9 +1143,11 @@ void InlineTextBox::paintDocumentMarkers(GraphicsContext* pt, const IntPoint& bo paintTextMatchMarker(pt, boxOrigin, marker, style, font); break; case DocumentMarker::CorrectionIndicator: - computeRectForReplacementMarker(marker, style, font); paintSpellingOrGrammarMarker(pt, boxOrigin, marker, style, font, false); break; + case DocumentMarker::Replacement: + computeRectForReplacementMarker(marker, style, font); + break; default: ASSERT_NOT_REACHED(); } @@ -1138,14 +1155,13 @@ void InlineTextBox::paintDocumentMarkers(GraphicsContext* pt, const IntPoint& bo } } - -void InlineTextBox::paintCompositionUnderline(GraphicsContext* ctx, const IntPoint& boxOrigin, const CompositionUnderline& underline) +void InlineTextBox::paintCompositionUnderline(GraphicsContext* ctx, const FloatPoint& boxOrigin, const CompositionUnderline& underline) { if (m_truncation == cFullTruncation) return; - int start = 0; // start of line to draw, relative to tx - int width = m_logicalWidth; // how much line to draw + float start = 0; // start of line to draw, relative to tx + float width = m_logicalWidth; // how much line to draw bool useWholeWidth = true; unsigned paintStart = m_start; unsigned paintEnd = end() + 1; // end points at the last char, not past it @@ -1181,7 +1197,7 @@ void InlineTextBox::paintCompositionUnderline(GraphicsContext* ctx, const IntPoi ctx->setStrokeColor(underline.color, renderer()->style()->colorSpace()); ctx->setStrokeThickness(lineThickness); - ctx->drawLineForText(IntPoint(boxOrigin.x() + start, boxOrigin.y() + logicalHeight() - lineThickness), width, textRenderer()->document()->printing()); + ctx->drawLineForText(FloatPoint(boxOrigin.x() + start, boxOrigin.y() + logicalHeight() - lineThickness), width, textRenderer()->document()->printing()); } int InlineTextBox::caretMinOffset() const @@ -1199,7 +1215,7 @@ unsigned InlineTextBox::caretMaxRenderedOffset() const return m_start + m_len; } -int InlineTextBox::textPos() const +float InlineTextBox::textPos() const { // When computing the width of a text run, RenderBlock::computeInlineDirectionPositionsForLine() doesn't include the actual offset // from the containing block edge in its measurement. textPos() should be consistent so the text are rendered in the same width. @@ -1208,7 +1224,7 @@ int InlineTextBox::textPos() const return logicalLeft() - root()->logicalLeft(); } -int InlineTextBox::offsetForPosition(int lineOffset, bool includePartialGlyphs) const +int InlineTextBox::offsetForPosition(float lineOffset, bool includePartialGlyphs) const { if (isLineBreak()) return 0; @@ -1242,7 +1258,7 @@ int InlineTextBox::offsetForPosition(int lineOffset, bool includePartialGlyphs) return offset; } -int InlineTextBox::positionForOffset(int offset) const +float InlineTextBox::positionForOffset(int offset) const { ASSERT(offset >= m_start); ASSERT(offset <= m_start + m_len); @@ -1255,6 +1271,7 @@ int InlineTextBox::positionForOffset(int offset) const int from = !isLeftToRightDirection() ? offset - m_start : 0; int to = !isLeftToRightDirection() ? m_len : offset - m_start; // FIXME: Do we need to add rightBearing here? +<<<<<<< HEAD #ifdef ANDROID_DISABLE_ROUNDING_HACKS TextRun textRun = TextRun(text->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_expansion, trailingExpansionBehavior(), !isLeftToRightDirection(), m_dirOverride); if (m_disableRoundingHacks) @@ -1264,6 +1281,10 @@ int InlineTextBox::positionForOffset(int offset) const return enclosingIntRect(f.selectionRectForText(TextRun(text->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_expansion, trailingExpansionBehavior(), !isLeftToRightDirection(), m_dirOverride), IntPoint(logicalLeft(), 0), 0, from, to)).maxX(); #endif +======= + return f.selectionRectForText(TextRun(text->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_expansion, trailingExpansionBehavior(), !isLeftToRightDirection(), m_dirOverride), + IntPoint(logicalLeft(), 0), 0, from, to).maxX(); +>>>>>>> WebKit at r80534 } bool InlineTextBox::containsCaretOffset(int offset) const diff --git a/Source/WebCore/rendering/InlineTextBox.h b/Source/WebCore/rendering/InlineTextBox.h index 095fa16..a900a71 100644 --- a/Source/WebCore/rendering/InlineTextBox.h +++ b/Source/WebCore/rendering/InlineTextBox.h @@ -112,12 +112,12 @@ public: private: virtual void clearTruncation() { m_truncation = cNoTruncation; } - virtual int placeEllipsisBox(bool flowIsLTR, int visibleLeftEdge, int visibleRightEdge, int ellipsisWidth, bool& foundBox); + virtual float placeEllipsisBox(bool flowIsLTR, float visibleLeftEdge, float visibleRightEdge, float ellipsisWidth, bool& foundBox); public: virtual bool isLineBreak() const; - void setExpansion(int expansion) { m_logicalWidth -= m_expansion; m_expansion = expansion; m_logicalWidth += m_expansion; } + void setExpansion(float expansion) { m_logicalWidth -= m_expansion; m_expansion = expansion; m_logicalWidth += m_expansion; } private: virtual bool isInlineTextBox() const { return true; } @@ -129,11 +129,11 @@ public: private: virtual unsigned caretMaxRenderedOffset() const; - int textPos() const; // returns the x position relative to the left start of the text line. + float textPos() const; // returns the x position relative to the left start of the text line. public: - virtual int offsetForPosition(int x, bool includePartialGlyphs = true) const; - virtual int positionForOffset(int offset) const; + virtual int offsetForPosition(float x, bool includePartialGlyphs = true) const; + virtual float positionForOffset(int offset) const; bool containsCaretOffset(int offset) const; // false for offset after line break @@ -154,18 +154,18 @@ private: #endif protected: - void paintCompositionBackground(GraphicsContext*, const IntPoint& boxOrigin, RenderStyle*, const Font&, int startPos, int endPos); - void paintDocumentMarkers(GraphicsContext*, const IntPoint& boxOrigin, RenderStyle*, const Font&, bool background); - void paintCompositionUnderline(GraphicsContext*, const IntPoint& boxOrigin, const CompositionUnderline&); + void paintCompositionBackground(GraphicsContext*, const FloatPoint& boxOrigin, RenderStyle*, const Font&, int startPos, int endPos); + void paintDocumentMarkers(GraphicsContext*, const FloatPoint& boxOrigin, RenderStyle*, const Font&, bool background); + void paintCompositionUnderline(GraphicsContext*, const FloatPoint& boxOrigin, const CompositionUnderline&); #if PLATFORM(MAC) void paintCustomHighlight(int tx, int ty, const AtomicString& type); #endif private: - void paintDecoration(GraphicsContext*, const IntPoint& boxOrigin, int decoration, const ShadowData*); - void paintSelection(GraphicsContext*, const IntPoint& boxOrigin, RenderStyle*, const Font&); - void paintSpellingOrGrammarMarker(GraphicsContext*, const IntPoint& boxOrigin, const DocumentMarker&, RenderStyle*, const Font&, bool grammar); - void paintTextMatchMarker(GraphicsContext*, const IntPoint& boxOrigin, const DocumentMarker&, RenderStyle*, const Font&); + void paintDecoration(GraphicsContext*, const FloatPoint& boxOrigin, int decoration, const ShadowData*); + void paintSelection(GraphicsContext*, const FloatPoint& boxOrigin, RenderStyle*, const Font&); + void paintSpellingOrGrammarMarker(GraphicsContext*, const FloatPoint& boxOrigin, const DocumentMarker&, RenderStyle*, const Font&, bool grammar); + void paintTextMatchMarker(GraphicsContext*, const FloatPoint& boxOrigin, const DocumentMarker&, RenderStyle*, const Font&); void computeRectForReplacementMarker(const DocumentMarker&, RenderStyle*, const Font&); TextRun::TrailingExpansionBehavior trailingExpansionBehavior() const { return m_expansion && nextLeafChild() ? TextRun::AllowTrailingExpansion : TextRun::ForbidTrailingExpansion; } diff --git a/Source/WebCore/rendering/MediaControlElements.cpp b/Source/WebCore/rendering/MediaControlElements.cpp index 6defbb7..32aac90 100644 --- a/Source/WebCore/rendering/MediaControlElements.cpp +++ b/Source/WebCore/rendering/MediaControlElements.cpp @@ -487,13 +487,6 @@ inline MediaControlMuteButtonElement::MediaControlMuteButtonElement(HTMLMediaEle { } -PassRefPtr<MediaControlMuteButtonElement> MediaControlMuteButtonElement::create(HTMLMediaElement* mediaElement) -{ - RefPtr<MediaControlMuteButtonElement> button = adoptRef(new MediaControlMuteButtonElement(mediaElement, MediaMuteButton)); - button->setType("button"); - return button.release(); -} - void MediaControlMuteButtonElement::defaultEventHandler(Event* event) { if (event->type() == eventNames().clickEvent) { @@ -503,17 +496,33 @@ void MediaControlMuteButtonElement::defaultEventHandler(Event* event) HTMLInputElement::defaultEventHandler(event); } -const AtomicString& MediaControlMuteButtonElement::shadowPseudoId() const +void MediaControlMuteButtonElement::updateDisplayType() { - DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-mute-button")); - return id; + setDisplayType(mediaElement()->muted() ? MediaUnMuteButton : MediaMuteButton); } -void MediaControlMuteButtonElement::updateDisplayType() +// ---------------------------- + +inline MediaControlPanelMuteButtonElement::MediaControlPanelMuteButtonElement(HTMLMediaElement* mediaElement) + : MediaControlMuteButtonElement(mediaElement, MediaMuteButton) { - setDisplayType(mediaElement()->muted() ? MediaUnMuteButton : MediaMuteButton); } +PassRefPtr<MediaControlPanelMuteButtonElement> MediaControlPanelMuteButtonElement::create(HTMLMediaElement* mediaElement) +{ + RefPtr<MediaControlPanelMuteButtonElement> button = adoptRef(new MediaControlPanelMuteButtonElement(mediaElement)); + button->setType("button"); + return button.release(); +} + +const AtomicString& MediaControlPanelMuteButtonElement::shadowPseudoId() const +{ + DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-mute-button")); + return id; +} + +// ---------------------------- + inline MediaControlVolumeSliderMuteButtonElement::MediaControlVolumeSliderMuteButtonElement(HTMLMediaElement* mediaElement) : MediaControlMuteButtonElement(mediaElement, MediaVolumeSliderMuteButton) { diff --git a/Source/WebCore/rendering/MediaControlElements.h b/Source/WebCore/rendering/MediaControlElements.h index ff9541d..44e8811 100644 --- a/Source/WebCore/rendering/MediaControlElements.h +++ b/Source/WebCore/rendering/MediaControlElements.h @@ -210,8 +210,6 @@ private: class MediaControlMuteButtonElement : public MediaControlInputElement { public: - static PassRefPtr<MediaControlMuteButtonElement> create(HTMLMediaElement*); - virtual void defaultEventHandler(Event*); protected: @@ -219,6 +217,17 @@ protected: private: virtual void updateDisplayType(); +}; + +// ---------------------------- + +class MediaControlPanelMuteButtonElement : public MediaControlMuteButtonElement { +public: + static PassRefPtr<MediaControlPanelMuteButtonElement> create(HTMLMediaElement*); + +private: + MediaControlPanelMuteButtonElement(HTMLMediaElement*); + virtual const AtomicString& shadowPseudoId() const; }; diff --git a/Source/WebCore/rendering/RenderBR.h b/Source/WebCore/rendering/RenderBR.h index 72a4514..25717b1 100644 --- a/Source/WebCore/rendering/RenderBR.h +++ b/Source/WebCore/rendering/RenderBR.h @@ -40,8 +40,8 @@ public: virtual IntRect selectionRectForRepaint(RenderBoxModelObject* /*repaintContainer*/, bool /*clipToVisibleContent*/) { return IntRect(); } - virtual unsigned width(unsigned /*from*/, unsigned /*len*/, const Font&, int /*xPos*/, HashSet<const SimpleFontData*>* = 0 /*fallbackFonts*/ , GlyphOverflow* = 0) const { return 0; } - virtual unsigned width(unsigned /*from*/, unsigned /*len*/, int /*xpos*/, bool = false /*firstLine*/, HashSet<const SimpleFontData*>* = 0 /*fallbackFonts*/, GlyphOverflow* = 0) const { return 0; } + virtual float width(unsigned /*from*/, unsigned /*len*/, const Font&, float /*xPos*/, HashSet<const SimpleFontData*>* = 0 /*fallbackFonts*/ , GlyphOverflow* = 0) const { return 0; } + virtual float width(unsigned /*from*/, unsigned /*len*/, float /*xpos*/, bool = false /*firstLine*/, HashSet<const SimpleFontData*>* = 0 /*fallbackFonts*/, GlyphOverflow* = 0) const { return 0; } int lineHeight(bool firstLine) const; diff --git a/Source/WebCore/rendering/RenderBlock.cpp b/Source/WebCore/rendering/RenderBlock.cpp index 87aa630..7488ff5 100644 --- a/Source/WebCore/rendering/RenderBlock.cpp +++ b/Source/WebCore/rendering/RenderBlock.cpp @@ -126,8 +126,8 @@ RenderBlock::RenderBlock(Node* node) RenderBlock::~RenderBlock() { - delete m_floatingObjects; - delete m_positionedObjects; + if (m_floatingObjects) + deleteAllValues(m_floatingObjects->set()); if (hasColumns()) delete gColumnInfoMap->take(this); @@ -1387,9 +1387,11 @@ void RenderBlock::addOverflowFromFloats() { if (!m_floatingObjects) return; - FloatingObject* r; - DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); - for (; (r = it.current()); ++it) { + + FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); + FloatingObjectSetIterator end = floatingObjectSet.end(); + for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { + FloatingObject* r = *it; if (r->m_isDescendant) addOverflowFromChild(r->m_renderer, IntSize(xPositionForFloatIncludingMargin(r), yPositionForFloatIncludingMargin(r))); } @@ -1420,32 +1422,32 @@ bool RenderBlock::expandsToEncloseOverhangingFloats() const void RenderBlock::adjustPositionedBlock(RenderBox* child, const MarginInfo& marginInfo) { - if (child->style()->hasStaticX()) { - if (style()->isLeftToRightDirection()) - child->layer()->setStaticX(borderLeft() + paddingLeft()); - else - child->layer()->setStaticX(borderRight() + paddingRight()); - } + bool isHorizontal = style()->isHorizontalWritingMode(); + bool hasStaticInlinePosition = child->style()->hasStaticInlinePosition(isHorizontal); + bool hasStaticBlockPosition = child->style()->hasStaticBlockPosition(isHorizontal); + RenderLayer* childLayer = child->layer(); + + if (hasStaticInlinePosition) + childLayer->setStaticInlinePosition(borderAndPaddingStart()); - if (child->style()->hasStaticY()) { - int y = height(); + if (hasStaticBlockPosition) { + int logicalTop = logicalHeight(); if (!marginInfo.canCollapseWithMarginBefore()) { child->computeBlockDirectionMargins(this); - int marginTop = child->marginTop(); - int collapsedTopPos = marginInfo.positiveMargin(); - int collapsedTopNeg = marginInfo.negativeMargin(); - if (marginTop > 0) { - if (marginTop > collapsedTopPos) - collapsedTopPos = marginTop; + int marginBefore = marginBeforeForChild(child); + int collapsedBeforePos = marginInfo.positiveMargin(); + int collapsedBeforeNeg = marginInfo.negativeMargin(); + if (marginBefore > 0) { + if (marginBefore > collapsedBeforePos) + collapsedBeforePos = marginBefore; } else { - if (-marginTop > collapsedTopNeg) - collapsedTopNeg = -marginTop; + if (-marginBefore > collapsedBeforeNeg) + collapsedBeforeNeg = -marginBefore; } - y += (collapsedTopPos - collapsedTopNeg) - marginTop; + logicalTop += (collapsedBeforePos - collapsedBeforeNeg) - marginBefore; } - RenderLayer* childLayer = child->layer(); - if (childLayer->staticY() != y) { - child->layer()->setStaticY(y); + if (childLayer->staticBlockPosition() != logicalTop) { + childLayer->setStaticBlockPosition(logicalTop); child->setChildNeedsLayout(true, false); } } @@ -2135,7 +2137,7 @@ void RenderBlock::layoutPositionedObjects(bool relayoutChildren) // non-positioned block. Rather than trying to detect all of these movement cases, we just always lay out positioned // objects that are positioned implicitly like this. Such objects are rare, and so in typical DHTML menu usage (where everything is // positioned explicitly) this should not incur a performance penalty. - if (relayoutChildren || (r->style()->hasStaticY() && r->parent() != this && r->parent()->isBlockFlow())) + if (relayoutChildren || (r->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode()) && r->parent() != this && r->parent()->isBlockFlow())) r->setChildNeedsLayout(true, false); // If relayoutChildren is set and we have percentage padding, we also need to invalidate the child's pref widths. @@ -2187,14 +2189,14 @@ void RenderBlock::repaintOverhangingFloats(bool paintAllDescendants) ASSERT(m_floatingObjects); if (!m_floatingObjects) return; - - FloatingObject* r; - DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); // FIXME: Avoid disabling LayoutState. At the very least, don't disable it for floats originating // in this block. Better yet would be to push extra state for the containers of other floats. view()->disableLayoutState(); - for ( ; (r = it.current()); ++it) { + FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); + FloatingObjectSetIterator end = floatingObjectSet.end(); + for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { + FloatingObject* r = *it; // Only repaint the object if it is overhanging, is not in its own layer, and // is our responsibility to paint (m_shouldPaint is set). When paintAllDescendants is true, the latter // condition is replaced with being a descendant of us. @@ -2518,9 +2520,10 @@ void RenderBlock::paintFloats(PaintInfo& paintInfo, int tx, int ty, bool preserv if (!m_floatingObjects) return; - FloatingObject* r; - DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); - for (; (r = it.current()); ++it) { + FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); + FloatingObjectSetIterator end = floatingObjectSet.end(); + for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { + FloatingObject* r = *it; // Only paint the object if our m_shouldPaint flag is set. if (r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer()) { PaintInfo currentPaintInfo(paintInfo); @@ -2605,6 +2608,19 @@ void RenderBlock::addContinuationWithOutline(RenderInline* flow) continuations->add(flow); } +bool RenderBlock::paintsContinuationOutline(RenderInline* flow) +{ + ContinuationOutlineTableMap* table = continuationOutlineTable(); + if (table->isEmpty()) + return false; + + ListHashSet<RenderInline*>* continuations = table->get(this); + if (!continuations) + return false; + + return continuations->contains(flow); +} + void RenderBlock::paintContinuationOutlines(PaintInfo& info, int tx, int ty) { ContinuationOutlineTableMap* table = continuationOutlineTable(); @@ -2752,13 +2768,15 @@ GapRects RenderBlock::selectionGaps(RenderBlock* rootBlock, const IntPoint& root IntRect flippedBlockRect = IntRect(offsetFromRootBlock.width(), offsetFromRootBlock.height(), width(), height()); rootBlock->flipForWritingMode(flippedBlockRect); flippedBlockRect.move(rootBlockPhysicalPosition.x(), rootBlockPhysicalPosition.y()); - clipOutPositionedObjects(paintInfo, flippedBlockRect.location(), m_positionedObjects); + clipOutPositionedObjects(paintInfo, flippedBlockRect.location(), m_positionedObjects.get()); if (isBody() || isRoot()) // The <body> must make sure to examine its containingBlock's positioned objects. for (RenderBlock* cb = containingBlock(); cb && !cb->isRenderView(); cb = cb->containingBlock()) - clipOutPositionedObjects(paintInfo, IntPoint(cb->x(), cb->y()), cb->m_positionedObjects); // FIXME: Not right for flipped writing modes. + clipOutPositionedObjects(paintInfo, IntPoint(cb->x(), cb->y()), cb->m_positionedObjects.get()); // FIXME: Not right for flipped writing modes. if (m_floatingObjects) { - for (DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); it.current(); ++it) { - FloatingObject* r = it.current(); + FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); + FloatingObjectSetIterator end = floatingObjectSet.end(); + for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { + FloatingObject* r = *it; IntRect floatBox = IntRect(offsetFromRootBlock.width() + xPositionForFloatIncludingMargin(r), offsetFromRootBlock.height() + yPositionForFloatIncludingMargin(r), r->m_renderer->width(), r->m_renderer->height()); @@ -3016,7 +3034,7 @@ void RenderBlock::insertPositionedObject(RenderBox* o) { // Create the list of special objects if we don't aleady have one if (!m_positionedObjects) - m_positionedObjects = new PositionedObjectsListHashSet; + m_positionedObjects = adoptPtr(new PositionedObjectsListHashSet); m_positionedObjects->add(o); } @@ -3065,18 +3083,14 @@ RenderBlock::FloatingObject* RenderBlock::insertFloatingObject(RenderBox* o) ASSERT(o->isFloating()); // Create the list of special objects if we don't aleady have one - if (!m_floatingObjects) { - m_floatingObjects = new DeprecatedPtrList<FloatingObject>; - m_floatingObjects->setAutoDelete(true); - } else { + if (!m_floatingObjects) + m_floatingObjects = adoptPtr(new FloatingObjects); + else { // Don't insert the object again if it's already in the list - DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); - FloatingObject* f; - while ( (f = it.current()) ) { - if (f->m_renderer == o) - return f; - ++it; - } + FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); + FloatingObjectSetIterator it = floatingObjectSet.find<RenderBox*, FloatingObjectHashTranslator>(o); + if (it != floatingObjectSet.end()) + return *it; } // Create the special object entry & append it to the list @@ -3102,7 +3116,8 @@ RenderBlock::FloatingObject* RenderBlock::insertFloatingObject(RenderBox* o) newObj->m_isDescendant = true; newObj->m_renderer = o; - m_floatingObjects->append(newObj); + m_floatingObjects->increaseObjectsCount(newObj->type()); + m_floatingObjects->set().add(newObj); return newObj; } @@ -3110,22 +3125,28 @@ RenderBlock::FloatingObject* RenderBlock::insertFloatingObject(RenderBox* o) void RenderBlock::removeFloatingObject(RenderBox* o) { if (m_floatingObjects) { - DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); - while (it.current()) { - if (it.current()->m_renderer == o) { - if (childrenInline()) { - int logicalTop = logicalTopForFloat(it.current()); - int logicalBottom = logicalBottomForFloat(it.current()); - + FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); + FloatingObjectSet::iterator it = floatingObjectSet.find<RenderBox*, FloatingObjectHashTranslator>(o); + if (it != floatingObjectSet.end()) { + FloatingObject* r = *it; + if (childrenInline()) { + int logicalTop = logicalTopForFloat(r); + int logicalBottom = logicalBottomForFloat(r); + + // Fix for https://bugs.webkit.org/show_bug.cgi?id=54995. + if (logicalBottom < 0 || logicalBottom < logicalTop || logicalTop == numeric_limits<int>::max()) + logicalBottom = numeric_limits<int>::max(); + else { // Special-case zero- and less-than-zero-height floats: those don't touch // the line that they're on, but it still needs to be dirtied. This is // accomplished by pretending they have a height of 1. - logicalBottom = max(logicalBottom, logicalTop == numeric_limits<int>::max() ? logicalTop : logicalTop + 1); - markLinesDirtyInBlockRange(0, logicalBottom); + logicalBottom = max(logicalBottom, logicalTop + 1); } - m_floatingObjects->removeRef(it.current()); + markLinesDirtyInBlockRange(0, logicalBottom); } - ++it; + m_floatingObjects->decreaseObjectsCount(r->type()); + floatingObjectSet.remove(it); + delete r; } } } @@ -3135,10 +3156,13 @@ void RenderBlock::removeFloatingObjectsBelow(FloatingObject* lastFloat, int logi if (!m_floatingObjects) return; - FloatingObject* curr = m_floatingObjects->last(); + FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); + FloatingObject* curr = floatingObjectSet.last(); while (curr != lastFloat && (!curr->isPlaced() || logicalTopForFloat(curr) >= logicalOffset)) { - m_floatingObjects->removeLast(); - curr = m_floatingObjects->last(); + m_floatingObjects->decreaseObjectsCount(curr->type()); + floatingObjectSet.removeLast(); + delete curr; + curr = floatingObjectSet.last(); } } @@ -3146,36 +3170,45 @@ bool RenderBlock::positionNewFloats() { if (!m_floatingObjects) return false; - - FloatingObject* floatingObject = m_floatingObjects->last(); + + FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); + if (floatingObjectSet.isEmpty()) + return false; // If all floats have already been positioned, then we have no work to do. - if (!floatingObject || floatingObject->isPlaced()) + if (floatingObjectSet.last()->isPlaced()) return false; // Move backwards through our floating object list until we find a float that has // already been positioned. Then we'll be able to move forward, positioning all of // the new floats that need it. - FloatingObject* lastFloat = m_floatingObjects->getPrev(); - while (lastFloat && !lastFloat->isPlaced()) { - floatingObject = m_floatingObjects->prev(); - lastFloat = m_floatingObjects->getPrev(); + FloatingObjectSetIterator it = floatingObjectSet.end(); + --it; // Go to last item. + FloatingObjectSetIterator begin = floatingObjectSet.begin(); + FloatingObject* lastPlacedFloatingObject = 0; + while (it != begin) { + --it; + if ((*it)->isPlaced()) { + lastPlacedFloatingObject = *it; + ++it; + break; + } } int logicalTop = logicalHeight(); // The float cannot start above the top position of the last positioned float. - if (lastFloat) - logicalTop = max(logicalTopForFloat(lastFloat), logicalTop); + if (lastPlacedFloatingObject) + logicalTop = max(logicalTopForFloat(lastPlacedFloatingObject), logicalTop); + FloatingObjectSetIterator end = floatingObjectSet.end(); // Now walk through the set of unpositioned floats and place them. - while (floatingObject) { + for (; it != end; ++it) { + FloatingObject* floatingObject = *it; // The containing block is responsible for positioning floats, so if we have floats in our // list that come from somewhere else, do not attempt to position them. - if (floatingObject->renderer()->containingBlock() != this) { - floatingObject = m_floatingObjects->next(); + if (floatingObject->renderer()->containingBlock() != this) continue; - } RenderBox* childBox = floatingObject->renderer(); int childLogicalLeftMargin = style()->isLeftToRightDirection() ? marginStartForChild(childBox) : marginEndForChild(childBox); @@ -3257,8 +3290,6 @@ bool RenderBlock::positionNewFloats() // If the child moved, we have to repaint it. if (childBox->checkForRepaintDuringLayout()) childBox->repaintDuringLayoutIfMoved(oldRect); - - floatingObject = m_floatingObjects->next(); } return true; } @@ -3269,16 +3300,23 @@ bool RenderBlock::positionNewFloatOnLine(FloatingObject* newFloat, FloatingObjec if (!didPosition || !newFloat->m_paginationStrut) return didPosition; + FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); + ASSERT(floatingObjectSet.last() == newFloat); + int floatLogicalTop = logicalTopForFloat(newFloat); int paginationStrut = newFloat->m_paginationStrut; - FloatingObject* f = m_floatingObjects->last(); - ASSERT(f == newFloat); - if (floatLogicalTop - paginationStrut != logicalHeight()) return didPosition; - for (f = m_floatingObjects->prev(); f && f != lastFloatFromPreviousLine; f = m_floatingObjects->prev()) { + FloatingObjectSetIterator it = floatingObjectSet.end(); + --it; // Last float is newFloat, skip that one. + FloatingObjectSetIterator begin = floatingObjectSet.begin(); + while (it != begin) { + --it; + FloatingObject* f = *it; + if (f == lastFloatFromPreviousLine) + break; if (logicalTopForFloat(f) == logicalHeight()) { ASSERT(!f->m_paginationStrut); f->m_paginationStrut = paginationStrut; @@ -3381,12 +3419,14 @@ HashSet<RenderBox*>* RenderBlock::percentHeightDescendants() const int RenderBlock::logicalLeftOffsetForLine(int logicalTop, int fixedOffset, bool applyTextIndent, int* heightRemaining) const { int left = fixedOffset; - if (m_floatingObjects) { + if (m_floatingObjects && m_floatingObjects->hasLeftObjects()) { if (heightRemaining) *heightRemaining = 1; - FloatingObject* r; - DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); - for ( ; (r = it.current()); ++it) { + + FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); + FloatingObjectSetIterator end = floatingObjectSet.end(); + for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { + FloatingObject* r = *it; if (r->isPlaced() && logicalTopForFloat(r) <= logicalTop && logicalBottomForFloat(r) > logicalTop && r->type() == FloatingObject::FloatLeft && logicalRightForFloat(r) > left) { @@ -3411,12 +3451,13 @@ int RenderBlock::logicalRightOffsetForLine(int logicalTop, int fixedOffset, bool { int right = fixedOffset; - if (m_floatingObjects) { + if (m_floatingObjects && m_floatingObjects->hasRightObjects()) { if (heightRemaining) *heightRemaining = 1; - FloatingObject* r; - DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); - for ( ; (r = it.current()); ++it) { + FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); + FloatingObjectSetIterator end = floatingObjectSet.end(); + for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { + FloatingObject* r = *it; if (r->isPlaced() && logicalTopForFloat(r) <= logicalTop && logicalBottomForFloat(r) > logicalTop && r->type() == FloatingObject::FloatRight && logicalLeftForFloat(r) < right) { @@ -3437,8 +3478,7 @@ int RenderBlock::logicalRightOffsetForLine(int logicalTop, int fixedOffset, bool return right; } -int -RenderBlock::availableLogicalWidthForLine(int position, bool firstLine) const +int RenderBlock::availableLogicalWidthForLine(int position, bool firstLine) const { int result = logicalRightOffsetForLine(position, firstLine) - logicalLeftOffsetForLine(position, firstLine); return (result < 0) ? 0 : result; @@ -3450,9 +3490,10 @@ int RenderBlock::nextFloatLogicalBottomBelow(int logicalHeight) const return 0; int bottom = INT_MAX; - FloatingObject* r; - DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); - for ( ; (r = it.current()); ++it) { + FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); + FloatingObjectSetIterator end = floatingObjectSet.end(); + for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { + FloatingObject* r = *it; int floatBottom = logicalBottomForFloat(r); if (floatBottom > logicalHeight) bottom = min(floatBottom, bottom); @@ -3466,9 +3507,10 @@ int RenderBlock::lowestFloatLogicalBottom(FloatingObject::Type floatType) const if (!m_floatingObjects) return 0; int lowestFloatBottom = 0; - FloatingObject* r; - DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); - for ( ; (r = it.current()); ++it) { + FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); + FloatingObjectSetIterator end = floatingObjectSet.end(); + for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { + FloatingObject* r = *it; if (r->isPlaced() && r->type() & floatType) lowestFloatBottom = max(lowestFloatBottom, logicalBottomForFloat(r)); } @@ -3487,7 +3529,7 @@ void RenderBlock::markLinesDirtyInBlockRange(int logicalTop, int logicalBottom, lowestDirtyLine = lowestDirtyLine->prevRootBox(); } - while (afterLowest && afterLowest != highest && afterLowest->blockLogicalHeight() >= logicalTop) { + while (afterLowest && afterLowest != highest && (afterLowest->blockLogicalHeight() >= logicalTop || afterLowest->blockLogicalHeight() < 0)) { afterLowest->markDirty(); afterLowest = afterLowest->prevRootBox(); } @@ -3497,8 +3539,10 @@ void RenderBlock::clearFloats() { // Inline blocks are covered by the isReplaced() check in the avoidFloats method. if (avoidsFloats() || isRoot() || isRenderView() || isFloatingOrPositioned() || isTableCell()) { - if (m_floatingObjects) + if (m_floatingObjects) { + deleteAllValues(m_floatingObjects->set()); m_floatingObjects->clear(); + } return; } @@ -3506,12 +3550,16 @@ void RenderBlock::clearFloats() RendererToFloatInfoMap floatMap; if (m_floatingObjects) { + FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); if (childrenInline()) { - m_floatingObjects->first(); - while (FloatingObject* f = m_floatingObjects->take()) + FloatingObjectSet::iterator end = floatingObjectSet.end(); + for (FloatingObjectSet::iterator it = floatingObjectSet.begin(); it != end; ++it) { + FloatingObject* f = *it; floatMap.add(f->m_renderer, f); + } } else - m_floatingObjects->clear(); + deleteAllValues(floatingObjectSet); + m_floatingObjects->clear(); } // We should not process floats if the parent node is not a RenderBlock. Otherwise, we will add @@ -3557,7 +3605,10 @@ void RenderBlock::clearFloats() int changeLogicalTop = numeric_limits<int>::max(); int changeLogicalBottom = numeric_limits<int>::min(); if (m_floatingObjects) { - for (FloatingObject* f = m_floatingObjects->first(); f; f = m_floatingObjects->next()) { + FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); + FloatingObjectSetIterator end = floatingObjectSet.end(); + for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { + FloatingObject* f = *it; FloatingObject* oldFloatingObject = floatMap.get(f->m_renderer); int logicalBottom = logicalBottomForFloat(f); if (oldFloatingObject) { @@ -3603,8 +3654,9 @@ int RenderBlock::addOverhangingFloats(RenderBlock* child, int logicalLeftOffset, // Floats that will remain the child's responsibility to paint should factor into its // overflow. - DeprecatedPtrListIterator<FloatingObject> it(*child->m_floatingObjects); - for (FloatingObject* r; (r = it.current()); ++it) { + FloatingObjectSetIterator childEnd = child->m_floatingObjects->set().end(); + for (FloatingObjectSetIterator childIt = child->m_floatingObjects->set().begin(); childIt != childEnd; ++childIt) { + FloatingObject* r = *childIt; int logicalBottom = child->logicalTop() + logicalBottomForFloat(r); lowestFloatLogicalBottom = max(lowestFloatLogicalBottom, logicalBottom); @@ -3628,11 +3680,11 @@ int RenderBlock::addOverhangingFloats(RenderBlock* child, int logicalLeftOffset, floatingObj->m_isDescendant = true; // We create the floating object list lazily. - if (!m_floatingObjects) { - m_floatingObjects = new DeprecatedPtrList<FloatingObject>; - m_floatingObjects->setAutoDelete(true); - } - m_floatingObjects->append(floatingObj); + if (!m_floatingObjects) + m_floatingObjects = adoptPtr(new FloatingObjects); + + m_floatingObjects->increaseObjectsCount(floatingObj->type()); + m_floatingObjects->set().add(floatingObj); } } else { if (makeChildPaintOtherFloats && !r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer() && @@ -3661,22 +3713,13 @@ void RenderBlock::addIntrudingFloats(RenderBlock* prev, int logicalLeftOffset, i return; logicalLeftOffset += (style()->isHorizontalWritingMode() ? marginLeft() : marginTop()); - - DeprecatedPtrListIterator<FloatingObject> it(*prev->m_floatingObjects); - for (FloatingObject *r; (r = it.current()); ++it) { + + FloatingObjectSet& prevSet = prev->m_floatingObjects->set(); + FloatingObjectSetIterator prevEnd = prevSet.end(); + for (FloatingObjectSetIterator prevIt = prevSet.begin(); prevIt != prevEnd; ++prevIt) { + FloatingObject* r = *prevIt; if (logicalBottomForFloat(r) > logicalTopOffset) { - // The object may already be in our list. Check for it up front to avoid - // creating duplicate entries. - FloatingObject* f = 0; - if (m_floatingObjects) { - DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); - while ((f = it.current())) { - if (f->m_renderer == r->m_renderer) - break; - ++it; - } - } - if (!f) { + if (!m_floatingObjects || !m_floatingObjects->set().contains(r)) { int leftOffset = style()->isHorizontalWritingMode() ? logicalLeftOffset : logicalTopOffset; int topOffset = style()->isHorizontalWritingMode() ? logicalTopOffset : logicalLeftOffset; @@ -3698,11 +3741,10 @@ void RenderBlock::addIntrudingFloats(RenderBlock* prev, int logicalLeftOffset, i floatingObj->m_renderer = r->m_renderer; // We create the floating object list lazily. - if (!m_floatingObjects) { - m_floatingObjects = new DeprecatedPtrList<FloatingObject>; - m_floatingObjects->setAutoDelete(true); - } - m_floatingObjects->append(floatingObj); + if (!m_floatingObjects) + m_floatingObjects = adoptPtr(new FloatingObjects); + m_floatingObjects->increaseObjectsCount(floatingObj->type()); + m_floatingObjects->set().add(floatingObj); } } } @@ -3714,17 +3756,9 @@ bool RenderBlock::avoidsFloats() const return RenderBox::avoidsFloats() || !style()->hasAutoColumnCount() || !style()->hasAutoColumnWidth(); } -bool RenderBlock::containsFloat(RenderObject* o) +bool RenderBlock::containsFloat(RenderBox* renderer) { - if (m_floatingObjects) { - DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); - while (it.current()) { - if (it.current()->m_renderer == o) - return true; - ++it; - } - } - return false; + return m_floatingObjects && m_floatingObjects->set().contains<RenderBox*, FloatingObjectHashTranslator>(renderer); } void RenderBlock::markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove, bool inLayout) @@ -3882,9 +3916,11 @@ bool RenderBlock::hitTestFloats(const HitTestRequest& request, HitTestResult& re ty += toRenderView(this)->frameView()->scrollY(); } - FloatingObject* floatingObject; - DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); - for (it.toLast(); (floatingObject = it.current()); --it) { + FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); + FloatingObjectSetIterator begin = floatingObjectSet.begin(); + for (FloatingObjectSetIterator it = floatingObjectSet.end(); it != begin;) { + --it; + FloatingObject* floatingObject = *it; if (floatingObject->m_shouldPaint && !floatingObject->m_renderer->hasSelfPaintingLayer()) { int xOffset = xPositionForFloatIncludingMargin(floatingObject) - floatingObject->m_renderer->x(); int yOffset = yPositionForFloatIncludingMargin(floatingObject) - floatingObject->m_renderer->y(); @@ -4631,7 +4667,7 @@ static int getBorderPaddingMargin(const RenderBoxModelObject* child, bool endOfI child->borderStart(); } -static inline void stripTrailingSpace(int& inlineMax, int& inlineMin, +static inline void stripTrailingSpace(float& inlineMax, float& inlineMin, RenderObject* trailingSpaceChild) { if (trailingSpaceChild && trailingSpaceChild->isText()) { @@ -4639,17 +4675,23 @@ static inline void stripTrailingSpace(int& inlineMax, int& inlineMin, RenderText* t = toRenderText(trailingSpaceChild); const UChar space = ' '; const Font& font = t->style()->font(); // FIXME: This ignores first-line. - int spaceWidth = font.width(TextRun(&space, 1)); + float spaceWidth = font.width(TextRun(&space, 1)); inlineMax -= spaceWidth + font.wordSpacing(); if (inlineMin > inlineMax) inlineMin = inlineMax; } } +static inline void updatePreferredWidth(int& preferredWidth, float& result) +{ + int snappedResult = ceilf(result); + preferredWidth = max(snappedResult, preferredWidth); +} + void RenderBlock::computeInlinePreferredLogicalWidths() { - int inlineMax = 0; - int inlineMin = 0; + float inlineMax = 0; + float inlineMin = 0; int cw = containingBlock()->contentLogicalWidth(); @@ -4710,15 +4752,15 @@ void RenderBlock::computeInlinePreferredLogicalWidths() // the width of the last non-breakable run and use that to start a new line // (unless we end in whitespace). RenderStyle* cstyle = child->style(); - int childMin = 0; - int childMax = 0; + float childMin = 0; + float childMax = 0; if (!child->isText()) { // Case (1) and (2). Inline replaced and inline flow elements. if (child->isRenderInline()) { // Add in padding/border/margin from the appropriate side of // the element. - int bpm = getBorderPaddingMargin(toRenderInline(child), childIterator.endOfInline); + float bpm = getBorderPaddingMargin(toRenderInline(child), childIterator.endOfInline); childMin += bpm; childMax += bpm; @@ -4728,7 +4770,7 @@ void RenderBlock::computeInlinePreferredLogicalWidths() child->setPreferredLogicalWidthsDirty(false); } else { // Inline replaced elts add in their margins to their min/max values. - int margins = 0; + float margins = 0; Length startMargin = cstyle->marginStart(); Length endMargin = cstyle->marginEnd(); if (startMargin.isFixed()) @@ -4758,13 +4800,13 @@ void RenderBlock::computeInlinePreferredLogicalWidths() bool canBreakReplacedElement = !child->isImage() || allowImagesToBreak; if ((canBreakReplacedElement && (autoWrap || oldAutoWrap)) || clearPreviousFloat) { - m_minPreferredLogicalWidth = max(inlineMin, m_minPreferredLogicalWidth); + updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin); inlineMin = 0; } // If we're supposed to clear the previous float, then terminate maxwidth as well. if (clearPreviousFloat) { - m_maxPreferredLogicalWidth = max(inlineMax, m_maxPreferredLogicalWidth); + updatePreferredWidth(m_maxPreferredLogicalWidth, inlineMax); inlineMax = 0; } @@ -4782,12 +4824,12 @@ void RenderBlock::computeInlinePreferredLogicalWidths() if (!autoWrap || !canBreakReplacedElement) { if (child->isFloating()) - m_minPreferredLogicalWidth = max(childMin, m_minPreferredLogicalWidth); + updatePreferredWidth(m_minPreferredLogicalWidth, childMin); else inlineMin += childMin; } else { // Now check our line. - m_minPreferredLogicalWidth = max(childMin, m_minPreferredLogicalWidth); + updatePreferredWidth(m_minPreferredLogicalWidth, childMin); // Now start a new line. inlineMin = 0; @@ -4804,7 +4846,7 @@ void RenderBlock::computeInlinePreferredLogicalWidths() RenderText* t = toRenderText(child); if (t->isWordBreak()) { - m_minPreferredLogicalWidth = max(inlineMin, m_minPreferredLogicalWidth); + updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin); inlineMin = 0; continue; } @@ -4818,9 +4860,9 @@ void RenderBlock::computeInlinePreferredLogicalWidths() // then they shouldn't be considered in the breakable char // check. bool hasBreakableChar, hasBreak; - int beginMin, endMin; + float beginMin, endMin; bool beginWS, endWS; - int beginMax, endMax; + float beginMax, endMax; t->trimmedPrefWidths(inlineMax, beginMin, beginWS, endMin, endWS, hasBreakableChar, hasBreak, beginMax, endMax, childMin, childMax, stripFrontSpaces); @@ -4828,7 +4870,7 @@ void RenderBlock::computeInlinePreferredLogicalWidths() // This text object will not be rendered, but it may still provide a breaking opportunity. if (!hasBreak && childMax == 0) { if (autoWrap && (beginWS || endWS)) { - m_minPreferredLogicalWidth = max(inlineMin, m_minPreferredLogicalWidth); + updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin); inlineMin = 0; } continue; @@ -4858,10 +4900,10 @@ void RenderBlock::computeInlinePreferredLogicalWidths() // we start and end with whitespace. if (beginWS) // Go ahead and end the current line. - m_minPreferredLogicalWidth = max(inlineMin, m_minPreferredLogicalWidth); + updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin); else { inlineMin += beginMin; - m_minPreferredLogicalWidth = max(inlineMin, m_minPreferredLogicalWidth); + updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin); childMin -= ti; } @@ -4870,18 +4912,18 @@ void RenderBlock::computeInlinePreferredLogicalWidths() if (endWS) { // We end in whitespace, which means we can go ahead // and end our current line. - m_minPreferredLogicalWidth = max(inlineMin, m_minPreferredLogicalWidth); + updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin); inlineMin = 0; } else { - m_minPreferredLogicalWidth = max(inlineMin, m_minPreferredLogicalWidth); + updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin); inlineMin = endMin; } } if (hasBreak) { inlineMax += beginMax; - m_maxPreferredLogicalWidth = max(inlineMax, m_maxPreferredLogicalWidth); - m_maxPreferredLogicalWidth = max(childMax, m_maxPreferredLogicalWidth); + updatePreferredWidth(m_maxPreferredLogicalWidth, inlineMax); + updatePreferredWidth(m_maxPreferredLogicalWidth, childMax); inlineMax = endMax; } else inlineMax += childMax; @@ -4891,8 +4933,8 @@ void RenderBlock::computeInlinePreferredLogicalWidths() if (child->isListMarker()) stripFrontSpaces = true; } else { - m_minPreferredLogicalWidth = max(inlineMin, m_minPreferredLogicalWidth); - m_maxPreferredLogicalWidth = max(inlineMax, m_maxPreferredLogicalWidth); + updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin); + updatePreferredWidth(m_maxPreferredLogicalWidth, inlineMax); inlineMin = inlineMax = 0; stripFrontSpaces = true; trailingSpaceChild = 0; @@ -4904,8 +4946,8 @@ void RenderBlock::computeInlinePreferredLogicalWidths() if (style()->collapseWhiteSpace()) stripTrailingSpace(inlineMax, inlineMin, trailingSpaceChild); - m_minPreferredLogicalWidth = max(inlineMin, m_minPreferredLogicalWidth); - m_maxPreferredLogicalWidth = max(inlineMax, m_maxPreferredLogicalWidth); + updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin); + updatePreferredWidth(m_maxPreferredLogicalWidth, inlineMax); } // Use a very large value (in effect infinite). @@ -5284,13 +5326,25 @@ void RenderBlock::updateFirstLetter() firstLetter->removeChild(child); newFirstLetter->addChild(child, 0); } - RenderTextFragment* remainingText = toRenderTextFragment(firstLetter->nextSibling()); - ASSERT(remainingText->node()->renderer() == remainingText); - // Replace the old renderer with the new one. - remainingText->setFirstLetter(newFirstLetter); + + RenderTextFragment* remainingText = 0; + RenderObject* nextSibling = firstLetter->nextSibling(); + RenderObject* next = nextSibling; + while (next) { + if (next->isText() && toRenderText(next)->isTextFragment()) { + remainingText = toRenderTextFragment(next); + break; + } + next = next->nextSibling(); + } + if (remainingText) { + ASSERT(remainingText->node()->renderer() == remainingText); + // Replace the old renderer with the new one. + remainingText->setFirstLetter(newFirstLetter); + } firstLetter->destroy(); firstLetter = newFirstLetter; - firstLetterContainer->addChild(firstLetter, remainingText); + firstLetterContainer->addChild(firstLetter, nextSibling); view()->enableLayoutState(); } else firstLetter->setStyle(pseudoStyle); @@ -5471,9 +5525,9 @@ void RenderBlock::adjustForBorderFit(int x, int& left, int& right) const if (childrenInline()) { for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox()) { if (box->firstChild()) - left = min(left, x + box->firstChild()->x()); + left = min(left, x + static_cast<int>(box->firstChild()->x())); if (box->lastChild()) - right = max(right, x + box->lastChild()->x() + box->lastChild()->logicalWidth()); + right = max(right, x + static_cast<int>(ceilf(box->lastChild()->logicalRight()))); } } else { @@ -5491,9 +5545,10 @@ void RenderBlock::adjustForBorderFit(int x, int& left, int& right) const } if (m_floatingObjects) { - FloatingObject* r; - DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); - for (; (r = it.current()); ++it) { + FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); + FloatingObjectSetIterator end = floatingObjectSet.end(); + for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { + FloatingObject* r = *it; // Only examine the object if our m_shouldPaint flag is set. if (r->m_shouldPaint) { int floatLeft = xPositionForFloatIncludingMargin(r) - r->m_renderer->x(); @@ -5773,8 +5828,8 @@ void RenderBlock::addFocusRingRects(Vector<IntRect>& rects, int tx, int ty) if (!hasOverflowClip() && !hasControlClip()) { for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) { - int top = max(curr->lineTop(), curr->y()); - int bottom = min(curr->lineBottom(), curr->y() + curr->logicalHeight()); + int top = max(curr->lineTop(), curr->logicalTop()); + int bottom = min(curr->lineBottom(), curr->logicalTop() + curr->logicalHeight()); IntRect rect(tx + curr->x(), ty + top, curr->logicalWidth(), bottom - top); if (!rect.isEmpty()) rects.append(rect); @@ -6200,4 +6255,27 @@ const char* RenderBlock::renderName() const return "RenderBlock"; } +inline void RenderBlock::FloatingObjects::clear() +{ + m_set.clear(); + m_leftObjectsCount = 0; + m_rightObjectsCount = 0; +} + +inline void RenderBlock::FloatingObjects::increaseObjectsCount(FloatingObject::Type type) +{ + if (type == FloatingObject::FloatLeft) + m_leftObjectsCount++; + else + m_rightObjectsCount++; +} + +inline void RenderBlock::FloatingObjects::decreaseObjectsCount(FloatingObject::Type type) +{ + if (type == FloatingObject::FloatLeft) + m_leftObjectsCount--; + else + m_rightObjectsCount--; +} + } // namespace WebCore diff --git a/Source/WebCore/rendering/RenderBlock.h b/Source/WebCore/rendering/RenderBlock.h index 2c61331..8d054a6 100644 --- a/Source/WebCore/rendering/RenderBlock.h +++ b/Source/WebCore/rendering/RenderBlock.h @@ -23,11 +23,11 @@ #ifndef RenderBlock_h #define RenderBlock_h -#include "DeprecatedPtrList.h" #include "GapRects.h" #include "RenderBox.h" #include "RenderLineBoxList.h" #include "RootInlineBox.h" +#include <wtf/OwnPtr.h> #include <wtf/ListHashSet.h> namespace WebCore { @@ -35,6 +35,7 @@ namespace WebCore { class ColumnInfo; class InlineIterator; class LayoutStateMaintainer; +class LazyLineBreakIterator; class RenderInline; struct BidiRun; @@ -80,7 +81,7 @@ public: void removePositionedObjects(RenderBlock*); typedef ListHashSet<RenderBox*, 4> PositionedObjectsListHashSet; - PositionedObjectsListHashSet* positionedObjects() const { return m_positionedObjects; } + PositionedObjectsListHashSet* positionedObjects() const { return m_positionedObjects.get(); } void addPercentHeightDescendant(RenderBox*); static void removePercentHeightDescendant(RenderBox*); @@ -94,13 +95,14 @@ public: void markPositionedObjectsForLayout(); virtual void markForPaginationRelayoutIfNeeded(); - bool containsFloats() { return m_floatingObjects && !m_floatingObjects->isEmpty(); } - bool containsFloat(RenderObject*); + bool containsFloats() { return m_floatingObjects && !m_floatingObjects->set().isEmpty(); } + bool containsFloat(RenderBox*); int availableLogicalWidthForLine(int position, bool firstLine) const; int logicalRightOffsetForLine(int position, bool firstLine) const { return logicalRightOffsetForLine(position, logicalRightOffsetForContent(), firstLine); } int logicalLeftOffsetForLine(int position, bool firstLine) const { return logicalLeftOffsetForLine(position, logicalLeftOffsetForContent(), firstLine); } - + int startOffsetForLine(int position, bool firstLine) const { return style()->isLeftToRightDirection() ? logicalLeftOffsetForLine(position, firstLine) : logicalRightOffsetForLine(position, firstLine); } + virtual VisiblePosition positionForPoint(const IntPoint&); // Block flows subclass availableWidth to handle multi column layout (shrinking the width available to children when laying out.) @@ -132,6 +134,7 @@ public: virtual void adjustForColumns(IntSize&, const IntPoint&) const; void addContinuationWithOutline(RenderInline*); + bool paintsContinuationOutline(RenderInline*); virtual RenderBoxModelObject* virtualContinuation() const { return continuation(); } bool isAnonymousBlockContinuation() const { return continuation() && isAnonymousBlock(); } @@ -270,6 +273,9 @@ protected: int logicalRightOffsetForLine(int position, int fixedOffset, bool applyTextIndent = true, int* logicalHeightRemaining = 0) const; int logicalLeftOffsetForLine(int position, int fixedOffset, bool applyTextIndent = true, int* logicalHeightRemaining = 0) const; + virtual ETextAlign textAlignmentForLine(bool endsWithSoftBreak) const; + virtual void adjustInlineDirectionLineBounds(int /* expansionOpportunityCount */, float& /* logicalLeft */, float& /* logicalWidth */) const { } + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); virtual void computePreferredLogicalWidths(); @@ -300,9 +306,9 @@ protected: void addOverflowFromBlockChildren(); void addOverflowFromInlineChildren(); -#if ENABLE(SVG) -protected: + virtual void addFocusRingRects(Vector<IntRect>&, int tx, int ty); +#if ENABLE(SVG) // Only used by RenderSVGText, which explicitely overrides RenderBlock::layoutBlock(), do NOT use for anything else. void forceLayoutInlineChildren() { @@ -485,10 +491,12 @@ private: void skipTrailingWhitespace(InlineIterator&, bool isLineEmpty, bool previousLineBrokeCleanly); int skipLeadingWhitespace(InlineBidiResolver&, bool firstLine, bool isLineEmpty, bool previousLineBrokeCleanly, FloatingObject* lastFloatFromPreviousLine); - void fitBelowFloats(int widthToFit, bool firstLine, int& availableWidth); - InlineIterator findNextLineBreak(InlineBidiResolver&, bool firstLine, bool& isLineEmpty, bool& previousLineBrokeCleanly, bool& hyphenated, EClear*, FloatingObject* lastFloatFromPreviousLine); + void fitBelowFloats(float widthToFit, bool firstLine, float& availableWidth); + typedef std::pair<RenderText*, LazyLineBreakIterator> LineBreakIteratorInfo; + InlineIterator findNextLineBreak(InlineBidiResolver&, bool firstLine, bool& isLineEmpty, LineBreakIteratorInfo&, bool& previousLineBrokeCleanly, bool& hyphenated, EClear*, FloatingObject* lastFloatFromPreviousLine); RootInlineBox* constructLine(unsigned runCount, BidiRun* firstRun, BidiRun* lastRun, bool firstLine, bool lastLine, RenderObject* endObject); InlineFlowBox* createLineBoxes(RenderObject*, bool firstLine); + void computeInlineDirectionPositionsForLine(RootInlineBox*, bool firstLine, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd, GlyphOverflowAndFallbackFontsMap&); void computeBlockDirectionPositionsForLine(RootInlineBox*, BidiRun*, GlyphOverflowAndFallbackFontsMap&, VerticalPositionCache&); void deleteEllipsisLineBoxes(); @@ -580,8 +588,6 @@ private: virtual IntRect localCaretRect(InlineBox*, int caretOffset, int* extraWidthToEndOfLine = 0); - virtual void addFocusRingRects(Vector<IntRect>&, int tx, int ty); - void adjustPointToColumnContents(IntPoint&) const; void adjustForBorderFit(int x, int& left, int& right) const; // Helper function for borderFitAdjust @@ -695,10 +701,41 @@ private: int adjustForUnsplittableChild(RenderBox* child, int logicalOffset, bool includeMargins = false); // If the child is unsplittable and can't fit on the current page, return the top of the next page/column. void adjustLinePositionForPagination(RootInlineBox*, int& deltaOffset); // Computes a deltaOffset value that put a line at the top of the next page if it doesn't fit on the current page. - typedef PositionedObjectsListHashSet::const_iterator Iterator; - DeprecatedPtrList<FloatingObject>* m_floatingObjects; + struct FloatingObjectHashFunctions { + static unsigned hash(FloatingObject* key) { return DefaultHash<RenderBox*>::Hash::hash(key->m_renderer); } + static bool equal(FloatingObject* a, FloatingObject* b) { return a->m_renderer == b->m_renderer; } + static const bool safeToCompareToEmptyOrDeleted = true; + }; + struct FloatingObjectHashTranslator { + static unsigned hash(RenderBox* key) { return DefaultHash<RenderBox*>::Hash::hash(key); } + static bool equal(FloatingObject* a, RenderBox* b) { return a->m_renderer == b; } + }; + typedef ListHashSet<FloatingObject*, 4, FloatingObjectHashFunctions> FloatingObjectSet; + typedef FloatingObjectSet::const_iterator FloatingObjectSetIterator; + class FloatingObjects { + public: + FloatingObjects() + : m_leftObjectsCount(0) + , m_rightObjectsCount(0) + { + } + + void clear(); + void increaseObjectsCount(FloatingObject::Type); + void decreaseObjectsCount(FloatingObject::Type); + bool hasLeftObjects() const { return m_leftObjectsCount > 0; } + bool hasRightObjects() const { return m_rightObjectsCount > 0; } + FloatingObjectSet& set() { return m_set; } + + private: + FloatingObjectSet m_set; + unsigned m_leftObjectsCount; + unsigned m_rightObjectsCount; + }; + OwnPtr<FloatingObjects> m_floatingObjects; - PositionedObjectsListHashSet* m_positionedObjects; + typedef PositionedObjectsListHashSet::const_iterator Iterator; + OwnPtr<PositionedObjectsListHashSet> m_positionedObjects; // Allocated only when some of these fields have non-default values struct RenderBlockRareData { diff --git a/Source/WebCore/rendering/RenderBlockLineLayout.cpp b/Source/WebCore/rendering/RenderBlockLineLayout.cpp index 5e2b52d..d1fce88 100644 --- a/Source/WebCore/rendering/RenderBlockLineLayout.cpp +++ b/Source/WebCore/rendering/RenderBlockLineLayout.cpp @@ -34,6 +34,7 @@ #include "RenderListMarker.h" #include "RenderView.h" #include "Settings.h" +#include "TextBreakIterator.h" #include "TextRun.h" #include "TrailingFloatsRootInlineBox.h" #include "VerticalPositionCache.h" @@ -122,7 +123,7 @@ static void addMidpoint(LineMidpointState& lineMidpointState, const InlineIterat void RenderBlock::appendRunsForObject(int start, int end, RenderObject* obj, InlineBidiResolver& resolver) { if (start > end || obj->isFloating() || - (obj->isPositioned() && !obj->style()->hasStaticX() && !obj->style()->hasStaticY() && !obj->container()->isRenderInline())) + (obj->isPositioned() && !obj->style()->hasAutoLeftAndRight() && !obj->style()->hasAutoTopAndBottom() && !obj->container()->isRenderInline())) return; LineMidpointState& lineMidpointState = resolver.midpointState(); @@ -185,7 +186,7 @@ static inline InlineBox* createInlineBoxForRenderer(RenderObject* obj, bool isRo static inline void dirtyLineBoxesForRenderer(RenderObject* o, bool fullLayout) { if (o->isText()) { - if (o->preferredLogicalWidthsDirty() && o->isCounter()) + if (o->preferredLogicalWidthsDirty() && (o->isCounter() || o->isQuote())) toRenderText(o)->computePreferredLogicalWidths(0); // FIXME: Counters depend on this hack. No clue why. Should be investigated and removed. toRenderText(o)->dirtyLineBoxes(fullLayout); } else @@ -289,7 +290,7 @@ RootInlineBox* RenderBlock::constructLine(unsigned runCount, BidiRun* firstRun, parentBox->addToLine(box); bool visuallyOrdered = r->m_object->style()->visuallyOrdered(); - box->setBidiLevel(visuallyOrdered ? 0 : r->level()); + box->setBidiLevel(r->level()); if (box->isInlineTextBox()) { InlineTextBox* text = static_cast<InlineTextBox*>(box); @@ -323,16 +324,26 @@ RootInlineBox* RenderBlock::constructLine(unsigned runCount, BidiRun* firstRun, return lastRootBox(); } +ETextAlign RenderBlock::textAlignmentForLine(bool endsWithSoftBreak) const +{ + ETextAlign alignment = style()->textAlign(); + if (!endsWithSoftBreak && alignment == JUSTIFY) + alignment = TAAUTO; + + return alignment; +} + void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox, bool firstLine, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd, GlyphOverflowAndFallbackFontsMap& textBoxDataMap) { - // First determine our total logical width. - int availableLogicalWidth = availableLogicalWidthForLine(logicalHeight(), firstLine); - int totalLogicalWidth = lineBox->getFlowSpacingLogicalWidth(); + ETextAlign textAlign = textAlignmentForLine(!reachedEnd && !lineBox->endsWithBreak()); + float logicalLeft = logicalLeftOffsetForLine(logicalHeight(), firstLine); + float availableLogicalWidth = logicalRightOffsetForLine(logicalHeight(), firstLine) - logicalLeft; + bool needsWordSpacing = false; + float totalLogicalWidth = lineBox->getFlowSpacingLogicalWidth(); unsigned expansionOpportunityCount = 0; bool isAfterExpansion = true; Vector<unsigned, 16> expansionOpportunities; - ETextAlign textAlign = style()->textAlign(); for (BidiRun* r = firstRun; r; r = r->next()) { if (!r->m_box || r->m_object->isPositioned() || r->m_box->isLineBreak()) @@ -394,7 +405,6 @@ void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox, // we now examine our text-align property in order to determine where to position the // objects horizontally. The total width of the line can be increased if we end up // justifying text. - int logicalLeft = logicalLeftOffsetForLine(logicalHeight(), firstLine); switch (textAlign) { case LEFT: case WEBKIT_LEFT: @@ -402,7 +412,7 @@ void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox, // particular with RTL blocks, wide lines should still spill out to the left. if (style()->isLeftToRightDirection()) { if (totalLogicalWidth > availableLogicalWidth && trailingSpaceRun) - trailingSpaceRun->m_box->setLogicalWidth(max(0, trailingSpaceRun->m_box->logicalWidth() - totalLogicalWidth + availableLogicalWidth)); + trailingSpaceRun->m_box->setLogicalWidth(max<float>(0, trailingSpaceRun->m_box->logicalWidth() - totalLogicalWidth + availableLogicalWidth)); } else { if (trailingSpaceRun) trailingSpaceRun->m_box->setLogicalWidth(0); @@ -411,7 +421,8 @@ void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox, } break; case JUSTIFY: - if (expansionOpportunityCount && !reachedEnd && !lineBox->endsWithBreak()) { + adjustInlineDirectionLineBounds(expansionOpportunityCount, logicalLeft, availableLogicalWidth); + if (expansionOpportunityCount) { if (trailingSpaceRun) { totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth(); trailingSpaceRun->m_box->setLogicalWidth(0); @@ -420,11 +431,10 @@ void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox, } // fall through case TAAUTO: - expansionOpportunityCount = 0; // for right to left fall through to right aligned if (style()->isLeftToRightDirection()) { if (totalLogicalWidth > availableLogicalWidth && trailingSpaceRun) - trailingSpaceRun->m_box->setLogicalWidth(max(0, trailingSpaceRun->m_box->logicalWidth() - totalLogicalWidth + availableLogicalWidth)); + trailingSpaceRun->m_box->setLogicalWidth(max<float>(0, trailingSpaceRun->m_box->logicalWidth() - totalLogicalWidth + availableLogicalWidth)); break; } case RIGHT: @@ -441,7 +451,7 @@ void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox, logicalLeft += availableLogicalWidth - totalLogicalWidth; } else { if (totalLogicalWidth > availableLogicalWidth && trailingSpaceRun) { - trailingSpaceRun->m_box->setLogicalWidth(max(0, trailingSpaceRun->m_box->logicalWidth() - totalLogicalWidth + availableLogicalWidth)); + trailingSpaceRun->m_box->setLogicalWidth(max<float>(0, trailingSpaceRun->m_box->logicalWidth() - totalLogicalWidth + availableLogicalWidth)); totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth(); } else logicalLeft += availableLogicalWidth - totalLogicalWidth; @@ -449,14 +459,14 @@ void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox, break; case CENTER: case WEBKIT_CENTER: - int trailingSpaceWidth = 0; + float trailingSpaceWidth = 0; if (trailingSpaceRun) { totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth(); trailingSpaceWidth = min(trailingSpaceRun->m_box->logicalWidth(), (availableLogicalWidth - totalLogicalWidth + 1) / 2); - trailingSpaceRun->m_box->setLogicalWidth(max(0, trailingSpaceWidth)); + trailingSpaceRun->m_box->setLogicalWidth(max<float>(0, trailingSpaceWidth)); } if (style()->isLeftToRightDirection()) - logicalLeft += max((availableLogicalWidth - totalLogicalWidth) / 2, 0); + logicalLeft += max<float>((availableLogicalWidth - totalLogicalWidth) / 2, 0); else logicalLeft += totalLogicalWidth > availableLogicalWidth ? (availableLogicalWidth - totalLogicalWidth) : (availableLogicalWidth - totalLogicalWidth) / 2 - trailingSpaceWidth; break; @@ -476,7 +486,7 @@ void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox, // Only justify text if whitespace is collapsed. if (r->m_object->style()->collapseWhiteSpace()) { InlineTextBox* textBox = static_cast<InlineTextBox*>(r->m_box); - int expansion = (availableLogicalWidth - totalLogicalWidth) * opportunitiesInRun / expansionOpportunityCount; + float expansion = (availableLogicalWidth - totalLogicalWidth) * opportunitiesInRun / expansionOpportunityCount; textBox->setExpansion(expansion); totalLogicalWidth += expansion; } @@ -728,7 +738,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogica } } - FloatingObject* lastFloat = m_floatingObjects ? m_floatingObjects->last() : 0; + FloatingObject* lastFloat = (m_floatingObjects && !m_floatingObjects->set().isEmpty()) ? m_floatingObjects->set().last() : 0; LineMidpointState& lineMidpointState = resolver.midpointState(); @@ -782,6 +792,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogica bool isLineEmpty = true; bool paginated = view()->layoutState() && view()->layoutState()->isPaginated(); + LineBreakIteratorInfo lineBreakIteratorInfo; VerticalPositionCache verticalPositionCache; while (!end.atEnd()) { @@ -797,8 +808,8 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogica bool hyphenated; InlineIterator oldEnd = end; - FloatingObject* lastFloatFromPreviousLine = m_floatingObjects ? m_floatingObjects->last() : 0; - end = findNextLineBreak(resolver, firstLine, isLineEmpty, previousLineBrokeCleanly, hyphenated, &clear, lastFloatFromPreviousLine); + FloatingObject* lastFloatFromPreviousLine = (m_floatingObjects && !m_floatingObjects->set().isEmpty()) ? m_floatingObjects->set().last() : 0; + end = findNextLineBreak(resolver, firstLine, isLineEmpty, lineBreakIteratorInfo, previousLineBrokeCleanly, hyphenated, &clear, lastFloatFromPreviousLine); if (resolver.position().atEnd()) { resolver.deleteRuns(); checkForFloatsFromLastLine = true; @@ -807,7 +818,8 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogica ASSERT(end != resolver.position()); if (!isLineEmpty) { - resolver.createBidiRunsForLine(end, style()->visuallyOrdered(), previousLineBrokeCleanly); + VisualDirectionOverride override = (style()->visuallyOrdered() ? (style()->direction() == LTR ? VisualLeftToRightOverride : VisualRightToLeftOverride) : NoVisualOverride); + resolver.createBidiRunsForLine(end, override, previousLineBrokeCleanly); ASSERT(resolver.position() == end); BidiRun* trailingSpaceRun = 0; @@ -947,13 +959,17 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogica } if (m_floatingObjects && lastRootBox()) { + FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); + FloatingObjectSetIterator it = floatingObjectSet.begin(); + FloatingObjectSetIterator end = floatingObjectSet.end(); if (lastFloat) { - for (FloatingObject* f = m_floatingObjects->last(); f != lastFloat; f = m_floatingObjects->prev()) { - } - m_floatingObjects->next(); - } else - m_floatingObjects->first(); - for (FloatingObject* f = m_floatingObjects->current(); f; f = m_floatingObjects->next()) { + FloatingObjectSetIterator lastFloatIterator = floatingObjectSet.find(lastFloat); + ASSERT(lastFloatIterator != end); + ++lastFloatIterator; + it = lastFloatIterator; + } + for (; it != end; ++it) { + FloatingObject* f = *it; lastRootBox()->floats().append(f->m_renderer); ASSERT(f->m_renderer == floats[floatIndex].object); // If a float's geometry has changed, give up on syncing with clean lines. @@ -961,7 +977,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogica checkForEndLineMatch = false; floatIndex++; } - lastFloat = m_floatingObjects->last(); + lastFloat = !floatingObjectSet.isEmpty() ? floatingObjectSet.last() : 0; } lineMidpointState.reset(); @@ -1024,15 +1040,19 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogica trailingFloatsLineBox->setOverflowFromLogicalRects(logicalLayoutOverflow, logicalVisualOverflow); trailingFloatsLineBox->setBlockLogicalHeight(logicalHeight()); } + + FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); + FloatingObjectSetIterator it = floatingObjectSet.begin(); + FloatingObjectSetIterator end = floatingObjectSet.end(); if (lastFloat) { - for (FloatingObject* f = m_floatingObjects->last(); f != lastFloat; f = m_floatingObjects->prev()) { - } - m_floatingObjects->next(); - } else - m_floatingObjects->first(); - for (FloatingObject* f = m_floatingObjects->current(); f; f = m_floatingObjects->next()) - lastRootBox()->floats().append(f->m_renderer); - lastFloat = m_floatingObjects->last(); + FloatingObjectSetIterator lastFloatIterator = floatingObjectSet.find(lastFloat); + ASSERT(lastFloatIterator != end); + ++lastFloatIterator; + it = lastFloatIterator; + } + for (; it != end; ++it) + lastRootBox()->floats().append((*it)->m_renderer); + lastFloat = !floatingObjectSet.isEmpty() ? floatingObjectSet.last() : 0; } size_t floatCount = floats.size(); // Floats that did not have layout did not repaint when we laid them out. They would have @@ -1269,7 +1289,10 @@ bool RenderBlock::matchedEndLine(const InlineBidiResolver& resolver, const Inlin int logicalBottom = lastLine->blockLogicalHeight() + abs(delta); - for (FloatingObject* f = m_floatingObjects->first(); f; f = m_floatingObjects->next()) { + FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); + FloatingObjectSetIterator end = floatingObjectSet.end(); + for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { + FloatingObject* f = *it; if (logicalBottomForFloat(f) >= logicalTop && logicalBottomForFloat(f) < logicalBottom) return false; } @@ -1303,7 +1326,10 @@ bool RenderBlock::matchedEndLine(const InlineBidiResolver& resolver, const Inlin int logicalBottom = lastLine->blockLogicalHeight() + abs(delta); - for (FloatingObject* f = m_floatingObjects->first(); f; f = m_floatingObjects->next()) { + FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); + FloatingObjectSetIterator end = floatingObjectSet.end(); + for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { + FloatingObject* f = *it; if (logicalBottomForFloat(f) >= logicalTop && logicalBottomForFloat(f) < logicalBottom) return false; } @@ -1394,6 +1420,34 @@ bool RenderBlock::generatesLineBoxesForInlineChild(RenderObject* inlineObj, bool return !it.atEnd(); } +static void setStaticPositions(RenderBlock* block, RenderBox* child) +{ + // FIXME: The math here is actually not really right. It's a best-guess approximation that + // will work for the common cases + RenderObject* containerBlock = child->container(); + if (containerBlock->isRenderInline()) { + // A relative positioned inline encloses us. In this case, we also have to determine our + // position as though we were an inline. Set |staticInlinePosition| and |staticBlockPosition| on the relative positioned + // inline so that we can obtain the value later. + toRenderInline(containerBlock)->layer()->setStaticInlinePosition(block->startOffsetForLine(block->logicalHeight(), false)); + toRenderInline(containerBlock)->layer()->setStaticBlockPosition(block->logicalHeight()); + } + + bool isHorizontal = block->style()->isHorizontalWritingMode(); + bool hasStaticInlinePosition = child->style()->hasStaticInlinePosition(isHorizontal); + bool hasStaticBlockPosition = child->style()->hasStaticBlockPosition(isHorizontal); + + if (hasStaticInlinePosition) { + if (child->style()->isOriginalDisplayInlineType()) + child->layer()->setStaticInlinePosition(block->startOffsetForLine(block->logicalHeight(), false)); + else + child->layer()->setStaticInlinePosition(block->borderAndPaddingStart()); + } + + if (hasStaticBlockPosition) + child->layer()->setStaticBlockPosition(block->logicalHeight()); +} + // FIXME: The entire concept of the skipTrailingWhitespace function is flawed, since we really need to be building // line boxes even for containers that may ultimately collapse away. Otherwise we'll never get positioned // elements quite right. In other words, we need to build this function's work into the normal line @@ -1406,29 +1460,8 @@ void RenderBlock::skipTrailingWhitespace(InlineIterator& iterator, bool isLineEm RenderObject* object = iterator.obj; if (object->isFloating()) { insertFloatingObject(toRenderBox(object)); - } else if (object->isPositioned()) { - // FIXME: The math here is actually not really right. It's a best-guess approximation that - // will work for the common cases - RenderObject* c = object->container(); - if (c->isRenderInline()) { - // A relative positioned inline encloses us. In this case, we also have to determine our - // position as though we were an inline. Set |staticX| and |staticY| on the relative positioned - // inline so that we can obtain the value later. - toRenderInline(c)->layer()->setStaticX(style()->isLeftToRightDirection() ? logicalLeftOffsetForLine(height(), false) : logicalRightOffsetForLine(height(), false)); - toRenderInline(c)->layer()->setStaticY(height()); - } - - RenderBox* box = toRenderBox(object); - if (box->style()->hasStaticX()) { - if (box->style()->isOriginalDisplayInlineType()) - box->layer()->setStaticX(style()->isLeftToRightDirection() ? logicalLeftOffsetForLine(height(), false) : width() - logicalRightOffsetForLine(height(), false)); - else - box->layer()->setStaticX(style()->isLeftToRightDirection() ? borderLeft() + paddingLeft() : borderRight() + paddingRight()); - } - - if (box->style()->hasStaticY()) - box->layer()->setStaticY(height()); - } + } else if (object->isPositioned()) + setStaticPositions(this, toRenderBox(object)); iterator.increment(); } } @@ -1442,29 +1475,8 @@ int RenderBlock::skipLeadingWhitespace(InlineBidiResolver& resolver, bool firstL if (object->isFloating()) { positionNewFloatOnLine(insertFloatingObject(toRenderBox(object)), lastFloatFromPreviousLine); availableWidth = availableLogicalWidthForLine(logicalHeight(), firstLine); - } else if (object->isPositioned()) { - // FIXME: The math here is actually not really right. It's a best-guess approximation that - // will work for the common cases - RenderObject* c = object->container(); - if (c->isRenderInline()) { - // A relative positioned inline encloses us. In this case, we also have to determine our - // position as though we were an inline. Set |staticX| and |staticY| on the relative positioned - // inline so that we can obtain the value later. - toRenderInline(c)->layer()->setStaticX(style()->isLeftToRightDirection() ? logicalLeftOffsetForLine(height(), firstLine) : logicalRightOffsetForLine(height(), firstLine)); - toRenderInline(c)->layer()->setStaticY(height()); - } - - RenderBox* box = toRenderBox(object); - if (box->style()->hasStaticX()) { - if (box->style()->isOriginalDisplayInlineType()) - box->layer()->setStaticX(style()->isLeftToRightDirection() ? logicalLeftOffsetForLine(height(), firstLine) : width() - logicalRightOffsetForLine(height(), firstLine)); - else - box->layer()->setStaticX(style()->isLeftToRightDirection() ? borderLeft() + paddingLeft() : borderRight() + paddingRight()); - } - - if (box->style()->hasStaticY()) - box->layer()->setStaticY(height()); - } + } else if (object->isPositioned()) + setStaticPositions(this, toRenderBox(object)); resolver.increment(); } resolver.commitExplicitEmbedding(); @@ -1488,13 +1500,13 @@ static bool shouldSkipWhitespaceAfterStartObject(RenderBlock* block, RenderObjec return false; } -void RenderBlock::fitBelowFloats(int widthToFit, bool firstLine, int& availableWidth) +void RenderBlock::fitBelowFloats(float widthToFit, bool firstLine, float& availableWidth) { ASSERT(widthToFit > availableWidth); int floatLogicalBottom; int lastFloatLogicalBottom = logicalHeight(); - int newLineWidth = availableWidth; + float newLineWidth = availableWidth; while (true) { floatLogicalBottom = nextFloatLogicalBottomBelow(lastFloatLogicalBottom); if (!floatLogicalBottom) @@ -1512,34 +1524,49 @@ void RenderBlock::fitBelowFloats(int widthToFit, bool firstLine, int& availableW } } -static inline unsigned textWidth(RenderText* text, unsigned from, unsigned len, const Font& font, int xPos, bool isFixedPitch, bool collapseWhiteSpace) +static inline float textWidth(RenderText* text, unsigned from, unsigned len, const Font& font, float xPos, bool isFixedPitch, bool collapseWhiteSpace) { if (isFixedPitch || (!from && len == text->textLength()) || text->style()->hasTextCombine()) return text->width(from, len, font, xPos); return font.width(TextRun(text->characters() + from, len, !collapseWhiteSpace, xPos)); } -static void tryHyphenating(RenderText* text, const Font& font, const AtomicString& localeIdentifier, int lastSpace, int pos, int xPos, int availableWidth, bool isFixedPitch, bool collapseWhiteSpace, int lastSpaceWordSpacing, InlineIterator& lineBreak, int nextBreakable, bool& hyphenated) +static void tryHyphenating(RenderText* text, const Font& font, const AtomicString& localeIdentifier, int minimumPrefixLength, int minimumSuffixLength, int lastSpace, int pos, float xPos, int availableWidth, bool isFixedPitch, bool collapseWhiteSpace, int lastSpaceWordSpacing, InlineIterator& lineBreak, int nextBreakable, bool& hyphenated) { + // Map 'hyphenate-limit-{before,after}: auto;' to 2. + if (minimumPrefixLength < 0) + minimumPrefixLength = 2; + + if (minimumSuffixLength < 0) + minimumSuffixLength = 2; + + if (pos - lastSpace <= minimumSuffixLength) + return; + const AtomicString& hyphenString = text->style()->hyphenString(); int hyphenWidth = font.width(TextRun(hyphenString.characters(), hyphenString.length())); - int maxPrefixWidth = availableWidth - xPos - hyphenWidth - lastSpaceWordSpacing; + float maxPrefixWidth = availableWidth - xPos - hyphenWidth - lastSpaceWordSpacing; // If the maximum width available for the prefix before the hyphen is small, then it is very unlikely // that an hyphenation opportunity exists, so do not bother to look for it. if (maxPrefixWidth <= font.pixelSize() * 5 / 4) return; unsigned prefixLength = font.offsetForPosition(TextRun(text->characters() + lastSpace, pos - lastSpace, !collapseWhiteSpace, xPos + lastSpaceWordSpacing), maxPrefixWidth, false); - if (!prefixLength) + if (prefixLength < static_cast<unsigned>(minimumPrefixLength)) return; - prefixLength = lastHyphenLocation(text->characters() + lastSpace, pos - lastSpace, prefixLength + 1, localeIdentifier); - if (!prefixLength) + prefixLength = lastHyphenLocation(text->characters() + lastSpace, pos - lastSpace, min(prefixLength, static_cast<unsigned>(pos - lastSpace - minimumSuffixLength)) + 1, localeIdentifier); + // FIXME: The following assumes that the character at lastSpace is a space (and therefore should not factor + // into hyphenate-limit-before) unless lastSpace is 0. This is wrong in the rare case of hyphenating + // the first word in a text node which has leading whitespace. + if (prefixLength - (lastSpace ? 1 : 0) < static_cast<unsigned>(minimumPrefixLength)) return; + ASSERT(pos - lastSpace - prefixLength >= static_cast<unsigned>(minimumSuffixLength)); + #if !ASSERT_DISABLED - int prefixWidth = hyphenWidth + textWidth(text, lastSpace, prefixLength, font, xPos, isFixedPitch, collapseWhiteSpace) + lastSpaceWordSpacing; + float prefixWidth = hyphenWidth + textWidth(text, lastSpace, prefixLength, font, xPos, isFixedPitch, collapseWhiteSpace) + lastSpaceWordSpacing; ASSERT(xPos + prefixWidth <= availableWidth); #else UNUSED_PARAM(isFixedPitch); @@ -1551,7 +1578,7 @@ static void tryHyphenating(RenderText* text, const Font& font, const AtomicStrin hyphenated = true; } -InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool firstLine, bool& isLineEmpty, bool& previousLineBrokeCleanly, +InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool firstLine, bool& isLineEmpty, LineBreakIteratorInfo& lineBreakIteratorInfo, bool& previousLineBrokeCleanly, bool& hyphenated, EClear* clear, FloatingObject* lastFloatFromPreviousLine) { ASSERT(resolver.position().block == this); @@ -1559,10 +1586,10 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool bool appliedStartWidth = resolver.position().pos > 0; LineMidpointState& lineMidpointState = resolver.midpointState(); - int width = skipLeadingWhitespace(resolver, firstLine, isLineEmpty, previousLineBrokeCleanly, lastFloatFromPreviousLine); + float width = skipLeadingWhitespace(resolver, firstLine, isLineEmpty, previousLineBrokeCleanly, lastFloatFromPreviousLine); - int w = 0; - int tmpW = 0; + float w = 0; + float tmpW = 0; if (resolver.position().atEnd()) return resolver.position(); @@ -1581,8 +1608,8 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool InlineIterator lBreak = resolver.position(); - RenderObject *o = resolver.position().obj; - RenderObject *last = o; + RenderObject* o = resolver.position().obj; + RenderObject* last = o; unsigned pos = resolver.position().pos; int nextBreakable = resolver.position().nextBreakablePosition; bool atStart = true; @@ -1655,28 +1682,26 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool floatsFitOnLine = false; } else if (o->isPositioned()) { // If our original display wasn't an inline type, then we can - // go ahead and determine our static x position now. + // go ahead and determine our static inline position now. RenderBox* box = toRenderBox(o); bool isInlineType = box->style()->isOriginalDisplayInlineType(); - bool needToSetStaticX = box->style()->hasStaticX(); - if (box->style()->hasStaticX() && !isInlineType) { - box->layer()->setStaticX(o->parent()->style()->isLeftToRightDirection() ? - borderLeft() + paddingLeft() : - borderRight() + paddingRight()); - needToSetStaticX = false; + bool needToSetStaticInlinePosition = box->style()->hasStaticInlinePosition(style()->isHorizontalWritingMode()); + if (needToSetStaticInlinePosition && !isInlineType) { + box->layer()->setStaticInlinePosition(borderAndPaddingStart()); + needToSetStaticInlinePosition = false; } // If our original display was an INLINE type, then we can go ahead // and determine our static y position now. - bool needToSetStaticY = box->style()->hasStaticY(); - if (box->style()->hasStaticY() && isInlineType) { - box->layer()->setStaticY(height()); - needToSetStaticY = false; + bool needToSetStaticBlockPosition = box->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode()); + if (needToSetStaticBlockPosition && isInlineType) { + box->layer()->setStaticBlockPosition(logicalHeight()); + needToSetStaticBlockPosition = false; } - bool needToCreateLineBox = needToSetStaticX || needToSetStaticY; + bool needToCreateLineBox = needToSetStaticInlinePosition || needToSetStaticBlockPosition; RenderObject* c = o->container(); - if (c->isRenderInline() && (!needToSetStaticX || !needToSetStaticY)) + if (c->isRenderInline() && (!needToSetStaticInlinePosition || !needToSetStaticBlockPosition)) needToCreateLineBox = true; // If we're ignoring spaces, we have to stop and include this object and @@ -1776,25 +1801,25 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool const Font& f = style->font(); bool isFixedPitch = f.isFixedPitch(); - bool canHyphenate = style->hyphens() == HyphensAuto && WebCore::canHyphenate(style->hyphenationLocale()); + bool canHyphenate = style->hyphens() == HyphensAuto && WebCore::canHyphenate(style->locale()); int lastSpace = pos; - int wordSpacing = o->style()->wordSpacing(); - int lastSpaceWordSpacing = 0; + float wordSpacing = o->style()->wordSpacing(); + float lastSpaceWordSpacing = 0; // Non-zero only when kerning is enabled, in which case we measure words with their trailing // space, then subtract its width. - int wordTrailingSpaceWidth = f.typesettingFeatures() & Kerning ? f.width(TextRun(&space, 1)) + wordSpacing : 0; + float wordTrailingSpaceWidth = f.typesettingFeatures() & Kerning ? f.width(TextRun(&space, 1)) + wordSpacing : 0; - int wrapW = tmpW + inlineLogicalWidth(o, !appliedStartWidth, true); - int charWidth = 0; + float wrapW = tmpW + inlineLogicalWidth(o, !appliedStartWidth, true); + float charWidth = 0; bool breakNBSP = autoWrap && o->style()->nbspMode() == SPACE; // Auto-wrapping text should wrap in the middle of a word only if it could not wrap before the word, // which is only possible if the word is the first thing on the line, that is, if |w| is zero. bool breakWords = o->style()->breakWords() && ((autoWrap && !w) || currWS == PRE); bool midWordBreak = false; bool breakAll = o->style()->wordBreak() == BreakAllWordBreak && autoWrap; - int hyphenWidth = 0; + float hyphenWidth = 0; if (t->isWordBreak()) { w += tmpW; @@ -1842,7 +1867,12 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool midWordBreak = w + wrapW + charWidth > width; } - bool betweenWords = c == '\n' || (currWS != PRE && !atStart && isBreakable(str, pos, strlen, nextBreakable, breakNBSP) && (style->hyphens() != HyphensNone || (pos && str[pos - 1] != softHyphen))); + if (lineBreakIteratorInfo.first != t) { + lineBreakIteratorInfo.first = t; + lineBreakIteratorInfo.second.reset(str, strlen); + } + + bool betweenWords = c == '\n' || (currWS != PRE && !atStart && isBreakable(lineBreakIteratorInfo.second, pos, nextBreakable, breakNBSP) && (style->hyphens() != HyphensNone || (pos && str[pos - 1] != softHyphen))); if (betweenWords || midWordBreak) { bool stoppedIgnoringSpaces = false; @@ -1863,7 +1893,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool } } - int additionalTmpW; + float additionalTmpW; if (wordTrailingSpaceWidth && currentCharacterIsSpace) additionalTmpW = textWidth(t, lastSpace, pos + 1 - lastSpace, f, w + tmpW, isFixedPitch, collapseWhiteSpace) - wordTrailingSpaceWidth + lastSpaceWordSpacing; else @@ -1900,7 +1930,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool } if (lineWasTooWide || w + tmpW > width) { if (canHyphenate && w + tmpW > width) { - tryHyphenating(t, f, style->hyphenationLocale(), lastSpace, pos, w + tmpW - additionalTmpW, width, isFixedPitch, collapseWhiteSpace, lastSpaceWordSpacing, lBreak, nextBreakable, hyphenated); + tryHyphenating(t, f, style->locale(), style->hyphenationLimitBefore(), style->hyphenationLimitAfter(), lastSpace, pos, w + tmpW - additionalTmpW, width, isFixedPitch, collapseWhiteSpace, lastSpaceWordSpacing, lBreak, nextBreakable, hyphenated); if (hyphenated) goto end; } @@ -2013,12 +2043,12 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool } // IMPORTANT: pos is > length here! - int additionalTmpW = ignoringSpaces ? 0 : textWidth(t, lastSpace, pos - lastSpace, f, w + tmpW, isFixedPitch, collapseWhiteSpace) + lastSpaceWordSpacing; + float additionalTmpW = ignoringSpaces ? 0 : textWidth(t, lastSpace, pos - lastSpace, f, w + tmpW, isFixedPitch, collapseWhiteSpace) + lastSpaceWordSpacing; tmpW += additionalTmpW; tmpW += inlineLogicalWidth(o, !appliedStartWidth, true); if (canHyphenate && w + tmpW > width) { - tryHyphenating(t, f, style->hyphenationLocale(), lastSpace, pos, w + tmpW - additionalTmpW, width, isFixedPitch, collapseWhiteSpace, lastSpaceWordSpacing, lBreak, nextBreakable, hyphenated); + tryHyphenating(t, f, style->locale(), style->hyphenationLimitBefore(), style->hyphenationLimitAfter(), lastSpace, pos, w + tmpW - additionalTmpW, width, isFixedPitch, collapseWhiteSpace, lastSpaceWordSpacing, lBreak, nextBreakable, hyphenated); if (hyphenated) goto end; } @@ -2249,7 +2279,7 @@ void RenderBlock::checkLinesForTextOverflow() // space. int width = curr == firstRootBox() ? firstLineEllipsisWidth : ellipsisWidth; int blockEdge = ltr ? blockRightEdge : blockLeftEdge; - if (curr->canAccommodateEllipsis(ltr, blockEdge, lineBoxEdge, width)) + if (curr->lineCanAccommodateEllipsis(ltr, blockEdge, lineBoxEdge, width)) curr->placeEllipsis(ellipsisStr, ltr, blockLeftEdge, blockRightEdge, width); } } diff --git a/Source/WebCore/rendering/RenderBox.cpp b/Source/WebCore/rendering/RenderBox.cpp index 39c80d4..4d90284 100644 --- a/Source/WebCore/rendering/RenderBox.cpp +++ b/Source/WebCore/rendering/RenderBox.cpp @@ -236,8 +236,6 @@ void RenderBox::removeFloatingOrPositionedChildFromBlockLists() RenderBlock* currBlock = toRenderBlock(curr); if (currBlock->containsFloat(this)) parentBlock = currBlock; - else - break; } } @@ -576,14 +574,14 @@ IntRect RenderBox::reflectedRect(const IntRect& r) const bool RenderBox::includeVerticalScrollbarSize() const { - return !ScrollbarTheme::nativeTheme()->usesOverlayScrollbars() - && hasOverflowClip() && (style()->overflowY() == OSCROLL || style()->overflowY() == OAUTO); + return hasOverflowClip() && !layer()->hasOverlayScrollbars() + && (style()->overflowY() == OSCROLL || style()->overflowY() == OAUTO); } bool RenderBox::includeHorizontalScrollbarSize() const { - return !ScrollbarTheme::nativeTheme()->usesOverlayScrollbars() - && hasOverflowClip() && (style()->overflowX() == OSCROLL || style()->overflowX() == OAUTO); + return hasOverflowClip() && !layer()->hasOverlayScrollbars() + && (style()->overflowX() == OSCROLL || style()->overflowX() == OAUTO); } int RenderBox::verticalScrollbarWidth() const @@ -1288,7 +1286,7 @@ IntSize RenderBox::offsetFromContainer(RenderObject* o, const IntPoint& point) c } else offset += locationOffsetIncludingFlipping(); } else - offset += locationOffset(); + offset += locationOffsetIncludingFlipping(); } if (o->hasOverflowClip()) @@ -1321,18 +1319,18 @@ void RenderBox::positionLineBox(InlineBox* box) if (isPositioned()) { // Cache the x position only if we were an INLINE type originally. bool wasInline = style()->isOriginalDisplayInlineType(); - if (wasInline && style()->hasStaticX()) { + if (wasInline && style()->hasStaticInlinePosition(box->isHorizontal())) { // The value is cached in the xPos of the box. We only need this value if // our object was inline originally, since otherwise it would have ended up underneath // the inlines. - layer()->setStaticX(box->x()); + layer()->setStaticInlinePosition(lroundf(box->logicalLeft())); setChildNeedsLayout(true, false); // Just go ahead and mark the positioned object as needing layout, so it will update its position properly. - } else if (!wasInline && style()->hasStaticY()) { + } else if (!wasInline && style()->hasStaticBlockPosition(box->isHorizontal())) { // Our object was a block originally, so we make our normal flow position be // just below the line box (as though all the inlines that came before us got // wrapped in an anonymous block, which is what would have happened had we been // in flow). This value was cached in the y() of the box. - layer()->setStaticY(box->y()); + layer()->setStaticBlockPosition(box->logicalTop()); setChildNeedsLayout(true, false); // Just go ahead and mark the positioned object as needing layout, so it will update its position properly. } @@ -1340,7 +1338,7 @@ void RenderBox::positionLineBox(InlineBox* box) box->remove(); box->destroy(renderArena()); } else if (isReplaced()) { - setLocation(box->x(), box->y()); + setLocation(lroundf(box->x()), lroundf(box->y())); m_inlineBoxWrapper = box; } } @@ -1994,7 +1992,7 @@ int RenderBox::computeReplacedLogicalWidthUsing(Length logicalWidth) const // FIXME: containingBlockLogicalWidthForContent() is wrong if the replaced element's block-flow is perpendicular to the // containing block's block-flow. // https://bugs.webkit.org/show_bug.cgi?id=46496 - const int cw = isPositioned() ? containingBlockWidthForPositioned(toRenderBoxModelObject(container())) : containingBlockLogicalWidthForContent(); + const int cw = isPositioned() ? containingBlockLogicalWidthForPositioned(toRenderBoxModelObject(container())) : containingBlockLogicalWidthForContent(); if (cw > 0) return computeContentBoxLogicalWidth(logicalWidth.calcMinValue(cw)); } @@ -2041,7 +2039,7 @@ int RenderBox::computeReplacedLogicalHeightUsing(Length logicalHeight) const // FIXME: availableLogicalHeight() is wrong if the replaced element's block-flow is perpendicular to the // containing block's block-flow. // https://bugs.webkit.org/show_bug.cgi?id=46496 - int availableHeight = isPositioned() ? containingBlockHeightForPositioned(toRenderBoxModelObject(cb)) : toRenderBox(cb)->availableLogicalHeight(); + int availableHeight = isPositioned() ? containingBlockLogicalHeightForPositioned(toRenderBoxModelObject(cb)) : toRenderBox(cb)->availableLogicalHeight(); // It is necessary to use the border-box to match WinIE's broken // box model. This is essential for sizing inside @@ -2117,8 +2115,9 @@ void RenderBox::computeBlockDirectionMargins(RenderBlock* containingBlock) containingBlock->setMarginAfterForChild(this, style()->marginAfterUsing(containingBlockStyle).calcMinValue(cw)); } -int RenderBox::containingBlockWidthForPositioned(const RenderBoxModelObject* containingBlock) const +int RenderBox::containingBlockLogicalWidthForPositioned(const RenderBoxModelObject* containingBlock, bool checkForPerpendicularWritingMode) const { +<<<<<<< HEAD #if PLATFORM(ANDROID) // Fixed element's position should be decided by the visible screen size. // That is in the doc coordindate. @@ -2132,6 +2131,14 @@ int RenderBox::containingBlockWidthForPositioned(const RenderBoxModelObject* con return containingBlockBox->width() - containingBlockBox->borderLeft() - containingBlockBox->borderRight() - containingBlockBox->verticalScrollbarWidth(); } +======= + if (checkForPerpendicularWritingMode && containingBlock->style()->isHorizontalWritingMode() != style()->isHorizontalWritingMode()) + return containingBlockLogicalHeightForPositioned(containingBlock, false); + + if (containingBlock->isBox()) + return toRenderBox(containingBlock)->clientLogicalWidth(); + +>>>>>>> WebKit at r80534 ASSERT(containingBlock->isRenderInline() && containingBlock->isRelPositioned()); const RenderInline* flow = toRenderInline(containingBlock); @@ -2155,6 +2162,7 @@ int RenderBox::containingBlockWidthForPositioned(const RenderBoxModelObject* con return max(0, (fromRight - fromLeft)); } +<<<<<<< HEAD int RenderBox::containingBlockHeightForPositioned(const RenderBoxModelObject* containingBlock) const { #if PLATFORM(ANDROID) @@ -2166,13 +2174,60 @@ int RenderBox::containingBlockHeightForPositioned(const RenderBoxModelObject* co } #endif int heightResult = 0; +======= +int RenderBox::containingBlockLogicalHeightForPositioned(const RenderBoxModelObject* containingBlock, bool checkForPerpendicularWritingMode) const +{ + if (checkForPerpendicularWritingMode && containingBlock->style()->isHorizontalWritingMode() != style()->isHorizontalWritingMode()) + return containingBlockLogicalWidthForPositioned(containingBlock, false); + +>>>>>>> WebKit at r80534 if (containingBlock->isBox()) - heightResult = toRenderBox(containingBlock)->height(); - else if (containingBlock->isRenderInline()) { - ASSERT(containingBlock->isRelPositioned()); - heightResult = toRenderInline(containingBlock)->linesBoundingBox().height(); + return toRenderBox(containingBlock)->clientLogicalHeight(); + + ASSERT(containingBlock->isRenderInline() && containingBlock->isRelPositioned()); + + const RenderInline* flow = toRenderInline(containingBlock); + InlineFlowBox* first = flow->firstLineBox(); + InlineFlowBox* last = flow->lastLineBox(); + + // If the containing block is empty, return a height of 0. + if (!first || !last) + return 0; + + int heightResult; + IntRect boundingBox = flow->linesBoundingBox(); + if (containingBlock->style()->isHorizontalWritingMode()) + heightResult = boundingBox.height(); + else + heightResult = boundingBox.width(); + heightResult -= (containingBlock->borderBefore() + containingBlock->borderAfter()); + return heightResult; +} + +static void computeInlineStaticDistance(Length& logicalLeft, Length& logicalRight, const RenderBox* child, const RenderBoxModelObject* containerBlock, int containerLogicalWidth, + TextDirection containerDirection) +{ + if (!logicalLeft.isAuto() || !logicalRight.isAuto()) + return; + + // FIXME: The static distance computation has not been patched for mixed writing modes yet. + if (containerDirection == LTR) { + int staticPosition = child->layer()->staticInlinePosition() - containerBlock->borderLogicalLeft(); + for (RenderObject* curr = child->parent(); curr && curr != containerBlock; curr = curr->parent()) { + if (curr->isBox()) + staticPosition += toRenderBox(curr)->logicalLeft(); + } + logicalLeft.setValue(Fixed, staticPosition); + } else { + RenderBox* enclosingBox = child->parent()->enclosingBox(); + int staticPosition = child->layer()->staticInlinePosition() + containerLogicalWidth + containerBlock->borderLogicalRight(); + staticPosition -= enclosingBox->logicalWidth(); + for (RenderObject* curr = enclosingBox; curr && curr != containerBlock; curr = curr->parent()) { + if (curr->isBox()) + staticPosition -= toRenderBox(curr)->logicalLeft(); + } + logicalRight.setValue(Fixed, staticPosition); } - return heightResult - containingBlock->borderTop() - containingBlock->borderBottom(); } void RenderBox::computePositionedLogicalWidth() @@ -2211,17 +2266,21 @@ void RenderBox::computePositionedLogicalWidth() // relative positioned inline. const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container()); - const int containerWidth = containingBlockWidthForPositioned(containerBlock); + const int containerLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock); // To match WinIE, in quirks mode use the parent's 'direction' property // instead of the the container block's. TextDirection containerDirection = (document()->inQuirksMode()) ? parent()->style()->direction() : containerBlock->style()->direction(); - const int bordersPlusPadding = borderAndPaddingWidth(); - const Length marginLeft = style()->marginLeft(); - const Length marginRight = style()->marginRight(); - Length left = style()->left(); - Length right = style()->right(); + bool isHorizontal = style()->isHorizontalWritingMode(); + const int bordersPlusPadding = borderAndPaddingLogicalWidth(); + const Length marginLogicalLeft = isHorizontal ? style()->marginLeft() : style()->marginTop(); + const Length marginLogicalRight = isHorizontal ? style()->marginRight() : style()->marginBottom(); + int& marginLogicalLeftAlias = isHorizontal ? m_marginLeft : m_marginTop; + int& marginLogicalRightAlias = isHorizontal ? m_marginRight : m_marginBottom; + + Length logicalLeft = style()->logicalLeft(); + Length logicalRight = style()->logicalRight(); /*---------------------------------------------------------------------------*\ * For the purposes of this section and the next, the term "static position" @@ -2249,107 +2308,98 @@ void RenderBox::computePositionedLogicalWidth() // see FIXME 2 // Calculate the static distance if needed. - if (left.isAuto() && right.isAuto()) { - if (containerDirection == LTR) { - // 'staticX' should already have been set through layout of the parent. - int staticPosition = layer()->staticX() - containerBlock->borderLeft(); - for (RenderObject* curr = parent(); curr && curr != containerBlock; curr = curr->parent()) { - if (curr->isBox()) - staticPosition += toRenderBox(curr)->x(); - } - left.setValue(Fixed, staticPosition); - } else { - RenderBox* enclosingBox = parent()->enclosingBox(); - // 'staticX' should already have been set through layout of the parent. - int staticPosition = layer()->staticX() + containerWidth + containerBlock->borderRight(); - staticPosition -= enclosingBox->width(); - for (RenderObject* curr = enclosingBox; curr && curr != containerBlock; curr = curr->parent()) { - if (curr->isBox()) - staticPosition -= toRenderBox(curr)->x(); - } - right.setValue(Fixed, staticPosition); - } - } - + computeInlineStaticDistance(logicalLeft, logicalRight, this, containerBlock, containerLogicalWidth, containerDirection); + // Calculate constraint equation values for 'width' case. - int widthResult; - int xResult; - computePositionedLogicalWidthUsing(style()->width(), containerBlock, containerDirection, - containerWidth, bordersPlusPadding, - left, right, marginLeft, marginRight, - widthResult, m_marginLeft, m_marginRight, xResult); - setWidth(widthResult); - setX(xResult); + int logicalWidthResult; + int logicalLeftResult; + computePositionedLogicalWidthUsing(style()->logicalWidth(), containerBlock, containerDirection, + containerLogicalWidth, bordersPlusPadding, + logicalLeft, logicalRight, marginLogicalLeft, marginLogicalRight, + logicalWidthResult, marginLogicalLeftAlias, marginLogicalRightAlias, logicalLeftResult); + setLogicalWidth(logicalWidthResult); + setLogicalLeft(logicalLeftResult); // Calculate constraint equation values for 'max-width' case. - if (!style()->maxWidth().isUndefined()) { - int maxWidth; - int maxMarginLeft; - int maxMarginRight; - int maxXPos; - - computePositionedLogicalWidthUsing(style()->maxWidth(), containerBlock, containerDirection, - containerWidth, bordersPlusPadding, - left, right, marginLeft, marginRight, - maxWidth, maxMarginLeft, maxMarginRight, maxXPos); - - if (width() > maxWidth) { - setWidth(maxWidth); - m_marginLeft = maxMarginLeft; - m_marginRight = maxMarginRight; - m_frameRect.setX(maxXPos); + if (!style()->logicalMaxWidth().isUndefined()) { + int maxLogicalWidth; + int maxMarginLogicalLeft; + int maxMarginLogicalRight; + int maxLogicalLeftPos; + + computePositionedLogicalWidthUsing(style()->logicalMaxWidth(), containerBlock, containerDirection, + containerLogicalWidth, bordersPlusPadding, + logicalLeft, logicalRight, marginLogicalLeft, marginLogicalRight, + maxLogicalWidth, maxMarginLogicalLeft, maxMarginLogicalRight, maxLogicalLeftPos); + + if (logicalWidth() > maxLogicalWidth) { + setLogicalWidth(maxLogicalWidth); + marginLogicalLeftAlias = maxMarginLogicalLeft; + marginLogicalRightAlias = maxMarginLogicalRight; + setLogicalLeft(maxLogicalLeftPos); } } // Calculate constraint equation values for 'min-width' case. - if (!style()->minWidth().isZero()) { - int minWidth; - int minMarginLeft; - int minMarginRight; - int minXPos; - - computePositionedLogicalWidthUsing(style()->minWidth(), containerBlock, containerDirection, - containerWidth, bordersPlusPadding, - left, right, marginLeft, marginRight, - minWidth, minMarginLeft, minMarginRight, minXPos); - - if (width() < minWidth) { - setWidth(minWidth); - m_marginLeft = minMarginLeft; - m_marginRight = minMarginRight; - m_frameRect.setX(minXPos); + if (!style()->logicalMinWidth().isZero()) { + int minLogicalWidth; + int minMarginLogicalLeft; + int minMarginLogicalRight; + int minLogicalLeftPos; + + computePositionedLogicalWidthUsing(style()->logicalMinWidth(), containerBlock, containerDirection, + containerLogicalWidth, bordersPlusPadding, + logicalLeft, logicalRight, marginLogicalLeft, marginLogicalRight, + minLogicalWidth, minMarginLogicalLeft, minMarginLogicalRight, minLogicalLeftPos); + + if (logicalWidth() < minLogicalWidth) { + setLogicalWidth(minLogicalWidth); + marginLogicalLeftAlias = minMarginLogicalLeft; + marginLogicalRightAlias = minMarginLogicalRight; + setLogicalLeft(minLogicalLeftPos); } } - if (stretchesToMinIntrinsicLogicalWidth() && width() < minPreferredLogicalWidth() - bordersPlusPadding) { + if (stretchesToMinIntrinsicLogicalWidth() && logicalWidth() < minPreferredLogicalWidth() - bordersPlusPadding) { computePositionedLogicalWidthUsing(Length(minPreferredLogicalWidth() - bordersPlusPadding, Fixed), containerBlock, containerDirection, - containerWidth, bordersPlusPadding, - left, right, marginLeft, marginRight, - widthResult, m_marginLeft, m_marginRight, xResult); - setWidth(widthResult); - setX(xResult); + containerLogicalWidth, bordersPlusPadding, + logicalLeft, logicalRight, marginLogicalLeft, marginLogicalRight, + logicalWidthResult, marginLogicalLeftAlias, marginLogicalRightAlias, logicalLeftResult); + setLogicalWidth(logicalWidthResult); + setLogicalLeft(logicalLeftResult); } - // Put width() into correct form. - setWidth(width() + bordersPlusPadding); + // Put logicalWidth() into correct form. + setLogicalWidth(logicalWidth() + bordersPlusPadding); } -void RenderBox::computePositionedLogicalWidthUsing(Length width, const RenderBoxModelObject* containerBlock, TextDirection containerDirection, - const int containerWidth, const int bordersPlusPadding, - const Length left, const Length right, const Length marginLeft, const Length marginRight, - int& widthValue, int& marginLeftValue, int& marginRightValue, int& xPos) +static void computeLogicalLeftPositionedOffset(int& logicalLeftPos, const RenderBox* child, int logicalWidthValue, const RenderBoxModelObject* containerBlock, int containerLogicalWidth) +{ + // Deal with differing writing modes here. Our offset needs to be in the containing block's coordinate space. If the containing block is flipped + // along this axis, then we need to flip the coordinate. This can only happen if the containing block is both a flipped mode and perpendicular to us. + if (containerBlock->style()->isHorizontalWritingMode() != child->style()->isHorizontalWritingMode() && containerBlock->style()->isFlippedBlocksWritingMode()) { + logicalLeftPos = containerLogicalWidth - logicalWidthValue - logicalLeftPos; + logicalLeftPos += (child->style()->isHorizontalWritingMode() ? containerBlock->borderRight() : containerBlock->borderBottom()); + } else + logicalLeftPos += (child->style()->isHorizontalWritingMode() ? containerBlock->borderLeft() : containerBlock->borderTop()); +} + +void RenderBox::computePositionedLogicalWidthUsing(Length logicalWidth, const RenderBoxModelObject* containerBlock, TextDirection containerDirection, + int containerLogicalWidth, int bordersPlusPadding, + Length logicalLeft, Length logicalRight, Length marginLogicalLeft, Length marginLogicalRight, + int& logicalWidthValue, int& marginLogicalLeftValue, int& marginLogicalRightValue, int& logicalLeftPos) { // 'left' and 'right' cannot both be 'auto' because one would of been // converted to the static position already - ASSERT(!(left.isAuto() && right.isAuto())); + ASSERT(!(logicalLeft.isAuto() && logicalRight.isAuto())); - int leftValue = 0; + int logicalLeftValue = 0; - bool widthIsAuto = width.isIntrinsicOrAuto(); - bool leftIsAuto = left.isAuto(); - bool rightIsAuto = right.isAuto(); + bool logicalWidthIsAuto = logicalWidth.isIntrinsicOrAuto(); + bool logicalLeftIsAuto = logicalLeft.isAuto(); + bool logicalRightIsAuto = logicalRight.isAuto(); - if (!leftIsAuto && !widthIsAuto && !rightIsAuto) { + if (!logicalLeftIsAuto && !logicalWidthIsAuto && !logicalRightIsAuto) { /*-----------------------------------------------------------------------*\ * If none of the three is 'auto': If both 'margin-left' and 'margin- * right' are 'auto', solve the equation under the extra constraint that @@ -2365,43 +2415,43 @@ void RenderBox::computePositionedLogicalWidthUsing(Length width, const RenderBox // NOTE: It is not necessary to solve for 'right' in the over constrained // case because the value is not used for any further calculations. - leftValue = left.calcValue(containerWidth); - widthValue = computeContentBoxLogicalWidth(width.calcValue(containerWidth)); + logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth); + logicalWidthValue = computeContentBoxLogicalWidth(logicalWidth.calcValue(containerLogicalWidth)); - const int availableSpace = containerWidth - (leftValue + widthValue + right.calcValue(containerWidth) + bordersPlusPadding); + const int availableSpace = containerLogicalWidth - (logicalLeftValue + logicalWidthValue + logicalRight.calcValue(containerLogicalWidth) + bordersPlusPadding); // Margins are now the only unknown - if (marginLeft.isAuto() && marginRight.isAuto()) { + if (marginLogicalLeft.isAuto() && marginLogicalRight.isAuto()) { // Both margins auto, solve for equality if (availableSpace >= 0) { - marginLeftValue = availableSpace / 2; // split the difference - marginRightValue = availableSpace - marginLeftValue; // account for odd valued differences + marginLogicalLeftValue = availableSpace / 2; // split the difference + marginLogicalRightValue = availableSpace - marginLogicalLeftValue; // account for odd valued differences } else { // see FIXME 1 if (containerDirection == LTR) { - marginLeftValue = 0; - marginRightValue = availableSpace; // will be negative + marginLogicalLeftValue = 0; + marginLogicalRightValue = availableSpace; // will be negative } else { - marginLeftValue = availableSpace; // will be negative - marginRightValue = 0; + marginLogicalLeftValue = availableSpace; // will be negative + marginLogicalRightValue = 0; } } - } else if (marginLeft.isAuto()) { + } else if (marginLogicalLeft.isAuto()) { // Solve for left margin - marginRightValue = marginRight.calcValue(containerWidth); - marginLeftValue = availableSpace - marginRightValue; - } else if (marginRight.isAuto()) { + marginLogicalRightValue = marginLogicalRight.calcValue(containerLogicalWidth); + marginLogicalLeftValue = availableSpace - marginLogicalRightValue; + } else if (marginLogicalRight.isAuto()) { // Solve for right margin - marginLeftValue = marginLeft.calcValue(containerWidth); - marginRightValue = availableSpace - marginLeftValue; + marginLogicalLeftValue = marginLogicalLeft.calcValue(containerLogicalWidth); + marginLogicalRightValue = availableSpace - marginLogicalLeftValue; } else { // Over-constrained, solve for left if direction is RTL - marginLeftValue = marginLeft.calcValue(containerWidth); - marginRightValue = marginRight.calcValue(containerWidth); + marginLogicalLeftValue = marginLogicalLeft.calcValue(containerLogicalWidth); + marginLogicalRightValue = marginLogicalRight.calcValue(containerLogicalWidth); // see FIXME 1 -- used to be "this->style()->direction()" if (containerDirection == RTL) - leftValue = (availableSpace + leftValue) - marginLeftValue - marginRightValue; + logicalLeftValue = (availableSpace + logicalLeftValue) - marginLogicalLeftValue - marginLogicalRightValue; } } else { /*--------------------------------------------------------------------*\ @@ -2446,51 +2496,51 @@ void RenderBox::computePositionedLogicalWidthUsing(Length width, const RenderBox // because the value is not used for any further calculations. // Calculate margins, 'auto' margins are ignored. - marginLeftValue = marginLeft.calcMinValue(containerWidth); - marginRightValue = marginRight.calcMinValue(containerWidth); + marginLogicalLeftValue = marginLogicalLeft.calcMinValue(containerLogicalWidth); + marginLogicalRightValue = marginLogicalRight.calcMinValue(containerLogicalWidth); - const int availableSpace = containerWidth - (marginLeftValue + marginRightValue + bordersPlusPadding); + const int availableSpace = containerLogicalWidth - (marginLogicalLeftValue + marginLogicalRightValue + bordersPlusPadding); // FIXME: Is there a faster way to find the correct case? // Use rule/case that applies. - if (leftIsAuto && widthIsAuto && !rightIsAuto) { + if (logicalLeftIsAuto && logicalWidthIsAuto && !logicalRightIsAuto) { // RULE 1: (use shrink-to-fit for width, and solve of left) - int rightValue = right.calcValue(containerWidth); + int logicalRightValue = logicalRight.calcValue(containerLogicalWidth); // FIXME: would it be better to have shrink-to-fit in one step? int preferredWidth = maxPreferredLogicalWidth() - bordersPlusPadding; int preferredMinWidth = minPreferredLogicalWidth() - bordersPlusPadding; - int availableWidth = availableSpace - rightValue; - widthValue = min(max(preferredMinWidth, availableWidth), preferredWidth); - leftValue = availableSpace - (widthValue + rightValue); - } else if (!leftIsAuto && widthIsAuto && rightIsAuto) { + int availableWidth = availableSpace - logicalRightValue; + logicalWidthValue = min(max(preferredMinWidth, availableWidth), preferredWidth); + logicalLeftValue = availableSpace - (logicalWidthValue + logicalRightValue); + } else if (!logicalLeftIsAuto && logicalWidthIsAuto && logicalRightIsAuto) { // RULE 3: (use shrink-to-fit for width, and no need solve of right) - leftValue = left.calcValue(containerWidth); + logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth); // FIXME: would it be better to have shrink-to-fit in one step? int preferredWidth = maxPreferredLogicalWidth() - bordersPlusPadding; int preferredMinWidth = minPreferredLogicalWidth() - bordersPlusPadding; - int availableWidth = availableSpace - leftValue; - widthValue = min(max(preferredMinWidth, availableWidth), preferredWidth); - } else if (leftIsAuto && !width.isAuto() && !rightIsAuto) { + int availableWidth = availableSpace - logicalLeftValue; + logicalWidthValue = min(max(preferredMinWidth, availableWidth), preferredWidth); + } else if (logicalLeftIsAuto && !logicalWidthIsAuto && !logicalRightIsAuto) { // RULE 4: (solve for left) - widthValue = computeContentBoxLogicalWidth(width.calcValue(containerWidth)); - leftValue = availableSpace - (widthValue + right.calcValue(containerWidth)); - } else if (!leftIsAuto && widthIsAuto && !rightIsAuto) { + logicalWidthValue = computeContentBoxLogicalWidth(logicalWidth.calcValue(containerLogicalWidth)); + logicalLeftValue = availableSpace - (logicalWidthValue + logicalRight.calcValue(containerLogicalWidth)); + } else if (!logicalLeftIsAuto && logicalWidthIsAuto && !logicalRightIsAuto) { // RULE 5: (solve for width) - leftValue = left.calcValue(containerWidth); - widthValue = availableSpace - (leftValue + right.calcValue(containerWidth)); - } else if (!leftIsAuto&& !widthIsAuto && rightIsAuto) { + logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth); + logicalWidthValue = availableSpace - (logicalLeftValue + logicalRight.calcValue(containerLogicalWidth)); + } else if (!logicalLeftIsAuto && !logicalWidthIsAuto && logicalRightIsAuto) { // RULE 6: (no need solve for right) - leftValue = left.calcValue(containerWidth); - widthValue = computeContentBoxLogicalWidth(width.calcValue(containerWidth)); + logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth); + logicalWidthValue = computeContentBoxLogicalWidth(logicalWidth.calcValue(containerLogicalWidth)); } } // Use computed values to calculate the horizontal position. - // FIXME: This hack is needed to calculate the xPos for a 'rtl' relatively - // positioned, inline because right now, it is using the xPos + // FIXME: This hack is needed to calculate the logical left position for a 'rtl' relatively + // positioned, inline because right now, it is using the logical left position // of the first line box when really it should use the last line box. When // this is fixed elsewhere, this block should be removed. if (containerBlock->isRenderInline() && !containerBlock->style()->isLeftToRightDirection()) { @@ -2498,12 +2548,27 @@ void RenderBox::computePositionedLogicalWidthUsing(Length width, const RenderBox InlineFlowBox* firstLine = flow->firstLineBox(); InlineFlowBox* lastLine = flow->lastLineBox(); if (firstLine && lastLine && firstLine != lastLine) { - xPos = leftValue + marginLeftValue + lastLine->borderLogicalLeft() + (lastLine->x() - firstLine->x()); + logicalLeftPos = logicalLeftValue + marginLogicalLeftValue + lastLine->borderLogicalLeft() + (lastLine->logicalLeft() - firstLine->logicalLeft()); return; } } - xPos = leftValue + marginLeftValue + containerBlock->borderLeft(); + logicalLeftPos = logicalLeftValue + marginLogicalLeftValue; + computeLogicalLeftPositionedOffset(logicalLeftPos, this, logicalWidthValue, containerBlock, containerLogicalWidth); +} + +static void computeBlockStaticDistance(Length& logicalTop, Length& logicalBottom, const RenderBox* child, const RenderBoxModelObject* containerBlock) +{ + if (!logicalTop.isAuto() || !logicalBottom.isAuto()) + return; + + // FIXME: The static distance computation has not been patched for mixed writing modes. + int staticLogicalTop = child->layer()->staticBlockPosition() - containerBlock->borderBefore(); + for (RenderObject* curr = child->parent(); curr && curr != containerBlock; curr = curr->parent()) { + if (curr->isBox() && !curr->isTableRow()) + staticLogicalTop += toRenderBox(curr)->logicalTop(); + } + logicalTop.setValue(Fixed, staticLogicalTop); } void RenderBox::computePositionedLogicalHeight() @@ -2523,14 +2588,19 @@ void RenderBox::computePositionedLogicalHeight() // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline. const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container()); - const int containerHeight = containingBlockHeightForPositioned(containerBlock); + const int containerLogicalHeight = containingBlockLogicalHeightForPositioned(containerBlock); - const int bordersPlusPadding = borderAndPaddingHeight(); - const Length marginTop = style()->marginTop(); - const Length marginBottom = style()->marginBottom(); - Length top = style()->top(); - Length bottom = style()->bottom(); + bool isHorizontal = style()->isHorizontalWritingMode(); + bool isFlipped = style()->isFlippedBlocksWritingMode(); + const int bordersPlusPadding = borderAndPaddingLogicalHeight(); + const Length marginBefore = style()->marginBefore(); + const Length marginAfter = style()->marginAfter(); + int& marginBeforeAlias = isHorizontal ? (isFlipped ? m_marginBottom : m_marginTop) : (isFlipped ? m_marginRight: m_marginLeft); + int& marginAfterAlias = isHorizontal ? (isFlipped ? m_marginTop : m_marginBottom) : (isFlipped ? m_marginLeft: m_marginRight); + Length logicalTop = style()->logicalTop(); + Length logicalBottom = style()->logicalBottom(); + /*---------------------------------------------------------------------------*\ * For the purposes of this section and the next, the term "static position" * (of an element) refers, roughly, to the position an element would have had @@ -2550,95 +2620,108 @@ void RenderBox::computePositionedLogicalHeight() // see FIXME 2 // Calculate the static distance if needed. - if (top.isAuto() && bottom.isAuto()) { - // staticY should already have been set through layout of the parent() - int staticTop = layer()->staticY() - containerBlock->borderTop(); - for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent()) { - if (po->isBox() && !po->isTableRow()) - staticTop += toRenderBox(po)->y(); - } - top.setValue(Fixed, staticTop); - } - + computeBlockStaticDistance(logicalTop, logicalBottom, this, containerBlock); - int h; // Needed to compute overflow. - int y; + int logicalHeightResult; // Needed to compute overflow. + int logicalTopPos; // Calculate constraint equation values for 'height' case. - computePositionedLogicalHeightUsing(style()->height(), containerBlock, containerHeight, bordersPlusPadding, - top, bottom, marginTop, marginBottom, - h, m_marginTop, m_marginBottom, y); - setY(y); + computePositionedLogicalHeightUsing(style()->logicalHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding, + logicalTop, logicalBottom, marginBefore, marginAfter, + logicalHeightResult, marginBeforeAlias, marginAfterAlias, logicalTopPos); + setLogicalTop(logicalTopPos); // Avoid doing any work in the common case (where the values of min-height and max-height are their defaults). // see FIXME 3 // Calculate constraint equation values for 'max-height' case. - if (!style()->maxHeight().isUndefined()) { - int maxHeight; - int maxMarginTop; - int maxMarginBottom; - int maxYPos; - - computePositionedLogicalHeightUsing(style()->maxHeight(), containerBlock, containerHeight, bordersPlusPadding, - top, bottom, marginTop, marginBottom, - maxHeight, maxMarginTop, maxMarginBottom, maxYPos); - - if (h > maxHeight) { - h = maxHeight; - m_marginTop = maxMarginTop; - m_marginBottom = maxMarginBottom; - m_frameRect.setY(maxYPos); + if (!style()->logicalMaxHeight().isUndefined()) { + int maxLogicalHeight; + int maxMarginBefore; + int maxMarginAfter; + int maxLogicalTopPos; + + computePositionedLogicalHeightUsing(style()->logicalMaxHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding, + logicalTop, logicalBottom, marginBefore, marginAfter, + maxLogicalHeight, maxMarginBefore, maxMarginAfter, maxLogicalTopPos); + + if (logicalHeightResult > maxLogicalHeight) { + logicalHeightResult = maxLogicalHeight; + marginBeforeAlias = maxMarginBefore; + marginAfterAlias = maxMarginAfter; + setLogicalTop(maxLogicalTopPos); } } // Calculate constraint equation values for 'min-height' case. - if (!style()->minHeight().isZero()) { - int minHeight; - int minMarginTop; - int minMarginBottom; - int minYPos; - - computePositionedLogicalHeightUsing(style()->minHeight(), containerBlock, containerHeight, bordersPlusPadding, - top, bottom, marginTop, marginBottom, - minHeight, minMarginTop, minMarginBottom, minYPos); - - if (h < minHeight) { - h = minHeight; - m_marginTop = minMarginTop; - m_marginBottom = minMarginBottom; - m_frameRect.setY(minYPos); + if (!style()->logicalMinHeight().isZero()) { + int minLogicalHeight; + int minMarginBefore; + int minMarginAfter; + int minLogicalTopPos; + + computePositionedLogicalHeightUsing(style()->logicalMinHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding, + logicalTop, logicalBottom, marginBefore, marginAfter, + minLogicalHeight, minMarginBefore, minMarginAfter, minLogicalTopPos); + + if (logicalHeightResult < minLogicalHeight) { + logicalHeightResult = minLogicalHeight; + marginBeforeAlias = minMarginBefore; + marginAfterAlias = minMarginAfter; + setLogicalTop(minLogicalTopPos); } } // Set final height value. - setHeight(h + bordersPlusPadding); + setLogicalHeight(logicalHeightResult + bordersPlusPadding); } -void RenderBox::computePositionedLogicalHeightUsing(Length h, const RenderBoxModelObject* containerBlock, - const int containerHeight, const int bordersPlusPadding, - const Length top, const Length bottom, const Length marginTop, const Length marginBottom, - int& heightValue, int& marginTopValue, int& marginBottomValue, int& yPos) +static void computeLogicalTopPositionedOffset(int& logicalTopPos, const RenderBox* child, int logicalHeightValue, const RenderBoxModelObject* containerBlock, int containerLogicalHeight) +{ + // Deal with differing writing modes here. Our offset needs to be in the containing block's coordinate space. If the containing block is flipped + // along this axis, then we need to flip the coordinate. This can only happen if the containing block is both a flipped mode and perpendicular to us. + if ((child->style()->isFlippedBlocksWritingMode() && child->style()->isHorizontalWritingMode() != containerBlock->style()->isHorizontalWritingMode()) + || (child->style()->isFlippedBlocksWritingMode() != containerBlock->style()->isFlippedBlocksWritingMode() && child->style()->isHorizontalWritingMode() == containerBlock->style()->isHorizontalWritingMode())) + logicalTopPos = containerLogicalHeight - logicalHeightValue - logicalTopPos; + + // Our offset is from the logical bottom edge in a flipped environment, e.g., right for vertical-rl and bottom for horizontal-bt. + if (containerBlock->style()->isFlippedBlocksWritingMode() && child->style()->isHorizontalWritingMode() == containerBlock->style()->isHorizontalWritingMode()) { + if (child->style()->isHorizontalWritingMode()) + logicalTopPos += containerBlock->borderBottom(); + else + logicalTopPos += containerBlock->borderRight(); + } else { + if (child->style()->isHorizontalWritingMode()) + logicalTopPos += containerBlock->borderTop(); + else + logicalTopPos += containerBlock->borderLeft(); + } +} + +void RenderBox::computePositionedLogicalHeightUsing(Length logicalHeightLength, const RenderBoxModelObject* containerBlock, + int containerLogicalHeight, int bordersPlusPadding, + Length logicalTop, Length logicalBottom, Length marginBefore, Length marginAfter, + int& logicalHeightValue, int& marginBeforeValue, int& marginAfterValue, int& logicalTopPos) { // 'top' and 'bottom' cannot both be 'auto' because 'top would of been // converted to the static position in computePositionedLogicalHeight() - ASSERT(!(top.isAuto() && bottom.isAuto())); + ASSERT(!(logicalTop.isAuto() && logicalBottom.isAuto())); - int contentHeight = height() - bordersPlusPadding; + int contentLogicalHeight = logicalHeight() - bordersPlusPadding; - int topValue = 0; + int logicalTopValue = 0; - bool heightIsAuto = h.isAuto(); - bool topIsAuto = top.isAuto(); - bool bottomIsAuto = bottom.isAuto(); + bool logicalHeightIsAuto = logicalHeightLength.isAuto(); + bool logicalTopIsAuto = logicalTop.isAuto(); + bool logicalBottomIsAuto = logicalBottom.isAuto(); // Height is never unsolved for tables. if (isTable()) { - h.setValue(Fixed, contentHeight); - heightIsAuto = false; + logicalHeightLength.setValue(Fixed, contentLogicalHeight); + logicalHeightIsAuto = false; } - if (!topIsAuto && !heightIsAuto && !bottomIsAuto) { + if (!logicalTopIsAuto && !logicalHeightIsAuto && !logicalBottomIsAuto) { /*-----------------------------------------------------------------------*\ * If none of the three are 'auto': If both 'margin-top' and 'margin- * bottom' are 'auto', solve the equation under the extra constraint that @@ -2650,29 +2733,29 @@ void RenderBox::computePositionedLogicalHeightUsing(Length h, const RenderBoxMod // NOTE: It is not necessary to solve for 'bottom' in the over constrained // case because the value is not used for any further calculations. - heightValue = computeContentBoxLogicalHeight(h.calcValue(containerHeight)); - topValue = top.calcValue(containerHeight); + logicalHeightValue = computeContentBoxLogicalHeight(logicalHeightLength.calcValue(containerLogicalHeight)); + logicalTopValue = logicalTop.calcValue(containerLogicalHeight); - const int availableSpace = containerHeight - (topValue + heightValue + bottom.calcValue(containerHeight) + bordersPlusPadding); + const int availableSpace = containerLogicalHeight - (logicalTopValue + logicalHeightValue + logicalBottom.calcValue(containerLogicalHeight) + bordersPlusPadding); // Margins are now the only unknown - if (marginTop.isAuto() && marginBottom.isAuto()) { + if (marginBefore.isAuto() && marginAfter.isAuto()) { // Both margins auto, solve for equality // NOTE: This may result in negative values. - marginTopValue = availableSpace / 2; // split the difference - marginBottomValue = availableSpace - marginTopValue; // account for odd valued differences - } else if (marginTop.isAuto()) { + marginBeforeValue = availableSpace / 2; // split the difference + marginAfterValue = availableSpace - marginBeforeValue; // account for odd valued differences + } else if (marginBefore.isAuto()) { // Solve for top margin - marginBottomValue = marginBottom.calcValue(containerHeight); - marginTopValue = availableSpace - marginBottomValue; - } else if (marginBottom.isAuto()) { + marginAfterValue = marginAfter.calcValue(containerLogicalHeight); + marginBeforeValue = availableSpace - marginAfterValue; + } else if (marginAfter.isAuto()) { // Solve for bottom margin - marginTopValue = marginTop.calcValue(containerHeight); - marginBottomValue = availableSpace - marginTopValue; + marginBeforeValue = marginBefore.calcValue(containerLogicalHeight); + marginAfterValue = availableSpace - marginBeforeValue; } else { // Over-constrained, (no need solve for bottom) - marginTopValue = marginTop.calcValue(containerHeight); - marginBottomValue = marginBottom.calcValue(containerHeight); + marginBeforeValue = marginBefore.calcValue(containerLogicalHeight); + marginAfterValue = marginAfter.calcValue(containerLogicalHeight); } } else { /*--------------------------------------------------------------------*\ @@ -2701,37 +2784,38 @@ void RenderBox::computePositionedLogicalHeightUsing(Length h, const RenderBoxMod // because the value is not used for any further calculations. // Calculate margins, 'auto' margins are ignored. - marginTopValue = marginTop.calcMinValue(containerHeight); - marginBottomValue = marginBottom.calcMinValue(containerHeight); + marginBeforeValue = marginBefore.calcMinValue(containerLogicalHeight); + marginAfterValue = marginAfter.calcMinValue(containerLogicalHeight); - const int availableSpace = containerHeight - (marginTopValue + marginBottomValue + bordersPlusPadding); + const int availableSpace = containerLogicalHeight - (marginBeforeValue + marginAfterValue + bordersPlusPadding); // Use rule/case that applies. - if (topIsAuto && heightIsAuto && !bottomIsAuto) { + if (logicalTopIsAuto && logicalHeightIsAuto && !logicalBottomIsAuto) { // RULE 1: (height is content based, solve of top) - heightValue = contentHeight; - topValue = availableSpace - (heightValue + bottom.calcValue(containerHeight)); - } else if (!topIsAuto && heightIsAuto && bottomIsAuto) { + logicalHeightValue = contentLogicalHeight; + logicalTopValue = availableSpace - (logicalHeightValue + logicalBottom.calcValue(containerLogicalHeight)); + } else if (!logicalTopIsAuto && logicalHeightIsAuto && logicalBottomIsAuto) { // RULE 3: (height is content based, no need solve of bottom) - topValue = top.calcValue(containerHeight); - heightValue = contentHeight; - } else if (topIsAuto && !heightIsAuto && !bottomIsAuto) { + logicalTopValue = logicalTop.calcValue(containerLogicalHeight); + logicalHeightValue = contentLogicalHeight; + } else if (logicalTopIsAuto && !logicalHeightIsAuto && !logicalBottomIsAuto) { // RULE 4: (solve of top) - heightValue = computeContentBoxLogicalHeight(h.calcValue(containerHeight)); - topValue = availableSpace - (heightValue + bottom.calcValue(containerHeight)); - } else if (!topIsAuto && heightIsAuto && !bottomIsAuto) { + logicalHeightValue = computeContentBoxLogicalHeight(logicalHeightLength.calcValue(containerLogicalHeight)); + logicalTopValue = availableSpace - (logicalHeightValue + logicalBottom.calcValue(containerLogicalHeight)); + } else if (!logicalTopIsAuto && logicalHeightIsAuto && !logicalBottomIsAuto) { // RULE 5: (solve of height) - topValue = top.calcValue(containerHeight); - heightValue = max(0, availableSpace - (topValue + bottom.calcValue(containerHeight))); - } else if (!topIsAuto && !heightIsAuto && bottomIsAuto) { + logicalTopValue = logicalTop.calcValue(containerLogicalHeight); + logicalHeightValue = max(0, availableSpace - (logicalTopValue + logicalBottom.calcValue(containerLogicalHeight))); + } else if (!logicalTopIsAuto && !logicalHeightIsAuto && logicalBottomIsAuto) { // RULE 6: (no need solve of bottom) - heightValue = computeContentBoxLogicalHeight(h.calcValue(containerHeight)); - topValue = top.calcValue(containerHeight); + logicalHeightValue = computeContentBoxLogicalHeight(logicalHeightLength.calcValue(containerLogicalHeight)); + logicalTopValue = logicalTop.calcValue(containerLogicalHeight); } } // Use computed values to calculate the vertical position. - yPos = topValue + marginTopValue + containerBlock->borderTop(); + logicalTopPos = logicalTopValue + marginBeforeValue; + computeLogicalTopPositionedOffset(logicalTopPos, this, logicalHeightValue, containerBlock, containerLogicalHeight); } void RenderBox::computePositionedLogicalWidthReplaced() @@ -2746,18 +2830,20 @@ void RenderBox::computePositionedLogicalWidthReplaced() // relative positioned inline. const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container()); - const int containerWidth = containingBlockWidthForPositioned(containerBlock); + const int containerLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock); // To match WinIE, in quirks mode use the parent's 'direction' property // instead of the the container block's. TextDirection containerDirection = (document()->inQuirksMode()) ? parent()->style()->direction() : containerBlock->style()->direction(); // Variables to solve. - Length left = style()->left(); - Length right = style()->right(); - Length marginLeft = style()->marginLeft(); - Length marginRight = style()->marginRight(); - + bool isHorizontal = style()->isHorizontalWritingMode(); + Length logicalLeft = style()->logicalLeft(); + Length logicalRight = style()->logicalRight(); + Length marginLogicalLeft = isHorizontal ? style()->marginLeft() : style()->marginTop(); + Length marginLogicalRight = isHorizontal ? style()->marginRight() : style()->marginBottom(); + int& marginLogicalLeftAlias = isHorizontal ? m_marginLeft : m_marginTop; + int& marginLogicalRightAlias = isHorizontal ? m_marginRight : m_marginBottom; /*-----------------------------------------------------------------------*\ * 1. The used value of 'width' is determined as for inline replaced @@ -2766,8 +2852,8 @@ void RenderBox::computePositionedLogicalWidthReplaced() // NOTE: This value of width is FINAL in that the min/max width calculations // are dealt with in computeReplacedWidth(). This means that the steps to produce // correct max/min in the non-replaced version, are not necessary. - setWidth(computeReplacedLogicalWidth() + borderAndPaddingWidth()); - const int availableSpace = containerWidth - width(); + setLogicalWidth(computeReplacedLogicalWidth() + borderAndPaddingLogicalWidth()); + const int availableSpace = containerLogicalWidth - logicalWidth(); /*-----------------------------------------------------------------------*\ * 2. If both 'left' and 'right' have the value 'auto', then if 'direction' @@ -2775,37 +2861,17 @@ void RenderBox::computePositionedLogicalWidthReplaced() * else if 'direction' is 'rtl', set 'right' to the static position. \*-----------------------------------------------------------------------*/ // see FIXME 2 - if (left.isAuto() && right.isAuto()) { - // see FIXME 1 - if (containerDirection == LTR) { - // 'staticX' should already have been set through layout of the parent. - int staticPosition = layer()->staticX() - containerBlock->borderLeft(); - for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent()) { - if (po->isBox()) - staticPosition += toRenderBox(po)->x(); - } - left.setValue(Fixed, staticPosition); - } else { - RenderObject* po = parent(); - // 'staticX' should already have been set through layout of the parent. - int staticPosition = layer()->staticX() + containerWidth + containerBlock->borderRight(); - for ( ; po && po != containerBlock; po = po->parent()) { - if (po->isBox()) - staticPosition += toRenderBox(po)->x(); - } - right.setValue(Fixed, staticPosition); - } - } + computeInlineStaticDistance(logicalLeft, logicalRight, this, containerBlock, containerLogicalWidth, containerDirection); /*-----------------------------------------------------------------------*\ * 3. If 'left' or 'right' are 'auto', replace any 'auto' on 'margin-left' * or 'margin-right' with '0'. \*-----------------------------------------------------------------------*/ - if (left.isAuto() || right.isAuto()) { - if (marginLeft.isAuto()) - marginLeft.setValue(Fixed, 0); - if (marginRight.isAuto()) - marginRight.setValue(Fixed, 0); + if (logicalLeft.isAuto() || logicalRight.isAuto()) { + if (marginLogicalLeft.isAuto()) + marginLogicalLeft.setValue(Fixed, 0); + if (marginLogicalRight.isAuto()) + marginLogicalRight.setValue(Fixed, 0); } /*-----------------------------------------------------------------------*\ @@ -2816,28 +2882,28 @@ void RenderBox::computePositionedLogicalWidthReplaced() * ('rtl'), set 'margin-left' ('margin-right') to zero and solve for * 'margin-right' ('margin-left'). \*-----------------------------------------------------------------------*/ - int leftValue = 0; - int rightValue = 0; + int logicalLeftValue = 0; + int logicalRightValue = 0; - if (marginLeft.isAuto() && marginRight.isAuto()) { + if (marginLogicalLeft.isAuto() && marginLogicalRight.isAuto()) { // 'left' and 'right' cannot be 'auto' due to step 3 - ASSERT(!(left.isAuto() && right.isAuto())); + ASSERT(!(logicalLeft.isAuto() && logicalRight.isAuto())); - leftValue = left.calcValue(containerWidth); - rightValue = right.calcValue(containerWidth); + logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth); + logicalRightValue = logicalRight.calcValue(containerLogicalWidth); - int difference = availableSpace - (leftValue + rightValue); + int difference = availableSpace - (logicalLeftValue + logicalRightValue); if (difference > 0) { - m_marginLeft = difference / 2; // split the difference - m_marginRight = difference - m_marginLeft; // account for odd valued differences + marginLogicalLeftAlias = difference / 2; // split the difference + marginLogicalRightAlias = difference - marginLogicalLeftAlias; // account for odd valued differences } else { // see FIXME 1 if (containerDirection == LTR) { - m_marginLeft = 0; - m_marginRight = difference; // will be negative + marginLogicalLeftAlias = 0; + marginLogicalRightAlias = difference; // will be negative } else { - m_marginLeft = difference; // will be negative - m_marginRight = 0; + marginLogicalLeftAlias = difference; // will be negative + marginLogicalRightAlias = 0; } } @@ -2845,40 +2911,40 @@ void RenderBox::computePositionedLogicalWidthReplaced() * 5. If at this point there is an 'auto' left, solve the equation for * that value. \*-----------------------------------------------------------------------*/ - } else if (left.isAuto()) { - m_marginLeft = marginLeft.calcValue(containerWidth); - m_marginRight = marginRight.calcValue(containerWidth); - rightValue = right.calcValue(containerWidth); + } else if (logicalLeft.isAuto()) { + marginLogicalLeftAlias = marginLogicalLeft.calcValue(containerLogicalWidth); + marginLogicalRightAlias = marginLogicalRight.calcValue(containerLogicalWidth); + logicalRightValue = logicalRight.calcValue(containerLogicalWidth); // Solve for 'left' - leftValue = availableSpace - (rightValue + m_marginLeft + m_marginRight); - } else if (right.isAuto()) { - m_marginLeft = marginLeft.calcValue(containerWidth); - m_marginRight = marginRight.calcValue(containerWidth); - leftValue = left.calcValue(containerWidth); + logicalLeftValue = availableSpace - (logicalRightValue + marginLogicalLeftAlias + marginLogicalRightAlias); + } else if (logicalRight.isAuto()) { + marginLogicalLeftAlias = marginLogicalLeft.calcValue(containerLogicalWidth); + marginLogicalRightAlias = marginLogicalRight.calcValue(containerLogicalWidth); + logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth); // Solve for 'right' - rightValue = availableSpace - (leftValue + m_marginLeft + m_marginRight); - } else if (marginLeft.isAuto()) { - m_marginRight = marginRight.calcValue(containerWidth); - leftValue = left.calcValue(containerWidth); - rightValue = right.calcValue(containerWidth); + logicalRightValue = availableSpace - (logicalLeftValue + marginLogicalLeftAlias + marginLogicalRightAlias); + } else if (marginLogicalLeft.isAuto()) { + marginLogicalRightAlias = marginLogicalRight.calcValue(containerLogicalWidth); + logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth); + logicalRightValue = logicalRight.calcValue(containerLogicalWidth); // Solve for 'margin-left' - m_marginLeft = availableSpace - (leftValue + rightValue + m_marginRight); - } else if (marginRight.isAuto()) { - m_marginLeft = marginLeft.calcValue(containerWidth); - leftValue = left.calcValue(containerWidth); - rightValue = right.calcValue(containerWidth); + marginLogicalLeftAlias = availableSpace - (logicalLeftValue + logicalRightValue + marginLogicalRightAlias); + } else if (marginLogicalRight.isAuto()) { + marginLogicalLeftAlias = marginLogicalLeft.calcValue(containerLogicalWidth); + logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth); + logicalRightValue = logicalRight.calcValue(containerLogicalWidth); // Solve for 'margin-right' - m_marginRight = availableSpace - (leftValue + rightValue + m_marginLeft); + marginLogicalRightAlias = availableSpace - (logicalLeftValue + logicalRightValue + marginLogicalLeftAlias); } else { // Nothing is 'auto', just calculate the values. - m_marginLeft = marginLeft.calcValue(containerWidth); - m_marginRight = marginRight.calcValue(containerWidth); - rightValue = right.calcValue(containerWidth); - leftValue = left.calcValue(containerWidth); + marginLogicalLeftAlias = marginLogicalLeft.calcValue(containerLogicalWidth); + marginLogicalRightAlias = marginLogicalRight.calcValue(containerLogicalWidth); + logicalRightValue = logicalRight.calcValue(containerLogicalWidth); + logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth); } /*-----------------------------------------------------------------------*\ @@ -2889,14 +2955,17 @@ void RenderBox::computePositionedLogicalWidthReplaced() \*-----------------------------------------------------------------------*/ // NOTE: It is not necessary to solve for 'right' when the direction is // LTR because the value is not used. - int totalWidth = width() + leftValue + rightValue + m_marginLeft + m_marginRight; - if (totalWidth > containerWidth && (containerDirection == RTL)) - leftValue = containerWidth - (totalWidth - leftValue); + int totalLogicalWidth = logicalWidth() + logicalLeftValue + logicalRightValue + marginLogicalLeftAlias + marginLogicalRightAlias; + if (totalLogicalWidth > containerLogicalWidth && (containerDirection == RTL)) + logicalLeftValue = containerLogicalWidth - (totalLogicalWidth - logicalLeftValue); + // FIXME: Deal with differing writing modes here. Our offset needs to be in the containing block's coordinate space, so that + // can make the result here rather complicated to compute. + // Use computed values to calculate the horizontal position. - // FIXME: This hack is needed to calculate the xPos for a 'rtl' relatively - // positioned, inline containing block because right now, it is using the xPos + // FIXME: This hack is needed to calculate the logical left position for a 'rtl' relatively + // positioned, inline containing block because right now, it is using the logical left position // of the first line box when really it should use the last line box. When // this is fixed elsewhere, this block should be removed. if (containerBlock->isRenderInline() && !containerBlock->style()->isLeftToRightDirection()) { @@ -2904,12 +2973,14 @@ void RenderBox::computePositionedLogicalWidthReplaced() InlineFlowBox* firstLine = flow->firstLineBox(); InlineFlowBox* lastLine = flow->lastLineBox(); if (firstLine && lastLine && firstLine != lastLine) { - m_frameRect.setX(leftValue + m_marginLeft + lastLine->borderLogicalLeft() + (lastLine->x() - firstLine->x())); + setLogicalLeft(logicalLeftValue + marginLogicalLeftAlias + lastLine->borderLogicalLeft() + (lastLine->logicalLeft() - firstLine->logicalLeft())); return; } } - m_frameRect.setX(leftValue + m_marginLeft + containerBlock->borderLeft()); + int logicalLeftPos = logicalLeftValue + marginLogicalLeftAlias; + computeLogicalLeftPositionedOffset(logicalLeftPos, this, logicalWidth(), containerBlock, containerLogicalWidth); + setLogicalLeft(logicalLeftPos); } void RenderBox::computePositionedLogicalHeightReplaced() @@ -2923,14 +2994,18 @@ void RenderBox::computePositionedLogicalHeightReplaced() // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline. const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container()); - const int containerHeight = containingBlockHeightForPositioned(containerBlock); + const int containerLogicalHeight = containingBlockLogicalHeightForPositioned(containerBlock); // Variables to solve. - Length top = style()->top(); - Length bottom = style()->bottom(); - Length marginTop = style()->marginTop(); - Length marginBottom = style()->marginBottom(); + bool isHorizontal = style()->isHorizontalWritingMode(); + bool isFlipped = style()->isFlippedBlocksWritingMode(); + Length marginBefore = style()->marginBefore(); + Length marginAfter = style()->marginAfter(); + int& marginBeforeAlias = isHorizontal ? (isFlipped ? m_marginBottom : m_marginTop) : (isFlipped ? m_marginRight: m_marginLeft); + int& marginAfterAlias = isHorizontal ? (isFlipped ? m_marginTop : m_marginBottom) : (isFlipped ? m_marginLeft: m_marginRight); + Length logicalTop = style()->logicalTop(); + Length logicalBottom = style()->logicalBottom(); /*-----------------------------------------------------------------------*\ * 1. The used value of 'height' is determined as for inline replaced @@ -2939,23 +3014,15 @@ void RenderBox::computePositionedLogicalHeightReplaced() // NOTE: This value of height is FINAL in that the min/max height calculations // are dealt with in computeReplacedHeight(). This means that the steps to produce // correct max/min in the non-replaced version, are not necessary. - setHeight(computeReplacedLogicalHeight() + borderAndPaddingHeight()); - const int availableSpace = containerHeight - height(); + setLogicalHeight(computeReplacedLogicalHeight() + borderAndPaddingLogicalHeight()); + const int availableSpace = containerLogicalHeight - logicalHeight(); /*-----------------------------------------------------------------------*\ * 2. If both 'top' and 'bottom' have the value 'auto', replace 'top' * with the element's static position. \*-----------------------------------------------------------------------*/ // see FIXME 2 - if (top.isAuto() && bottom.isAuto()) { - // staticY should already have been set through layout of the parent(). - int staticTop = layer()->staticY() - containerBlock->borderTop(); - for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent()) { - if (po->isBox() && !po->isTableRow()) - staticTop += toRenderBox(po)->y(); - } - top.setValue(Fixed, staticTop); - } + computeBlockStaticDistance(logicalTop, logicalBottom, this, containerBlock); /*-----------------------------------------------------------------------*\ * 3. If 'bottom' is 'auto', replace any 'auto' on 'margin-top' or @@ -2963,11 +3030,11 @@ void RenderBox::computePositionedLogicalHeightReplaced() \*-----------------------------------------------------------------------*/ // FIXME: The spec. says that this step should only be taken when bottom is // auto, but if only top is auto, this makes step 4 impossible. - if (top.isAuto() || bottom.isAuto()) { - if (marginTop.isAuto()) - marginTop.setValue(Fixed, 0); - if (marginBottom.isAuto()) - marginBottom.setValue(Fixed, 0); + if (logicalTop.isAuto() || logicalBottom.isAuto()) { + if (marginBefore.isAuto()) + marginBefore.setValue(Fixed, 0); + if (marginAfter.isAuto()) + marginAfter.setValue(Fixed, 0); } /*-----------------------------------------------------------------------*\ @@ -2975,59 +3042,59 @@ void RenderBox::computePositionedLogicalHeightReplaced() * 'auto', solve the equation under the extra constraint that the two * margins must get equal values. \*-----------------------------------------------------------------------*/ - int topValue = 0; - int bottomValue = 0; + int logicalTopValue = 0; + int logicalBottomValue = 0; - if (marginTop.isAuto() && marginBottom.isAuto()) { + if (marginBefore.isAuto() && marginAfter.isAuto()) { // 'top' and 'bottom' cannot be 'auto' due to step 2 and 3 combined. - ASSERT(!(top.isAuto() || bottom.isAuto())); + ASSERT(!(logicalTop.isAuto() || logicalBottom.isAuto())); - topValue = top.calcValue(containerHeight); - bottomValue = bottom.calcValue(containerHeight); + logicalTopValue = logicalTop.calcValue(containerLogicalHeight); + logicalBottomValue = logicalBottom.calcValue(containerLogicalHeight); - int difference = availableSpace - (topValue + bottomValue); + int difference = availableSpace - (logicalTopValue + logicalBottomValue); // NOTE: This may result in negative values. - m_marginTop = difference / 2; // split the difference - m_marginBottom = difference - m_marginTop; // account for odd valued differences + marginBeforeAlias = difference / 2; // split the difference + marginAfterAlias = difference - marginBeforeAlias; // account for odd valued differences /*-----------------------------------------------------------------------*\ * 5. If at this point there is only one 'auto' left, solve the equation * for that value. \*-----------------------------------------------------------------------*/ - } else if (top.isAuto()) { - m_marginTop = marginTop.calcValue(containerHeight); - m_marginBottom = marginBottom.calcValue(containerHeight); - bottomValue = bottom.calcValue(containerHeight); + } else if (logicalTop.isAuto()) { + marginBeforeAlias = marginBefore.calcValue(containerLogicalHeight); + marginAfterAlias = marginAfter.calcValue(containerLogicalHeight); + logicalBottomValue = logicalBottom.calcValue(containerLogicalHeight); // Solve for 'top' - topValue = availableSpace - (bottomValue + m_marginTop + m_marginBottom); - } else if (bottom.isAuto()) { - m_marginTop = marginTop.calcValue(containerHeight); - m_marginBottom = marginBottom.calcValue(containerHeight); - topValue = top.calcValue(containerHeight); + logicalTopValue = availableSpace - (logicalBottomValue + marginBeforeAlias + marginAfterAlias); + } else if (logicalBottom.isAuto()) { + marginBeforeAlias = marginBefore.calcValue(containerLogicalHeight); + marginAfterAlias = marginAfter.calcValue(containerLogicalHeight); + logicalTopValue = logicalTop.calcValue(containerLogicalHeight); // Solve for 'bottom' // NOTE: It is not necessary to solve for 'bottom' because we don't ever // use the value. - } else if (marginTop.isAuto()) { - m_marginBottom = marginBottom.calcValue(containerHeight); - topValue = top.calcValue(containerHeight); - bottomValue = bottom.calcValue(containerHeight); + } else if (marginBefore.isAuto()) { + marginAfterAlias = marginAfter.calcValue(containerLogicalHeight); + logicalTopValue = logicalTop.calcValue(containerLogicalHeight); + logicalBottomValue = logicalBottom.calcValue(containerLogicalHeight); // Solve for 'margin-top' - m_marginTop = availableSpace - (topValue + bottomValue + m_marginBottom); - } else if (marginBottom.isAuto()) { - m_marginTop = marginTop.calcValue(containerHeight); - topValue = top.calcValue(containerHeight); - bottomValue = bottom.calcValue(containerHeight); + marginBeforeAlias = availableSpace - (logicalTopValue + logicalBottomValue + marginAfterAlias); + } else if (marginAfter.isAuto()) { + marginBeforeAlias = marginBefore.calcValue(containerLogicalHeight); + logicalTopValue = logicalTop.calcValue(containerLogicalHeight); + logicalBottomValue = logicalBottom.calcValue(containerLogicalHeight); // Solve for 'margin-bottom' - m_marginBottom = availableSpace - (topValue + bottomValue + m_marginTop); + marginAfterAlias = availableSpace - (logicalTopValue + logicalBottomValue + marginBeforeAlias); } else { // Nothing is 'auto', just calculate the values. - m_marginTop = marginTop.calcValue(containerHeight); - m_marginBottom = marginBottom.calcValue(containerHeight); - topValue = top.calcValue(containerHeight); + marginBeforeAlias = marginBefore.calcValue(containerLogicalHeight); + marginAfterAlias = marginAfter.calcValue(containerLogicalHeight); + logicalTopValue = logicalTop.calcValue(containerLogicalHeight); // NOTE: It is not necessary to solve for 'bottom' because we don't ever // use the value. } @@ -3041,7 +3108,9 @@ void RenderBox::computePositionedLogicalHeightReplaced() // or not. // Use computed values to calculate the vertical position. - m_frameRect.setY(topValue + m_marginTop + containerBlock->borderTop()); + int logicalTopPos = logicalTopValue + marginBeforeAlias; + computeLogicalTopPositionedOffset(logicalTopPos, this, logicalHeight(), containerBlock, containerLogicalHeight); + setLogicalTop(logicalTopPos); } IntRect RenderBox::localCaretRect(InlineBox* box, int caretOffset, int* extraWidthToEndOfLine) @@ -3439,13 +3508,32 @@ IntSize RenderBox::flipForWritingMode(const IntSize& offset) const return style()->isHorizontalWritingMode() ? IntSize(offset.width(), height() - offset.height()) : IntSize(width() - offset.width(), offset.height()); } +FloatPoint RenderBox::flipForWritingMode(const FloatPoint& position) const +{ + if (!style()->isFlippedBlocksWritingMode()) + return position; + return style()->isHorizontalWritingMode() ? FloatPoint(position.x(), height() - position.y()) : FloatPoint(width() - position.x(), position.y()); +} + +void RenderBox::flipForWritingMode(FloatRect& rect) const +{ + if (!style()->isFlippedBlocksWritingMode()) + return; + + if (style()->isHorizontalWritingMode()) + rect.setY(height() - rect.maxY()); + else + rect.setX(width() - rect.maxX()); +} + IntSize RenderBox::locationOffsetIncludingFlipping() const { - if (!parent() || !parent()->isBox()) + RenderBlock* containerBlock = containingBlock(); + if (!containerBlock || containerBlock == this) return locationOffset(); IntRect rect(frameRect()); - parentBox()->flipForWritingMode(rect); + containerBlock->flipForWritingMode(rect); // FIXME: This is wrong if we are an absolutely positioned object enclosed by a relative-positioned inline. return IntSize(rect.x(), rect.y()); } diff --git a/Source/WebCore/rendering/RenderBox.h b/Source/WebCore/rendering/RenderBox.h index 7241ed1..f0bd30d 100644 --- a/Source/WebCore/rendering/RenderBox.h +++ b/Source/WebCore/rendering/RenderBox.h @@ -176,7 +176,9 @@ public: int clientTop() const { return borderTop(); } int clientWidth() const; int clientHeight() const; - int clientLogicalBottom() const { return borderBefore() + (style()->isHorizontalWritingMode() ? clientHeight() : clientWidth()); } + int clientLogicalWidth() const { return style()->isHorizontalWritingMode() ? clientWidth() : clientHeight(); } + int clientLogicalHeight() const { return style()->isHorizontalWritingMode() ? clientHeight() : clientWidth(); } + int clientLogicalBottom() const { return borderBefore() + clientLogicalHeight(); } IntRect clientBoxRect() const { return IntRect(clientLeft(), clientTop(), clientWidth(), clientHeight()); } // scrollWidth/scrollHeight will be the same as clientWidth/clientHeight unless the @@ -385,6 +387,8 @@ public: IntPoint flipForWritingModeIncludingColumns(const IntPoint&) const; IntSize flipForWritingMode(const IntSize&) const; void flipForWritingMode(IntRect&) const; + FloatPoint flipForWritingMode(const FloatPoint&) const; + void flipForWritingMode(FloatRect&) const; IntSize locationOffsetIncludingFlipping() const; IntRect logicalVisualOverflowRectForPropagation(RenderStyle*) const; @@ -426,18 +430,18 @@ private: // Returns true if we did a full repaint bool repaintLayerRectsForImage(WrappedImagePtr image, const FillLayer* layers, bool drawingBackground); - int containingBlockWidthForPositioned(const RenderBoxModelObject* containingBlock) const; - int containingBlockHeightForPositioned(const RenderBoxModelObject* containingBlock) const; + int containingBlockLogicalWidthForPositioned(const RenderBoxModelObject* containingBlock, bool checkForPerpendicularWritingMode = true) const; + int containingBlockLogicalHeightForPositioned(const RenderBoxModelObject* containingBlock, bool checkForPerpendicularWritingMode = true) const; void computePositionedLogicalHeight(); - void computePositionedLogicalWidthUsing(Length width, const RenderBoxModelObject* cb, TextDirection containerDirection, - int containerWidth, int bordersPlusPadding, - Length left, Length right, Length marginLeft, Length marginRight, - int& widthValue, int& marginLeftValue, int& marginRightValue, int& xPos); - void computePositionedLogicalHeightUsing(Length height, const RenderBoxModelObject* cb, - int containerHeight, int bordersPlusPadding, - Length top, Length bottom, Length marginTop, Length marginBottom, - int& heightValue, int& marginTopValue, int& marginBottomValue, int& yPos); + void computePositionedLogicalWidthUsing(Length logicalWidth, const RenderBoxModelObject* containerBlock, TextDirection containerDirection, + int containerLogicalWidth, int bordersPlusPadding, + Length logicalLeft, Length logicalRight, Length marginLogicalLeft, Length marginLogicalRight, + int& logicalWidthValue, int& marginLogicalLeftValue, int& marginLogicalRightValue, int& logicalLeftPos); + void computePositionedLogicalHeightUsing(Length logicalHeight, const RenderBoxModelObject* containerBlock, + int containerLogicalHeight, int bordersPlusPadding, + Length logicalTop, Length logicalBottom, Length marginLogicalTop, Length marginLogicalBottom, + int& logicalHeightValue, int& marginLogicalTopValue, int& marginLogicalBottomValue, int& logicalTopPos); void computePositionedLogicalHeightReplaced(); void computePositionedLogicalWidthReplaced(); diff --git a/Source/WebCore/rendering/RenderBoxModelObject.cpp b/Source/WebCore/rendering/RenderBoxModelObject.cpp index ffbecce..eec048e 100644 --- a/Source/WebCore/rendering/RenderBoxModelObject.cpp +++ b/Source/WebCore/rendering/RenderBoxModelObject.cpp @@ -1593,7 +1593,7 @@ void RenderBoxModelObject::paintBoxShadow(GraphicsContext* context, int tx, int { // FIXME: Deal with border-image. Would be great to use border-image as a mask. - if (context->paintingDisabled()) + if (context->paintingDisabled() || !s->boxShadow()) return; RoundedIntRect border(tx, ty, w, h); diff --git a/Source/WebCore/rendering/RenderBoxModelObject.h b/Source/WebCore/rendering/RenderBoxModelObject.h index f6bcb94..2e0bdda 100644 --- a/Source/WebCore/rendering/RenderBoxModelObject.h +++ b/Source/WebCore/rendering/RenderBoxModelObject.h @@ -89,6 +89,11 @@ public: int borderAndPaddingWidth() const { return borderLeft() + borderRight() + paddingLeft() + paddingRight(); } int borderAndPaddingLogicalHeight() const { return borderBefore() + borderAfter() + paddingBefore() + paddingAfter(); } int borderAndPaddingLogicalWidth() const { return borderStart() + borderEnd() + paddingStart() + paddingEnd(); } + int borderAndPaddingLogicalLeft() const { return style()->isHorizontalWritingMode() ? borderLeft() + paddingLeft() : borderTop() + paddingTop(); } + + int borderAndPaddingStart() const { return borderStart() + paddingStart(); } + int borderLogicalLeft() const { return style()->isHorizontalWritingMode() ? borderLeft() : borderTop(); } + int borderLogicalRight() const { return style()->isHorizontalWritingMode() ? borderRight() : borderBottom(); } virtual int marginTop() const = 0; virtual int marginBottom() const = 0; diff --git a/Source/WebCore/rendering/RenderCombineText.cpp b/Source/WebCore/rendering/RenderCombineText.cpp index 1b20bd8..250ec9b 100644 --- a/Source/WebCore/rendering/RenderCombineText.cpp +++ b/Source/WebCore/rendering/RenderCombineText.cpp @@ -52,7 +52,7 @@ void RenderCombineText::setTextInternal(PassRefPtr<StringImpl> text) m_needsFontUpdate = true; } -unsigned RenderCombineText::width(unsigned from, unsigned length, const Font& font, int xPosition, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const +float RenderCombineText::width(unsigned from, unsigned length, const Font& font, float xPosition, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const { if (!characters()) return 0; @@ -63,7 +63,7 @@ unsigned RenderCombineText::width(unsigned from, unsigned length, const Font& fo return RenderText::width(from, length, font, xPosition, fallbackFonts, glyphOverflow); } -void RenderCombineText::adjustTextOrigin(IntPoint& textOrigin, const IntRect& boxRect) const +void RenderCombineText::adjustTextOrigin(FloatPoint& textOrigin, const FloatRect& boxRect) const { if (m_isCombined) textOrigin.move(boxRect.height() / 2 - ceilf(m_combinedTextWidth) / 2, style()->font().pixelSize()); @@ -98,7 +98,7 @@ void RenderCombineText::combineText() bool shouldUpdateFont = false; description.setOrientation(Horizontal); // We are going to draw combined text horizontally. - m_combinedTextWidth = style()->font().floatWidth(run); + m_combinedTextWidth = style()->font().width(run); m_isCombined = m_combinedTextWidth <= emWidth; if (m_isCombined) @@ -110,7 +110,7 @@ void RenderCombineText::combineText() description.setWidthVariant(widthVariants[i]); Font compressedFont = Font(description, style()->font().letterSpacing(), style()->font().wordSpacing()); compressedFont.update(style()->font().fontSelector()); - float runWidth = compressedFont.floatWidth(run); + float runWidth = compressedFont.width(run); if (runWidth <= emWidth) { m_combinedTextWidth = runWidth; m_isCombined = true; diff --git a/Source/WebCore/rendering/RenderCombineText.h b/Source/WebCore/rendering/RenderCombineText.h index 582cbd6..3484ab7 100644 --- a/Source/WebCore/rendering/RenderCombineText.h +++ b/Source/WebCore/rendering/RenderCombineText.h @@ -30,13 +30,13 @@ public: RenderCombineText(Node*, PassRefPtr<StringImpl>); void combineText(); - void adjustTextOrigin(IntPoint& textOrigin, const IntRect& boxRect) const; + void adjustTextOrigin(FloatPoint& textOrigin, const FloatRect& boxRect) const; void charactersToRender(int start, const UChar*& characters, int& length) const; bool isCombined() const { return m_isCombined; } - int combinedTextWidth(const Font& font) const { return font.size(); } + float combinedTextWidth(const Font& font) const { return font.size(); } private: - virtual unsigned width(unsigned from, unsigned length, const Font&, int xPosition, HashSet<const SimpleFontData*>* fallbackFonts = 0, GlyphOverflow* = 0) const; + virtual float width(unsigned from, unsigned length, const Font&, float xPosition, HashSet<const SimpleFontData*>* fallbackFonts = 0, GlyphOverflow* = 0) const; virtual const char* renderName() const { return "RenderCombineText"; } virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); virtual void setTextInternal(PassRefPtr<StringImpl>); diff --git a/Source/WebCore/rendering/RenderCounter.cpp b/Source/WebCore/rendering/RenderCounter.cpp index fbd5545..f4a8736 100644 --- a/Source/WebCore/rendering/RenderCounter.cpp +++ b/Source/WebCore/rendering/RenderCounter.cpp @@ -385,7 +385,7 @@ static bool findPlaceForCounter(RenderObject* counterOwner, const AtomicString& if (previousSibling) currentRenderer = previousSiblingOrParent(currentRenderer); else - currentRenderer = currentRenderer->previousInPreOrder(); + currentRenderer = previousInPreOrder(currentRenderer); } return false; } @@ -493,7 +493,7 @@ PassRefPtr<StringImpl> RenderCounter::originalText() const return text.impl(); } -void RenderCounter::computePreferredLogicalWidths(int lead) +void RenderCounter::computePreferredLogicalWidths(float lead) { setTextInternal(originalText()); RenderText::computePreferredLogicalWidths(lead); diff --git a/Source/WebCore/rendering/RenderCounter.h b/Source/WebCore/rendering/RenderCounter.h index de0ee1b..35ffc35 100644 --- a/Source/WebCore/rendering/RenderCounter.h +++ b/Source/WebCore/rendering/RenderCounter.h @@ -50,7 +50,7 @@ private: virtual bool isCounter() const; virtual PassRefPtr<StringImpl> originalText() const; - virtual void computePreferredLogicalWidths(int leadWidth); + virtual void computePreferredLogicalWidths(float leadWidth); CounterContent m_counter; mutable CounterNode* m_counterNode; diff --git a/Source/WebCore/rendering/RenderEmbeddedObject.cpp b/Source/WebCore/rendering/RenderEmbeddedObject.cpp index cdd6c55..3561fe0 100644 --- a/Source/WebCore/rendering/RenderEmbeddedObject.cpp +++ b/Source/WebCore/rendering/RenderEmbeddedObject.cpp @@ -199,8 +199,7 @@ bool RenderEmbeddedObject::getReplacementTextGeometry(int tx, int ty, FloatRect& font.update(0); run = TextRun(m_replacementText.characters(), m_replacementText.length()); - run.disableRoundingHacks(); - textWidth = font.floatWidth(run); + textWidth = font.width(run); replacementTextRect.setSize(FloatSize(textWidth + replacementTextRoundedRectLeftRightTextMargin * 2, replacementTextRoundedRectHeight)); float x = (contentRect.size().width() / 2 - replacementTextRect.size().width() / 2) + contentRect.location().x(); diff --git a/Source/WebCore/rendering/RenderFileUploadControl.cpp b/Source/WebCore/rendering/RenderFileUploadControl.cpp index f72edad..b50b2ad 100644 --- a/Source/WebCore/rendering/RenderFileUploadControl.cpp +++ b/Source/WebCore/rendering/RenderFileUploadControl.cpp @@ -273,7 +273,7 @@ void RenderFileUploadControl::computePreferredLogicalWidths() // Figure out how big the filename space needs to be for a given number of characters // (using "0" as the nominal character). const UChar ch = '0'; - float charWidth = style()->font().floatWidth(TextRun(&ch, 1, false, 0, 0, TextRun::AllowTrailingExpansion, false, false, false)); + float charWidth = style()->font().width(TextRun(&ch, 1, false, 0, 0, TextRun::AllowTrailingExpansion, false)); m_maxPreferredLogicalWidth = (int)ceilf(charWidth * defaultWidthNumChars); } diff --git a/Source/WebCore/rendering/RenderFlexibleBox.cpp b/Source/WebCore/rendering/RenderFlexibleBox.cpp index 9ab3c3f..8241dcd 100644 --- a/Source/WebCore/rendering/RenderFlexibleBox.cpp +++ b/Source/WebCore/rendering/RenderFlexibleBox.cpp @@ -420,15 +420,12 @@ void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren) while (child) { if (child->isPositioned()) { child->containingBlock()->insertPositionedObject(child); - if (child->style()->hasStaticX()) { - if (style()->isLeftToRightDirection()) - child->layer()->setStaticX(xPos); - else child->layer()->setStaticX(width() - xPos); - } - if (child->style()->hasStaticY()) { - RenderLayer* childLayer = child->layer(); - if (childLayer->staticY() != yPos) { - child->layer()->setStaticY(yPos); + RenderLayer* childLayer = child->layer(); + if (child->style()->hasStaticInlinePosition(style()->isHorizontalWritingMode())) + childLayer->setStaticInlinePosition(xPos); + if (child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode())) { + if (childLayer->staticBlockPosition() != yPos) { + childLayer->setStaticBlockPosition(yPos); child->setChildNeedsLayout(true, false); } } @@ -686,16 +683,16 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren) if (child->isPositioned()) { child->containingBlock()->insertPositionedObject(child); - if (child->style()->hasStaticX()) { + RenderLayer* childLayer = child->layer(); + if (child->style()->hasStaticInlinePosition(style()->isHorizontalWritingMode())) { if (style()->isLeftToRightDirection()) - child->layer()->setStaticX(borderLeft()+paddingLeft()); + childLayer->setStaticInlinePosition(borderLeft() + paddingLeft()); else - child->layer()->setStaticX(borderRight()+paddingRight()); + childLayer->setStaticInlinePosition(borderRight() + paddingRight()); } - if (child->style()->hasStaticY()) { - RenderLayer* childLayer = child->layer(); - if (childLayer->staticY() != height()) { - child->layer()->setStaticY(height()); + if (child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode())) { + if (childLayer->staticBlockPosition() != height()) { + childLayer->setStaticBlockPosition(height()); child->setChildNeedsLayout(true, false); } } @@ -1012,7 +1009,7 @@ void RenderFlexibleBox::applyLineClamp(FlexBoxIterator& iterator, bool relayoutC int blockLeftEdge = destBlock->logicalLeftOffsetForLine(lastVisibleLine->y(), false); int blockEdge = leftToRight ? blockRightEdge : blockLeftEdge; - if (!lastVisibleLine->canAccommodateEllipsis(leftToRight, blockEdge, lastVisibleLine->x() + lastVisibleLine->logicalWidth(), totalWidth)) + if (!lastVisibleLine->lineCanAccommodateEllipsis(leftToRight, blockEdge, lastVisibleLine->x() + lastVisibleLine->logicalWidth(), totalWidth)) continue; // Let the truncation code kick in. diff --git a/Source/WebCore/rendering/RenderImage.cpp b/Source/WebCore/rendering/RenderImage.cpp index 7369f4e..9500aeb 100644 --- a/Source/WebCore/rendering/RenderImage.cpp +++ b/Source/WebCore/rendering/RenderImage.cpp @@ -85,7 +85,7 @@ static const unsigned short paddingHeight = 4; // Alt text is restricted to this maximum size, in pixels. These are // signed integers because they are compared with other signed values. -static const int maxAltTextWidth = 1024; +static const float maxAltTextWidth = 1024; static const int maxAltTextHeight = 256; IntSize RenderImage::imageSizeForError(CachedImage* newImage) const @@ -449,7 +449,6 @@ bool RenderImage::isLogicalWidthSpecified() const return true; case Auto: case Relative: // FIXME: Shouldn't this case return true? - case Static: case Intrinsic: case MinIntrinsic: return false; @@ -466,7 +465,6 @@ bool RenderImage::isLogicalHeightSpecified() const return true; case Auto: case Relative: // FIXME: Shouldn't this case return true? - case Static: case Intrinsic: case MinIntrinsic: return false; diff --git a/Source/WebCore/rendering/RenderInline.cpp b/Source/WebCore/rendering/RenderInline.cpp index 3768774..234d63c 100644 --- a/Source/WebCore/rendering/RenderInline.cpp +++ b/Source/WebCore/rendering/RenderInline.cpp @@ -53,6 +53,19 @@ RenderInline::RenderInline(Node* node) void RenderInline::destroy() { +#ifndef NDEBUG + // Make sure we do not retain "this" in the continuation outline table map of our containing blocks. + if (parent() && style()->visibility() == VISIBLE && hasOutline()) { + bool containingBlockPaintsContinuationOutline = continuation() || isInlineElementContinuation(); + if (containingBlockPaintsContinuationOutline) { + if (RenderBlock* cb = containingBlock()) { + if (RenderBlock* cbCb = cb->containingBlock()) + ASSERT(!cbCb->paintsContinuationOutline(this)); + } + } + } +#endif + // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise. children()->destroyLeftoverChildren(); @@ -559,8 +572,8 @@ IntRect RenderInline::linesBoundingBox() const ASSERT(!firstLineBox() == !lastLineBox()); // Either both are null or both exist. if (firstLineBox() && lastLineBox()) { // Return the width of the minimal left side and the maximal right side. - int logicalLeftSide = 0; - int logicalRightSide = 0; + float logicalLeftSide = 0; + float logicalRightSide = 0; for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) { if (curr == firstLineBox() || curr->logicalLeft() < logicalLeftSide) logicalLeftSide = curr->logicalLeft(); @@ -570,11 +583,11 @@ IntRect RenderInline::linesBoundingBox() const bool isHorizontal = style()->isHorizontalWritingMode(); - int x = isHorizontal ? logicalLeftSide : firstLineBox()->x(); - int y = isHorizontal ? firstLineBox()->y() : logicalLeftSide; - int width = isHorizontal ? logicalRightSide - logicalLeftSide : lastLineBox()->logicalBottom() - x; - int height = isHorizontal ? lastLineBox()->logicalBottom() - y : logicalRightSide - logicalLeftSide; - result = IntRect(x, y, width, height); + float x = isHorizontal ? logicalLeftSide : firstLineBox()->x(); + float y = isHorizontal ? firstLineBox()->y() : logicalLeftSide; + float width = isHorizontal ? logicalRightSide - logicalLeftSide : lastLineBox()->logicalBottom() - x; + float height = isHorizontal ? lastLineBox()->logicalBottom() - y : logicalRightSide - logicalLeftSide; + result = enclosingIntRect(FloatRect(x, y, width, height)); } return result; @@ -586,20 +599,20 @@ IntRect RenderInline::linesVisualOverflowBoundingBox() const return IntRect(); // Return the width of the minimal left side and the maximal right side. - int logicalLeftSide = numeric_limits<int>::max(); - int logicalRightSide = numeric_limits<int>::min(); + float logicalLeftSide = numeric_limits<int>::max(); + float logicalRightSide = numeric_limits<int>::min(); for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) { - logicalLeftSide = min(logicalLeftSide, curr->logicalLeftVisualOverflow()); - logicalRightSide = max(logicalRightSide, curr->logicalRightVisualOverflow()); + logicalLeftSide = min(logicalLeftSide, static_cast<float>(curr->logicalLeftVisualOverflow())); + logicalRightSide = max(logicalRightSide, static_cast<float>(curr->logicalRightVisualOverflow())); } bool isHorizontal = style()->isHorizontalWritingMode(); - int x = isHorizontal ? logicalLeftSide : firstLineBox()->minXVisualOverflow(); - int y = isHorizontal ? firstLineBox()->minYVisualOverflow() : logicalLeftSide; - int width = isHorizontal ? logicalRightSide - logicalLeftSide : lastLineBox()->maxXVisualOverflow() - firstLineBox()->minXVisualOverflow(); - int height = isHorizontal ? lastLineBox()->maxYVisualOverflow() - firstLineBox()->minYVisualOverflow() : logicalRightSide - logicalLeftSide; - return IntRect(x, y, width, height); + float x = isHorizontal ? logicalLeftSide : firstLineBox()->minXVisualOverflow(); + float y = isHorizontal ? firstLineBox()->minYVisualOverflow() : logicalLeftSide; + float width = isHorizontal ? logicalRightSide - logicalLeftSide : lastLineBox()->maxXVisualOverflow() - firstLineBox()->minXVisualOverflow(); + float height = isHorizontal ? lastLineBox()->maxYVisualOverflow() - firstLineBox()->minYVisualOverflow() : logicalRightSide - logicalLeftSide; + return enclosingIntRect(FloatRect(x, y, width, height)); } IntRect RenderInline::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) @@ -915,6 +928,8 @@ int RenderInline::baselinePosition(FontBaseline baselineType, bool firstLine, Li IntSize RenderInline::relativePositionedInlineOffset(const RenderBox* child) const { + // FIXME: This function isn't right with mixed writing modes. + ASSERT(isRelPositioned()); if (!isRelPositioned()) return IntSize(); @@ -923,31 +938,32 @@ IntSize RenderInline::relativePositionedInlineOffset(const RenderBox* child) con // box from the rest of the content, but only in the cases where we know we're positioned // relative to the inline itself. - IntSize offset; - int sx; - int sy; + IntSize logicalOffset; + int inlinePosition; + int blockPosition; if (firstLineBox()) { - sx = firstLineBox()->x(); - sy = firstLineBox()->y(); + inlinePosition = lroundf(firstLineBox()->logicalLeft()); + blockPosition = firstLineBox()->logicalTop(); } else { - sx = layer()->staticX(); - sy = layer()->staticY(); + inlinePosition = layer()->staticInlinePosition(); + blockPosition = layer()->staticBlockPosition(); } - if (!child->style()->hasStaticX()) - offset.setWidth(sx); + if (!child->style()->hasStaticInlinePosition(style()->isHorizontalWritingMode())) + logicalOffset.setWidth(inlinePosition); + // This is not terribly intuitive, but we have to match other browsers. Despite being a block display type inside // an inline, we still keep our x locked to the left of the relative positioned inline. Arguably the correct // behavior would be to go flush left to the block that contains the inline, but that isn't what other browsers // do. else if (!child->style()->isOriginalDisplayInlineType()) // Avoid adding in the left border/padding of the containing block twice. Subtract it out. - offset.setWidth(sx - (child->containingBlock()->borderLeft() + child->containingBlock()->paddingLeft())); + logicalOffset.setWidth(inlinePosition - child->containingBlock()->borderAndPaddingLogicalLeft()); - if (!child->style()->hasStaticY()) - offset.setHeight(sy); + if (!child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode())) + logicalOffset.setHeight(blockPosition); - return offset; + return style()->isHorizontalWritingMode() ? logicalOffset : logicalOffset.transposedSize(); } void RenderInline::imageChanged(WrappedImagePtr, const IntRect*) @@ -963,8 +979,8 @@ void RenderInline::addFocusRingRects(Vector<IntRect>& rects, int tx, int ty) { for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) { RootInlineBox* root = curr->root(); - int top = max(root->lineTop(), curr->y()); - int bottom = min(root->lineBottom(), curr->y() + curr->logicalHeight()); + int top = max(root->lineTop(), curr->logicalTop()); + int bottom = min(root->lineBottom(), curr->logicalBottom()); IntRect rect(tx + curr->x(), ty + top, curr->logicalWidth(), bottom - top); if (!rect.isEmpty()) rects.append(rect); @@ -1015,8 +1031,8 @@ void RenderInline::paintOutline(GraphicsContext* graphicsContext, int tx, int ty rects.append(IntRect()); for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) { RootInlineBox* root = curr->root(); - int top = max(root->lineTop(), curr->y()); - int bottom = min(root->lineBottom(), curr->y() + curr->logicalHeight()); + int top = max(root->lineTop(), curr->logicalTop()); + int bottom = min(root->lineBottom(), curr->logicalBottom()); rects.append(IntRect(curr->x(), top, curr->logicalWidth(), bottom - top)); } rects.append(IntRect()); diff --git a/Source/WebCore/rendering/RenderLayer.cpp b/Source/WebCore/rendering/RenderLayer.cpp index e278c75..5f32933 100644 --- a/Source/WebCore/rendering/RenderLayer.cpp +++ b/Source/WebCore/rendering/RenderLayer.cpp @@ -182,8 +182,8 @@ RenderLayer::RenderLayer(RenderBoxModelObject* renderer) , m_hasOverflowScroll(false) #endif , m_marquee(0) - , m_staticX(0) - , m_staticY(0) + , m_staticInlinePosition(0) + , m_staticBlockPosition(0) , m_reflection(0) , m_scrollCorner(0) , m_resizer(0) @@ -413,7 +413,7 @@ void RenderLayer::updateRepaintRectsAfterScroll(bool fixed) if (fixed || renderer()->style()->position() == FixedPosition) { computeRepaintRects(); fixed = true; - } else if (renderer()->hasTransform()) { + } else if (renderer()->hasTransform() && !renderer()->isRenderView()) { // Transforms act as fixed position containers, so nothing inside a // transformed element can be fixed relative to the viewport if the // transformed element is not fixed itself or child of a fixed element. @@ -1839,8 +1839,13 @@ PassRefPtr<Scrollbar> RenderLayer::createScrollbar(ScrollbarOrientation orientat bool hasCustomScrollbarStyle = actualRenderer->isBox() && actualRenderer->style()->hasPseudoStyle(SCROLLBAR); if (hasCustomScrollbarStyle) widget = RenderScrollbar::createCustomScrollbar(this, orientation, toRenderBox(actualRenderer)); - else + else { widget = Scrollbar::createNativeScrollbar(this, orientation, RegularScrollbar); + if (orientation == HorizontalScrollbar) + didAddHorizontalScrollbar(widget.get()); + else + didAddVerticalScrollbar(widget.get()); + } renderer()->document()->view()->addChild(widget.get()); return widget.release(); } @@ -1851,6 +1856,12 @@ void RenderLayer::destroyScrollbar(ScrollbarOrientation orientation) if (scrollbar) { if (scrollbar->isCustomScrollbar()) static_cast<RenderScrollbar*>(scrollbar.get())->clearOwningRenderer(); + else { + if (orientation == HorizontalScrollbar) + willRemoveHorizontalScrollbar(scrollbar.get()); + else + willRemoveVerticalScrollbar(scrollbar.get()); + } scrollbar->removeFromParent(); scrollbar->disconnectFromScrollableArea(); @@ -1863,13 +1874,10 @@ void RenderLayer::setHasHorizontalScrollbar(bool hasScrollbar) if (hasScrollbar == (m_hBar != 0)) return; - if (hasScrollbar) { + if (hasScrollbar) m_hBar = createScrollbar(HorizontalScrollbar); - ScrollableArea::didAddHorizontalScrollbar(m_hBar.get()); - } else { - ScrollableArea::willRemoveHorizontalScrollbar(m_hBar.get()); + else destroyScrollbar(HorizontalScrollbar); - } // Destroying or creating one bar can cause our scrollbar corner to come and go. We need to update the opposite scrollbar's style. if (m_hBar) @@ -1889,13 +1897,10 @@ void RenderLayer::setHasVerticalScrollbar(bool hasScrollbar) if (hasScrollbar == (m_vBar != 0)) return; - if (hasScrollbar) { + if (hasScrollbar) m_vBar = createScrollbar(VerticalScrollbar); - ScrollableArea::didAddVerticalScrollbar(m_vBar.get()); - } else { - ScrollableArea::willRemoveVerticalScrollbar(m_vBar.get()); + else destroyScrollbar(VerticalScrollbar); - } // Destroying or creating one bar can cause our scrollbar corner to come and go. We need to update the opposite scrollbar's style. if (m_hBar) @@ -1912,14 +1917,14 @@ void RenderLayer::setHasVerticalScrollbar(bool hasScrollbar) int RenderLayer::verticalScrollbarWidth() const { - if (!m_vBar || ScrollbarTheme::nativeTheme()->usesOverlayScrollbars()) + if (!m_vBar || m_vBar->isOverlayScrollbar()) return 0; return m_vBar->width(); } int RenderLayer::horizontalScrollbarHeight() const { - if (!m_hBar || ScrollbarTheme::nativeTheme()->usesOverlayScrollbars()) + if (!m_hBar || m_hBar->isOverlayScrollbar()) return 0; return m_hBar->height(); } @@ -3283,8 +3288,8 @@ void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, ClipRects& cl RenderView* view = renderer()->view(); ASSERT(view); if (view && clipRects.fixed() && rootLayer->renderer() == view) { - x -= view->frameView()->scrollX(); - y -= view->frameView()->scrollY(); + x -= view->frameView()->scrollXForFixedPosition(); + y -= view->frameView()->scrollYForFixedPosition(); } if (renderer()->hasOverflowClip()) { @@ -3336,7 +3341,7 @@ IntRect RenderLayer::backgroundClipRect(const RenderLayer* rootLayer, bool tempo RenderView* view = renderer()->view(); ASSERT(view); if (view && parentRects.fixed() && rootLayer->renderer() == view) - backgroundRect.move(view->frameView()->scrollX(), view->frameView()->scrollY()); + backgroundRect.move(view->frameView()->scrollXForFixedPosition(), view->frameView()->scrollYForFixedPosition()); } return backgroundRect; } @@ -3580,26 +3585,6 @@ bool RenderLayer::hasCompositedMask() const } #endif -bool RenderLayer::scrollbarWillRenderIntoCompositingLayer() const -{ -#if USE(ACCELERATED_COMPOSITING) - if (enclosingCompositingLayer()) - return true; - - RenderView* view = renderer()->view(); - if (!view) - return false; - - FrameView* frameView = view->frameView(); - if (!frameView) - return false; - - return frameView->isEnclosedInCompositingLayer(); -#else - return false; -#endif -} - bool RenderLayer::paintsWithTransform(PaintBehavior paintBehavior) const { #if USE(ACCELERATED_COMPOSITING) diff --git a/Source/WebCore/rendering/RenderLayer.h b/Source/WebCore/rendering/RenderLayer.h index 66281ce..7dddbc8 100644 --- a/Source/WebCore/rendering/RenderLayer.h +++ b/Source/WebCore/rendering/RenderLayer.h @@ -444,10 +444,10 @@ public: void updateRepaintRectsAfterScroll(bool fixed = false); void setNeedsFullRepaint(bool f = true) { m_needsFullRepaint = f; } - int staticX() const { return m_staticX; } - int staticY() const { return m_staticY; } - void setStaticX(int staticX) { m_staticX = staticX; } - void setStaticY(int staticY) { m_staticY = staticY; } + int staticInlinePosition() const { return m_staticInlinePosition; } + int staticBlockPosition() const { return m_staticBlockPosition; } + void setStaticInlinePosition(int position) { m_staticInlinePosition = position; } + void setStaticBlockPosition(int position) { m_staticBlockPosition = position; } bool hasTransform() const { return renderer()->hasTransform(); } // Note that this transform has the transform-origin baked in. @@ -483,7 +483,6 @@ public: bool isComposited() const { return false; } bool hasCompositedMask() const { return false; } #endif - virtual bool scrollbarWillRenderIntoCompositingLayer() const; bool paintsWithTransparency(PaintBehavior paintBehavior) const { @@ -745,8 +744,8 @@ protected: RenderMarquee* m_marquee; // Used by layers with overflow:marquee // Cached normal flow values for absolute positioned elements with static left/top values. - int m_staticX; - int m_staticY; + int m_staticInlinePosition; + int m_staticBlockPosition; OwnPtr<TransformationMatrix> m_transform; diff --git a/Source/WebCore/rendering/RenderLayerBacking.cpp b/Source/WebCore/rendering/RenderLayerBacking.cpp index d0a36c7..bda34ee 100644 --- a/Source/WebCore/rendering/RenderLayerBacking.cpp +++ b/Source/WebCore/rendering/RenderLayerBacking.cpp @@ -36,7 +36,6 @@ #include "CSSStyleSelector.h" #include "FrameView.h" #include "GraphicsContext.h" -#include "GraphicsContext3D.h" #include "GraphicsLayer.h" #include "HTMLCanvasElement.h" #include "HTMLElement.h" @@ -55,7 +54,10 @@ #include "RenderVideo.h" #include "RenderView.h" #include "Settings.h" -#include "WebGLRenderingContext.h" + +#if ENABLE(WEBGL) || ENABLE(ACCELERATED_2D_CANVAS) +#include "GraphicsContext3D.h" +#endif using namespace std; diff --git a/Source/WebCore/rendering/RenderLayerCompositor.cpp b/Source/WebCore/rendering/RenderLayerCompositor.cpp index f9c0f32..4ab274f 100644 --- a/Source/WebCore/rendering/RenderLayerCompositor.cpp +++ b/Source/WebCore/rendering/RenderLayerCompositor.cpp @@ -344,7 +344,9 @@ bool RenderLayerCompositor::updateBacking(RenderLayer* layer, CompositingChangeR layer->ensureBacking(); #if PLATFORM(MAC) && PLATFORM(CA) - if (layer->renderer()->isCanvas()) { + if (m_renderView->document()->settings()->acceleratedDrawingEnabled()) + layer->backing()->graphicsLayer()->setAcceleratesDrawing(true); + else if (layer->renderer()->isCanvas()) { HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(layer->renderer()->node()); if (canvas->renderingContext() && canvas->renderingContext()->isAccelerated()) layer->backing()->graphicsLayer()->setAcceleratesDrawing(true); @@ -1159,6 +1161,10 @@ void RenderLayerCompositor::updateRootLayerPosition() m_rootPlatformLayer->setSize(FloatSize(m_renderView->docWidth(), m_renderView->docHeight())); m_rootPlatformLayer->setPosition(FloatPoint(m_renderView->docLeft(), m_renderView->docTop())); } + if (m_clipLayer) { + FrameView* frameView = m_renderView->frameView(); + m_clipLayer->setSize(FloatSize(frameView->layoutWidth(), frameView->layoutHeight())); + } } void RenderLayerCompositor::didStartAcceleratedAnimation(CSSPropertyID property) @@ -1453,6 +1459,7 @@ bool RenderLayerCompositor::requiresCompositingForFullScreen(RenderObject* rende #if ENABLE(FULLSCREEN_API) return renderer->isRenderFullScreen() && toRenderFullScreen(renderer)->isAnimating(); #else + UNUSED_PARAM(renderer); return false; #endif } diff --git a/Source/WebCore/rendering/RenderLineBoxList.cpp b/Source/WebCore/rendering/RenderLineBoxList.cpp index 274905e..9a40baf 100644 --- a/Source/WebCore/rendering/RenderLineBoxList.cpp +++ b/Source/WebCore/rendering/RenderLineBoxList.cpp @@ -363,11 +363,9 @@ void RenderLineBoxList::dirtyLinesFromChangedChild(RenderObject* container, Rend adjacentBox = box->prevRootBox(); if (adjacentBox) adjacentBox->markDirty(); - if (child->isBR() || (curr && curr->isBR())) { - adjacentBox = box->nextRootBox(); - if (adjacentBox) - adjacentBox->markDirty(); - } + adjacentBox = box->nextRootBox(); + if (adjacentBox && (adjacentBox->lineBreakObj() == child || child->isBR() || (curr && curr->isBR()))) + adjacentBox->markDirty(); } } diff --git a/Source/WebCore/rendering/RenderListBox.cpp b/Source/WebCore/rendering/RenderListBox.cpp index 13e8e58..4457285 100644 --- a/Source/WebCore/rendering/RenderListBox.cpp +++ b/Source/WebCore/rendering/RenderListBox.cpp @@ -111,7 +111,7 @@ void RenderListBox::updateFromElement() } if (!text.isEmpty()) { - float textWidth = itemFont.floatWidth(TextRun(text.impl(), false, 0, 0, TextRun::AllowTrailingExpansion, false, false, false, false)); + float textWidth = itemFont.width(TextRun(text.impl(), false, 0, 0, TextRun::AllowTrailingExpansion, false, false)); width = max(width, textWidth); } } @@ -278,6 +278,32 @@ void RenderListBox::paintObject(PaintInfo& paintInfo, int tx, int ty) } } +void RenderListBox::addFocusRingRects(Vector<IntRect>& rects, int tx, int ty) +{ + if (!isSpatialNavigationEnabled(frame())) + return RenderBlock::addFocusRingRects(rects, tx, ty); + + SelectElement* select = toSelectElement(static_cast<Element*>(node())); + + // Focus the last selected item. + int selectedItem = select->activeSelectionEndListIndex(); + if (selectedItem >= 0) { + rects.append(itemBoundingBoxRect(tx, ty, selectedItem)); + return; + } + + // No selected items, find the first non-disabled item. + int size = numItems(); + const Vector<Element*>& listItems = select->listItems(); + for (int i = 0; i < size; ++i) { + OptionElement* optionElement = toOptionElement(listItems[i]); + if (optionElement && !optionElement->disabled()) { + rects.append(itemBoundingBoxRect(tx, ty, i)); + return; + } + } +} + void RenderListBox::paintScrollbar(PaintInfo& paintInfo, int tx, int ty) { if (m_vBar) { @@ -333,7 +359,7 @@ void RenderListBox::paintItemForeground(PaintInfo& paintInfo, int tx, int ty, in unsigned length = itemText.length(); const UChar* string = itemText.characters(); - TextRun textRun(string, length, false, 0, 0, TextRun::AllowTrailingExpansion, !itemStyle->isLeftToRightDirection(), itemStyle->unicodeBidi() == Override, false, false); + TextRun textRun(string, length, false, 0, 0, TextRun::AllowTrailingExpansion, !itemStyle->isLeftToRightDirection(), itemStyle->unicodeBidi() == Override); // Draw the item text if (itemStyle->visibility() != HIDDEN) @@ -557,7 +583,7 @@ int RenderListBox::itemHeight() const int RenderListBox::verticalScrollbarWidth() const { - return m_vBar && !ScrollbarTheme::nativeTheme()->usesOverlayScrollbars() ? m_vBar->width() : 0; + return m_vBar && !m_vBar->isOverlayScrollbar() ? m_vBar->width() : 0; } // FIXME: We ignore padding in the vertical direction as far as these values are concerned, since that's @@ -721,22 +747,16 @@ IntPoint RenderListBox::currentMousePosition() const return view->frameView()->currentMousePosition(); } -bool RenderListBox::scrollbarWillRenderIntoCompositingLayer() const -{ - RenderLayer* layer = this->enclosingLayer(); - if (!layer) - return false; - return layer->scrollbarWillRenderIntoCompositingLayer(); -} - PassRefPtr<Scrollbar> RenderListBox::createScrollbar() { RefPtr<Scrollbar> widget; bool hasCustomScrollbarStyle = style()->hasPseudoStyle(SCROLLBAR); if (hasCustomScrollbarStyle) widget = RenderScrollbar::createCustomScrollbar(this, VerticalScrollbar, this); - else + else { widget = Scrollbar::createNativeScrollbar(this, VerticalScrollbar, theme()->scrollbarControlSizeForPart(ListboxPart)); + didAddVerticalScrollbar(widget.get()); + } document()->view()->addChild(widget.get()); return widget.release(); } @@ -745,7 +765,9 @@ void RenderListBox::destroyScrollbar() { if (!m_vBar) return; - + + if (!m_vBar->isCustomScrollbar()) + ScrollableArea::willRemoveVerticalScrollbar(m_vBar.get()); m_vBar->removeFromParent(); m_vBar->disconnectFromScrollableArea(); m_vBar = 0; @@ -756,13 +778,10 @@ void RenderListBox::setHasVerticalScrollbar(bool hasScrollbar) if (hasScrollbar == (m_vBar != 0)) return; - if (hasScrollbar) { + if (hasScrollbar) m_vBar = createScrollbar(); - ScrollableArea::didAddVerticalScrollbar(m_vBar.get()); - } else { - ScrollableArea::willRemoveVerticalScrollbar(m_vBar.get()); + else destroyScrollbar(); - } if (m_vBar) m_vBar->styleChanged(); diff --git a/Source/WebCore/rendering/RenderListBox.h b/Source/WebCore/rendering/RenderListBox.h index 1eb2036..faeede1 100644 --- a/Source/WebCore/rendering/RenderListBox.h +++ b/Source/WebCore/rendering/RenderListBox.h @@ -77,6 +77,8 @@ private: virtual void layout(); + virtual void addFocusRingRects(Vector<IntRect>&, int tx, int ty); + virtual bool canBeProgramaticallyScrolled(bool) const { return true; } virtual void autoscroll(); virtual void stopAutoscroll(); @@ -110,7 +112,6 @@ private: virtual int visibleHeight() const; virtual int visibleWidth() const; virtual IntPoint currentMousePosition() const; - virtual bool scrollbarWillRenderIntoCompositingLayer() const; // NOTE: This should only be called by the overriden setScrollOffset from ScrollableArea. void scrollTo(int newOffset); diff --git a/Source/WebCore/rendering/RenderMedia.cpp b/Source/WebCore/rendering/RenderMedia.cpp index 16cd874..bbb5880 100644 --- a/Source/WebCore/rendering/RenderMedia.cpp +++ b/Source/WebCore/rendering/RenderMedia.cpp @@ -31,6 +31,7 @@ #include "HTMLMediaElement.h" #include "MediaControlElements.h" #include "MediaControls.h" +#include "RenderView.h" namespace WebCore { @@ -80,17 +81,24 @@ void RenderMedia::layout() if (!controlsRenderer) return; IntSize newSize = contentBoxRect().size(); - if (newSize != oldSize || controlsRenderer->needsLayout()) { + if (newSize == oldSize && !controlsRenderer->needsLayout()) + return; + + // When calling layout() on a child node, a parent must either push a LayoutStateMaintainter, or + // call view()->disableLayoutState(). Since using a LayoutStateMaintainer is slightly more efficient, + // and this method will be called many times per second during playback, use a LayoutStateMaintainer: + LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode()); + + m_controls->updateTimeDisplayVisibility(); - m_controls->updateTimeDisplayVisibility(); + controlsRenderer->setLocation(borderLeft() + paddingLeft(), borderTop() + paddingTop()); + controlsRenderer->style()->setHeight(Length(newSize.height(), Fixed)); + controlsRenderer->style()->setWidth(Length(newSize.width(), Fixed)); + controlsRenderer->setNeedsLayout(true, false); + controlsRenderer->layout(); + setChildNeedsLayout(false); - controlsRenderer->setLocation(borderLeft() + paddingLeft(), borderTop() + paddingTop()); - controlsRenderer->style()->setHeight(Length(newSize.height(), Fixed)); - controlsRenderer->style()->setWidth(Length(newSize.width(), Fixed)); - controlsRenderer->setNeedsLayout(true, false); - controlsRenderer->layout(); - setChildNeedsLayout(false); - } + statePusher.pop(); } void RenderMedia::updateFromElement() diff --git a/Source/WebCore/rendering/RenderMediaControls.cpp b/Source/WebCore/rendering/RenderMediaControls.cpp index 9c4757c..dd58cd2 100644 --- a/Source/WebCore/rendering/RenderMediaControls.cpp +++ b/Source/WebCore/rendering/RenderMediaControls.cpp @@ -24,29 +24,37 @@ */ #include "config.h" + +#if ENABLE(VIDEO) + #include "RenderMediaControls.h" #include "GraphicsContext.h" #include "HTMLMediaElement.h" #include "HTMLNames.h" #include "RenderTheme.h" + +// FIXME: Unify more of the code for Mac and Win. +#if PLATFORM(WIN) + #include <CoreGraphics/CoreGraphics.h> #include <WebKitSystemInterface/WebKitSystemInterface.h> -#if PLATFORM(WIN) // The Windows version of WKSI defines these functions as capitalized, while the Mac version defines them as lower case. +// FIXME: Is this necessary anymore? #define wkMediaControllerThemeAvailable(themeStyle) WKMediaControllerThemeAvailable(themeStyle) #define wkHitTestMediaUIPart(part, themeStyle, bounds, point) WKHitTestMediaUIPart(part, themeStyle, bounds, point) #define wkMeasureMediaUIPart(part, themeStyle, bounds, naturalSize) WKMeasureMediaUIPart(part, themeStyle, bounds, naturalSize) #define wkDrawMediaUIPart(part, themeStyle, context, rect, state) WKDrawMediaUIPart(part, themeStyle, context, rect, state) #define wkDrawMediaSliderTrack(themeStyle, context, rect, timeLoaded, currentTime, duration, state) WKDrawMediaSliderTrack(themeStyle, context, rect, timeLoaded, currentTime, duration, state) + #endif using namespace std; namespace WebCore { -#if ENABLE(VIDEO) +#if PLATFORM(WIN) static WKMediaControllerThemeState determineState(RenderObject* o) { @@ -169,19 +177,21 @@ bool RenderMediaControls::paintMediaControlsPart(MediaControlElementType part, R return false; } -IntPoint RenderMediaControls::volumeSliderOffsetFromMuteButton(Node* muteButton, const IntSize& size) +#endif + +IntPoint RenderMediaControls::volumeSliderOffsetFromMuteButton(RenderBox* muteButtonBox, const IntSize& size) { static const int xOffset = -4; static const int yOffset = 5; - float zoomLevel = muteButton->renderer()->style()->effectiveZoom(); - int y = yOffset * zoomLevel + muteButton->renderBox()->offsetHeight() - size.height(); - FloatPoint absPoint = muteButton->renderer()->localToAbsolute(FloatPoint(muteButton->renderBox()->offsetLeft(), y), true, true); + float zoomLevel = muteButtonBox->style()->effectiveZoom(); + int y = yOffset * zoomLevel + muteButtonBox->offsetHeight() - size.height(); + FloatPoint absPoint = muteButtonBox->localToAbsolute(FloatPoint(muteButtonBox->offsetLeft(), y), true, true); if (absPoint.y() < 0) - y = muteButton->renderBox()->height(); + y = muteButtonBox->height(); return IntPoint(xOffset * zoomLevel, y); +} } -#endif // #if ENABLE(VIDEO) -} // namespace WebCore +#endif diff --git a/Source/WebCore/rendering/RenderMediaControls.h b/Source/WebCore/rendering/RenderMediaControls.h index 9edeef1..3d3b017 100644 --- a/Source/WebCore/rendering/RenderMediaControls.h +++ b/Source/WebCore/rendering/RenderMediaControls.h @@ -34,11 +34,15 @@ namespace WebCore { class HTMLMediaElement; + class RenderMediaControls { public: + +#if PLATFORM(WIN) static bool paintMediaControlsPart(MediaControlElementType, RenderObject*, const PaintInfo&, const IntRect&); static void adjustMediaSliderThumbSize(RenderObject*); - static IntPoint volumeSliderOffsetFromMuteButton(Node*, const IntSize&); +#endif + static IntPoint volumeSliderOffsetFromMuteButton(RenderBox*, const IntSize&); }; } // namespace WebCore diff --git a/Source/WebCore/rendering/RenderMenuList.cpp b/Source/WebCore/rendering/RenderMenuList.cpp index 3e9d198..8c11959 100644 --- a/Source/WebCore/rendering/RenderMenuList.cpp +++ b/Source/WebCore/rendering/RenderMenuList.cpp @@ -153,10 +153,10 @@ void RenderMenuList::updateOptionsWidth() if (RenderStyle* optionStyle = element->renderStyle()) optionWidth += optionStyle->textIndent().calcMinValue(0); if (!text.isEmpty()) - optionWidth += style()->font().floatWidth(text); + optionWidth += style()->font().width(text); maxOptionWidth = max(maxOptionWidth, optionWidth); } else if (!text.isEmpty()) - maxOptionWidth = max(maxOptionWidth, style()->font().floatWidth(text)); + maxOptionWidth = max(maxOptionWidth, style()->font().width(text)); } int width = static_cast<int>(ceilf(maxOptionWidth)); diff --git a/Source/WebCore/rendering/RenderObject.cpp b/Source/WebCore/rendering/RenderObject.cpp index ebab355..d06db14 100644 --- a/Source/WebCore/rendering/RenderObject.cpp +++ b/Source/WebCore/rendering/RenderObject.cpp @@ -2651,13 +2651,14 @@ VisiblePosition RenderObject::createVisiblePosition(int offset, EAffinity affini // If it can be found, we prefer a visually equivalent position that is editable. Position position(node, offset); Position candidate = position.downstream(CanCrossEditingBoundary); - if (candidate.node()->isContentEditable()) + if (candidate.deprecatedNode()->isContentEditable()) return VisiblePosition(candidate, affinity); candidate = position.upstream(CanCrossEditingBoundary); - if (candidate.node()->isContentEditable()) + if (candidate.deprecatedNode()->isContentEditable()) return VisiblePosition(candidate, affinity); } - return VisiblePosition(node, offset, affinity); + // FIXME: Eliminate legacy editing positions + return VisiblePosition(Position(node, offset), affinity); } // We don't want to cross the boundary between editable and non-editable @@ -2672,7 +2673,7 @@ VisiblePosition RenderObject::createVisiblePosition(int offset, EAffinity affini RenderObject* renderer = child; while ((renderer = renderer->nextInPreOrder(parent))) { if (Node* node = renderer->node()) - return VisiblePosition(node, 0, DOWNSTREAM); + return VisiblePosition(firstPositionInOrBeforeNode(node), DOWNSTREAM); } // Find non-anonymous content before. @@ -2681,12 +2682,12 @@ VisiblePosition RenderObject::createVisiblePosition(int offset, EAffinity affini if (renderer == parent) break; if (Node* node = renderer->node()) - return VisiblePosition(lastDeepEditingPositionForNode(node), DOWNSTREAM); + return VisiblePosition(lastPositionInOrAfterNode(node), DOWNSTREAM); } // Use the parent itself unless it too is anonymous. if (Node* node = parent->node()) - return VisiblePosition(node, 0, DOWNSTREAM); + return VisiblePosition(firstPositionInOrBeforeNode(node), DOWNSTREAM); // Repeat at the next level up. child = parent; diff --git a/Source/WebCore/rendering/RenderObject.h b/Source/WebCore/rendering/RenderObject.h index 43e6bea..8b9fa38 100644 --- a/Source/WebCore/rendering/RenderObject.h +++ b/Source/WebCore/rendering/RenderObject.h @@ -252,6 +252,7 @@ public: virtual bool isBlockFlow() const { return false; } virtual bool isBoxModelObject() const { return false; } virtual bool isCounter() const { return false; } + virtual bool isQuote() const { return false; } virtual bool isDetails() const { return false; } virtual bool isDetailsMarker() const { return false; } virtual bool isEmbeddedObject() const { return false; } @@ -981,7 +982,7 @@ inline void RenderObject::markContainingBlocksForLayout(bool scheduleRelayout, R if (!container && !o->isRenderView()) return; if (!last->isText() && (last->style()->position() == FixedPosition || last->style()->position() == AbsolutePosition)) { - if ((last->style()->top().isAuto() && last->style()->bottom().isAuto()) || last->style()->top().isStatic()) { + if (last->style()->top().isAuto() && last->style()->bottom().isAuto()) { RenderObject* parent = last->parent(); if (!parent->normalChildNeedsLayout()) { parent->setChildNeedsLayout(true, false); diff --git a/Source/WebCore/rendering/RenderObjectChildList.cpp b/Source/WebCore/rendering/RenderObjectChildList.cpp index 6a773dc..4df7180 100644 --- a/Source/WebCore/rendering/RenderObjectChildList.cpp +++ b/Source/WebCore/rendering/RenderObjectChildList.cpp @@ -36,6 +36,7 @@ #include "RenderInline.h" #include "RenderLayer.h" #include "RenderListItem.h" +#include "RenderQuote.h" #include "RenderStyle.h" #include "RenderTextFragment.h" #include "RenderView.h" @@ -130,6 +131,7 @@ RenderObject* RenderObjectChildList::removeChildNode(RenderObject* owner, Render if (oldChild->m_hasCounterNodeMap) RenderCounter::destroyCounterNodes(oldChild); + RenderQuote::rendererRemovedFromTree(oldChild); if (AXObjectCache::accessibilityEnabled()) owner->document()->axObjectCache()->childrenChanged(owner); @@ -177,8 +179,8 @@ void RenderObjectChildList::appendChildNode(RenderObject* owner, RenderObject* n if (!newChild->isFloatingOrPositioned() && owner->childrenInline()) owner->dirtyLinesFromChangedChild(newChild); } - RenderCounter::rendererSubtreeAttached(newChild); + RenderQuote::rendererSubtreeAttached(newChild); newChild->setNeedsLayoutAndPrefWidthsRecalc(); // Goes up the containing block hierarchy. if (!owner->normalChildNeedsLayout()) owner->setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child. @@ -239,6 +241,7 @@ void RenderObjectChildList::insertChildNode(RenderObject* owner, RenderObject* c } RenderCounter::rendererSubtreeAttached(child); + RenderQuote::rendererSubtreeAttached(child); child->setNeedsLayoutAndPrefWidthsRecalc(); if (!owner->normalChildNeedsLayout()) owner->setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child. @@ -460,10 +463,14 @@ void RenderObjectChildList::updateBeforeAfterContent(RenderObject* owner, Pseudo renderer = image; break; } - case CONTENT_COUNTER: - renderer = new (owner->renderArena()) RenderCounter(owner->document(), *content->counter()); - renderer->setStyle(pseudoElementStyle); - break; + case CONTENT_COUNTER: + renderer = new (owner->renderArena()) RenderCounter(owner->document(), *content->counter()); + renderer->setStyle(pseudoElementStyle); + break; + case CONTENT_QUOTE: + renderer = new (owner->renderArena()) RenderQuote(owner->document(), content->quote()); + renderer->setStyle(pseudoElementStyle); + break; } if (renderer) { diff --git a/Source/WebCore/rendering/RenderQuote.cpp b/Source/WebCore/rendering/RenderQuote.cpp new file mode 100644 index 0000000..4523df8 --- /dev/null +++ b/Source/WebCore/rendering/RenderQuote.cpp @@ -0,0 +1,331 @@ +/** + * Copyright (C) 2011 Nokia Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "RenderQuote.h" + +#include "Document.h" +#include "Element.h" +#include "HTMLElement.h" +#include "QuotesData.h" +#include "RenderStyle.h" +#include <algorithm> +#include <wtf/text/AtomicString.h> +#include <wtf/text/CString.h> + +#define UNKNOWN_DEPTH -1 + +namespace WebCore { +static inline void adjustDepth(int &depth, QuoteType type) +{ + switch (type) { + case OPEN_QUOTE: + case NO_OPEN_QUOTE: + ++depth; + break; + case CLOSE_QUOTE: + case NO_CLOSE_QUOTE: + if (depth) + --depth; + break; + default: + ASSERT_NOT_REACHED(); + } +} + +RenderQuote::RenderQuote(Document* node, QuoteType quote) + : RenderText(node, StringImpl::empty()) + , m_type(quote) + , m_depth(UNKNOWN_DEPTH) + , m_next(0) + , m_previous(0) +{ +} + +RenderQuote::~RenderQuote() +{ +} + +const char* RenderQuote::renderName() const +{ + return "RenderQuote"; +} + +// This function places a list of quote renderers starting at "this" in the list of quote renderers already +// in the document's renderer tree. +// The assumptions are made (for performance): +// 1. The list of quotes already in the renderers tree of the document is already in a consistent state +// (All quote renderers are linked and have the correct depth set) +// 2. The quote renderers of the inserted list are in a tree of renderers of their own which has been just +// inserted in the main renderer tree with its root as child of some renderer. +// 3. The quote renderers in the inserted list have depths consistent with their position in the list relative +// to "this", thus if "this" does not need to change its depth upon insertion, the other renderers in the list don't +// need to either. +void RenderQuote::placeQuote() +{ + RenderQuote* head = this; + ASSERT(!head->m_previous); + RenderQuote* tail = 0; + for (RenderObject* predecessor = head->previousInPreOrder(); predecessor; predecessor = predecessor->previousInPreOrder()) { + if (!predecessor->isQuote()) + continue; + head->m_previous = toRenderQuote(predecessor); + if (head->m_previous->m_next) { + // We need to splice the list of quotes headed by head into the document's list of quotes. + tail = head; + while (tail->m_next) + tail = tail->m_next; + tail->m_next = head->m_previous->m_next; + ASSERT(tail->m_next->m_previous == head->m_previous); + tail->m_next->m_previous = tail; + tail = tail->m_next; // This marks the splicing point here there may be a depth discontinuity + } + head->m_previous->m_next = head; + ASSERT(head->m_previous->m_depth != UNKNOWN_DEPTH); + break; + } + int newDepth; + if (!head->m_previous) { + newDepth = 0; + goto skipNewDepthCalc; + } + newDepth = head->m_previous->m_depth; + do { + adjustDepth(newDepth, head->m_previous->m_type); +skipNewDepthCalc: + if (head->m_depth == newDepth) { // All remaining depth should be correct except if splicing was done. + if (!tail) // We've done the post splicing section already or there was no splicing. + break; + head = tail; // Continue after the splicing point + tail = 0; // Mark the possible splicing point discontinuity fixed. + newDepth = head->m_previous->m_depth; + continue; + } + head->m_depth = newDepth; + // FIXME: If the width and height of the quotation characters does not change we may only need to + // Invalidate the renderer's area not a relayout. + head->setNeedsLayoutAndPrefWidthsRecalc(); + head = head->m_next; + if (head == tail) // We are at the splicing point + tail = 0; // Mark the possible depth discontinuity fixed. + } while (head); +} + +#define ARRAY_SIZE(Carray) (sizeof(Carray) / sizeof(*Carray)) +#define LANGUAGE_DATA(name, languageSourceArray) { name, languageSourceArray, ARRAY_SIZE(languageSourceArray) } +#define U(x) ((const UChar*)L##x) + +static const UChar* simpleQuotes[] = {U("\""), U("\""), U("'"), U("'")}; + +static const UChar* englishQuotes[] = {U("\x201C"), U("\x201D"), U("\x2018"), U("\x2019")}; +static const UChar* norwegianQuotes[] = { U("\x00AB"), U("\x00BB"), U("\x2039"), U("\x203A") }; +static const UChar* romanianQuotes[] = { U("\x201E"), U("\x201D")}; +static const UChar* russianQuotes[] = { U("\x00AB"), U("\x00BB"), U("\x201E"), U("\x201C") }; +#undef U + +struct LanguageData { + const char *name; + const UChar* const* const array; + const int arraySize; + bool operator<(const LanguageData& compareTo) const + { + return strcmp(name, compareTo.name); + } +}; + +// Data mast be alphabetically sorted and in all lower case for fast comparison +LanguageData languageData[] = { + LANGUAGE_DATA("en", englishQuotes), + LANGUAGE_DATA("no", norwegianQuotes), + LANGUAGE_DATA("ro", romanianQuotes), + LANGUAGE_DATA("ru", russianQuotes) +}; +#undef LANGUAGE_DATA +const LanguageData* const languageDataEnd = languageData + ARRAY_SIZE(languageData); + +#define defaultLanguageQuotesSource simpleQuotes +#define defaultLanguageQuotesCount ARRAY_SIZE(defaultLanguageQuotesSource) + +static QuotesData* defaultLanguageQuotesValue = 0; +static const QuotesData* defaultLanguageQuotes() +{ + if (!defaultLanguageQuotesValue) { + defaultLanguageQuotesValue = QuotesData::create(defaultLanguageQuotesCount); + if (!defaultLanguageQuotesValue) + return 0; + String* data = defaultLanguageQuotesValue->data(); + for (size_t i = 0; i < defaultLanguageQuotesCount; ++i) + data[i] = defaultLanguageQuotesSource[i]; + } + return defaultLanguageQuotesValue; +} +#undef defaultLanguageQuotesSource +#undef defaultLanguageQuotesCount + +typedef HashMap<RefPtr<AtomicStringImpl>, QuotesData* > QuotesMap; + +static QuotesMap& quotesMap() +{ + DEFINE_STATIC_LOCAL(QuotesMap, staticQuotesMap, ()); + return staticQuotesMap; +} + +static const QuotesData* quotesForLanguage(AtomicStringImpl* language) +{ + QuotesData* returnValue; + AtomicString lower(language->lower()); + returnValue = quotesMap().get(lower.impl()); + if (returnValue) + return returnValue; + CString s(static_cast<const String&>(lower).ascii()); + LanguageData request = { s.buffer()->data(), 0, 0 }; + const LanguageData* lowerBound = std::lower_bound<const LanguageData*, const LanguageData>(languageData, languageDataEnd, request); + if (lowerBound == languageDataEnd) + return defaultLanguageQuotes(); + if (strncmp(lowerBound->name, request.name, strlen(lowerBound->name))) + return defaultLanguageQuotes(); + returnValue = QuotesData::create(lowerBound->arraySize); + if (!returnValue) + return defaultLanguageQuotes(); + String* data = returnValue->data(); + for (int i = 0; i < lowerBound->arraySize; ++i) + data[i] = lowerBound->array[i]; + quotesMap().set(lower.impl(), returnValue); + return returnValue; +} +#undef ARRAY_SIZE + +static const QuotesData* defaultQuotes(const RenderObject* object) +{ + DEFINE_STATIC_LOCAL(String, langString, ("lang")); + Node* node = object->generatingNode(); + Element* element; + if (!node) { + element = object->document()->body(); + if (!element) + element = object->document()->documentElement(); + } else if (!node->isElementNode()) { + element = node->parentElement(); + if (!element) + return defaultLanguageQuotes(); + } else + element = toElement(node); + const AtomicString* language; + while ((language = &element->getAttribute(langString)) && language->isNull()) { + element = element->parentElement(); + if (!element) + return defaultLanguageQuotes(); + } + return quotesForLanguage(language->impl()); +} + +PassRefPtr<StringImpl> RenderQuote::originalText() const +{ + if (!parent()) + return 0; + ASSERT(m_depth != UNKNOWN_DEPTH); + const QuotesData* quotes = style()->quotes(); + if (!quotes) + quotes = defaultQuotes(this); + if (!quotes->length) + return emptyAtom.impl(); + int index = m_depth * 2; + switch (m_type) { + case NO_OPEN_QUOTE: + case NO_CLOSE_QUOTE: + return String("").impl(); + case CLOSE_QUOTE: + if (index) + --index; + else + ++index; + break; + case OPEN_QUOTE: + break; + default: + ASSERT_NOT_REACHED(); + return emptyAtom.impl(); + } + if (index >= quotes->length) + index = (quotes->length-2) | (index & 1); + if (index < 0) + return emptyAtom.impl(); + return quotes->data()[index].impl(); +} + +void RenderQuote::computePreferredLogicalWidths(float lead) +{ + setTextInternal(originalText()); + RenderText::computePreferredLogicalWidths(lead); +} + +void RenderQuote::rendererSubtreeAttached(RenderObject* renderer) +{ + if (renderer->documentBeingDestroyed()) + return; + for (RenderObject* descendant = renderer; descendant; descendant = descendant->nextInPreOrder(renderer)) + if (descendant->isQuote()) { + toRenderQuote(descendant)->placeQuote(); + break; + } +} + +void RenderQuote::rendererRemovedFromTree(RenderObject* subtreeRoot) +{ + if (subtreeRoot->documentBeingDestroyed()) + return; + for (RenderObject* descendant = subtreeRoot; descendant; descendant = descendant->nextInPreOrder(subtreeRoot)) + if (descendant->isQuote()) { + RenderQuote* removedQuote = toRenderQuote(descendant); + RenderQuote* lastQuoteBefore = removedQuote->m_previous; + removedQuote->m_previous = 0; + int depth = removedQuote->m_depth; + for (descendant = descendant->nextInPreOrder(subtreeRoot); descendant; descendant = descendant->nextInPreOrder(subtreeRoot)) + if (descendant->isQuote()) + removedQuote = toRenderQuote(descendant); + RenderQuote* quoteAfter = removedQuote->m_next; + removedQuote->m_next = 0; + if (lastQuoteBefore) + lastQuoteBefore->m_next = quoteAfter; + if (quoteAfter) { + quoteAfter->m_previous = lastQuoteBefore; + do { + if (depth == quoteAfter->m_depth) + break; + quoteAfter->m_depth = depth; + quoteAfter->setNeedsLayoutAndPrefWidthsRecalc(); + adjustDepth(depth, quoteAfter->m_type); + quoteAfter = quoteAfter->m_next; + } while (quoteAfter); + } + break; + } +} + +void RenderQuote::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) +{ + const QuotesData* newQuotes = style()->quotes(); + const QuotesData* oldQuotes = oldStyle ? oldStyle->quotes() : 0; + if (!((newQuotes && oldQuotes && (*newQuotes == *oldQuotes)) || (!newQuotes && !oldQuotes))) + setNeedsLayoutAndPrefWidthsRecalc(); + RenderText::styleDidChange(diff, oldStyle); +} + +} // namespace WebCore diff --git a/Source/WebCore/rendering/RenderQuote.h b/Source/WebCore/rendering/RenderQuote.h new file mode 100644 index 0000000..d9e5437 --- /dev/null +++ b/Source/WebCore/rendering/RenderQuote.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2011 Nokia Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef RenderQuote_h +#define RenderQuote_h + +#include "RenderStyleConstants.h" +#include "RenderText.h" + +namespace WebCore { + +class RenderQuote : public RenderText { +public: + RenderQuote(Document*, const QuoteType); + virtual ~RenderQuote(); + + static void rendererSubtreeAttached(RenderObject*); + static void rendererRemovedFromTree(RenderObject*); +protected: + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); +private: + virtual const char* renderName() const; + virtual bool isQuote() const { return true; }; + virtual PassRefPtr<StringImpl> originalText() const; + virtual void computePreferredLogicalWidths(float leadWidth); + QuoteType m_type; + int m_depth; + RenderQuote* m_next; + RenderQuote* m_previous; + void placeQuote(); +}; + +inline RenderQuote* toRenderQuote(RenderObject* object) +{ + ASSERT(!object || object->isQuote()); + return static_cast<RenderQuote*>(object); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderQuote(const RenderQuote*); + +} // namespace WebCore + +#endif // RenderQuote_h diff --git a/Source/WebCore/rendering/RenderRubyBase.cpp b/Source/WebCore/rendering/RenderRubyBase.cpp index 83399a1..d285157 100644 --- a/Source/WebCore/rendering/RenderRubyBase.cpp +++ b/Source/WebCore/rendering/RenderRubyBase.cpp @@ -31,6 +31,10 @@ #include "config.h" #include "RenderRubyBase.h" +#include "RenderRubyRun.h" +#include "RenderRubyText.h" + +using namespace std; namespace WebCore { @@ -182,4 +186,30 @@ void RenderRubyBase::mergeBlockChildren(RenderRubyBase* toBase, RenderObject* fr moveChildrenTo(toBase, firstChild(), fromBeforeChild); } +RenderRubyRun* RenderRubyBase::rubyRun() const +{ + ASSERT(parent()); + ASSERT(parent()->isRubyRun()); + + return static_cast<RenderRubyRun*>(parent()); +} + +ETextAlign RenderRubyBase::textAlignmentForLine(bool /* endsWithSoftBreak */) const +{ + return JUSTIFY; +} + +void RenderRubyBase::adjustInlineDirectionLineBounds(int expansionOpportunityCount, float& logicalLeft, float& logicalWidth) const +{ + int maxPreferredLogicalWidth = this->maxPreferredLogicalWidth(); + if (maxPreferredLogicalWidth >= logicalWidth) + return; + + // Inset the ruby base by half the inter-ideograph expansion amount. + float inset = (logicalWidth - maxPreferredLogicalWidth) / (expansionOpportunityCount + 1); + + logicalLeft += inset / 2; + logicalWidth -= inset; +} + } // namespace WebCore diff --git a/Source/WebCore/rendering/RenderRubyBase.h b/Source/WebCore/rendering/RenderRubyBase.h index c029bd5..850ab65 100644 --- a/Source/WebCore/rendering/RenderRubyBase.h +++ b/Source/WebCore/rendering/RenderRubyBase.h @@ -35,6 +35,8 @@ namespace WebCore { +class RenderRubyRun; + class RenderRubyBase : public RenderBlock { public: RenderRubyBase(Node*); @@ -47,13 +49,18 @@ public: virtual bool isChildAllowed(RenderObject*, RenderStyle*) const; private: + virtual ETextAlign textAlignmentForLine(bool endsWithSoftBreak) const; + virtual void adjustInlineDirectionLineBounds(int expansionOpportunityCount, float& logicalLeft, float& logicalWidth) const; + bool hasOnlyWrappedInlineChildren(RenderObject* beforeChild = 0) const; void moveChildren(RenderRubyBase* toBase, RenderObject* fromBeforeChild = 0); void moveInlineChildren(RenderRubyBase* toBase, RenderObject* fromBeforeChild = 0); void moveBlockChildren(RenderRubyBase* toBase, RenderObject* fromBeforeChild = 0); void mergeBlockChildren(RenderRubyBase* toBase, RenderObject* fromBeforeChild = 0); - + + RenderRubyRun* rubyRun() const; + // Allow RenderRubyRun to manipulate the children within ruby bases. friend class RenderRubyRun; }; diff --git a/Source/WebCore/rendering/RenderRubyRun.cpp b/Source/WebCore/rendering/RenderRubyRun.cpp index f2e30eb..016c2a1 100644 --- a/Source/WebCore/rendering/RenderRubyRun.cpp +++ b/Source/WebCore/rendering/RenderRubyRun.cpp @@ -110,7 +110,6 @@ void RenderRubyRun::addChild(RenderObject* child, RenderObject* beforeChild) { ASSERT(child); - // If child is a ruby text if (child->isRubyText()) { if (!beforeChild) { // RenderRuby has already ascertained that we can add the child here. @@ -133,16 +132,14 @@ void RenderRubyRun::addChild(RenderObject* child, RenderObject* beforeChild) RenderBlock::addChild(child, beforeChild); RenderBlock::removeChild(beforeChild); newRun->addChild(beforeChild); - } else { - if (hasRubyBase()) { - // Insertion before a ruby base object. - // In this case we need insert a new run before the current one and split the base. - RenderObject* ruby = parent(); - RenderRubyRun* newRun = staticCreateRubyRun(ruby); - ruby->addChild(newRun, this); - newRun->addChild(child); - rubyBaseSafe()->moveChildren(newRun->rubyBaseSafe(), beforeChild); - } + } else if (hasRubyBase()) { + // Insertion before a ruby base object. + // In this case we need insert a new run before the current one and split the base. + RenderObject* ruby = parent(); + RenderRubyRun* newRun = staticCreateRubyRun(ruby); + ruby->addChild(newRun, this); + newRun->addChild(child); + rubyBaseSafe()->moveChildren(newRun->rubyBaseSafe(), beforeChild); } } else { // child is not a text -> insert it into the base diff --git a/Source/WebCore/rendering/RenderRubyText.cpp b/Source/WebCore/rendering/RenderRubyText.cpp index 14cf7fc..2b0a360 100644 --- a/Source/WebCore/rendering/RenderRubyText.cpp +++ b/Source/WebCore/rendering/RenderRubyText.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2009 Google Inc. All rights reserved. + * Copyright (C) 2011 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -32,6 +33,8 @@ #include "RenderRubyText.h" +using namespace std; + namespace WebCore { RenderRubyText::RenderRubyText(Node* node) @@ -48,4 +51,34 @@ bool RenderRubyText::isChildAllowed(RenderObject* child, RenderStyle*) const return child->isInline(); } +ETextAlign RenderRubyText::textAlignmentForLine(bool endsWithSoftBreak) const +{ + ETextAlign textAlign = style()->textAlign(); + if (textAlign != TAAUTO) + return RenderBlock::textAlignmentForLine(endsWithSoftBreak); + + // The default behavior is to allow ruby text to expand if it is shorter than the ruby base. + return JUSTIFY; +} + +void RenderRubyText::adjustInlineDirectionLineBounds(int expansionOpportunityCount, float& logicalLeft, float& logicalWidth) const +{ + ETextAlign textAlign = style()->textAlign(); + if (textAlign != TAAUTO) + return RenderBlock::adjustInlineDirectionLineBounds(expansionOpportunityCount, logicalLeft, logicalWidth); + + int maxPreferredLogicalWidth = this->maxPreferredLogicalWidth(); + if (maxPreferredLogicalWidth >= logicalWidth) + return; + + // Inset the ruby text by half the inter-ideograph expansion amount, but no more than a full-width + // ruby character on each side. + float inset = (logicalWidth - maxPreferredLogicalWidth) / (expansionOpportunityCount + 1); + if (expansionOpportunityCount) + inset = min<float>(2 * style()->fontSize(), inset); + + logicalLeft += inset / 2; + logicalWidth -= inset; +} + } // namespace WebCore diff --git a/Source/WebCore/rendering/RenderRubyText.h b/Source/WebCore/rendering/RenderRubyText.h index e475914..1c397ae 100644 --- a/Source/WebCore/rendering/RenderRubyText.h +++ b/Source/WebCore/rendering/RenderRubyText.h @@ -45,6 +45,10 @@ public: virtual bool isRubyText() const { return true; } virtual bool isChildAllowed(RenderObject*, RenderStyle*) const; + +private: + virtual ETextAlign textAlignmentForLine(bool endsWithSoftBreak) const; + virtual void adjustInlineDirectionLineBounds(int expansionOpportunityCount, float& logicalLeft, float& logicalWidth) const; }; } // namespace WebCore diff --git a/Source/WebCore/rendering/RenderScrollbar.h b/Source/WebCore/rendering/RenderScrollbar.h index 8f4de4f..810c98f 100644 --- a/Source/WebCore/rendering/RenderScrollbar.h +++ b/Source/WebCore/rendering/RenderScrollbar.h @@ -60,6 +60,8 @@ public: int minimumThumbLength(); + virtual bool isOverlayScrollbar() const { return false; } + private: virtual void setParent(ScrollView*); virtual void setEnabled(bool); diff --git a/Source/WebCore/rendering/RenderTable.cpp b/Source/WebCore/rendering/RenderTable.cpp index bb90e97..69c073c 100644 --- a/Source/WebCore/rendering/RenderTable.cpp +++ b/Source/WebCore/rendering/RenderTable.cpp @@ -261,6 +261,18 @@ void RenderTable::computeLogicalWidth() } } +void RenderTable::adjustLogicalHeightForCaption() +{ + ASSERT(m_caption); + IntRect captionRect(m_caption->x(), m_caption->y(), m_caption->width(), m_caption->height()); + + m_caption->setLogicalLocation(m_caption->marginStart(), logicalHeight()); + if (!selfNeedsLayout() && m_caption->checkForRepaintDuringLayout()) + m_caption->repaintDuringLayoutIfMoved(captionRect); + + setLogicalHeight(logicalHeight() + m_caption->logicalHeight() + m_caption->marginBefore() + m_caption->marginAfter()); +} + void RenderTable::layout() { ASSERT(needsLayout()); @@ -367,14 +379,7 @@ void RenderTable::layout() // FIXME: Collapse caption margin. if (m_caption && m_caption->style()->captionSide() != CAPBOTTOM) { - IntRect captionRect(m_caption->x(), m_caption->y(), m_caption->width(), m_caption->height()); - - m_caption->setLogicalLocation(m_caption->marginStart(), logicalHeight()); - if (!selfNeedsLayout() && m_caption->checkForRepaintDuringLayout()) - m_caption->repaintDuringLayoutIfMoved(captionRect); - - setLogicalHeight(logicalHeight() + m_caption->logicalHeight() + m_caption->marginBefore() + m_caption->marginAfter()); - + adjustLogicalHeightForCaption(); if (logicalHeight() != oldTableLogicalTop) { sectionMoved = true; movedSectionLogicalTop = min(logicalHeight(), oldTableLogicalTop); @@ -429,15 +434,8 @@ void RenderTable::layout() setLogicalHeight(logicalHeight() + borderAndPaddingAfter); - if (m_caption && m_caption->style()->captionSide() == CAPBOTTOM) { - IntRect captionRect(m_caption->x(), m_caption->y(), m_caption->width(), m_caption->height()); - - m_caption->setLogicalLocation(m_caption->marginStart(), logicalHeight()); - if (!selfNeedsLayout() && m_caption->checkForRepaintDuringLayout()) - m_caption->repaintDuringLayoutIfMoved(captionRect); - - setLogicalHeight(logicalHeight() + m_caption->logicalHeight() + m_caption->marginBefore() + m_caption->marginAfter()); - } + if (m_caption && m_caption->style()->captionSide() == CAPBOTTOM) + adjustLogicalHeightForCaption(); if (isPositioned()) computeLogicalHeight(); @@ -577,6 +575,10 @@ void RenderTable::paintObject(PaintInfo& paintInfo, int tx, int ty) } m_currentBorder = 0; } + + // Paint outline. + if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && hasOutline() && style()->visibility() == VISIBLE) + paintOutline(paintInfo.context, tx, ty, width(), height()); } void RenderTable::subtractCaptionRect(IntRect& rect) const diff --git a/Source/WebCore/rendering/RenderTable.h b/Source/WebCore/rendering/RenderTable.h index b9a7bad..67a311c 100644 --- a/Source/WebCore/rendering/RenderTable.h +++ b/Source/WebCore/rendering/RenderTable.h @@ -243,6 +243,7 @@ private: void subtractCaptionRect(IntRect&) const; void recalcSections() const; + void adjustLogicalHeightForCaption(); mutable Vector<int> m_columnPos; mutable Vector<ColumnStruct> m_columns; diff --git a/Source/WebCore/rendering/RenderTableCell.cpp b/Source/WebCore/rendering/RenderTableCell.cpp index 1593a5c..2293bac 100644 --- a/Source/WebCore/rendering/RenderTableCell.cpp +++ b/Source/WebCore/rendering/RenderTableCell.cpp @@ -300,7 +300,7 @@ void RenderTableCell::computeRectForRepaint(RenderBoxModelObject* repaintContain RenderBlock::computeRectForRepaint(repaintContainer, r, fixed); } -int RenderTableCell::baselinePosition() const +int RenderTableCell::cellBaselinePosition() const { // <http://www.w3.org/TR/2007/CR-CSS21-20070719/tables.html#height-layout>: The baseline of a cell is the baseline of // the first in-flow line box in the cell, or the first in-flow table-row in the cell, whichever comes first. If there @@ -1014,13 +1014,12 @@ void RenderTableCell::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty) int w = width(); int h = height(); - if (style()->boxShadow()) - paintBoxShadow(paintInfo.context, tx, ty, w, h, style(), Normal); + paintBoxShadow(paintInfo.context, tx, ty, w, h, style(), Normal); // Paint our cell background. paintBackgroundsBehindCell(paintInfo, tx, ty, this); - if (style()->boxShadow()) - paintBoxShadow(paintInfo.context, tx, ty, w, h, style(), Inset); + + paintBoxShadow(paintInfo.context, tx, ty, w, h, style(), Inset); if (!style()->hasBorder() || tableElt->collapseBorders()) return; diff --git a/Source/WebCore/rendering/RenderTableCell.h b/Source/WebCore/rendering/RenderTableCell.h index 5b5992a..cfdb739 100644 --- a/Source/WebCore/rendering/RenderTableCell.h +++ b/Source/WebCore/rendering/RenderTableCell.h @@ -98,7 +98,7 @@ public: void paintBackgroundsBehindCell(PaintInfo&, int tx, int ty, RenderObject* backgroundObject); - int baselinePosition() const; + int cellBaselinePosition() const; void setIntrinsicPaddingBefore(int p) { m_intrinsicPaddingBefore = p; } void setIntrinsicPaddingAfter(int p) { m_intrinsicPaddingAfter = p; } diff --git a/Source/WebCore/rendering/RenderTableSection.cpp b/Source/WebCore/rendering/RenderTableSection.cpp index f20c236..3d46ece 100644 --- a/Source/WebCore/rendering/RenderTableSection.cpp +++ b/Source/WebCore/rendering/RenderTableSection.cpp @@ -400,7 +400,7 @@ int RenderTableSection::calcRowLogicalHeight() // find out the baseline EVerticalAlign va = cell->style()->verticalAlign(); if (va == BASELINE || va == TEXT_BOTTOM || va == TEXT_TOP || va == SUPER || va == SUB) { - int b = cell->baselinePosition(); + int b = cell->cellBaselinePosition(); if (b > cell->borderBefore() + cell->paddingBefore()) { baseline = max(baseline, b - cell->intrinsicPaddingBefore()); bdesc = max(bdesc, m_rowPos[indx] + ch - (b - cell->intrinsicPaddingBefore())); @@ -655,7 +655,7 @@ int RenderTableSection::layoutRows(int toAdd) // If the baseline moved, we may have to update the data for our row. Find out the new baseline. EVerticalAlign va = cell->style()->verticalAlign(); if (va == BASELINE || va == TEXT_BOTTOM || va == TEXT_TOP || va == SUPER || va == SUB) { - int b = cell->baselinePosition(); + int b = cell->cellBaselinePosition(); if (b > cell->borderBefore() + cell->paddingBefore()) m_grid[r].baseline = max(m_grid[r].baseline, b); } @@ -672,7 +672,7 @@ int RenderTableSection::layoutRows(int toAdd) case TEXT_TOP: case TEXT_BOTTOM: case BASELINE: { - int b = cell->baselinePosition(); + int b = cell->cellBaselinePosition(); if (b > cell->borderBefore() + cell->paddingBefore()) intrinsicPaddingBefore = getBaseline(r) - (b - oldIntrinsicPaddingBefore); break; diff --git a/Source/WebCore/rendering/RenderText.cpp b/Source/WebCore/rendering/RenderText.cpp index 1b05af2..d4f4166 100644 --- a/Source/WebCore/rendering/RenderText.cpp +++ b/Source/WebCore/rendering/RenderText.cpp @@ -506,15 +506,19 @@ IntRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, int* e int height = box->root()->selectionHeight(); int top = box->root()->selectionTop(); - int left = box->positionForOffset(caretOffset); + // Go ahead and round left to snap it to the nearest pixel. + float left = box->positionForOffset(caretOffset); // Distribute the caret's width to either side of the offset. int caretWidthLeftOfOffset = caretWidth / 2; left -= caretWidthLeftOfOffset; int caretWidthRightOfOffset = caretWidth - caretWidthLeftOfOffset; - int rootLeft = box->root()->logicalLeft(); - int rootRight = rootLeft + box->root()->logicalWidth(); + left = roundf(left); + + float rootLeft = box->root()->logicalLeft(); + float rootRight = box->root()->logicalRight(); + // FIXME: should we use the width of the root inline box or the // width of the containing block for this? if (extraWidthToEndOfLine) @@ -522,14 +526,14 @@ IntRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, int* e RenderBlock* cb = containingBlock(); RenderStyle* cbStyle = cb->style(); - int leftEdge; - int rightEdge; + float leftEdge; + float rightEdge; if (style()->autoWrap()) { leftEdge = cb->logicalLeft(); rightEdge = cb->logicalRight(); } else { - leftEdge = min(cb->logicalLeft(), rootLeft); - rightEdge = max(cb->logicalRight(), rootRight); + leftEdge = min(static_cast<float>(cb->logicalLeft()), rootLeft); + rightEdge = max(static_cast<float>(cb->logicalRight()), rootRight); } bool rightAligned = false; @@ -560,7 +564,7 @@ IntRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, int* e return style()->isHorizontalWritingMode() ? IntRect(left, top, caretWidth, height) : IntRect(top, left, height, caretWidth); } -ALWAYS_INLINE int RenderText::widthFromCache(const Font& f, int start, int len, int xPos, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const +ALWAYS_INLINE float RenderText::widthFromCache(const Font& f, int start, int len, float xPos, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const { if (style()->hasTextCombine()) { const RenderCombineText* combineText = toRenderCombineText(this); @@ -569,9 +573,9 @@ ALWAYS_INLINE int RenderText::widthFromCache(const Font& f, int start, int len, } if (f.isFixedPitch() && !f.isSmallCaps() && m_isAllASCII) { - int monospaceCharacterWidth = f.spaceWidth(); - int tabWidth = allowTabs() ? monospaceCharacterWidth * 8 : 0; - int w = 0; + float monospaceCharacterWidth = f.spaceWidth(); + float tabWidth = allowTabs() ? monospaceCharacterWidth * 8 : 0; + float w = 0; bool isSpace; bool previousCharWasSpace = true; // FIXME: Preserves historical behavior, but seems wrong for start > 0. ASSERT(m_text); @@ -583,7 +587,7 @@ ALWAYS_INLINE int RenderText::widthFromCache(const Font& f, int start, int len, w += monospaceCharacterWidth; isSpace = true; } else if (c == '\t') { - w += tabWidth ? tabWidth - ((xPos + w) % tabWidth) : monospaceCharacterWidth; + w += tabWidth ? tabWidth - fmodf(xPos + w, tabWidth) : monospaceCharacterWidth; isSpace = true; } else isSpace = false; @@ -601,12 +605,12 @@ ALWAYS_INLINE int RenderText::widthFromCache(const Font& f, int start, int len, return f.width(TextRun(text()->characters() + start, len, allowTabs(), xPos), fallbackFonts, glyphOverflow); } -void RenderText::trimmedPrefWidths(int leadWidth, - int& beginMinW, bool& beginWS, - int& endMinW, bool& endWS, +void RenderText::trimmedPrefWidths(float leadWidth, + float& beginMinW, bool& beginWS, + float& endMinW, bool& endWS, bool& hasBreakableChar, bool& hasBreak, - int& beginMaxW, int& endMaxW, - int& minW, int& maxW, bool& stripFrontSpaces) + float& beginMaxW, float& endMaxW, + float& minW, float& maxW, bool& stripFrontSpaces) { bool collapseWhiteSpace = style()->collapseWhiteSpace(); if (!collapseWhiteSpace) @@ -646,7 +650,7 @@ void RenderText::trimmedPrefWidths(int leadWidth, const Font& f = style()->font(); // FIXME: This ignores first-line. if (stripFrontSpaces) { const UChar space = ' '; - int spaceWidth = f.width(TextRun(&space, 1)); + float spaceWidth = f.width(TextRun(&space, 1)); maxW -= spaceWidth; } else maxW += f.wordSpacing(); @@ -695,7 +699,7 @@ static inline bool isSpaceAccordingToStyle(UChar c, RenderStyle* style) return c == ' ' || (c == noBreakSpace && style->nbspMode() == SPACE); } -int RenderText::minPreferredLogicalWidth() const +float RenderText::minLogicalWidth() const { if (preferredLogicalWidthsDirty()) const_cast<RenderText*>(this)->computePreferredLogicalWidths(0); @@ -703,7 +707,7 @@ int RenderText::minPreferredLogicalWidth() const return m_minWidth; } -int RenderText::maxPreferredLogicalWidth() const +float RenderText::maxLogicalWidth() const { if (preferredLogicalWidthsDirty()) const_cast<RenderText*>(this)->computePreferredLogicalWidths(0); @@ -711,7 +715,7 @@ int RenderText::maxPreferredLogicalWidth() const return m_maxWidth; } -void RenderText::computePreferredLogicalWidths(int leadWidth) +void RenderText::computePreferredLogicalWidths(float leadWidth) { HashSet<const SimpleFontData*> fallbackFonts; GlyphOverflow glyphOverflow; @@ -720,7 +724,7 @@ void RenderText::computePreferredLogicalWidths(int leadWidth) m_knownToHaveNoOverflowAndNoFallbackFonts = true; } -void RenderText::computePreferredLogicalWidths(int leadWidth, HashSet<const SimpleFontData*>& fallbackFonts, GlyphOverflow& glyphOverflow) +void RenderText::computePreferredLogicalWidths(float leadWidth, HashSet<const SimpleFontData*>& fallbackFonts, GlyphOverflow& glyphOverflow) { ASSERT(m_hasTab || preferredLogicalWidthsDirty() || !m_knownToHaveNoOverflowAndNoFallbackFonts); @@ -732,8 +736,8 @@ void RenderText::computePreferredLogicalWidths(int leadWidth, HashSet<const Simp if (isBR()) return; - int currMinWidth = 0; - int currMaxWidth = 0; + float currMinWidth = 0; + float currMaxWidth = 0; m_hasBreakableChar = false; m_hasBreak = false; m_hasTab = false; @@ -741,9 +745,10 @@ void RenderText::computePreferredLogicalWidths(int leadWidth, HashSet<const Simp m_hasEndWS = false; const Font& f = style()->font(); // FIXME: This ignores first-line. - int wordSpacing = style()->wordSpacing(); + float wordSpacing = style()->wordSpacing(); int len = textLength(); const UChar* txt = characters(); + LazyLineBreakIterator breakIterator(txt, len); bool needsWordSpacing = false; bool ignoringSpaces = false; bool isSpace = false; @@ -803,7 +808,7 @@ void RenderText::computePreferredLogicalWidths(int leadWidth, HashSet<const Simp continue; } - bool hasBreak = breakAll || isBreakable(txt, i, len, nextBreakable, breakNBSP); + bool hasBreak = breakAll || isBreakable(breakIterator, i, nextBreakable, breakNBSP); bool betweenWords = true; int j = i; while (c != '\n' && !isSpaceAccordingToStyle(c, style()) && c != '\t' && c != softHyphen) { @@ -811,7 +816,7 @@ void RenderText::computePreferredLogicalWidths(int leadWidth, HashSet<const Simp if (j == len) break; c = txt[j]; - if (isBreakable(txt, j, len, nextBreakable, breakNBSP)) + if (isBreakable(breakIterator, j, nextBreakable, breakNBSP)) break; if (breakAll) { betweenWords = false; @@ -821,7 +826,7 @@ void RenderText::computePreferredLogicalWidths(int leadWidth, HashSet<const Simp int wordLen = j - i; if (wordLen) { - int w = widthFromCache(f, i, wordLen, leadWidth + currMaxWidth, &fallbackFonts, &glyphOverflow); + float w = widthFromCache(f, i, wordLen, leadWidth + currMaxWidth, &fallbackFonts, &glyphOverflow); if (firstGlyphLeftOverflow < 0) firstGlyphLeftOverflow = glyphOverflow.left; currMinWidth += w; @@ -933,17 +938,17 @@ bool RenderText::containsOnlyWhitespace(unsigned from, unsigned len) const return currPos >= (from + len); } -IntPoint RenderText::firstRunOrigin() const +FloatPoint RenderText::firstRunOrigin() const { return IntPoint(firstRunX(), firstRunY()); } -int RenderText::firstRunX() const +float RenderText::firstRunX() const { return m_firstTextBox ? m_firstTextBox->m_x : 0; } -int RenderText::firstRunY() const +float RenderText::firstRunY() const { return m_firstTextBox ? m_firstTextBox->m_y : 0; } @@ -1240,7 +1245,7 @@ void RenderText::positionLineBox(InlineBox* box) m_containsReversedText |= !s->isLeftToRightDirection(); } -unsigned RenderText::width(unsigned from, unsigned len, int xPos, bool firstLine, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const +float RenderText::width(unsigned from, unsigned len, float xPos, bool firstLine, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const { if (from >= textLength()) return 0; @@ -1251,13 +1256,13 @@ unsigned RenderText::width(unsigned from, unsigned len, int xPos, bool firstLine return width(from, len, style(firstLine)->font(), xPos, fallbackFonts, glyphOverflow); } -unsigned RenderText::width(unsigned from, unsigned len, const Font& f, int xPos, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const +float RenderText::width(unsigned from, unsigned len, const Font& f, float xPos, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const { ASSERT(from + len <= textLength()); if (!characters()) return 0; - int w; + float w; if (&f == &style()->font()) { if (!style()->preserveNewline() && !from && len == textLength()) { if (fallbackFonts) { @@ -1269,7 +1274,7 @@ unsigned RenderText::width(unsigned from, unsigned len, const Font& f, int xPos, } w = m_maxWidth; } else - w = maxPreferredLogicalWidth(); + w = maxLogicalWidth(); } else w = widthFromCache(f, from, len, xPos, fallbackFonts, glyphOverflow); } else @@ -1285,8 +1290,8 @@ IntRect RenderText::linesBoundingBox() const ASSERT(!firstTextBox() == !lastTextBox()); // Either both are null or both exist. if (firstTextBox() && lastTextBox()) { // Return the width of the minimal left side and the maximal right side. - int logicalLeftSide = 0; - int logicalRightSide = 0; + float logicalLeftSide = 0; + float logicalRightSide = 0; for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBox()) { if (curr == firstTextBox() || curr->logicalLeft() < logicalLeftSide) logicalLeftSide = curr->logicalLeft(); @@ -1296,11 +1301,11 @@ IntRect RenderText::linesBoundingBox() const bool isHorizontal = style()->isHorizontalWritingMode(); - int x = isHorizontal ? logicalLeftSide : firstTextBox()->x(); - int y = isHorizontal ? firstTextBox()->y() : logicalLeftSide; - int width = isHorizontal ? logicalRightSide - logicalLeftSide : lastTextBox()->logicalBottom() - x; - int height = isHorizontal ? lastTextBox()->logicalBottom() - y : logicalRightSide - logicalLeftSide; - result = IntRect(x, y, width, height); + float x = isHorizontal ? logicalLeftSide : firstTextBox()->x(); + float y = isHorizontal ? firstTextBox()->y() : logicalLeftSide; + float width = isHorizontal ? logicalRightSide - logicalLeftSide : lastTextBox()->logicalBottom() - x; + float height = isHorizontal ? lastTextBox()->logicalBottom() - y : logicalRightSide - logicalLeftSide; + result = enclosingIntRect(FloatRect(x, y, width, height)); } return result; diff --git a/Source/WebCore/rendering/RenderText.h b/Source/WebCore/rendering/RenderText.h index 964a1d3..b88590c 100644 --- a/Source/WebCore/rendering/RenderText.h +++ b/Source/WebCore/rendering/RenderText.h @@ -71,24 +71,24 @@ public: unsigned textLength() const { return m_text.length(); } // non virtual implementation of length() void positionLineBox(InlineBox*); - virtual unsigned width(unsigned from, unsigned len, const Font&, int xPos, HashSet<const SimpleFontData*>* fallbackFonts = 0, GlyphOverflow* = 0) const; - virtual unsigned width(unsigned from, unsigned len, int xPos, bool firstLine = false, HashSet<const SimpleFontData*>* fallbackFonts = 0, GlyphOverflow* = 0) const; + virtual float width(unsigned from, unsigned len, const Font&, float xPos, HashSet<const SimpleFontData*>* fallbackFonts = 0, GlyphOverflow* = 0) const; + virtual float width(unsigned from, unsigned len, float xPos, bool firstLine = false, HashSet<const SimpleFontData*>* fallbackFonts = 0, GlyphOverflow* = 0) const; - virtual int minPreferredLogicalWidth() const; - virtual int maxPreferredLogicalWidth() const; + float minLogicalWidth() const; + float maxLogicalWidth() const; - void trimmedPrefWidths(int leadWidth, - int& beginMinW, bool& beginWS, - int& endMinW, bool& endWS, + void trimmedPrefWidths(float leadWidth, + float& beginMinW, bool& beginWS, + float& endMinW, bool& endWS, bool& hasBreakableChar, bool& hasBreak, - int& beginMaxW, int& endMaxW, - int& minW, int& maxW, bool& stripFrontSpaces); + float& beginMaxW, float& endMaxW, + float& minW, float& maxW, bool& stripFrontSpaces); virtual IntRect linesBoundingBox() const; - IntPoint firstRunOrigin() const; - int firstRunX() const; - int firstRunY() const; + FloatPoint firstRunOrigin() const; + float firstRunX() const; + float firstRunY() const; void setText(PassRefPtr<StringImpl>, bool force = false); void setTextWithOffset(PassRefPtr<StringImpl>, unsigned offset, unsigned len, bool force = false); @@ -122,7 +122,7 @@ public: void checkConsistency() const; - virtual void computePreferredLogicalWidths(int leadWidth); + virtual void computePreferredLogicalWidths(float leadWidth); bool isAllCollapsibleWhitespace(); protected: @@ -135,7 +135,7 @@ protected: virtual InlineTextBox* createTextBox(); // Subclassed by SVG. private: - void computePreferredLogicalWidths(int leadWidth, HashSet<const SimpleFontData*>& fallbackFonts, GlyphOverflow&); + void computePreferredLogicalWidths(float leadWidth, HashSet<const SimpleFontData*>& fallbackFonts, GlyphOverflow&); // Make length() private so that callers that have a RenderText* // will use the more efficient textLength() instead, while @@ -148,22 +148,22 @@ private: void deleteTextBoxes(); bool containsOnlyWhitespace(unsigned from, unsigned len) const; - int widthFromCache(const Font&, int start, int len, int xPos, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow*) const; + float widthFromCache(const Font&, int start, int len, float xPos, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow*) const; bool isAllASCII() const { return m_isAllASCII; } void updateNeedsTranscoding(); inline void transformText(String&) const; - int m_minWidth; // here to minimize padding in 64-bit. + float m_minWidth; // here to minimize padding in 64-bit. String m_text; InlineTextBox* m_firstTextBox; InlineTextBox* m_lastTextBox; - int m_maxWidth; - int m_beginMinWidth; - int m_endMinWidth; + float m_maxWidth; + float m_beginMinWidth; + float m_endMinWidth; bool m_hasBreakableChar : 1; // Whether or not we can be broken into multiple lines. bool m_hasBreak : 1; // Whether or not we have a hard break (e.g., <pre> with '\n'). diff --git a/Source/WebCore/rendering/RenderTextControl.cpp b/Source/WebCore/rendering/RenderTextControl.cpp index 72b20ec..8149f6c 100644 --- a/Source/WebCore/rendering/RenderTextControl.cpp +++ b/Source/WebCore/rendering/RenderTextControl.cpp @@ -74,7 +74,6 @@ static Color disabledTextColor(const Color& textColor, const Color& backgroundCo RenderTextControl::RenderTextControl(Node* node, bool placeholderVisible) : RenderBlock(node) , m_placeholderVisible(placeholderVisible) - , m_wasChangedSinceLastChangeEvent(false) , m_lastChangeWasUserEdit(false) { } @@ -249,7 +248,7 @@ void setSelectionRange(Node* node, int start, int end) // startPosition and endPosition can be null position for example when // "-webkit-user-select: none" style attribute is specified. if (startPosition.isNotNull() && endPosition.isNotNull()) { - ASSERT(startPosition.deepEquivalent().node()->shadowAncestorNode() == node && endPosition.deepEquivalent().node()->shadowAncestorNode() == node); + ASSERT(startPosition.deepEquivalent().deprecatedNode()->shadowAncestorNode() == node && endPosition.deepEquivalent().deprecatedNode()->shadowAncestorNode() == node); } VisibleSelection newSelection = VisibleSelection(startPosition, endPosition); @@ -321,7 +320,7 @@ PassRefPtr<Range> RenderTextControl::selection(int start, int end) const VisiblePosition RenderTextControl::visiblePositionForIndex(int index) const { if (index <= 0) - return VisiblePosition(m_innerText.get(), 0, DOWNSTREAM); + return VisiblePosition(Position(m_innerText.get(), 0, Position::PositionIsOffsetInAnchor), DOWNSTREAM); ExceptionCode ec = 0; RefPtr<Range> range = Range::create(document()); range->selectNodeContents(m_innerText.get(), ec); @@ -332,26 +331,25 @@ VisiblePosition RenderTextControl::visiblePositionForIndex(int index) const ASSERT(!ec); int endOffset = it.range()->endOffset(ec); ASSERT(!ec); - return VisiblePosition(endContainer, endOffset, UPSTREAM); + return VisiblePosition(Position(endContainer, endOffset, Position::PositionIsOffsetInAnchor), UPSTREAM); } int RenderTextControl::indexForVisiblePosition(const VisiblePosition& pos) const { Position indexPosition = pos.deepEquivalent(); - if (!isSelectableElement(indexPosition.node())) + if (!isSelectableElement(indexPosition.deprecatedNode())) return 0; ExceptionCode ec = 0; RefPtr<Range> range = Range::create(document()); range->setStart(m_innerText.get(), 0, ec); ASSERT(!ec); - range->setEnd(indexPosition.node(), indexPosition.deprecatedEditingOffset(), ec); + range->setEnd(indexPosition.deprecatedNode(), indexPosition.deprecatedEditingOffset(), ec); ASSERT(!ec); return TextIterator::rangeLength(range.get()); } void RenderTextControl::subtreeHasChanged() { - m_wasChangedSinceLastChangeEvent = true; m_lastChangeWasUserEdit = true; } @@ -544,7 +542,7 @@ float RenderTextControl::getAvgCharWidth(AtomicString family) return roundf(style()->font().primaryFont()->avgCharWidth()); const UChar ch = '0'; - return style()->font().floatWidth(TextRun(&ch, 1, false, 0, 0, TextRun::AllowTrailingExpansion, false, false, false)); + return style()->font().width(TextRun(&ch, 1, false, 0, 0, TextRun::AllowTrailingExpansion, false)); } float RenderTextControl::scaleEmToUnits(int x) const @@ -639,7 +637,7 @@ void RenderTextControl::paintPlaceholder(PaintInfo& paintInfo, int tx, int ty) paintInfo.context->setFillColor(placeholderStyle->visitedDependentColor(CSSPropertyColor), placeholderStyle->colorSpace()); String placeholderText = static_cast<HTMLTextFormControlElement*>(node())->strippedPlaceholder(); - TextRun textRun(placeholderText.characters(), placeholderText.length(), false, 0, 0, TextRun::AllowTrailingExpansion, !placeholderStyle->isLeftToRightDirection(), placeholderStyle->unicodeBidi() == Override, false, false); + TextRun textRun(placeholderText.characters(), placeholderText.length(), false, 0, 0, TextRun::AllowTrailingExpansion, !placeholderStyle->isLeftToRightDirection(), placeholderStyle->unicodeBidi() == Override); RenderBox* textRenderer = innerTextElement() ? innerTextElement()->renderBox() : 0; if (textRenderer) { diff --git a/Source/WebCore/rendering/RenderTextControl.h b/Source/WebCore/rendering/RenderTextControl.h index fdb7fdc..0c30ed6 100644 --- a/Source/WebCore/rendering/RenderTextControl.h +++ b/Source/WebCore/rendering/RenderTextControl.h @@ -34,8 +34,7 @@ class RenderTextControl : public RenderBlock { public: virtual ~RenderTextControl(); - bool wasChangedSinceLastChangeEvent() const { return m_wasChangedSinceLastChangeEvent; } - void setChangedSinceLastChangeEvent(bool wasChangedSinceLastChangeEvent) { m_wasChangedSinceLastChangeEvent = wasChangedSinceLastChangeEvent; } + HTMLElement* innerTextElement() const; bool lastChangeWasUserEdit() const { return m_lastChangeWasUserEdit; } void setLastChangeWasUserEdit(bool lastChangeWasUserEdit); @@ -83,9 +82,6 @@ protected: virtual void updateFromElement(); virtual void computeLogicalHeight(); - friend class TextIterator; - HTMLElement* innerTextElement() const; - bool m_placeholderVisible; private: @@ -116,7 +112,6 @@ private: void paintPlaceholder(PaintInfo&, int tx, int ty); - bool m_wasChangedSinceLastChangeEvent; bool m_lastChangeWasUserEdit; RefPtr<TextControlInnerTextElement> m_innerText; }; diff --git a/Source/WebCore/rendering/RenderTextControlMultiLine.cpp b/Source/WebCore/rendering/RenderTextControlMultiLine.cpp index cf32f68..ea2be5b 100644 --- a/Source/WebCore/rendering/RenderTextControlMultiLine.cpp +++ b/Source/WebCore/rendering/RenderTextControlMultiLine.cpp @@ -49,6 +49,7 @@ void RenderTextControlMultiLine::subtreeHasChanged() { RenderTextControl::subtreeHasChanged(); HTMLTextAreaElement* textArea = static_cast<HTMLTextAreaElement*>(node()); + textArea->setChangedSinceLastFormControlChangeEvent(true); textArea->setFormControlValueMatchesRenderer(false); textArea->setNeedsValidityCheck(); diff --git a/Source/WebCore/rendering/RenderTextControlSingleLine.cpp b/Source/WebCore/rendering/RenderTextControlSingleLine.cpp index de8fb0d..8b98335 100644 --- a/Source/WebCore/rendering/RenderTextControlSingleLine.cpp +++ b/Source/WebCore/rendering/RenderTextControlSingleLine.cpp @@ -51,6 +51,23 @@ namespace WebCore { using namespace HTMLNames; +VisiblePosition RenderTextControlInnerBlock::positionForPoint(const IntPoint& point) +{ + IntPoint contentsPoint(point); + + // Multiline text controls have the scroll on shadowAncestorNode, so we need to take that + // into account here. + if (m_multiLine) { + RenderTextControl* renderer = toRenderTextControl(node()->shadowAncestorNode()->renderer()); + if (renderer->hasOverflowClip()) + contentsPoint += renderer->layer()->scrolledContentOffset(); + } + + return RenderBlock::positionForPoint(contentsPoint); +} + +// ---------------------------- + RenderTextControlSingleLine::RenderTextControlSingleLine(Node* node, bool placeholderVisible) : RenderTextControl(node, placeholderVisible) , m_searchPopupIsVisible(false) @@ -164,9 +181,13 @@ void RenderTextControlSingleLine::hidePopup() void RenderTextControlSingleLine::subtreeHasChanged() { - bool wasChanged = wasChangedSinceLastChangeEvent(); RenderTextControl::subtreeHasChanged(); + ASSERT(node()->isElementNode()); + Element* element = static_cast<Element*>(node()); + bool wasChanged = element->wasChangedSinceLastFormControlChangeEvent(); + element->setChangedSinceLastFormControlChangeEvent(true); + InputElement* input = inputElement(); // We don't need to call sanitizeUserInputValue() function here because // InputElement::handleBeforeTextInsertedEvent() has already called @@ -174,7 +195,7 @@ void RenderTextControlSingleLine::subtreeHasChanged() // sanitizeValue() is needed because IME input doesn't dispatch BeforeTextInsertedEvent. String value = text(); if (input->isAcceptableValue(value)) - input->setValueFromRenderer(input->sanitizeValue(value)); + input->setValueFromRenderer(input->sanitizeValue(input->convertFromVisibleValue(value))); if (node()->isHTMLElement()) { // Recalc for :invalid and hasUnacceptableValue() change. static_cast<HTMLInputElement*>(input)->setNeedsStyleRecalc(); @@ -432,6 +453,9 @@ void RenderTextControlSingleLine::styleDidChange(StyleDifference diff, const Ren if (RenderObject* spinRenderer = m_outerSpinButton ? m_outerSpinButton->renderer() : 0) spinRenderer->setStyle(createOuterSpinButtonStyle()); + if (RenderObject* spinRenderer = m_innerSpinButton ? m_innerSpinButton->renderer() : 0) + spinRenderer->setStyle(createInnerSpinButtonStyle()); + #if ENABLE(INPUT_SPEECH) if (RenderObject* speechRenderer = m_speechButton ? m_speechButton->renderer() : 0) speechRenderer->setStyle(createSpeechButtonStyle()); @@ -609,9 +633,13 @@ void RenderTextControlSingleLine::adjustControlHeightBasedOnLineHeight(int lineH void RenderTextControlSingleLine::createSubtreeIfNeeded() { - bool createSubtree = inputElement()->isSearchField(); - if (!createSubtree) { - RenderTextControl::createSubtreeIfNeeded(m_innerBlock.get()); + if (inputElement()->isSearchField()) { + if (!m_innerBlock) { + // Create the inner block element + m_innerBlock = TextControlInnerElement::create(toHTMLElement(node())); + m_innerBlock->attachInnerElement(node(), createInnerBlockStyle(style()), renderArena()); + } + #if ENABLE(INPUT_SPEECH) if (inputElement()->isSpeechEnabled() && !m_speechButton) { // Create the speech button element. @@ -619,52 +647,42 @@ void RenderTextControlSingleLine::createSubtreeIfNeeded() m_speechButton->attachInnerElement(node(), createSpeechButtonStyle(), renderArena()); } #endif - bool hasSpinButton = inputElement()->hasSpinButton(); - if (hasSpinButton && !m_innerSpinButton) { - m_innerSpinButton = SpinButtonElement::create(toHTMLElement(node())); - m_innerSpinButton->attachInnerElement(node(), createInnerSpinButtonStyle(), renderArena()); - } - if (hasSpinButton && !m_outerSpinButton) { - m_outerSpinButton = SpinButtonElement::create(toHTMLElement(node())); - m_outerSpinButton->attachInnerElement(node(), createOuterSpinButtonStyle(), renderArena()); - } - return; - } - - if (!m_innerBlock) { - // Create the inner block element - m_innerBlock = TextControlInnerElement::create(toHTMLElement(node())); - m_innerBlock->attachInnerElement(node(), createInnerBlockStyle(style()), renderArena()); - } -#if ENABLE(INPUT_SPEECH) - if (inputElement()->isSpeechEnabled() && !m_speechButton) { - // Create the speech button element. - m_speechButton = InputFieldSpeechButtonElement::create(toHTMLElement(node())); - m_speechButton->attachInnerElement(node(), createSpeechButtonStyle(), renderArena()); - } -#endif - if (inputElement()->hasSpinButton() && !m_outerSpinButton) { - m_outerSpinButton = SpinButtonElement::create(toHTMLElement(node())); - m_outerSpinButton->attachInnerElement(node(), createOuterSpinButtonStyle(), renderArena()); - } - if (inputElement()->isSearchField()) { if (!m_resultsButton) { // Create the search results button element. m_resultsButton = SearchFieldResultsButtonElement::create(document()); m_resultsButton->attachInnerElement(m_innerBlock.get(), createResultsButtonStyle(m_innerBlock->renderer()->style()), renderArena()); } - } - // Create innerText element before adding the other buttons. - RenderTextControl::createSubtreeIfNeeded(m_innerBlock.get()); + // Create innerText element before adding the other buttons. + RenderTextControl::createSubtreeIfNeeded(m_innerBlock.get()); - if (inputElement()->isSearchField()) { if (!m_cancelButton) { // Create the cancel button element. m_cancelButton = SearchFieldCancelButtonElement::create(document()); m_cancelButton->attachInnerElement(m_innerBlock.get(), createCancelButtonStyle(m_innerBlock->renderer()->style()), renderArena()); } + } else { + RenderTextControl::createSubtreeIfNeeded(0); + +#if ENABLE(INPUT_SPEECH) + if (inputElement()->isSpeechEnabled() && !m_speechButton) { + // Create the speech button element. + m_speechButton = InputFieldSpeechButtonElement::create(toHTMLElement(node())); + m_speechButton->attachInnerElement(node(), createSpeechButtonStyle(), renderArena()); + } +#endif + + bool hasSpinButton = inputElement()->hasSpinButton(); + + if (hasSpinButton && !m_innerSpinButton) { + m_innerSpinButton = SpinButtonElement::create(toHTMLElement(node())); + m_innerSpinButton->attachInnerElement(node(), createInnerSpinButtonStyle(), renderArena()); + } + if (hasSpinButton && !m_outerSpinButton) { + m_outerSpinButton = SpinButtonElement::create(toHTMLElement(node())); + m_outerSpinButton->attachInnerElement(node(), createOuterSpinButtonStyle(), renderArena()); + } } } @@ -733,7 +751,7 @@ PassRefPtr<RenderStyle> RenderTextControlSingleLine::createInnerBlockStyle(const RefPtr<RenderStyle> innerBlockStyle = RenderStyle::create(); innerBlockStyle->inheritFrom(startStyle); - innerBlockStyle->setDisplay(inputElement()->hasSpinButton() ? INLINE_BLOCK : BLOCK); + innerBlockStyle->setDisplay(BLOCK); innerBlockStyle->setDirection(LTR); // We don't want the shadow dom to be editable, so we set this block to read-only in case the input itself is editable. @@ -951,7 +969,7 @@ int RenderTextControlSingleLine::clientPaddingLeft() const int padding = paddingLeft(); if (RenderBox* resultsRenderer = m_resultsButton ? m_resultsButton->renderBox() : 0) - padding += resultsRenderer->width(); + padding += resultsRenderer->width() + resultsRenderer->marginLeft() + resultsRenderer->paddingLeft() + resultsRenderer->marginRight() + resultsRenderer->paddingRight(); return padding; } @@ -961,7 +979,7 @@ int RenderTextControlSingleLine::clientPaddingRight() const int padding = paddingRight(); if (RenderBox* cancelRenderer = m_cancelButton ? m_cancelButton->renderBox() : 0) - padding += cancelRenderer->width(); + padding += cancelRenderer->width() + cancelRenderer->marginLeft() + cancelRenderer->paddingLeft() + cancelRenderer->marginRight() + cancelRenderer->paddingRight(); return padding; } diff --git a/Source/WebCore/rendering/RenderTextControlSingleLine.h b/Source/WebCore/rendering/RenderTextControlSingleLine.h index 6b99f59..18e5fc8 100644 --- a/Source/WebCore/rendering/RenderTextControlSingleLine.h +++ b/Source/WebCore/rendering/RenderTextControlSingleLine.h @@ -174,6 +174,19 @@ inline RenderTextControlSingleLine* toRenderTextControlSingleLine(RenderObject* // This will catch anyone doing an unnecessary cast. void toRenderTextControlSingleLine(const RenderTextControlSingleLine*); +// ---------------------------- + +class RenderTextControlInnerBlock : public RenderBlock { +public: + RenderTextControlInnerBlock(Node* node, bool isMultiLine) : RenderBlock(node), m_multiLine(isMultiLine) { } + +private: + virtual bool hasLineIfEmpty() const { return true; } + virtual VisiblePosition positionForPoint(const IntPoint&); + + bool m_multiLine; +}; + } #endif diff --git a/Source/WebCore/rendering/RenderTheme.cpp b/Source/WebCore/rendering/RenderTheme.cpp index e67ecfc..b68429c 100644 --- a/Source/WebCore/rendering/RenderTheme.cpp +++ b/Source/WebCore/rendering/RenderTheme.cpp @@ -541,12 +541,12 @@ String RenderTheme::formatMediaControlsRemainingTime(float currentTime, float du return formatMediaControlsTime(currentTime - duration); } -IntPoint RenderTheme::volumeSliderOffsetFromMuteButton(Node* muteButton, const IntSize& size) const +IntPoint RenderTheme::volumeSliderOffsetFromMuteButton(RenderBox* muteButtonBox, const IntSize& size) const { int y = -size.height(); - FloatPoint absPoint = muteButton->renderer()->localToAbsolute(FloatPoint(muteButton->renderBox()->offsetLeft(), y), true, true); + FloatPoint absPoint = muteButtonBox->localToAbsolute(FloatPoint(muteButtonBox->offsetLeft(), y), true, true); if (absPoint.y() < 0) - y = muteButton->renderBox()->height(); + y = muteButtonBox->height(); return IntPoint(0, y); } diff --git a/Source/WebCore/rendering/RenderTheme.h b/Source/WebCore/rendering/RenderTheme.h index e2b9c78..5021712 100644 --- a/Source/WebCore/rendering/RenderTheme.h +++ b/Source/WebCore/rendering/RenderTheme.h @@ -188,7 +188,7 @@ public: virtual String formatMediaControlsRemainingTime(float currentTime, float duration) const; // Returns the media volume slider container's offset from the mute button. - virtual IntPoint volumeSliderOffsetFromMuteButton(Node*, const IntSize&) const; + virtual IntPoint volumeSliderOffsetFromMuteButton(RenderBox*, const IntSize&) const; #endif #if ENABLE(METER_TAG) diff --git a/Source/WebCore/rendering/RenderThemeChromiumLinux.cpp b/Source/WebCore/rendering/RenderThemeChromiumLinux.cpp index 3a2874d..72ea7cb 100644 --- a/Source/WebCore/rendering/RenderThemeChromiumLinux.cpp +++ b/Source/WebCore/rendering/RenderThemeChromiumLinux.cpp @@ -227,6 +227,7 @@ bool RenderThemeChromiumLinux::paintButton(RenderObject* o, const PaintInfo& i, { PlatformBridge::ThemePaintExtraParams extraParams; extraParams.button.isDefault = isDefault(o); + extraParams.button.hasBorder = true; extraParams.button.backgroundColor = defaultButtonBackgroundColor; if (o->hasBackground()) extraParams.button.backgroundColor = o->style()->visitedDependentColor(CSSPropertyBackgroundColor).rgb(); @@ -260,12 +261,19 @@ bool RenderThemeChromiumLinux::paintTextField(RenderObject* o, const PaintInfo& bool RenderThemeChromiumLinux::paintMenuList(RenderObject* o, const PaintInfo& i, const IntRect& rect) { + if (!o->isBox()) + return false; + const int right = rect.x() + rect.width(); const int middle = rect.y() + rect.height() / 2; PlatformBridge::ThemePaintExtraParams extraParams; extraParams.menuList.arrowX = (o->style()->direction() == RTL) ? rect.x() + 7 : right - 13; extraParams.menuList.arrowY = middle; + const RenderBox* box = toRenderBox(o); + // Match Chromium Win behaviour of showing all borders if any are shown. + extraParams.menuList.hasBorder = box->borderRight() || box->borderLeft() || box->borderTop() || box->borderBottom(); + extraParams.menuList.hasBorderRadius = o->style()->hasBorderRadius(); extraParams.menuList.backgroundColor = SkColorSetRGB(0xdd, 0xdd, 0xdd); if (o->hasBackground()) extraParams.menuList.backgroundColor = o->style()->visitedDependentColor(CSSPropertyBackgroundColor).rgb(); diff --git a/Source/WebCore/rendering/RenderThemeChromiumMac.h b/Source/WebCore/rendering/RenderThemeChromiumMac.h index 80bbae4..4fd371f 100644 --- a/Source/WebCore/rendering/RenderThemeChromiumMac.h +++ b/Source/WebCore/rendering/RenderThemeChromiumMac.h @@ -45,7 +45,7 @@ protected: virtual bool paintMediaVolumeSliderContainer(RenderObject*, const PaintInfo&, const IntRect&); virtual bool paintMediaVolumeSliderTrack(RenderObject*, const PaintInfo&, const IntRect&); virtual bool paintMediaVolumeSliderThumb(RenderObject*, const PaintInfo&, const IntRect&); - virtual IntPoint volumeSliderOffsetFromMuteButton(Node*, const IntSize&) const; + virtual IntPoint volumeSliderOffsetFromMuteButton(RenderBox*, const IntSize&) const; virtual bool usesMediaControlStatusDisplay() { return false; } #endif diff --git a/Source/WebCore/rendering/RenderThemeChromiumMac.mm b/Source/WebCore/rendering/RenderThemeChromiumMac.mm index 10285ac..a7d59a9 100644 --- a/Source/WebCore/rendering/RenderThemeChromiumMac.mm +++ b/Source/WebCore/rendering/RenderThemeChromiumMac.mm @@ -155,9 +155,9 @@ bool RenderThemeChromiumMac::paintMediaSliderThumb(RenderObject* object, const P return RenderMediaControlsChromium::paintMediaControlsPart(MediaSliderThumb, object, paintInfo, rect); } -IntPoint RenderThemeChromiumMac::volumeSliderOffsetFromMuteButton(Node* muteButton, const IntSize& size) const +IntPoint RenderThemeChromiumMac::volumeSliderOffsetFromMuteButton(RenderBox* muteButtonBox, const IntSize& size) const { - return RenderTheme::volumeSliderOffsetFromMuteButton(muteButton, size); + return RenderTheme::volumeSliderOffsetFromMuteButton(muteButtonBox, size); } #endif diff --git a/Source/WebCore/rendering/RenderThemeChromiumWin.cpp b/Source/WebCore/rendering/RenderThemeChromiumWin.cpp index d538050..6f3be00 100644 --- a/Source/WebCore/rendering/RenderThemeChromiumWin.cpp +++ b/Source/WebCore/rendering/RenderThemeChromiumWin.cpp @@ -62,10 +62,15 @@ namespace WebCore { static const int kStandardMenuListButtonWidth = 17; namespace { +// We must not create multiple ThemePainter instances. class ThemePainter { public: ThemePainter(GraphicsContext* context, const IntRect& r) { +#ifndef NDEBUG + ASSERT(!s_hasInstance); + s_hasInstance = true; +#endif TransparencyWin::TransformMode transformMode = getTransformMode(context->getCTM()); m_helper.init(context, getLayerMode(context, transformMode), transformMode, r); @@ -85,6 +90,9 @@ public: ~ThemePainter() { m_helper.composite(); +#ifndef NDEBUG + s_hasInstance = false; +#endif } GraphicsContext* context() { return m_helper.context(); } @@ -120,8 +128,15 @@ private: } TransparencyWin m_helper; +#ifndef NDEBUG + static bool s_hasInstance; +#endif }; +#ifndef NDEBUG +bool ThemePainter::s_hasInstance = false; +#endif + } // namespace static void getNonClientMetrics(NONCLIENTMETRICS* metrics) @@ -707,23 +722,28 @@ bool RenderThemeChromiumWin::paintInnerSpinButton(RenderObject* object, const Pa { IntRect half = rect; - half.setHeight(rect.height() / 2); - const ThemeData& upThemeData = getThemeData(object, SpinButtonUp); - ThemePainter upPainter(info.context, half); - PlatformBridge::paintSpinButton(upPainter.context(), - upThemeData.m_part, - upThemeData.m_state, - upThemeData.m_classicState, - upPainter.drawRect()); - - half.setY(rect.y() + rect.height() / 2); - const ThemeData& downThemeData = getThemeData(object, SpinButtonDown); - ThemePainter downPainter(info.context, half); - PlatformBridge::paintSpinButton(downPainter.context(), - downThemeData.m_part, - downThemeData.m_state, - downThemeData.m_classicState, - downPainter.drawRect()); + // Need explicit blocks to avoid to create multiple ThemePainter instances. + { + half.setHeight(rect.height() / 2); + const ThemeData& upThemeData = getThemeData(object, SpinButtonUp); + ThemePainter upPainter(info.context, half); + PlatformBridge::paintSpinButton(upPainter.context(), + upThemeData.m_part, + upThemeData.m_state, + upThemeData.m_classicState, + upPainter.drawRect()); + } + + { + half.setY(rect.y() + rect.height() / 2); + const ThemeData& downThemeData = getThemeData(object, SpinButtonDown); + ThemePainter downPainter(info.context, half); + PlatformBridge::paintSpinButton(downPainter.context(), + downThemeData.m_part, + downThemeData.m_state, + downThemeData.m_classicState, + downPainter.drawRect()); + } return false; } diff --git a/Source/WebCore/rendering/RenderThemeMac.h b/Source/WebCore/rendering/RenderThemeMac.h index 9837c2a..d951ff6 100644 --- a/Source/WebCore/rendering/RenderThemeMac.h +++ b/Source/WebCore/rendering/RenderThemeMac.h @@ -166,7 +166,7 @@ protected: virtual bool shouldRenderMediaControlPart(ControlPart, Element*); virtual bool usesMediaControlStatusDisplay(); virtual void adjustMediaSliderThumbSize(RenderObject*) const; - virtual IntPoint volumeSliderOffsetFromMuteButton(Node*, const IntSize&) const; + virtual IntPoint volumeSliderOffsetFromMuteButton(RenderBox*, const IntSize&) const; #endif virtual bool shouldShowPlaceholderWhenFocused() const; diff --git a/Source/WebCore/rendering/RenderThemeMac.mm b/Source/WebCore/rendering/RenderThemeMac.mm index e3c75c5..f5611dc 100644 --- a/Source/WebCore/rendering/RenderThemeMac.mm +++ b/Source/WebCore/rendering/RenderThemeMac.mm @@ -37,6 +37,7 @@ #import "MediaControlElements.h" #import "PaintInfo.h" #import "RenderMedia.h" +#import "RenderMediaControls.h" #import "RenderSlider.h" #import "RenderView.h" #import "SharedBuffer.h" @@ -1986,17 +1987,9 @@ bool RenderThemeMac::usesMediaControlStatusDisplay() return mediaControllerTheme() == MediaControllerThemeQuickTime; } -IntPoint RenderThemeMac::volumeSliderOffsetFromMuteButton(Node* muteButton, const IntSize& size) const +IntPoint RenderThemeMac::volumeSliderOffsetFromMuteButton(RenderBox* muteButtonBox, const IntSize& size) const { - static const int xOffset = -4; - static const int yOffset = 5; - - float zoomLevel = muteButton->renderer()->style()->effectiveZoom(); - int y = yOffset * zoomLevel + muteButton->renderBox()->offsetHeight() - size.height(); - FloatPoint absPoint = muteButton->renderer()->localToAbsolute(FloatPoint(muteButton->renderBox()->offsetLeft(), y), true, true); - if (absPoint.y() < 0) - y = muteButton->renderBox()->height(); - return IntPoint(xOffset * zoomLevel, y); + return RenderMediaControls::volumeSliderOffsetFromMuteButton(muteButtonBox, size); } bool RenderThemeMac::shouldShowPlaceholderWhenFocused() const diff --git a/Source/WebCore/rendering/RenderThemeWin.cpp b/Source/WebCore/rendering/RenderThemeWin.cpp index 5581db8..d5e4155 100644 --- a/Source/WebCore/rendering/RenderThemeWin.cpp +++ b/Source/WebCore/rendering/RenderThemeWin.cpp @@ -1108,9 +1108,9 @@ bool RenderThemeWin::paintMediaVolumeSliderThumb(RenderObject* o, const PaintInf return RenderMediaControls::paintMediaControlsPart(MediaVolumeSliderThumb, o, paintInfo, r); } -IntPoint RenderThemeWin::volumeSliderOffsetFromMuteButton(Node* muteButton, const IntSize& size) const +IntPoint RenderThemeWin::volumeSliderOffsetFromMuteButton(RenderBox* muteButtonBox, const IntSize& size) const { - return RenderMediaControls::volumeSliderOffsetFromMuteButton(muteButton, size); + return RenderMediaControls::volumeSliderOffsetFromMuteButton(muteButtonBox, size); } diff --git a/Source/WebCore/rendering/RenderThemeWin.h b/Source/WebCore/rendering/RenderThemeWin.h index c05d2ee..7e0223a 100644 --- a/Source/WebCore/rendering/RenderThemeWin.h +++ b/Source/WebCore/rendering/RenderThemeWin.h @@ -138,7 +138,7 @@ public: virtual bool paintMediaVolumeSliderContainer(RenderObject*, const PaintInfo&, const IntRect&); virtual bool paintMediaVolumeSliderTrack(RenderObject*, const PaintInfo&, const IntRect&); virtual bool paintMediaVolumeSliderThumb(RenderObject*, const PaintInfo&, const IntRect&); - virtual IntPoint volumeSliderOffsetFromMuteButton(Node*, const IntSize&) const; + virtual IntPoint volumeSliderOffsetFromMuteButton(RenderBox*, const IntSize&) const; #endif private: diff --git a/Source/WebCore/rendering/RenderTreeAsText.cpp b/Source/WebCore/rendering/RenderTreeAsText.cpp index a81163b..cad5830 100644 --- a/Source/WebCore/rendering/RenderTreeAsText.cpp +++ b/Source/WebCore/rendering/RenderTreeAsText.cpp @@ -278,22 +278,22 @@ void RenderTreeAsText::writeRenderObject(TextStream& ts, const RenderObject& o, ts << " " << quoteAndEscapeNonPrintables(toRenderFileUploadControl(&o)->fileTextValue()); if (o.parent() && (o.parent()->style()->color() != o.style()->color())) - ts << " [color=" << o.style()->color().name() << "]"; + ts << " [color=" << o.style()->color().nameForRenderTreeAsText() << "]"; if (o.parent() && (o.parent()->style()->backgroundColor() != o.style()->backgroundColor()) && o.style()->backgroundColor().isValid() && o.style()->backgroundColor().rgb()) // Do not dump invalid or transparent backgrounds, since that is the default. - ts << " [bgcolor=" << o.style()->backgroundColor().name() << "]"; + ts << " [bgcolor=" << o.style()->backgroundColor().nameForRenderTreeAsText() << "]"; if (o.parent() && (o.parent()->style()->textFillColor() != o.style()->textFillColor()) && o.style()->textFillColor().isValid() && o.style()->textFillColor() != o.style()->color() && o.style()->textFillColor().rgb()) - ts << " [textFillColor=" << o.style()->textFillColor().name() << "]"; + ts << " [textFillColor=" << o.style()->textFillColor().nameForRenderTreeAsText() << "]"; if (o.parent() && (o.parent()->style()->textStrokeColor() != o.style()->textStrokeColor()) && o.style()->textStrokeColor().isValid() && o.style()->textStrokeColor() != o.style()->color() && o.style()->textStrokeColor().rgb()) - ts << " [textStrokeColor=" << o.style()->textStrokeColor().name() << "]"; + ts << " [textStrokeColor=" << o.style()->textStrokeColor().nameForRenderTreeAsText() << "]"; if (o.parent() && (o.parent()->style()->textStrokeWidth() != o.style()->textStrokeWidth()) && o.style()->textStrokeWidth() > 0) @@ -317,7 +317,7 @@ void RenderTreeAsText::writeRenderObject(TextStream& ts, const RenderObject& o, Color col = o.style()->borderTopColor(); if (!col.isValid()) col = o.style()->color(); - ts << col.name() << ")"; + ts << col.nameForRenderTreeAsText() << ")"; } } @@ -331,7 +331,7 @@ void RenderTreeAsText::writeRenderObject(TextStream& ts, const RenderObject& o, Color col = o.style()->borderRightColor(); if (!col.isValid()) col = o.style()->color(); - ts << col.name() << ")"; + ts << col.nameForRenderTreeAsText() << ")"; } } @@ -345,7 +345,7 @@ void RenderTreeAsText::writeRenderObject(TextStream& ts, const RenderObject& o, Color col = o.style()->borderBottomColor(); if (!col.isValid()) col = o.style()->color(); - ts << col.name() << ")"; + ts << col.nameForRenderTreeAsText() << ")"; } } @@ -359,7 +359,7 @@ void RenderTreeAsText::writeRenderObject(TextStream& ts, const RenderObject& o, Color col = o.style()->borderLeftColor(); if (!col.isValid()) col = o.style()->color(); - ts << col.name() << ")"; + ts << col.nameForRenderTreeAsText() << ")"; } } @@ -470,11 +470,17 @@ void RenderTreeAsText::writeRenderObject(TextStream& ts, const RenderObject& o, static void writeTextRun(TextStream& ts, const RenderText& o, const InlineTextBox& run) { - // FIXME: Table cell adjustment is temporary until results can be updated. + // FIXME: For now use an "enclosingIntRect" model for x, y and logicalWidth, although this makes it harder + // to detect any changes caused by the conversion to floating point. :( + int x = run.m_x; int y = run.m_y; + int logicalWidth = ceilf(run.m_x + run.m_logicalWidth) - x; + + // FIXME: Table cell adjustment is temporary until results can be updated. if (o.containingBlock()->isTableCell()) y -= toRenderTableCell(o.containingBlock())->intrinsicPaddingBefore(); - ts << "text run at (" << run.m_x << "," << y << ") width " << run.m_logicalWidth; + + ts << "text run at (" << x << "," << y << ") width " << logicalWidth; if (!run.isLeftToRightDirection() || run.m_dirOverride) { ts << (!run.isLeftToRightDirection() ? " RTL" : " LTR"); if (run.m_dirOverride) @@ -715,13 +721,13 @@ static void writeSelection(TextStream& ts, const RenderObject* o) VisibleSelection selection = frame->selection()->selection(); if (selection.isCaret()) { - ts << "caret: position " << selection.start().deprecatedEditingOffset() << " of " << nodePosition(selection.start().node()); + ts << "caret: position " << selection.start().deprecatedEditingOffset() << " of " << nodePosition(selection.start().deprecatedNode()); if (selection.affinity() == UPSTREAM) ts << " (upstream affinity)"; ts << "\n"; } else if (selection.isRange()) - ts << "selection start: position " << selection.start().deprecatedEditingOffset() << " of " << nodePosition(selection.start().node()) << "\n" - << "selection end: position " << selection.end().deprecatedEditingOffset() << " of " << nodePosition(selection.end().node()) << "\n"; + ts << "selection start: position " << selection.start().deprecatedEditingOffset() << " of " << nodePosition(selection.start().deprecatedNode()) << "\n" + << "selection end: position " << selection.end().deprecatedEditingOffset() << " of " << nodePosition(selection.end().deprecatedNode()) << "\n"; } String externalRepresentation(Frame* frame, RenderAsTextBehavior behavior) diff --git a/Source/WebCore/rendering/RenderingAllInOne.cpp b/Source/WebCore/rendering/RenderingAllInOne.cpp index 760f02d..c9f6707 100644 --- a/Source/WebCore/rendering/RenderingAllInOne.cpp +++ b/Source/WebCore/rendering/RenderingAllInOne.cpp @@ -79,6 +79,7 @@ #include "RenderObjectChildList.cpp" #include "RenderPart.cpp" #include "RenderProgress.cpp" +#include "RenderQuote.cpp" #include "RenderReplaced.cpp" #include "RenderReplica.cpp" #include "RenderRuby.cpp" @@ -110,6 +111,5 @@ #include "RootInlineBox.cpp" #include "ScrollBehavior.cpp" #include "ShadowElement.cpp" -#include "TextControlInnerElements.cpp" #include "TransformState.cpp" #include "break_lines.cpp" diff --git a/Source/WebCore/rendering/RootInlineBox.cpp b/Source/WebCore/rendering/RootInlineBox.cpp index aa87683..8617252 100644 --- a/Source/WebCore/rendering/RootInlineBox.cpp +++ b/Source/WebCore/rendering/RootInlineBox.cpp @@ -85,7 +85,7 @@ void RootInlineBox::clearTruncation() } } -bool RootInlineBox::canAccommodateEllipsis(bool ltr, int blockEdge, int lineBoxEdge, int ellipsisWidth) +bool RootInlineBox::lineCanAccommodateEllipsis(bool ltr, int blockEdge, int lineBoxEdge, int ellipsisWidth) { // First sanity-check the unoverflowed width of the whole line to see if there is sufficient room. int delta = ltr ? lineBoxEdge - blockEdge : blockEdge - lineBoxEdge; @@ -97,7 +97,7 @@ bool RootInlineBox::canAccommodateEllipsis(bool ltr, int blockEdge, int lineBoxE return InlineFlowBox::canAccommodateEllipsis(ltr, blockEdge, ellipsisWidth); } -void RootInlineBox::placeEllipsis(const AtomicString& ellipsisStr, bool ltr, int blockLeftEdge, int blockRightEdge, int ellipsisWidth, +void RootInlineBox::placeEllipsis(const AtomicString& ellipsisStr, bool ltr, float blockLeftEdge, float blockRightEdge, float ellipsisWidth, InlineBox* markupBox) { // Create an ellipsis box. @@ -123,9 +123,9 @@ void RootInlineBox::placeEllipsis(const AtomicString& ellipsisStr, bool ltr, in ellipsisBox->m_x = placeEllipsisBox(ltr, blockLeftEdge, blockRightEdge, ellipsisWidth, foundBox); } -int RootInlineBox::placeEllipsisBox(bool ltr, int blockLeftEdge, int blockRightEdge, int ellipsisWidth, bool& foundBox) +float RootInlineBox::placeEllipsisBox(bool ltr, float blockLeftEdge, float blockRightEdge, float ellipsisWidth, bool& foundBox) { - int result = InlineFlowBox::placeEllipsisBox(ltr, blockLeftEdge, blockRightEdge, ellipsisWidth, foundBox); + float result = InlineFlowBox::placeEllipsisBox(ltr, blockLeftEdge, blockRightEdge, ellipsisWidth, foundBox); if (result == -1) result = ltr ? blockRightEdge - ellipsisWidth : blockLeftEdge; return result; @@ -198,10 +198,10 @@ bool RootInlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re return InlineFlowBox::nodeAtPoint(request, result, x, y, tx, ty); } -void RootInlineBox::adjustPosition(int dx, int dy) +void RootInlineBox::adjustPosition(float dx, float dy) { InlineFlowBox::adjustPosition(dx, dy); - int blockDirectionDelta = isHorizontal() ? dy : dx; + int blockDirectionDelta = isHorizontal() ? dy : dx; // The block direction delta will always be integral. m_lineTop += blockDirectionDelta; m_lineBottom += blockDirectionDelta; m_blockLogicalHeight += blockDirectionDelta; @@ -268,10 +268,6 @@ int RootInlineBox::alignBoxesInBlockDirection(int heightOfBlock, GlyphOverflowAn maxHeight = max(0, maxHeight); - // Detect integer overflow. - if (heightOfBlock > numeric_limits<int>::max() - maxHeight) - return numeric_limits<int>::max(); - return heightOfBlock + maxHeight; } @@ -289,7 +285,7 @@ int RootInlineBox::beforeAnnotationsAdjustment() const // Annotations over this line may push us further down. int highestAllowedPosition = prevRootBox() ? min(prevRootBox()->lineBottom(), lineTop()) + result : block()->borderBefore(); - result = computeOverAnnotationAdjustment(highestAllowedPosition); + result = computeOverAnnotationAdjustment(highestAllowedPosition); } else { // Annotations under this line may push us up. if (hasAnnotationsBefore()) @@ -544,14 +540,14 @@ IntRect RootInlineBox::paddedLayoutOverflowRect(int endPadding) const if (isHorizontal()) { if (isLeftToRightDirection()) - lineLayoutOverflow.shiftMaxXEdgeTo(max(lineLayoutOverflow.maxX(), logicalRight() + endPadding)); + lineLayoutOverflow.shiftMaxXEdgeTo(max(lineLayoutOverflow.maxX(), pixelSnappedLogicalRight() + endPadding)); else - lineLayoutOverflow.shiftXEdgeTo(min(lineLayoutOverflow.x(), logicalLeft() - endPadding)); + lineLayoutOverflow.shiftXEdgeTo(min(lineLayoutOverflow.x(), pixelSnappedLogicalLeft() - endPadding)); } else { if (isLeftToRightDirection()) - lineLayoutOverflow.shiftMaxYEdgeTo(max(lineLayoutOverflow.maxY(), logicalRight() + endPadding)); + lineLayoutOverflow.shiftMaxYEdgeTo(max(lineLayoutOverflow.maxY(), pixelSnappedLogicalRight() + endPadding)); else - lineLayoutOverflow.shiftYEdgeTo(min(lineLayoutOverflow.y(), logicalRight() - endPadding)); + lineLayoutOverflow.shiftYEdgeTo(min(lineLayoutOverflow.y(), pixelSnappedLogicalLeft() - endPadding)); } return lineLayoutOverflow; diff --git a/Source/WebCore/rendering/RootInlineBox.h b/Source/WebCore/rendering/RootInlineBox.h index 7c4b15c..1a9f0a8 100644 --- a/Source/WebCore/rendering/RootInlineBox.h +++ b/Source/WebCore/rendering/RootInlineBox.h @@ -45,7 +45,7 @@ public: RootInlineBox* nextRootBox() const { return static_cast<RootInlineBox*>(m_nextLineBox); } RootInlineBox* prevRootBox() const { return static_cast<RootInlineBox*>(m_prevLineBox); } - virtual void adjustPosition(int dx, int dy); + virtual void adjustPosition(float dx, float dy); int lineTop() const { return m_lineTop; } int lineBottom() const { return m_lineBottom; } @@ -77,9 +77,9 @@ public: void childRemoved(InlineBox* box); - bool canAccommodateEllipsis(bool ltr, int blockEdge, int lineBoxEdge, int ellipsisWidth); - void placeEllipsis(const AtomicString& ellipsisStr, bool ltr, int blockLeftEdge, int blockRightEdge, int ellipsisWidth, InlineBox* markupBox = 0); - virtual int placeEllipsisBox(bool ltr, int blockLeftEdge, int blockRightEdge, int ellipsisWidth, bool& foundBox); + bool lineCanAccommodateEllipsis(bool ltr, int blockEdge, int lineBoxEdge, int ellipsisWidth); + void placeEllipsis(const AtomicString& ellipsisStr, bool ltr, float blockLeftEdge, float blockRightEdge, float ellipsisWidth, InlineBox* markupBox = 0); + virtual float placeEllipsisBox(bool ltr, float blockLeftEdge, float blockRightEdge, float ellipsisWidth, bool& foundBox); EllipsisBox* ellipsisBox() const; diff --git a/Source/WebCore/rendering/TextControlInnerElements.cpp b/Source/WebCore/rendering/TextControlInnerElements.cpp deleted file mode 100644 index 1162999..0000000 --- a/Source/WebCore/rendering/TextControlInnerElements.cpp +++ /dev/null @@ -1,535 +0,0 @@ -/* - * Copyright (C) 2006, 2008, 2010 Apple Inc. All rights reserved. - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "TextControlInnerElements.h" - -#include "BeforeTextInsertedEvent.h" -#include "Document.h" -#include "EventHandler.h" -#include "EventNames.h" -#include "Frame.h" -#include "HTMLInputElement.h" -#include "HTMLNames.h" -#include "HTMLTextAreaElement.h" -#include "MouseEvent.h" -#include "Page.h" -#include "RenderLayer.h" -#include "RenderTextControlSingleLine.h" -#include "ScrollbarTheme.h" -#include "SpeechInput.h" -#include "SpeechInputEvent.h" - -namespace WebCore { - -using namespace HTMLNames; - -class RenderTextControlInnerBlock : public RenderBlock { -public: - RenderTextControlInnerBlock(Node* node, bool isMultiLine) : RenderBlock(node), m_multiLine(isMultiLine) { } - -private: - virtual bool hasLineIfEmpty() const { return true; } - virtual VisiblePosition positionForPoint(const IntPoint&); - - bool m_multiLine; -}; - -VisiblePosition RenderTextControlInnerBlock::positionForPoint(const IntPoint& point) -{ - IntPoint contentsPoint(point); - - // Multiline text controls have the scroll on shadowAncestorNode, so we need to take that - // into account here. - if (m_multiLine) { - RenderTextControl* renderer = toRenderTextControl(node()->shadowAncestorNode()->renderer()); - if (renderer->hasOverflowClip()) - contentsPoint += renderer->layer()->scrolledContentOffset(); - } - - return RenderBlock::positionForPoint(contentsPoint); -} - -// ---------------------------- - -TextControlInnerElement::TextControlInnerElement(Document* document, HTMLElement* shadowParent) - : HTMLDivElement(divTag, document) -{ - setShadowHost(shadowParent); -} - -PassRefPtr<TextControlInnerElement> TextControlInnerElement::create(HTMLElement* shadowParent) -{ - return adoptRef(new TextControlInnerElement(shadowParent->document(), shadowParent)); -} - -void TextControlInnerElement::attachInnerElement(Node* parent, PassRefPtr<RenderStyle> style, RenderArena* arena) -{ - // When adding these elements, create the renderer & style first before adding to the DOM. - // Otherwise, the render tree will create some anonymous blocks that will mess up our layout. - - // Create the renderer with the specified style - RenderObject* renderer = createRenderer(arena, style.get()); - if (renderer) { - setRenderer(renderer); - renderer->setStyle(style); - } - - // Set these explicitly since this normally happens during an attach() - setAttached(); - setInDocument(); - - // For elements not yet in shadow DOM, add the node to the DOM normally. - if (!isShadowRoot()) { - // FIXME: This code seems very wrong. Why are we magically adding |this| to the DOM here? - // We shouldn't be calling parser API methods outside of the parser! - parent->deprecatedParserAddChild(this); - } - - // Add the renderer to the render tree - if (renderer) - parent->renderer()->addChild(renderer); -} - -void TextControlInnerElement::detach() -{ - HTMLDivElement::detach(); - // FIXME: Remove once shadow DOM uses Element::setShadowRoot(). - if (shadowHost()) - setShadowHost(0); -} - -// ---------------------------- - -inline TextControlInnerTextElement::TextControlInnerTextElement(Document* document, HTMLElement* shadowParent) - : TextControlInnerElement(document, shadowParent) -{ -} - -PassRefPtr<TextControlInnerTextElement> TextControlInnerTextElement::create(Document* document, HTMLElement* shadowParent) -{ - return adoptRef(new TextControlInnerTextElement(document, shadowParent)); -} - -void TextControlInnerTextElement::defaultEventHandler(Event* event) -{ - // FIXME: In the future, we should add a way to have default event listeners. - // Then we would add one to the text field's inner div, and we wouldn't need this subclass. - // Or possibly we could just use a normal event listener. - if (event->isBeforeTextInsertedEvent() || event->type() == eventNames().webkitEditableContentChangedEvent) { - Node* shadowAncestor = shadowAncestorNode(); - // A TextControlInnerTextElement can be its own shadow ancestor if its been detached, but kept alive by an EditCommand. - // In this case, an undo/redo can cause events to be sent to the TextControlInnerTextElement. - // To prevent an infinite loop, we must check for this case before sending the event up the chain. - if (shadowAncestor && shadowAncestor != this) - shadowAncestor->defaultEventHandler(event); - } - if (!event->defaultHandled()) - HTMLDivElement::defaultEventHandler(event); -} - -RenderObject* TextControlInnerTextElement::createRenderer(RenderArena* arena, RenderStyle*) -{ - bool multiLine = false; - Node* shadowAncestor = shadowAncestorNode(); - if (shadowAncestor && shadowAncestor->renderer()) { - ASSERT(shadowAncestor->renderer()->isTextField() || shadowAncestor->renderer()->isTextArea()); - multiLine = shadowAncestor->renderer()->isTextArea(); - } - return new (arena) RenderTextControlInnerBlock(this, multiLine); -} - -// ---------------------------- - -inline SearchFieldResultsButtonElement::SearchFieldResultsButtonElement(Document* document) - : TextControlInnerElement(document) -{ -} - -PassRefPtr<SearchFieldResultsButtonElement> SearchFieldResultsButtonElement::create(Document* document) -{ - return adoptRef(new SearchFieldResultsButtonElement(document)); -} - -void SearchFieldResultsButtonElement::defaultEventHandler(Event* event) -{ - // On mousedown, bring up a menu, if needed - HTMLInputElement* input = static_cast<HTMLInputElement*>(shadowAncestorNode()); - if (event->type() == eventNames().mousedownEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) { - input->focus(); - input->select(); - RenderTextControlSingleLine* renderer = toRenderTextControlSingleLine(input->renderer()); - if (renderer->popupIsVisible()) - renderer->hidePopup(); - else if (input->maxResults() > 0) - renderer->showPopup(); - event->setDefaultHandled(); - } - - if (!event->defaultHandled()) - HTMLDivElement::defaultEventHandler(event); -} - -// ---------------------------- - -inline SearchFieldCancelButtonElement::SearchFieldCancelButtonElement(Document* document) - : TextControlInnerElement(document) - , m_capturing(false) -{ -} - -PassRefPtr<SearchFieldCancelButtonElement> SearchFieldCancelButtonElement::create(Document* document) -{ - return adoptRef(new SearchFieldCancelButtonElement(document)); -} - -void SearchFieldCancelButtonElement::detach() -{ - if (m_capturing) { - if (Frame* frame = document()->frame()) - frame->eventHandler()->setCapturingMouseEventsNode(0); - } - TextControlInnerElement::detach(); -} - - -void SearchFieldCancelButtonElement::defaultEventHandler(Event* event) -{ - // If the element is visible, on mouseup, clear the value, and set selection - RefPtr<HTMLInputElement> input(static_cast<HTMLInputElement*>(shadowAncestorNode())); - if (event->type() == eventNames().mousedownEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) { - if (renderer() && renderer()->visibleToHitTesting()) { - if (Frame* frame = document()->frame()) { - frame->eventHandler()->setCapturingMouseEventsNode(this); - m_capturing = true; - } - } - input->focus(); - input->select(); - event->setDefaultHandled(); - } - if (event->type() == eventNames().mouseupEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) { - if (m_capturing) { - if (Frame* frame = document()->frame()) { - frame->eventHandler()->setCapturingMouseEventsNode(0); - m_capturing = false; - } - if (hovered()) { - String oldValue = input->value(); - input->setValue(""); - if (!oldValue.isEmpty()) { - toRenderTextControl(input->renderer())->setChangedSinceLastChangeEvent(true); - input->dispatchFormControlInputEvent(); - } - input->onSearch(); - event->setDefaultHandled(); - } - } - } - - if (!event->defaultHandled()) - HTMLDivElement::defaultEventHandler(event); -} - -// ---------------------------- - -inline SpinButtonElement::SpinButtonElement(HTMLElement* shadowParent) - : TextControlInnerElement(shadowParent->document(), shadowParent) - , m_capturing(false) - , m_upDownState(Indeterminate) - , m_pressStartingState(Indeterminate) - , m_repeatingTimer(this, &SpinButtonElement::repeatingTimerFired) -{ -} - -PassRefPtr<SpinButtonElement> SpinButtonElement::create(HTMLElement* shadowParent) -{ - return adoptRef(new SpinButtonElement(shadowParent)); -} - -void SpinButtonElement::detach() -{ - stopRepeatingTimer(); - if (m_capturing) { - if (Frame* frame = document()->frame()) { - frame->eventHandler()->setCapturingMouseEventsNode(0); - m_capturing = false; - } - } - TextControlInnerElement::detach(); -} - -void SpinButtonElement::defaultEventHandler(Event* event) -{ - if (!event->isMouseEvent()) { - if (!event->defaultHandled()) - HTMLDivElement::defaultEventHandler(event); - return; - } - - RenderBox* box = renderBox(); - if (!box) { - if (!event->defaultHandled()) - HTMLDivElement::defaultEventHandler(event); - return; - } - - RefPtr<HTMLInputElement> input(static_cast<HTMLInputElement*>(shadowAncestorNode())); - if (input->disabled() || input->isReadOnlyFormControl()) { - if (!event->defaultHandled()) - HTMLDivElement::defaultEventHandler(event); - return; - } - - MouseEvent* mouseEvent = static_cast<MouseEvent*>(event); - IntPoint local = roundedIntPoint(box->absoluteToLocal(mouseEvent->absoluteLocation(), false, true)); - if (mouseEvent->type() == eventNames().mousedownEvent && mouseEvent->button() == LeftButton) { - if (box->borderBoxRect().contains(local)) { - // The following functions of HTMLInputElement may run JavaScript - // code which detaches this shadow node. We need to take a reference - // and check renderer() after such function calls. - RefPtr<Node> protector(this); - input->focus(); - input->select(); - if (renderer()) { - input->stepUpFromRenderer(m_upDownState == Up ? 1 : -1); - if (renderer()) - startRepeatingTimer(); - } - event->setDefaultHandled(); - } - } else if (mouseEvent->type() == eventNames().mouseupEvent && mouseEvent->button() == LeftButton) - stopRepeatingTimer(); - else if (event->type() == eventNames().mousemoveEvent) { - if (box->borderBoxRect().contains(local)) { - if (!m_capturing) { - if (Frame* frame = document()->frame()) { - frame->eventHandler()->setCapturingMouseEventsNode(this); - m_capturing = true; - } - } - UpDownState oldUpDownState = m_upDownState; - m_upDownState = local.y() < box->height() / 2 ? Up : Down; - if (m_upDownState != oldUpDownState) - renderer()->repaint(); - } else { - if (m_capturing) { - stopRepeatingTimer(); - if (Frame* frame = document()->frame()) { - frame->eventHandler()->setCapturingMouseEventsNode(0); - m_capturing = false; - } - } - } - } - - if (!event->defaultHandled()) - HTMLDivElement::defaultEventHandler(event); -} - -void SpinButtonElement::startRepeatingTimer() -{ - m_pressStartingState = m_upDownState; - ScrollbarTheme* theme = ScrollbarTheme::nativeTheme(); - m_repeatingTimer.start(theme->initialAutoscrollTimerDelay(), theme->autoscrollTimerDelay()); -} - -void SpinButtonElement::stopRepeatingTimer() -{ - m_repeatingTimer.stop(); -} - -void SpinButtonElement::repeatingTimerFired(Timer<SpinButtonElement>*) -{ - HTMLInputElement* input = static_cast<HTMLInputElement*>(shadowAncestorNode()); - if (input->disabled() || input->isReadOnlyFormControl()) - return; - // On Mac OS, NSStepper updates the value for the button under the mouse - // cursor regardless of the button pressed at the beginning. So the - // following check is not needed for Mac OS. -#if !OS(MAC_OS_X) - if (m_upDownState != m_pressStartingState) - return; -#endif - input->stepUpFromRenderer(m_upDownState == Up ? 1 : -1); -} - -void SpinButtonElement::setHovered(bool flag) -{ - if (!hovered() && flag) - m_upDownState = Indeterminate; - TextControlInnerElement::setHovered(flag); -} - - -// ---------------------------- - -#if ENABLE(INPUT_SPEECH) - -inline InputFieldSpeechButtonElement::InputFieldSpeechButtonElement(HTMLElement* shadowParent) - : TextControlInnerElement(shadowParent->document(), shadowParent) - , m_capturing(false) - , m_state(Idle) - , m_listenerId(document()->page()->speechInput()->registerListener(this)) -{ -} - -InputFieldSpeechButtonElement::~InputFieldSpeechButtonElement() -{ - SpeechInput* speech = speechInput(); - if (speech && m_listenerId) { // Could be null when page is unloading. - if (m_state != Idle) - speech->cancelRecognition(m_listenerId); - speech->unregisterListener(m_listenerId); - } -} - -PassRefPtr<InputFieldSpeechButtonElement> InputFieldSpeechButtonElement::create(HTMLElement* shadowParent) -{ - return adoptRef(new InputFieldSpeechButtonElement(shadowParent)); -} - -void InputFieldSpeechButtonElement::defaultEventHandler(Event* event) -{ - // For privacy reasons, only allow clicks directly coming from the user. - if (!event->fromUserGesture()) { - HTMLDivElement::defaultEventHandler(event); - return; - } - - // The call to focus() below dispatches a focus event, and an event handler in the page might - // remove the input element from DOM. To make sure it remains valid until we finish our work - // here, we take a temporary reference. - RefPtr<HTMLInputElement> input(static_cast<HTMLInputElement*>(shadowAncestorNode())); - - // On mouse down, select the text and set focus. - if (event->type() == eventNames().mousedownEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) { - if (renderer() && renderer()->visibleToHitTesting()) { - if (Frame* frame = document()->frame()) { - frame->eventHandler()->setCapturingMouseEventsNode(this); - m_capturing = true; - } - } - RefPtr<InputFieldSpeechButtonElement> holdRefButton(this); - input->focus(); - input->select(); - event->setDefaultHandled(); - } - // On mouse up, release capture cleanly. - if (event->type() == eventNames().mouseupEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) { - if (m_capturing && renderer() && renderer()->visibleToHitTesting()) { - if (Frame* frame = document()->frame()) { - frame->eventHandler()->setCapturingMouseEventsNode(0); - m_capturing = false; - } - } - } - - if (event->type() == eventNames().clickEvent) { - switch (m_state) { - case Idle: { - AtomicString language = input->computeInheritedLanguage(); - String grammar = input->getAttribute(webkitgrammarAttr); - IntRect rect = input->renderer()->absoluteBoundingBoxRect(); - if (speechInput()->startRecognition(m_listenerId, rect, language, grammar, document()->securityOrigin())) - setState(Recording); - } - break; - case Recording: - speechInput()->stopRecording(m_listenerId); - break; - case Recognizing: - // Nothing to do here, we will continue to wait for results. - break; - } - event->setDefaultHandled(); - } - - if (!event->defaultHandled()) - HTMLDivElement::defaultEventHandler(event); -} - -void InputFieldSpeechButtonElement::setState(SpeechInputState state) -{ - if (m_state != state) { - m_state = state; - shadowAncestorNode()->renderer()->repaint(); - } -} - -SpeechInput* InputFieldSpeechButtonElement::speechInput() -{ - return document()->page() ? document()->page()->speechInput() : 0; -} - -void InputFieldSpeechButtonElement::didCompleteRecording(int) -{ - setState(Recognizing); -} - -void InputFieldSpeechButtonElement::didCompleteRecognition(int) -{ - setState(Idle); -} - -void InputFieldSpeechButtonElement::setRecognitionResult(int, const SpeechInputResultArray& results) -{ - m_results = results; - - // The call to setValue() below dispatches an event, and an event handler in the page might - // remove the input element from DOM. To make sure it remains valid until we finish our work - // here, we take a temporary reference. - RefPtr<HTMLInputElement> input(static_cast<HTMLInputElement*>(shadowAncestorNode())); - RefPtr<InputFieldSpeechButtonElement> holdRefButton(this); - input->setValue(results.isEmpty() ? "" : results[0]->utterance()); - input->dispatchEvent(SpeechInputEvent::create(eventNames().webkitspeechchangeEvent, results)); - - // Check before accessing the renderer as the above event could have potentially turned off - // speech in the input element, hence removing this button and renderer from the hierarchy. - if (renderer()) - renderer()->repaint(); -} - -void InputFieldSpeechButtonElement::detach() -{ - if (m_capturing) { - if (Frame* frame = document()->frame()) - frame->eventHandler()->setCapturingMouseEventsNode(0); - } - - if (m_listenerId) { - if (m_state != Idle) - speechInput()->cancelRecognition(m_listenerId); - speechInput()->unregisterListener(m_listenerId); - m_listenerId = 0; - } - - TextControlInnerElement::detach(); -} - -#endif // ENABLE(INPUT_SPEECH) - -} diff --git a/Source/WebCore/rendering/TextControlInnerElements.h b/Source/WebCore/rendering/TextControlInnerElements.h deleted file mode 100644 index 4ba7857..0000000 --- a/Source/WebCore/rendering/TextControlInnerElements.h +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (C) 2006, 2008, 2010 Apple Inc. All rights reserved. - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TextControlInnerElements_h -#define TextControlInnerElements_h - -#include "HTMLDivElement.h" -#include "SpeechInputListener.h" -#include "Timer.h" -#include <wtf/Forward.h> - -namespace WebCore { - -class SpeechInput; - -class TextControlInnerElement : public HTMLDivElement { -public: - static PassRefPtr<TextControlInnerElement> create(HTMLElement* shadowParent); - virtual void detach(); - - void attachInnerElement(Node*, PassRefPtr<RenderStyle>, RenderArena*); - -protected: - TextControlInnerElement(Document*, HTMLElement* shadowParent = 0); - -private: - virtual bool isMouseFocusable() const { return false; } -}; - -class TextControlInnerTextElement : public TextControlInnerElement { -public: - static PassRefPtr<TextControlInnerTextElement> create(Document*, HTMLElement* shadowParent); - - virtual void defaultEventHandler(Event*); - -private: - TextControlInnerTextElement(Document*, HTMLElement* shadowParent); - virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); -}; - -class SearchFieldResultsButtonElement : public TextControlInnerElement { -public: - static PassRefPtr<SearchFieldResultsButtonElement> create(Document*); - - virtual void defaultEventHandler(Event*); - -private: - SearchFieldResultsButtonElement(Document*); -}; - -class SearchFieldCancelButtonElement : public TextControlInnerElement { -public: - static PassRefPtr<SearchFieldCancelButtonElement> create(Document*); - - virtual void defaultEventHandler(Event*); - -private: - SearchFieldCancelButtonElement(Document*); - - virtual void detach(); - - bool m_capturing; -}; - -class SpinButtonElement : public TextControlInnerElement { -public: - enum UpDownState { - Indeterminate, // Hovered, but the event is not handled. - Down, - Up, - }; - - static PassRefPtr<SpinButtonElement> create(HTMLElement*); - UpDownState upDownState() const { return m_upDownState; } - -private: - SpinButtonElement(HTMLElement*); - - virtual void detach(); - virtual bool isSpinButtonElement() const { return true; } - // FIXME: shadowAncestorNode() should be const. - virtual bool isEnabledFormControl() const { return static_cast<Element*>(const_cast<SpinButtonElement*>(this)->shadowAncestorNode())->isEnabledFormControl(); } - virtual bool isReadOnlyFormControl() const { return static_cast<Element*>(const_cast<SpinButtonElement*>(this)->shadowAncestorNode())->isReadOnlyFormControl(); } - virtual void defaultEventHandler(Event*); - void startRepeatingTimer(); - void stopRepeatingTimer(); - void repeatingTimerFired(Timer<SpinButtonElement>*); - virtual void setHovered(bool = true); - - bool m_capturing; - UpDownState m_upDownState; - UpDownState m_pressStartingState; - Timer<SpinButtonElement> m_repeatingTimer; -}; - -#if ENABLE(INPUT_SPEECH) - -class InputFieldSpeechButtonElement - : public TextControlInnerElement, - public SpeechInputListener { -public: - enum SpeechInputState { - Idle, - Recording, - Recognizing, - }; - - static PassRefPtr<InputFieldSpeechButtonElement> create(HTMLElement*); - virtual ~InputFieldSpeechButtonElement(); - - virtual void detach(); - virtual void defaultEventHandler(Event*); - SpeechInputState state() const { return m_state; } - - // SpeechInputListener methods. - void didCompleteRecording(int); - void didCompleteRecognition(int); - void setRecognitionResult(int, const SpeechInputResultArray&); - -private: - InputFieldSpeechButtonElement(HTMLElement*); - SpeechInput* speechInput(); - void setState(SpeechInputState state); - - bool m_capturing; - SpeechInputState m_state; - int m_listenerId; - SpeechInputResultArray m_results; -}; - -#endif // ENABLE(INPUT_SPEECH) - -} // namespace - -#endif diff --git a/Source/WebCore/rendering/VerticalPositionCache.h b/Source/WebCore/rendering/VerticalPositionCache.h index b25b2f6..bb39877 100644 --- a/Source/WebCore/rendering/VerticalPositionCache.h +++ b/Source/WebCore/rendering/VerticalPositionCache.h @@ -34,8 +34,6 @@ namespace WebCore { class RenderObject; // Values for vertical alignment. -const int PositionTop = -0x7fffffff; -const int PositionBottom = 0x7fffffff; const int PositionUndefined = 0x80000000; class VerticalPositionCache { diff --git a/Source/WebCore/rendering/break_lines.cpp b/Source/WebCore/rendering/break_lines.cpp index b888fb8..9ac3375 100644 --- a/Source/WebCore/rendering/break_lines.cpp +++ b/Source/WebCore/rendering/break_lines.cpp @@ -158,11 +158,10 @@ static inline TextBreakLocatorRef lineBreakLocator() } #endif -int nextBreakablePosition(const UChar* str, int pos, int len, bool treatNoBreakSpaceAsBreak) +int nextBreakablePosition(LazyLineBreakIterator& lazyBreakIterator, int pos, bool treatNoBreakSpaceAsBreak) { -#if !PLATFORM(MAC) || !defined(BUILDING_ON_TIGER) - TextBreakIterator* breakIterator = 0; -#endif + const UChar* str = lazyBreakIterator.string(); + int len = lazyBreakIterator.length(); int nextBreak = -1; UChar lastCh = pos > 0 ? str[pos - 1] : 0; @@ -175,8 +174,7 @@ int nextBreakablePosition(const UChar* str, int pos, int len, bool treatNoBreakS if (needsLineBreakIterator(ch) || needsLineBreakIterator(lastCh)) { if (nextBreak < i && i) { #if !PLATFORM(MAC) || !defined(BUILDING_ON_TIGER) - if (!breakIterator) - breakIterator = lineBreakIterator(str, len); + TextBreakIterator* breakIterator = lazyBreakIterator.get(); if (breakIterator) nextBreak = textBreakFollowing(breakIterator, i - 1); #else diff --git a/Source/WebCore/rendering/break_lines.h b/Source/WebCore/rendering/break_lines.h index 4d6b8dc..6600e52 100644 --- a/Source/WebCore/rendering/break_lines.h +++ b/Source/WebCore/rendering/break_lines.h @@ -25,14 +25,16 @@ namespace WebCore { - int nextBreakablePosition(const UChar*, int pos, int len, bool breakNBSP = false); - - inline bool isBreakable(const UChar* str, int pos, int len, int& nextBreakable, bool breakNBSP = false) - { - if (pos > nextBreakable) - nextBreakable = nextBreakablePosition(str, pos, len, breakNBSP); - return pos == nextBreakable; - } +class LazyLineBreakIterator; + +int nextBreakablePosition(LazyLineBreakIterator&, int pos, bool breakNBSP = false); + +inline bool isBreakable(LazyLineBreakIterator& lazyBreakIterator, int pos, int& nextBreakable, bool breakNBSP = false) +{ + if (pos > nextBreakable) + nextBreakable = nextBreakablePosition(lazyBreakIterator, pos, breakNBSP); + return pos == nextBreakable; +} } // namespace WebCore diff --git a/Source/WebCore/rendering/style/ContentData.cpp b/Source/WebCore/rendering/style/ContentData.cpp index d150f77..ab504fd 100644 --- a/Source/WebCore/rendering/style/ContentData.cpp +++ b/Source/WebCore/rendering/style/ContentData.cpp @@ -51,6 +51,8 @@ bool ContentData::dataEquivalent(const ContentData& other) const return StyleImage::imagesEquivalent(image(), other.image()); case CONTENT_COUNTER: return *counter() == *other.counter(); + case CONTENT_QUOTE: + return quote() == other.quote(); } ASSERT_NOT_REACHED(); @@ -71,6 +73,8 @@ void ContentData::deleteContent() case CONTENT_COUNTER: delete m_content.m_counter; break; + case CONTENT_QUOTE: + break; } m_type = CONTENT_NONE; diff --git a/Source/WebCore/rendering/style/ContentData.h b/Source/WebCore/rendering/style/ContentData.h index 15f6912..cce3754 100644 --- a/Source/WebCore/rendering/style/ContentData.h +++ b/Source/WebCore/rendering/style/ContentData.h @@ -51,6 +51,7 @@ public: bool isCounter() const { return m_type == CONTENT_COUNTER; } bool isImage() const { return m_type == CONTENT_OBJECT; } bool isNone() const { return m_type == CONTENT_NONE; } + bool isQuote() const { return m_type == CONTENT_QUOTE; } bool isText() const { return m_type == CONTENT_TEXT; } StyleContentType type() const { return m_type; } @@ -93,6 +94,18 @@ public: m_content.m_counter = counter.leakPtr(); } + QuoteType quote() const + { + ASSERT(isQuote()); + return m_content.m_quote; + } + void setQuote(QuoteType type) + { + deleteContent(); + m_type = CONTENT_QUOTE; + m_content.m_quote = type; + } + ContentData* next() const { return m_next.get(); } void setNext(PassOwnPtr<ContentData> next) { m_next = next; } @@ -104,6 +117,7 @@ private: StyleImage* m_image; StringImpl* m_text; CounterContent* m_counter; + QuoteType m_quote; } m_content; OwnPtr<ContentData> m_next; }; diff --git a/Source/WebCore/rendering/style/QuotesData.cpp b/Source/WebCore/rendering/style/QuotesData.cpp new file mode 100644 index 0000000..829fe3f --- /dev/null +++ b/Source/WebCore/rendering/style/QuotesData.cpp @@ -0,0 +1,60 @@ +/** + * Copyright (C) 2011 Nokia Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "QuotesData.h" + +namespace WebCore { + +QuotesData* QuotesData::create(int stringCount) +{ + char* tmp = new char[sizeof(QuotesData)+sizeof(String)*stringCount]; + if (!tmp) + return 0; + new (tmp) QuotesData(stringCount); + for (int i = 0; i < stringCount; ++i) + new (tmp +sizeof(QuotesData) + sizeof(String)*i) String(); + return reinterpret_cast<QuotesData*>(tmp); +} + +bool QuotesData::operator==(const QuotesData& other) const +{ + if (this == &other) + return true; + if (!&other || !this) + return false; + if (length != other.length) + return false; + const String* myData = data(); + const String* otherData = other.data(); + for (int i = length-1; i >= 0; --i) + if (myData[i] != otherData[i]) + return false; + return true; +} + +QuotesData::~QuotesData() +{ + String* p = data(); + for (int i = 0; i < length; ++i) + p[i].~String(); +} + +} // namespace WebCore diff --git a/Source/WebCore/rendering/style/QuotesData.h b/Source/WebCore/rendering/style/QuotesData.h new file mode 100644 index 0000000..df8a6dd --- /dev/null +++ b/Source/WebCore/rendering/style/QuotesData.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2011 Nokia Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef QuotesData_h +#define QuotesData_h + +#include <wtf/RefPtr.h> +#include <wtf/text/WTFString.h> + +namespace WebCore { + +class QuotesData : public RefCounted<QuotesData> { +public: + virtual ~QuotesData(); + static QuotesData* create(int stringCount); + String* data() { return reinterpret_cast<String*>(this+1); } + const String* data() const { return reinterpret_cast<const String*>(this+1); } + int length; + bool operator==(const QuotesData&) const; + void operator delete(void* p) { delete[] static_cast<char*>(p); } +private: + QuotesData(int stringCount) : length(stringCount) {} +}; + +} +#endif // QuotesData_h diff --git a/Source/WebCore/rendering/style/RenderStyle.cpp b/Source/WebCore/rendering/style/RenderStyle.cpp index b76a350..122b762 100644 --- a/Source/WebCore/rendering/style/RenderStyle.cpp +++ b/Source/WebCore/rendering/style/RenderStyle.cpp @@ -27,6 +27,7 @@ #include "CSSPropertyNames.h" #include "CSSStyleSelector.h" #include "FontSelector.h" +#include "QuotesData.h" #include "RenderArena.h" #include "RenderObject.h" #include "ScaleTransformOperation.h" @@ -404,8 +405,10 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon rareInheritedData->khtmlLineBreak != other->rareInheritedData->khtmlLineBreak || rareInheritedData->textSecurity != other->rareInheritedData->textSecurity || rareInheritedData->hyphens != other->rareInheritedData->hyphens || + rareInheritedData->hyphenationLimitBefore != other->rareInheritedData->hyphenationLimitBefore || + rareInheritedData->hyphenationLimitAfter != other->rareInheritedData->hyphenationLimitAfter || rareInheritedData->hyphenationString != other->rareInheritedData->hyphenationString || - rareInheritedData->hyphenationLocale != other->rareInheritedData->hyphenationLocale || + rareInheritedData->locale != other->rareInheritedData->locale || rareInheritedData->textEmphasisMark != other->rareInheritedData->textEmphasisMark || rareInheritedData->textEmphasisPosition != other->rareInheritedData->textEmphasisPosition || rareInheritedData->textEmphasisCustomMark != other->rareInheritedData->textEmphasisCustomMark) @@ -605,6 +608,13 @@ void RenderStyle::setCursorList(PassRefPtr<CursorList> other) rareInheritedData.access()->cursorData = other; } +void RenderStyle::setQuotes(PassRefPtr<QuotesData> q) +{ + if (*rareInheritedData->quotes.get() == *q.get()) + return; + rareInheritedData.access()->quotes = q; +} + void RenderStyle::clearCursorList() { if (rareInheritedData->cursorData) @@ -672,6 +682,11 @@ void RenderStyle::setContent(PassOwnPtr<CounterContent> counter, bool add) prepareToSetContent(0, add)->setCounter(counter); } +void RenderStyle::setContent(QuoteType quote, bool add) +{ + prepareToSetContent(0, add)->setQuote(quote); +} + void RenderStyle::applyTransform(TransformationMatrix& transform, const IntSize& borderBoxSize, ApplyTransformOrigin applyOrigin) const { // transform-origin brackets the transform with translate operations. diff --git a/Source/WebCore/rendering/style/RenderStyle.h b/Source/WebCore/rendering/style/RenderStyle.h index 7b79db1..79ed6e4 100644 --- a/Source/WebCore/rendering/style/RenderStyle.h +++ b/Source/WebCore/rendering/style/RenderStyle.h @@ -372,10 +372,18 @@ public: Length top() const { return surround->offset.top(); } Length bottom() const { return surround->offset.bottom(); } + // Accessors for positioned object edges that take into account writing mode. + Length logicalLeft() const { return isHorizontalWritingMode() ? left() : top(); } + Length logicalRight() const { return isHorizontalWritingMode() ? right() : bottom(); } + Length logicalTop() const { return isHorizontalWritingMode() ? (isFlippedBlocksWritingMode() ? bottom() : top()) : (isFlippedBlocksWritingMode() ? right() : left()); } + Length logicalBottom() const { return isHorizontalWritingMode() ? (isFlippedBlocksWritingMode() ? top() : bottom()) : (isFlippedBlocksWritingMode() ? left() : right()); } + // Whether or not a positioned element requires normal flow x/y to be computed // to determine its position. - bool hasStaticX() const { return (left().isAuto() && right().isAuto()) || left().isStatic() || right().isStatic(); } - bool hasStaticY() const { return (top().isAuto() && bottom().isAuto()) || top().isStatic(); } + bool hasAutoLeftAndRight() const { return left().isAuto() && right().isAuto(); } + bool hasAutoTopAndBottom() const { return top().isAuto() && bottom().isAuto(); } + bool hasStaticInlinePosition(bool horizontal) const { return horizontal ? hasAutoLeftAndRight() : hasAutoTopAndBottom(); } + bool hasStaticBlockPosition(bool horizontal) const { return horizontal ? hasAutoTopAndBottom() : hasAutoLeftAndRight(); } EPosition position() const { return static_cast<EPosition>(noninherited_flags._position); } EFloat floating() const { return static_cast<EFloat>(noninherited_flags._floating); } @@ -686,8 +694,10 @@ public: EMatchNearestMailBlockquoteColor matchNearestMailBlockquoteColor() const { return static_cast<EMatchNearestMailBlockquoteColor>(rareNonInheritedData->matchNearestMailBlockquoteColor); } const AtomicString& highlight() const { return rareInheritedData->highlight; } Hyphens hyphens() const { return static_cast<Hyphens>(rareInheritedData->hyphens); } + short hyphenationLimitBefore() const { return rareInheritedData->hyphenationLimitBefore; } + short hyphenationLimitAfter() const { return rareInheritedData->hyphenationLimitAfter; } const AtomicString& hyphenationString() const { return rareInheritedData->hyphenationString; } - const AtomicString& hyphenationLocale() const { return rareInheritedData->hyphenationLocale; } + const AtomicString& locale() const { return rareInheritedData->locale; } EBorderFit borderFit() const { return static_cast<EBorderFit>(rareNonInheritedData->m_borderFit); } EResize resize() const { return static_cast<EResize>(rareInheritedData->resize); } float columnWidth() const { return rareNonInheritedData->m_multiCol->m_width; } @@ -1055,8 +1065,10 @@ public: void setMatchNearestMailBlockquoteColor(EMatchNearestMailBlockquoteColor c) { SET_VAR(rareNonInheritedData, matchNearestMailBlockquoteColor, c); } void setHighlight(const AtomicString& h) { SET_VAR(rareInheritedData, highlight, h); } void setHyphens(Hyphens h) { SET_VAR(rareInheritedData, hyphens, h); } + void setHyphenationLimitBefore(short limit) { SET_VAR(rareInheritedData, hyphenationLimitBefore, limit); } + void setHyphenationLimitAfter(short limit) { SET_VAR(rareInheritedData, hyphenationLimitAfter, limit); } void setHyphenationString(const AtomicString& h) { SET_VAR(rareInheritedData, hyphenationString, h); } - void setHyphenationLocale(const AtomicString& h) { SET_VAR(rareInheritedData, hyphenationLocale, h); } + void setLocale(const AtomicString& locale) { SET_VAR(rareInheritedData, locale, locale); } void setBorderFit(EBorderFit b) { SET_VAR(rareNonInheritedData, m_borderFit, b); } void setResize(EResize r) { SET_VAR(rareInheritedData, resize, r); } void setColumnWidth(float f) { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_autoWidth, false); SET_VAR(rareNonInheritedData.access()->m_multiCol, m_width, f); } @@ -1161,10 +1173,14 @@ public: void setContent(PassRefPtr<StringImpl>, bool add = false); void setContent(PassRefPtr<StyleImage>, bool add = false); void setContent(PassOwnPtr<CounterContent>, bool add = false); + void setContent(QuoteType, bool add = false); const CounterDirectiveMap* counterDirectives() const; CounterDirectiveMap& accessCounterDirectives(); + QuotesData* quotes() const { return rareInheritedData->quotes.get(); } + void setQuotes(PassRefPtr<QuotesData>); + const AtomicString& hyphenString() const; bool inheritedNotEqual(const RenderStyle*) const; @@ -1296,8 +1312,10 @@ public: static const AtomicString& initialHighlight() { return nullAtom; } static ESpeak initialSpeak() { return SpeakNormal; } static Hyphens initialHyphens() { return HyphensManual; } + static short initialHyphenationLimitBefore() { return -1; } + static short initialHyphenationLimitAfter() { return -1; } static const AtomicString& initialHyphenationString() { return nullAtom; } - static const AtomicString& initialHyphenationLocale() { return nullAtom; } + static const AtomicString& initialLocale() { return nullAtom; } static EBorderFit initialBorderFit() { return BorderFitBorder; } static EResize initialResize() { return RESIZE_NONE; } static ControlPart initialAppearance() { return NoControlPart; } diff --git a/Source/WebCore/rendering/style/RenderStyleConstants.h b/Source/WebCore/rendering/style/RenderStyleConstants.h index 44cd3f5..3c62dbe 100644 --- a/Source/WebCore/rendering/style/RenderStyleConstants.h +++ b/Source/WebCore/rendering/style/RenderStyleConstants.h @@ -297,7 +297,11 @@ enum EListStyleType { }; enum StyleContentType { - CONTENT_NONE, CONTENT_OBJECT, CONTENT_TEXT, CONTENT_COUNTER + CONTENT_NONE, CONTENT_OBJECT, CONTENT_TEXT, CONTENT_COUNTER, CONTENT_QUOTE +}; + +enum QuoteType { + OPEN_QUOTE, CLOSE_QUOTE, NO_OPEN_QUOTE, NO_CLOSE_QUOTE }; enum EBorderFit { BorderFitBorder, BorderFitLines }; diff --git a/Source/WebCore/rendering/style/SVGRenderStyle.cpp b/Source/WebCore/rendering/style/SVGRenderStyle.cpp index 28f80f2..1ee1f36 100644 --- a/Source/WebCore/rendering/style/SVGRenderStyle.cpp +++ b/Source/WebCore/rendering/style/SVGRenderStyle.cpp @@ -169,7 +169,9 @@ StyleDifference SVGRenderStyle::diff(const SVGRenderStyle* other) const // Some stroke properties, requires relayouts, as the cached stroke boundaries need to be recalculated. if (stroke != other->stroke) { if (stroke->width != other->stroke->width - || stroke->paint != other->stroke->paint + || stroke->paintType != other->stroke->paintType + || stroke->paintColor != other->stroke->paintColor + || stroke->paintUri != other->stroke->paintUri || stroke->miterLimit != other->stroke->miterLimit || stroke->dashArray != other->stroke->dashArray || stroke->dashOffset != other->stroke->dashOffset) @@ -191,7 +193,7 @@ StyleDifference SVGRenderStyle::diff(const SVGRenderStyle* other) const } // If fill changes, we just need to repaint. Fill boundaries are not influenced by this, only by the Path, that RenderSVGPath contains. - if (fill != other->fill) + if (fill->paintType != other->fill->paintType || fill->paintColor != other->fill->paintColor || fill->paintUri != other->fill->paintUri) return StyleDifferenceRepaint; // If gradient stops change, we just need to repaint. Style updates are already handled through RenderSVGGradientSTop. diff --git a/Source/WebCore/rendering/style/SVGRenderStyle.h b/Source/WebCore/rendering/style/SVGRenderStyle.h index 7f032e7..88a48df 100644 --- a/Source/WebCore/rendering/style/SVGRenderStyle.h +++ b/Source/WebCore/rendering/style/SVGRenderStyle.h @@ -70,15 +70,19 @@ public: static SVGWritingMode initialWritingMode() { return WM_LRTB; } static EGlyphOrientation initialGlyphOrientationHorizontal() { return GO_0DEG; } static EGlyphOrientation initialGlyphOrientationVertical() { return GO_AUTO; } - static float initialFillOpacity() { return 1.0f; } - static SVGPaint* initialFillPaint() { return SVGPaint::defaultFill(); } - static float initialStrokeOpacity() { return 1.0f; } - static SVGPaint* initialStrokePaint() { return SVGPaint::defaultStroke(); } + static float initialFillOpacity() { return 1; } + static SVGPaint::SVGPaintType initialFillPaintType() { return SVGPaint::SVG_PAINTTYPE_RGBCOLOR; } + static Color initialFillPaintColor() { return Color::black; } + static String initialFillPaintUri() { return String(); } + static float initialStrokeOpacity() { return 1; } + static SVGPaint::SVGPaintType initialStrokePaintType() { return SVGPaint::SVG_PAINTTYPE_NONE; } + static Color initialStrokePaintColor() { return Color(); } + static String initialStrokePaintUri() { return String(); } static Vector<SVGLength> initialStrokeDashArray() { return Vector<SVGLength>(); } - static float initialStrokeMiterLimit() { return 4.0f; } - static float initialStopOpacity() { return 1.0f; } + static float initialStrokeMiterLimit() { return 4; } + static float initialStopOpacity() { return 1; } static Color initialStopColor() { return Color(0, 0, 0); } - static float initialFloodOpacity() { return 1.0f; } + static float initialFloodOpacity() { return 1; } static Color initialFloodColor() { return Color(0, 0, 0); } static Color initialLightingColor() { return Color(255, 255, 255); } static ShadowData* initialShadow() { return 0; } @@ -150,10 +154,14 @@ public: fill.access()->opacity = obj; } - void setFillPaint(PassRefPtr<SVGPaint> obj) + void setFillPaint(SVGPaint::SVGPaintType type, const Color& color, const String& uri) { - if (!(fill->paint == obj)) - fill.access()->paint = obj; + if (!(fill->paintType == type)) + fill.access()->paintType = type; + if (!(fill->paintColor == color)) + fill.access()->paintColor = color; + if (!(fill->paintUri == uri)) + fill.access()->paintUri = uri; } void setStrokeOpacity(float obj) @@ -162,10 +170,14 @@ public: stroke.access()->opacity = obj; } - void setStrokePaint(PassRefPtr<SVGPaint> obj) + void setStrokePaint(SVGPaint::SVGPaintType type, const Color& color, const String& uri) { - if (!(stroke->paint == obj)) - stroke.access()->paint = obj; + if (!(stroke->paintType == type)) + stroke.access()->paintType = type; + if (!(stroke->paintColor == color)) + stroke.access()->paintColor = color; + if (!(stroke->paintUri == uri)) + stroke.access()->paintUri = uri; } void setStrokeDashArray(const Vector<SVGLength>& obj) @@ -293,9 +305,13 @@ public: EGlyphOrientation glyphOrientationHorizontal() const { return (EGlyphOrientation) svg_inherited_flags._glyphOrientationHorizontal; } EGlyphOrientation glyphOrientationVertical() const { return (EGlyphOrientation) svg_inherited_flags._glyphOrientationVertical; } float fillOpacity() const { return fill->opacity; } - SVGPaint* fillPaint() const { return fill->paint.get(); } + const SVGPaint::SVGPaintType& fillPaintType() const { return fill->paintType; } + const Color& fillPaintColor() const { return fill->paintColor; } + const String& fillPaintUri() const { return fill->paintUri; } float strokeOpacity() const { return stroke->opacity; } - SVGPaint* strokePaint() const { return stroke->paint.get(); } + const SVGPaint::SVGPaintType& strokePaintType() const { return stroke->paintType; } + const Color& strokePaintColor() const { return stroke->paintColor; } + const String& strokePaintUri() const { return stroke->paintUri; } Vector<SVGLength> strokeDashArray() const { return stroke->dashArray; } float strokeMiterLimit() const { return stroke->miterLimit; } SVGLength strokeWidth() const { return stroke->width; } @@ -320,8 +336,8 @@ public: bool hasMasker() const { return !maskerResource().isEmpty(); } bool hasFilter() const { return !filterResource().isEmpty(); } bool hasMarkers() const { return !markerStartResource().isEmpty() || !markerMidResource().isEmpty() || !markerEndResource().isEmpty(); } - bool hasStroke() const { return strokePaint()->paintType() != SVGPaint::SVG_PAINTTYPE_NONE; } - bool hasFill() const { return fillPaint()->paintType() != SVGPaint::SVG_PAINTTYPE_NONE; } + bool hasStroke() const { return strokePaintType() != SVGPaint::SVG_PAINTTYPE_NONE; } + bool hasFill() const { return fillPaintType() != SVGPaint::SVG_PAINTTYPE_NONE; } bool isVerticalWritingMode() const { return writingMode() == WM_TBRL || writingMode() == WM_TB; } protected: diff --git a/Source/WebCore/rendering/style/SVGRenderStyleDefs.cpp b/Source/WebCore/rendering/style/SVGRenderStyleDefs.cpp index c30ae6d..fb23e14 100644 --- a/Source/WebCore/rendering/style/SVGRenderStyleDefs.cpp +++ b/Source/WebCore/rendering/style/SVGRenderStyleDefs.cpp @@ -37,35 +37,27 @@ namespace WebCore { StyleFillData::StyleFillData() : opacity(SVGRenderStyle::initialFillOpacity()) - , paint(SVGRenderStyle::initialFillPaint()) + , paintType(SVGRenderStyle::initialFillPaintType()) + , paintColor(SVGRenderStyle::initialFillPaintColor()) + , paintUri(SVGRenderStyle::initialFillPaintUri()) { } StyleFillData::StyleFillData(const StyleFillData& other) : RefCounted<StyleFillData>() , opacity(other.opacity) - , paint(other.paint) + , paintType(other.paintType) + , paintColor(other.paintColor) + , paintUri(other.paintUri) { } bool StyleFillData::operator==(const StyleFillData& other) const { - if (opacity != other.opacity) - return false; - - if (!paint || !other.paint) - return paint == other.paint; - - if (paint->paintType() != other.paint->paintType()) - return false; - - if (paint->paintType() == SVGPaint::SVG_PAINTTYPE_URI) - return paint->uri() == other.paint->uri(); - - if (paint->paintType() == SVGPaint::SVG_PAINTTYPE_RGBCOLOR) - return paint->color() == other.paint->color(); - - return paint == other.paint; + return opacity == other.opacity + && paintType == other.paintType + && paintColor == other.paintColor + && paintUri == other.paintUri; } StyleStrokeData::StyleStrokeData() @@ -74,7 +66,9 @@ StyleStrokeData::StyleStrokeData() , width(SVGRenderStyle::initialStrokeWidth()) , dashOffset(SVGRenderStyle::initialStrokeDashOffset()) , dashArray(SVGRenderStyle::initialStrokeDashArray()) - , paint(SVGRenderStyle::initialStrokePaint()) + , paintType(SVGRenderStyle::initialStrokePaintType()) + , paintColor(SVGRenderStyle::initialStrokePaintColor()) + , paintUri(SVGRenderStyle::initialStrokePaintUri()) { } @@ -85,18 +79,22 @@ StyleStrokeData::StyleStrokeData(const StyleStrokeData& other) , width(other.width) , dashOffset(other.dashOffset) , dashArray(other.dashArray) - , paint(other.paint) + , paintType(other.paintType) + , paintColor(other.paintColor) + , paintUri(other.paintUri) { } bool StyleStrokeData::operator==(const StyleStrokeData& other) const { - return paint == other.paint - && width == other.width + return width == other.width && opacity == other.opacity && miterLimit == other.miterLimit && dashOffset == other.dashOffset - && dashArray == other.dashArray; + && dashArray == other.dashArray + && paintType == other.paintType + && paintColor == other.paintColor + && paintUri == other.paintUri; } StyleStopData::StyleStopData() diff --git a/Source/WebCore/rendering/style/SVGRenderStyleDefs.h b/Source/WebCore/rendering/style/SVGRenderStyleDefs.h index de058a2..00358a0 100644 --- a/Source/WebCore/rendering/style/SVGRenderStyleDefs.h +++ b/Source/WebCore/rendering/style/SVGRenderStyleDefs.h @@ -29,9 +29,8 @@ #define SVGRenderStyleDefs_h #if ENABLE(SVG) -#include "Color.h" -#include "PlatformString.h" #include "SVGLength.h" +#include "SVGPaint.h" #include "ShadowData.h" #include <wtf/OwnPtr.h> #include <wtf/PassOwnPtr.h> @@ -98,7 +97,7 @@ namespace WebCore { public: static PassRefPtr<StyleFillData> create() { return adoptRef(new StyleFillData); } PassRefPtr<StyleFillData> copy() const { return adoptRef(new StyleFillData(*this)); } - + bool operator==(const StyleFillData&) const; bool operator!=(const StyleFillData& other) const { @@ -106,7 +105,9 @@ namespace WebCore { } float opacity; - RefPtr<SVGPaint> paint; + SVGPaint::SVGPaintType paintType; + Color paintColor; + String paintUri; private: StyleFillData(); @@ -131,7 +132,9 @@ namespace WebCore { SVGLength dashOffset; Vector<SVGLength> dashArray; - RefPtr<SVGPaint> paint; + SVGPaint::SVGPaintType paintType; + Color paintColor; + String paintUri; private: StyleStrokeData(); @@ -262,5 +265,4 @@ namespace WebCore { } // namespace WebCore #endif // ENABLE(SVG) - #endif // SVGRenderStyleDefs_h diff --git a/Source/WebCore/rendering/style/StyleAllInOne.cpp b/Source/WebCore/rendering/style/StyleAllInOne.cpp index 25b539f..967fa00 100644 --- a/Source/WebCore/rendering/style/StyleAllInOne.cpp +++ b/Source/WebCore/rendering/style/StyleAllInOne.cpp @@ -30,6 +30,7 @@ #include "FillLayer.cpp" #include "KeyframeList.cpp" #include "NinePieceImage.cpp" +#include "QuotesData.cpp" #include "RenderStyle.cpp" #include "SVGRenderStyle.cpp" #include "SVGRenderStyleDefs.cpp" diff --git a/Source/WebCore/rendering/style/StyleRareInheritedData.cpp b/Source/WebCore/rendering/style/StyleRareInheritedData.cpp index 0953dae..2798fd1 100644 --- a/Source/WebCore/rendering/style/StyleRareInheritedData.cpp +++ b/Source/WebCore/rendering/style/StyleRareInheritedData.cpp @@ -23,6 +23,7 @@ #include "StyleRareInheritedData.h" #include "CursorList.h" +#include "QuotesData.h" #include "RenderStyle.h" #include "RenderStyleConstants.h" #include "ShadowData.h" @@ -65,6 +66,8 @@ StyleRareInheritedData::StyleRareInheritedData() , textEmphasisFill(TextEmphasisFillFilled) , textEmphasisMark(TextEmphasisMarkNone) , textEmphasisPosition(TextEmphasisPositionOver) + , hyphenationLimitBefore(-1) + , hyphenationLimitAfter(-1) { } @@ -111,7 +114,9 @@ StyleRareInheritedData::StyleRareInheritedData(const StyleRareInheritedData& o) , textEmphasisMark(o.textEmphasisMark) , textEmphasisPosition(o.textEmphasisPosition) , hyphenationString(o.hyphenationString) - , hyphenationLocale(o.hyphenationLocale) + , hyphenationLimitBefore(o.hyphenationLimitBefore) + , hyphenationLimitAfter(o.hyphenationLimitAfter) + , locale(o.locale) , textEmphasisCustomMark(o.textEmphasisCustomMark) { } @@ -169,12 +174,15 @@ bool StyleRareInheritedData::operator==(const StyleRareInheritedData& o) const && colorSpace == o.colorSpace && speak == o.speak && hyphens == o.hyphens + && hyphenationLimitBefore == o.hyphenationLimitBefore + && hyphenationLimitAfter == o.hyphenationLimitAfter && textEmphasisFill == o.textEmphasisFill && textEmphasisMark == o.textEmphasisMark && textEmphasisPosition == o.textEmphasisPosition && hyphenationString == o.hyphenationString - && hyphenationLocale == o.hyphenationLocale - && textEmphasisCustomMark == o.textEmphasisCustomMark; + && locale == o.locale + && textEmphasisCustomMark == o.textEmphasisCustomMark + && *quotes == *o.quotes; } bool StyleRareInheritedData::shadowDataEquivalent(const StyleRareInheritedData& o) const diff --git a/Source/WebCore/rendering/style/StyleRareInheritedData.h b/Source/WebCore/rendering/style/StyleRareInheritedData.h index a370934..d4f233c 100644 --- a/Source/WebCore/rendering/style/StyleRareInheritedData.h +++ b/Source/WebCore/rendering/style/StyleRareInheritedData.h @@ -34,6 +34,7 @@ namespace WebCore { class CursorList; +class QuotesData; class ShadowData; // This struct is for rarely used inherited CSS3, CSS2, and WebKit-specific properties. @@ -100,9 +101,13 @@ public: unsigned textEmphasisPosition : 1; // TextEmphasisPosition AtomicString hyphenationString; - AtomicString hyphenationLocale; + short hyphenationLimitBefore; + short hyphenationLimitAfter; + + AtomicString locale; AtomicString textEmphasisCustomMark; + RefPtr<QuotesData> quotes; private: StyleRareInheritedData(); diff --git a/Source/WebCore/rendering/svg/RenderSVGResource.cpp b/Source/WebCore/rendering/svg/RenderSVGResource.cpp index c0b16c5..12ed53a 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResource.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGResource.cpp @@ -51,33 +51,36 @@ static inline RenderSVGResource* requestPaintingResource(RenderSVGResourceMode m return 0; } - SVGPaint* paint = mode == ApplyToFillMode ? svgStyle->fillPaint() : svgStyle->strokePaint(); - ASSERT(paint); - - SVGPaint::SVGPaintType paintType = paint->paintType(); + bool applyToFill = mode == ApplyToFillMode; + SVGPaint::SVGPaintType paintType = applyToFill ? svgStyle->fillPaintType() : svgStyle->strokePaintType(); if (paintType == SVGPaint::SVG_PAINTTYPE_NONE) return 0; Color color; - if (paintType == SVGPaint::SVG_PAINTTYPE_RGBCOLOR - || paintType == SVGPaint::SVG_PAINTTYPE_RGBCOLOR_ICCCOLOR - || paintType == SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR - || paintType == SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR_ICCCOLOR) - color = paint->color(); - else if (paintType == SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR || paintType == SVGPaint::SVG_PAINTTYPE_URI_CURRENTCOLOR) - color = style->visitedDependentColor(CSSPropertyColor); + switch (paintType) { + case SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR: + case SVGPaint::SVG_PAINTTYPE_RGBCOLOR: + case SVGPaint::SVG_PAINTTYPE_RGBCOLOR_ICCCOLOR: + case SVGPaint::SVG_PAINTTYPE_URI_CURRENTCOLOR: + case SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR: + case SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR_ICCCOLOR: + color = applyToFill ? svgStyle->fillPaintColor() : svgStyle->strokePaintColor(); + default: + break; + } if (style->insideLink() == InsideVisitedLink) { RenderStyle* visitedStyle = style->getCachedPseudoStyle(VISITED_LINK); ASSERT(visitedStyle); - if (SVGPaint* visitedPaint = mode == ApplyToFillMode ? visitedStyle->svgStyle()->fillPaint() : visitedStyle->svgStyle()->strokePaint()) { - // For SVG_PAINTTYPE_CURRENTCOLOR, 'color' already contains the 'visitedColor'. - if (visitedPaint->paintType() < SVGPaint::SVG_PAINTTYPE_URI_NONE && visitedPaint->paintType() != SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR) { - const Color& visitedColor = visitedPaint->color(); - if (visitedColor.isValid()) - color = Color(visitedColor.red(), visitedColor.green(), visitedColor.blue(), color.alpha()); - } + const SVGRenderStyle* svgVisitedStyle = visitedStyle->svgStyle(); + SVGPaint::SVGPaintType visitedPaintType = applyToFill ? svgVisitedStyle->fillPaintType() : svgVisitedStyle->strokePaintType(); + + // For SVG_PAINTTYPE_CURRENTCOLOR, 'color' already contains the 'visitedColor'. + if (visitedPaintType < SVGPaint::SVG_PAINTTYPE_URI_NONE && visitedPaintType != SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR) { + const Color& visitedColor = applyToFill ? svgVisitedStyle->fillPaintColor() : svgVisitedStyle->strokePaintColor(); + if (visitedColor.isValid()) + color = Color(visitedColor.red(), visitedColor.green(), visitedColor.blue(), color.alpha()); } } diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceClipper.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceClipper.cpp index c57f8b0..245a859 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceClipper.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGResourceClipper.cpp @@ -254,8 +254,8 @@ bool RenderSVGResourceClipper::drawContentIntoMaskImage(ClipperData* clipperData RefPtr<RenderStyle> oldRenderStyle = renderer->style(); RefPtr<RenderStyle> newRenderStyle = RenderStyle::clone(oldRenderStyle.get()); SVGRenderStyle* svgStyle = newRenderStyle.get()->accessSVGStyle(); - svgStyle->setFillPaint(SVGPaint::defaultFill()); - svgStyle->setStrokePaint(SVGPaint::defaultStroke()); + svgStyle->setFillPaint(SVGRenderStyle::initialFillPaintType(), SVGRenderStyle::initialFillPaintColor(), SVGRenderStyle::initialFillPaintUri()); + svgStyle->setStrokePaint(SVGRenderStyle::initialStrokePaintType(), SVGRenderStyle::initialStrokePaintColor(), SVGRenderStyle::initialStrokePaintUri()); svgStyle->setFillRule(newClipRule); newRenderStyle.get()->setOpacity(1.0f); svgStyle->setFillOpacity(1.0f); diff --git a/Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp b/Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp index 1b14ce4..b82be1b 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp @@ -233,10 +233,8 @@ bool RenderSVGResourcePattern::buildTileImageTransform(RenderObject* renderer, // Apply viewBox/objectBoundingBox transformations. if (!viewBoxCTM.isIdentity()) tileImageTransform = viewBoxCTM; - else if (attributes.boundingBoxModeContent()) { - tileImageTransform.translate(objectBoundingBox.x(), objectBoundingBox.y()); + else if (attributes.boundingBoxModeContent()) tileImageTransform.scale(objectBoundingBox.width(), objectBoundingBox.height()); - } return true; } @@ -276,6 +274,8 @@ PassOwnPtr<ImageBuffer> RenderSVGResourcePattern::createTileImage(RenderObject* tileImageContext->concatCTM(tileImageTransform); AffineTransform contentTransformation; + if (attributes.boundingBoxModeContent()) + contentTransformation = tileImageTransform; // Draw the content into the ImageBuffer. for (Node* node = attributes.patternContentElement()->firstChild(); node; node = node->nextSibling()) { diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceSolidColor.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceSolidColor.cpp index 99ea763..d429bdc 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceSolidColor.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGResourceSolidColor.cpp @@ -26,7 +26,11 @@ #include "RenderStyle.h" #include "SVGRenderSupport.h" +<<<<<<< HEAD #if PLATFORM(SKIA) && !PLATFORM(ANDROID) +======= +#if USE(SKIA) +>>>>>>> WebKit at r80534 #include "PlatformContextSkia.h" #endif diff --git a/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp b/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp index 52976f2..05e1357 100644 --- a/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp +++ b/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp @@ -47,7 +47,7 @@ SVGInlineTextBox::SVGInlineTextBox(RenderObject* object) { } -int SVGInlineTextBox::offsetForPosition(int, bool) const +int SVGInlineTextBox::offsetForPosition(float, bool) const { // SVG doesn't use the standard offset <-> position selection system, as it's not suitable for SVGs complex needs. // vertical text selection, inline boxes spanning multiple lines (contrary to HTML, etc.) @@ -76,7 +76,7 @@ int SVGInlineTextBox::offsetForPositionInFragment(const SVGTextFragment& fragmen return fragment.positionListOffset - start() + textRenderer->scaledFont().offsetForPosition(textRun, position * scalingFactor, includePartialGlyphs); } -int SVGInlineTextBox::positionForOffset(int) const +float SVGInlineTextBox::positionForOffset(int) const { // SVG doesn't use the offset <-> position selection system. ASSERT_NOT_REACHED(); @@ -415,9 +415,6 @@ TextRun SVGInlineTextBox::constructTextRun(RenderStyle* style, const SVGTextFrag run.setReferencingRenderObject(text); #endif - // Disable any word/character rounding. - run.disableRoundingHacks(); - // We handle letter & word spacing ourselves. run.disableSpacing(); return run; @@ -519,6 +516,29 @@ void SVGInlineTextBox::paintDecoration(GraphicsContext* context, ETextDecoration } } +static inline void normalizeTransform(AffineTransform& transform) +{ + // Obtain consistent numerical results for the AffineTransform on both 32/64bit platforms. + // Tested with SnowLeopard on Core Duo vs. Core 2 Duo. + static const float s_floatEpsilon = std::numeric_limits<float>::epsilon(); + + if (fabs(transform.a() - 1) <= s_floatEpsilon) + transform.setA(1); + else if (fabs(transform.a() + 1) <= s_floatEpsilon) + transform.setA(-1); + + if (fabs(transform.d() - 1) <= s_floatEpsilon) + transform.setD(1); + else if (fabs(transform.d() + 1) <= s_floatEpsilon) + transform.setD(-1); + + if (fabs(transform.e()) <= s_floatEpsilon) + transform.setE(0); + + if (fabs(transform.f()) <= s_floatEpsilon) + transform.setF(0); +} + void SVGInlineTextBox::paintDecorationWithStyle(GraphicsContext* context, ETextDecoration decoration, const SVGTextFragment& fragment, RenderObject* decorationRenderer) { ASSERT(!m_paintingResource); @@ -546,7 +566,12 @@ void SVGInlineTextBox::paintDecorationWithStyle(GraphicsContext* context, ETextD if (scalingFactor != 1) { width *= scalingFactor; decorationOrigin.scale(scalingFactor, scalingFactor); - context->scale(FloatSize(1 / scalingFactor, 1 / scalingFactor)); + + AffineTransform newTransform = context->getCTM(); + newTransform.scale(1 / scalingFactor); + normalizeTransform(newTransform); + + context->setCTM(newTransform); } decorationOrigin.move(0, -scaledFontMetrics.floatAscent() + positionOffsetForDecoration(decoration, scaledFontMetrics, thickness)); @@ -589,13 +614,21 @@ void SVGInlineTextBox::paintTextWithShadows(GraphicsContext* context, RenderStyl if (shadow) extraOffset = applyShadowToGraphicsContext(context, shadow, shadowRect, false /* stroked */, true /* opaque */, true /* horizontal */); - if (scalingFactor != 1) - context->scale(FloatSize(1 / scalingFactor, 1 / scalingFactor)); + AffineTransform originalTransform; + if (scalingFactor != 1) { + originalTransform = context->getCTM(); + + AffineTransform newTransform = originalTransform; + newTransform.scale(1 / scalingFactor); + normalizeTransform(newTransform); + + context->setCTM(newTransform); + } scaledFont.drawText(context, textRun, textOrigin + extraOffset, startPosition, endPosition); if (scalingFactor != 1) - context->scale(FloatSize(scalingFactor, scalingFactor)); + context->setCTM(originalTransform); restoreGraphicsContextAfterTextPainting(context, textRun); diff --git a/Source/WebCore/rendering/svg/SVGInlineTextBox.h b/Source/WebCore/rendering/svg/SVGInlineTextBox.h index f2ca303..79c836f 100644 --- a/Source/WebCore/rendering/svg/SVGInlineTextBox.h +++ b/Source/WebCore/rendering/svg/SVGInlineTextBox.h @@ -42,8 +42,8 @@ public: virtual int selectionTop() { return m_y; } virtual int selectionHeight() { return m_logicalHeight; } - virtual int offsetForPosition(int x, bool includePartialGlyphs = true) const; - virtual int positionForOffset(int offset) const; + virtual int offsetForPosition(float x, bool includePartialGlyphs = true) const; + virtual float positionForOffset(int offset) const; void paintSelectionBackground(PaintInfo&); virtual void paint(PaintInfo&, int tx, int ty); diff --git a/Source/WebCore/rendering/svg/SVGRenderTreeAsText.cpp b/Source/WebCore/rendering/svg/SVGRenderTreeAsText.cpp index 97e15af..0f94fdd 100644 --- a/Source/WebCore/rendering/svg/SVGRenderTreeAsText.cpp +++ b/Source/WebCore/rendering/svg/SVGRenderTreeAsText.cpp @@ -222,7 +222,7 @@ static TextStream& operator<<(TextStream& ts, const SVGMarkerElement::SVGMarkerU TextStream& operator<<(TextStream& ts, const Color& c) { - return ts << c.name(); + return ts << c.nameForRenderTreeAsText(); } // FIXME: Maybe this should be in KCanvasRenderingStyle.cpp @@ -435,13 +435,16 @@ static void writeRenderSVGTextBox(TextStream& ts, const RenderBlock& text) if (!box) return; - ts << " at (" << text.x() << "," << text.y() << ") size " << box->logicalWidth() << "x" << box->logicalHeight(); + // FIXME: For now use an int for logicalWidth, although this makes it harder + // to detect any changes caused by the conversion to floating point. :( + int logicalWidth = ceilf(box->x() + box->logicalWidth()) - box->x(); + ts << " at (" << text.x() << "," << text.y() << ") size " << logicalWidth << "x" << box->logicalHeight(); // FIXME: Remove this hack, once the new text layout engine is completly landed. We want to preserve the old layout test results for now. ts << " contains 1 chunk(s)"; if (text.parent() && (text.parent()->style()->visitedDependentColor(CSSPropertyColor) != text.style()->visitedDependentColor(CSSPropertyColor))) - writeNameValuePair(ts, "color", text.style()->visitedDependentColor(CSSPropertyColor).name()); + writeNameValuePair(ts, "color", text.style()->visitedDependentColor(CSSPropertyColor).nameForRenderTreeAsText()); } static inline void writeSVGInlineTextBox(TextStream& ts, SVGInlineTextBox* textBox, int indent) diff --git a/Source/WebCore/rendering/svg/SVGResources.cpp b/Source/WebCore/rendering/svg/SVGResources.cpp index 9a2c999..d3cd184 100644 --- a/Source/WebCore/rendering/svg/SVGResources.cpp +++ b/Source/WebCore/rendering/svg/SVGResources.cpp @@ -152,15 +152,12 @@ static inline String targetReferenceFromResource(SVGElement* element) return SVGURIReference::getTarget(target); } -static inline RenderSVGResourceContainer* paintingResourceFromSVGPaint(Document* document, SVGPaint* paint, AtomicString& id, bool& hasPendingResource) +static inline RenderSVGResourceContainer* paintingResourceFromSVGPaint(Document* document, const SVGPaint::SVGPaintType& paintType, const String& paintUri, AtomicString& id, bool& hasPendingResource) { - ASSERT(paint); - - SVGPaint::SVGPaintType paintType = paint->paintType(); if (paintType != SVGPaint::SVG_PAINTTYPE_URI && paintType != SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR) return 0; - id = SVGURIReference::getTarget(paint->uri()); + id = SVGURIReference::getTarget(paintUri); RenderSVGResourceContainer* container = getRenderSVGResourceContainerById(document, id); if (!container) { hasPendingResource = true; @@ -259,7 +256,7 @@ bool SVGResources::buildCachedResources(const RenderObject* object, const SVGRen if (style->hasFill()) { bool hasPendingResource = false; AtomicString id; - if (setFill(paintingResourceFromSVGPaint(document, style->fillPaint(), id, hasPendingResource))) + if (setFill(paintingResourceFromSVGPaint(document, style->fillPaintType(), style->fillPaintUri(), id, hasPendingResource))) foundResources = true; else if (hasPendingResource) registerPendingResource(extensions, id, element); @@ -268,7 +265,7 @@ bool SVGResources::buildCachedResources(const RenderObject* object, const SVGRen if (style->hasStroke()) { bool hasPendingResource = false; AtomicString id; - if (setStroke(paintingResourceFromSVGPaint(document, style->strokePaint(), id, hasPendingResource))) + if (setStroke(paintingResourceFromSVGPaint(document, style->strokePaintType(), style->strokePaintUri(), id, hasPendingResource))) foundResources = true; else if (hasPendingResource) registerPendingResource(extensions, id, element); diff --git a/Source/WebCore/rendering/svg/SVGTextMetrics.cpp b/Source/WebCore/rendering/svg/SVGTextMetrics.cpp index ca20d3d..d75bdb3 100644 --- a/Source/WebCore/rendering/svg/SVGTextMetrics.cpp +++ b/Source/WebCore/rendering/svg/SVGTextMetrics.cpp @@ -47,8 +47,9 @@ SVGTextMetrics::SVGTextMetrics(RenderSVGInlineText* textRenderer, const TextRun& int length = 0; // Calculate width/height using the scaled font, divide this result by the scalingFactor afterwards. - m_width = scaledFont.floatWidth(run, extraCharsAvailable, length, m_glyph.name) / scalingFactor; + m_width = scaledFont.width(run, extraCharsAvailable, length, m_glyph.name) / scalingFactor; m_height = scaledFont.fontMetrics().floatHeight() / scalingFactor; + m_glyph.unicodeString = String(run.characters(), length); m_glyph.isValid = true; @@ -79,9 +80,6 @@ static TextRun constructTextRun(RenderSVGInlineText* text, const UChar* characte run.setReferencingRenderObject(text); #endif - // Disable any word/character rounding. - run.disableRoundingHacks(); - // We handle letter & word spacing ourselves. run.disableSpacing(); return run; |
