diff options
author | Steve Block <steveblock@google.com> | 2011-05-25 08:15:24 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2011-05-25 08:15:24 -0700 |
commit | fa91a01aee5d4a80ca6c80f722116b850f09996c (patch) | |
tree | f72740e60d3c3d4f0ab144e88c03d1f134944ce3 /Source/WebCore/rendering | |
parent | 96f37d6d1b390f6690858789706ee6ec25bc1677 (diff) | |
parent | feebf8e7a79ad68b04a1a948e2b8078d6e5f0048 (diff) | |
download | external_webkit-fa91a01aee5d4a80ca6c80f722116b850f09996c.zip external_webkit-fa91a01aee5d4a80ca6c80f722116b850f09996c.tar.gz external_webkit-fa91a01aee5d4a80ca6c80f722116b850f09996c.tar.bz2 |
Merge changes I78ff6a85,Ic85c6405,Ibf903baa,I3a0459db,I35140385,I54790419,I6bfe5d24,Ia9f39b83,I5bcecd5a,I1de96683,I543c6810,I8a5b0878,I0ae670bf,Ide4d58dc,I28ebaf3d,I499d6631,Ie5090e0d,I6d3e5f1f
* changes:
Merge WebKit at r78450: Update ThirdPartyProject.prop
Merge WebKit at r78450: Add new Font::canExpandAroundIdeographsInComplexText()
Merge WebKit at r78450: Add new ChromeClient::selectItemAlignmentFollowsMenuWritingDirection()
Merge WebKit at r78450: FrameLoaderClient::didRunInsecureContent() signature changed
Merge WebKit at r78450: HTMLAreaElement::getRect() renamed
Merge WebKit at r78450: FrameLoader::url() removed
Merge WebKit at r78450: HTMLParserQuirks removed
Merge WebKit at r78450: TextRun::padding() renamed
Merge WebKit at r78450: Use new FontMetrics
Merge WebKit at r78450: GraphicsContext current path removed
Merge WebKit at r78450: TransformationMatrix multiply methods renamed and meaning changed
Merge WebKit at r78450: FontCustomPlatformData::fontPlatformData() signature changed
Merge WebKit at r78450: IntRect::bottom()/right() renamed
Merge WebKit at r78450: Fix remaining conflicts
Merge WebKit at r78450: Fix conflicts due to new ENABLE_WEB_ARCHIVE guard
Merge WebKit at r78450: Fix conflicts in media controls
Merge WebKit at r78450: Fix Makefiles
Merge WebKit at r78450: Initial merge by git.
Diffstat (limited to 'Source/WebCore/rendering')
120 files changed, 2628 insertions, 1975 deletions
diff --git a/Source/WebCore/rendering/CounterNode.cpp b/Source/WebCore/rendering/CounterNode.cpp index fe2148a..eadd386 100644 --- a/Source/WebCore/rendering/CounterNode.cpp +++ b/Source/WebCore/rendering/CounterNode.cpp @@ -263,7 +263,7 @@ static void showTreeAndMark(const CounterNode* node) #ifndef NDEBUG -void showTree(const WebCore::CounterNode* counter) +void showCounterTree(const WebCore::CounterNode* counter) { if (counter) showTreeAndMark(counter); diff --git a/Source/WebCore/rendering/CounterNode.h b/Source/WebCore/rendering/CounterNode.h index 529d409..639946c 100644 --- a/Source/WebCore/rendering/CounterNode.h +++ b/Source/WebCore/rendering/CounterNode.h @@ -94,7 +94,7 @@ private: #ifndef NDEBUG // Outside the WebCore namespace for ease of invocation from gdb. -void showTree(const WebCore::CounterNode*); +void showCounterTree(const WebCore::CounterNode*); #endif #endif // CounterNode_h diff --git a/Source/WebCore/rendering/EllipsisBox.cpp b/Source/WebCore/rendering/EllipsisBox.cpp index d367c07..db66b43 100644 --- a/Source/WebCore/rendering/EllipsisBox.cpp +++ b/Source/WebCore/rendering/EllipsisBox.cpp @@ -53,7 +53,7 @@ void EllipsisBox::paint(PaintInfo& paintInfo, int tx, int ty) } const String& str = m_str; - context->drawText(style->font(), TextRun(str.characters(), str.length(), false, 0, 0, false, style->visuallyOrdered()), IntPoint(m_x + tx, m_y + ty + style->font().ascent())); + context->drawText(style->font(), TextRun(str.characters(), str.length(), false, 0, 0, TextRun::AllowTrailingExpansion, false, style->visuallyOrdered()), IntPoint(m_x + tx, m_y + ty + style->fontMetrics().ascent())); // Restore the regular fill color. if (textColor != context->fillColor()) @@ -65,7 +65,7 @@ void EllipsisBox::paint(PaintInfo& paintInfo, int tx, int ty) if (m_markupBox) { // Paint the markup box tx += m_x + m_logicalWidth - m_markupBox->x(); - ty += m_y + style->font().ascent() - (m_markupBox->y() + m_markupBox->renderer()->style(m_firstLine)->font().ascent()); + ty += m_y + style->fontMetrics().ascent() - (m_markupBox->y() + m_markupBox->renderer()->style(m_firstLine)->fontMetrics().ascent()); m_markupBox->paint(paintInfo, tx, ty); } } @@ -74,7 +74,7 @@ IntRect EllipsisBox::selectionRect(int tx, int ty) { RenderStyle* style = m_renderer->style(m_firstLine); const Font& f = style->font(); - return enclosingIntRect(f.selectionRectForText(TextRun(m_str.characters(), m_str.length(), false, 0, 0, false, style->visuallyOrdered()), + return enclosingIntRect(f.selectionRectForText(TextRun(m_str.characters(), m_str.length(), false, 0, 0, TextRun::AllowTrailingExpansion, false, style->visuallyOrdered()), IntPoint(m_x + tx, m_y + ty + root()->selectionTop()), root()->selectionHeight())); } @@ -94,7 +94,7 @@ void EllipsisBox::paintSelection(GraphicsContext* context, int tx, int ty, Rende int y = root()->selectionTop(); int h = root()->selectionHeight(); context->clip(IntRect(m_x + tx, y + ty, m_logicalWidth, h)); - context->drawHighlightForText(font, TextRun(m_str.characters(), m_str.length(), false, 0, 0, false, style->visuallyOrdered()), + context->drawHighlightForText(font, TextRun(m_str.characters(), m_str.length(), false, 0, 0, TextRun::AllowTrailingExpansion, false, style->visuallyOrdered()), IntPoint(m_x + tx, m_y + ty + y), h, c, style->colorSpace()); context->restore(); } @@ -108,7 +108,7 @@ bool EllipsisBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu if (m_markupBox) { RenderStyle* style = m_renderer->style(m_firstLine); int mtx = tx + m_logicalWidth - m_markupBox->x(); - int mty = ty + style->font().ascent() - (m_markupBox->y() + m_markupBox->renderer()->style(m_firstLine)->font().ascent()); + int mty = ty + style->fontMetrics().ascent() - (m_markupBox->y() + m_markupBox->renderer()->style(m_firstLine)->fontMetrics().ascent()); if (m_markupBox->nodeAtPoint(request, result, x, y, mtx, mty)) { renderer()->updateHitTestResult(result, IntPoint(x - mtx, y - mty)); return true; diff --git a/Source/WebCore/rendering/InlineBox.cpp b/Source/WebCore/rendering/InlineBox.cpp index bbf5a748..4fcbe2d 100644 --- a/Source/WebCore/rendering/InlineBox.cpp +++ b/Source/WebCore/rendering/InlineBox.cpp @@ -94,14 +94,14 @@ int InlineBox::logicalHeight() const #endif if (renderer()->isText()) - return m_isText ? renderer()->style(m_firstLine)->font().height() : 0; + return m_isText ? renderer()->style(m_firstLine)->fontMetrics().height() : 0; if (renderer()->isBox() && parent()) return isHorizontal() ? toRenderBox(m_renderer)->height() : toRenderBox(m_renderer)->width(); ASSERT(isInlineFlowBox()); RenderBoxModelObject* flowObject = boxModelObject(); - const Font& font = renderer()->style(m_firstLine)->font(); - int result = font.height(); + const FontMetrics& fontMetrics = renderer()->style(m_firstLine)->fontMetrics(); + int result = fontMetrics.height(); if (parent()) result += flowObject->borderAndPaddingLogicalHeight(); return result; diff --git a/Source/WebCore/rendering/InlineBox.h b/Source/WebCore/rendering/InlineBox.h index 5b3f682..d486ec0 100644 --- a/Source/WebCore/rendering/InlineBox.h +++ b/Source/WebCore/rendering/InlineBox.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2009, 2010, 2011 Apple 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 @@ -61,7 +61,7 @@ public: , m_determinedIfPrevOnLineExists(false) , m_nextOnLineExists(false) , m_prevOnLineExists(false) - , m_toAdd(0) + , m_expansion(0) #ifndef NDEBUG , m_hasBadParent(false) #endif @@ -95,7 +95,7 @@ public: , m_determinedIfPrevOnLineExists(false) , m_nextOnLineExists(false) , m_prevOnLineExists(false) - , m_toAdd(0) + , m_expansion(0) #ifndef NDEBUG , m_hasBadParent(false) #endif @@ -290,7 +290,7 @@ public: void setHasBadParent(); - int toAdd() const { return m_toAdd; } + int expansion() const { return m_expansion; } bool visibleToHitTesting() const { return renderer()->style()->visibility() == VISIBLE && renderer()->style()->pointerEvents() != PE_NONE; } @@ -348,7 +348,7 @@ protected: mutable bool m_determinedIfPrevOnLineExists : 1; mutable bool m_nextOnLineExists : 1; mutable bool m_prevOnLineExists : 1; - int m_toAdd : 11; // for justified text + int m_expansion : 11; // for justified text #ifndef NDEBUG private: diff --git a/Source/WebCore/rendering/InlineFlowBox.cpp b/Source/WebCore/rendering/InlineFlowBox.cpp index 75b23c5..aa9fcb5 100644 --- a/Source/WebCore/rendering/InlineFlowBox.cpp +++ b/Source/WebCore/rendering/InlineFlowBox.cpp @@ -408,6 +408,7 @@ static int verticalPositionForBox(InlineBox* box, FontBaseline baselineType, boo 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; @@ -417,11 +418,11 @@ static int verticalPositionForBox(InlineBox* box, FontBaseline baselineType, boo else if (verticalAlign == SUPER) verticalPosition -= fontSize / 3 + 1; else if (verticalAlign == TEXT_TOP) - verticalPosition += renderer->baselinePosition(baselineType, firstLine, lineDirection) - font.ascent(baselineType); + verticalPosition += renderer->baselinePosition(baselineType, firstLine, lineDirection) - fontMetrics.ascent(baselineType); else if (verticalAlign == MIDDLE) - verticalPosition += -static_cast<int>(font.xHeight() / 2) - renderer->lineHeight(firstLine, lineDirection) / 2 + renderer->baselinePosition(baselineType, firstLine, lineDirection); + verticalPosition += -static_cast<int>(fontMetrics.xHeight() / 2) - renderer->lineHeight(firstLine, lineDirection) / 2 + renderer->baselinePosition(baselineType, firstLine, lineDirection); else if (verticalAlign == TEXT_BOTTOM) { - verticalPosition += font.descent(baselineType); + 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)); @@ -503,9 +504,10 @@ void InlineFlowBox::computeLogicalBoxHeights(int& maxPositionTop, int& maxPositi baseline = 0; int baselineToBottom = 0; for (size_t i = 0; i < usedFonts->size(); ++i) { - int halfLeading = (usedFonts->at(i)->lineSpacing() - usedFonts->at(i)->height()) / 2; - int usedFontBaseline = halfLeading + usedFonts->at(i)->ascent(baselineType); - int usedFontBaselineToBottom = usedFonts->at(i)->lineSpacing() - usedFontBaseline; + const FontMetrics& fontMetrics = usedFonts->at(i)->fontMetrics(); + int halfLeading = (fontMetrics.lineSpacing() - fontMetrics.height()) / 2; + int usedFontBaseline = halfLeading + fontMetrics.ascent(baselineType); + int usedFontBaselineToBottom = fontMetrics.lineSpacing() - usedFontBaseline; if (!baselineSet) { baselineSet = true; baseline = usedFontBaseline; @@ -515,9 +517,9 @@ void InlineFlowBox::computeLogicalBoxHeights(int& maxPositionTop, int& maxPositi baselineToBottom = max(baselineToBottom, usedFontBaselineToBottom); } if (!affectsAscent) - affectsAscent = usedFonts->at(i)->ascent() - curr->logicalTop() > 0; + affectsAscent = fontMetrics.ascent() - curr->logicalTop() > 0; if (!affectsDescent) - affectsDescent = usedFonts->at(i)->descent() + curr->logicalTop() > 0; + affectsDescent = fontMetrics.descent() + curr->logicalTop() > 0; } lineHeight = baseline + baselineToBottom; } else { @@ -527,11 +529,12 @@ void InlineFlowBox::computeLogicalBoxHeights(int& maxPositionTop, int& maxPositi // Examine the font box for inline flows and text boxes to see if any part of it is above the baseline. // If the top of our font box relative to the root box baseline is above the root box baseline, then // we are contributing to the maxAscent value. - affectsAscent = curr->renderer()->style(m_firstLine)->font().ascent(baselineType) - curr->logicalTop() > 0; + const FontMetrics& fontMetrics = curr->renderer()->style(m_firstLine)->fontMetrics(); + affectsAscent = fontMetrics.ascent(baselineType) - curr->logicalTop() > 0; // Descent is similar. If any part of our font box is below the root box's baseline, then // we contribute to the maxDescent value. - affectsDescent = curr->renderer()->style(m_firstLine)->font().descent(baselineType) + curr->logicalTop() > 0; + affectsDescent = fontMetrics.descent(baselineType) + curr->logicalTop() > 0; } else { // Replaced elements always affect both the ascent and descent. affectsAscent = true; @@ -601,13 +604,13 @@ void InlineFlowBox::placeBoxesInBlockDirection(int top, int maxHeight, int maxAs } int newLogicalTop = curr->logicalTop(); - int newLogicalTopIncludingMargins; + int newLogicalTopIncludingMargins = newLogicalTop; int boxHeight = curr->logicalHeight(); int boxHeightIncludingMargins = boxHeight; if (curr->isText() || curr->isInlineFlowBox()) { - const Font& font = curr->renderer()->style(m_firstLine)->font(); - newLogicalTop += curr->baselinePosition(baselineType) - font.ascent(baselineType); + const FontMetrics& fontMetrics = curr->renderer()->style(m_firstLine)->fontMetrics(); + newLogicalTop += curr->baselinePosition(baselineType) - fontMetrics.ascent(baselineType); if (curr->isInlineFlowBox()) { RenderBoxModelObject* boxObject = toRenderBoxModelObject(curr->renderer()); newLogicalTop -= boxObject->style(m_firstLine)->isHorizontalWritingMode() ? boxObject->borderTop() + boxObject->paddingTop() : @@ -668,8 +671,8 @@ void InlineFlowBox::placeBoxesInBlockDirection(int top, int maxHeight, int maxAs } if (isRootInlineBox()) { - const Font& font = renderer()->style(m_firstLine)->font(); - setLogicalTop(logicalTop() + baselinePosition(baselineType) - font.ascent(baselineType)); + const FontMetrics& fontMetrics = renderer()->style(m_firstLine)->fontMetrics(); + setLogicalTop(logicalTop() + baselinePosition(baselineType) - fontMetrics.ascent(baselineType)); if (hasTextChildren() || strictMode) { if (!setLineTop) { @@ -715,14 +718,14 @@ void InlineFlowBox::addBoxShadowVisualOverflow(IntRect& logicalVisualOverflow) renderer()->style(m_firstLine)->getBoxShadowBlockDirectionExtent(boxShadowLogicalTop, boxShadowLogicalBottom); int logicalTopVisualOverflow = min(logicalTop() + boxShadowLogicalTop, logicalVisualOverflow.y()); - int logicalBottomVisualOverflow = max(logicalBottom() + boxShadowLogicalBottom, logicalVisualOverflow.bottom()); + int logicalBottomVisualOverflow = max(logicalBottom() + boxShadowLogicalBottom, logicalVisualOverflow.maxY()); int boxShadowLogicalLeft; int boxShadowLogicalRight; renderer()->style(m_firstLine)->getBoxShadowInlineDirectionExtent(boxShadowLogicalLeft, boxShadowLogicalRight); int logicalLeftVisualOverflow = min(logicalLeft() + boxShadowLogicalLeft, logicalVisualOverflow.x()); - int logicalRightVisualOverflow = max(logicalRight() + boxShadowLogicalRight, logicalVisualOverflow.right()); + int logicalRightVisualOverflow = max(logicalRight() + boxShadowLogicalRight, logicalVisualOverflow.maxX()); logicalVisualOverflow = IntRect(logicalLeftVisualOverflow, logicalTopVisualOverflow, logicalRightVisualOverflow - logicalLeftVisualOverflow, logicalBottomVisualOverflow - logicalTopVisualOverflow); @@ -777,9 +780,9 @@ void InlineFlowBox::addTextBoxVisualOverflow(const InlineTextBox* textBox, Glyph int childOverflowLogicalRight = max(textShadowLogicalRight + rightGlyphOverflow, rightGlyphOverflow); int logicalTopVisualOverflow = min(textBox->logicalTop() + childOverflowLogicalTop, logicalVisualOverflow.y()); - int logicalBottomVisualOverflow = max(textBox->logicalBottom() + childOverflowLogicalBottom, logicalVisualOverflow.bottom()); + int logicalBottomVisualOverflow = max(textBox->logicalBottom() + childOverflowLogicalBottom, logicalVisualOverflow.maxY()); int logicalLeftVisualOverflow = min(textBox->logicalLeft() + childOverflowLogicalLeft, logicalVisualOverflow.x()); - int logicalRightVisualOverflow = max(textBox->logicalRight() + childOverflowLogicalRight, logicalVisualOverflow.right()); + int logicalRightVisualOverflow = max(textBox->logicalRight() + childOverflowLogicalRight, logicalVisualOverflow.maxX()); logicalVisualOverflow = IntRect(logicalLeftVisualOverflow, logicalTopVisualOverflow, logicalRightVisualOverflow - logicalLeftVisualOverflow, logicalBottomVisualOverflow - logicalTopVisualOverflow); @@ -1005,14 +1008,21 @@ void InlineFlowBox::paintFillLayer(const PaintInfo& paintInfo, const Color& c, c // strip. Even though that strip has been broken up across multiple lines, you still paint it // as though you had one single line. This means each line has to pick up the background where // the previous line left off. - // FIXME: What the heck do we do with RTL here? The math we're using is obviously not right, - // but it isn't even clear how this should work at all. int logicalOffsetOnLine = 0; - for (InlineFlowBox* curr = prevLineBox(); curr; curr = curr->prevLineBox()) - logicalOffsetOnLine += curr->logicalWidth(); - int totalLogicalWidth = logicalOffsetOnLine; - for (InlineFlowBox* curr = this; curr; curr = curr->nextLineBox()) - totalLogicalWidth += curr->logicalWidth(); + int totalLogicalWidth; + if (renderer()->style()->direction() == LTR) { + for (InlineFlowBox* curr = prevLineBox(); curr; curr = curr->prevLineBox()) + logicalOffsetOnLine += curr->logicalWidth(); + totalLogicalWidth = logicalOffsetOnLine; + for (InlineFlowBox* curr = this; curr; curr = curr->nextLineBox()) + totalLogicalWidth += curr->logicalWidth(); + } else { + for (InlineFlowBox* curr = nextLineBox(); curr; curr = curr->nextLineBox()) + logicalOffsetOnLine += curr->logicalWidth(); + totalLogicalWidth = logicalOffsetOnLine; + for (InlineFlowBox* curr = this; curr; curr = curr->prevLineBox()) + totalLogicalWidth += curr->logicalWidth(); + } int stripX = tx - (isHorizontal() ? logicalOffsetOnLine : 0); int stripY = ty - (isHorizontal() ? 0 : logicalOffsetOnLine); int stripWidth = isHorizontal() ? totalLogicalWidth : width(); diff --git a/Source/WebCore/rendering/InlineFlowBox.h b/Source/WebCore/rendering/InlineFlowBox.h index 232c3b7..d47111f8 100644 --- a/Source/WebCore/rendering/InlineFlowBox.h +++ b/Source/WebCore/rendering/InlineFlowBox.h @@ -183,19 +183,18 @@ public: void checkConsistency() const; void setHasBadChildList(); - // Line visual and layout overflow are in the coordinate space of the block. This means that - unlike other unprefixed uses of the words - // top/right/bottom/left in the code - these aren't purely physical directions. 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 inverted when compared to - // their physical counterparts. - int topLayoutOverflow() const { return m_overflow ? m_overflow->topLayoutOverflow() : m_y; } - int bottomLayoutOverflow() const { return m_overflow ? m_overflow->bottomLayoutOverflow() : m_y + height(); } - int leftLayoutOverflow() const { return m_overflow ? m_overflow->leftLayoutOverflow() : m_x; } - int rightLayoutOverflow() const { return m_overflow ? m_overflow->rightLayoutOverflow() : m_x + width(); } + // Line visual and layout overflow are in the coordinate space of the block. This means that they aren't purely physical directions. + // 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 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 logicalLeftLayoutOverflow() const { return renderer()->style()->isHorizontalWritingMode() ? leftLayoutOverflow() : topLayoutOverflow(); } - int logicalRightLayoutOverflow() const { return renderer()->style()->isHorizontalWritingMode() ? rightLayoutOverflow() : bottomLayoutOverflow(); } - int logicalTopLayoutOverflow() const { return renderer()->style()->isHorizontalWritingMode() ? topVisualOverflow() : leftVisualOverflow(); } - int logicalBottomLayoutOverflow() const { return renderer()->style()->isHorizontalWritingMode() ? bottomLayoutOverflow() : rightLayoutOverflow(); } + 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(); } + int logicalBottomLayoutOverflow() const { return renderer()->style()->isHorizontalWritingMode() ? maxYLayoutOverflow() : maxXLayoutOverflow(); } IntRect logicalLayoutOverflowRect() const { IntRect result = layoutOverflowRect(); @@ -204,15 +203,15 @@ public: return result; } - int topVisualOverflow() const { return m_overflow ? m_overflow->topVisualOverflow() : m_y; } - int bottomVisualOverflow() const { return m_overflow ? m_overflow->bottomVisualOverflow() : m_y + height(); } - int leftVisualOverflow() const { return m_overflow ? m_overflow->leftVisualOverflow() : m_x; } - int rightVisualOverflow() const { return m_overflow ? m_overflow->rightVisualOverflow() : m_x + width(); } + int minYVisualOverflow() const { return m_overflow ? m_overflow->minYVisualOverflow() : m_y; } + int maxYVisualOverflow() const { return m_overflow ? m_overflow->maxYVisualOverflow() : 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 logicalLeftVisualOverflow() const { return renderer()->style()->isHorizontalWritingMode() ? leftVisualOverflow() : topVisualOverflow(); } - int logicalRightVisualOverflow() const { return renderer()->style()->isHorizontalWritingMode() ? rightVisualOverflow() : bottomVisualOverflow(); } - int logicalTopVisualOverflow() const { return renderer()->style()->isHorizontalWritingMode() ? topVisualOverflow() : leftVisualOverflow(); } - int logicalBottomVisualOverflow() const { return renderer()->style()->isHorizontalWritingMode() ? bottomVisualOverflow() : rightVisualOverflow(); } + 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(); } + int logicalBottomVisualOverflow() const { return renderer()->style()->isHorizontalWritingMode() ? maxYVisualOverflow() : maxXVisualOverflow(); } IntRect logicalVisualOverflowRect() const { IntRect result = visualOverflowRect(); diff --git a/Source/WebCore/rendering/InlineTextBox.cpp b/Source/WebCore/rendering/InlineTextBox.cpp index 8992964..4802f02 100644 --- a/Source/WebCore/rendering/InlineTextBox.cpp +++ b/Source/WebCore/rendering/InlineTextBox.cpp @@ -1,7 +1,7 @@ /* * (C) 1999 Lars Knoll (knoll@kde.org) * (C) 2000 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple 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 @@ -36,11 +36,11 @@ #include "PaintInfo.h" #include "RenderArena.h" #include "RenderBlock.h" +#include "RenderCombineText.h" #include "RenderRubyRun.h" #include "RenderRubyText.h" #include "RenderTheme.h" #include "Text.h" -#include "TextRun.h" #include "break_lines.h" #include <wtf/AlwaysInline.h> @@ -164,19 +164,19 @@ IntRect InlineTextBox::selectionRect(int tx, int ty, int startPos, int endPos) } #ifdef ANDROID_DISABLE_ROUNDING_HACKS - TextRun textRun = TextRun(characters, len, textObj->allowTabs(), textPos(), m_toAdd, !isLeftToRightDirection(), m_dirOverride); + TextRun textRun = TextRun(characters, len, textObj->allowTabs(), textPos(), m_expansion, trailingExpansionBehavior(), !isLeftToRightDirection(), m_dirOverride); if (m_disableRoundingHacks) textRun.disableRoundingHacks(); IntRect r = enclosingIntRect(f.selectionRectForText(textRun, IntPoint(), selHeight, sPos, ePos)); #else - IntRect r = enclosingIntRect(f.selectionRectForText(TextRun(characters, len, textObj->allowTabs(), textPos(), m_toAdd, !isLeftToRightDirection(), m_dirOverride), + IntRect r = enclosingIntRect(f.selectionRectForText(TextRun(characters, len, textObj->allowTabs(), textPos(), m_expansion, trailingExpansionBehavior(), !isLeftToRightDirection(), m_dirOverride), IntPoint(), selHeight, sPos, ePos)); #endif int logicalWidth = r.width(); if (r.x() > m_logicalWidth) logicalWidth = 0; - else if (r.right() > m_logicalWidth) + else if (r.maxX() > m_logicalWidth) logicalWidth = m_logicalWidth - r.x(); IntPoint topPoint = isHorizontal() ? IntPoint(tx + m_x + r.x(), ty + selTop) : IntPoint(tx + selTop, ty + m_y + r.x()); @@ -449,7 +449,7 @@ void InlineTextBox::paint(PaintInfo& paintInfo, int tx, int ty) int logicalStart = logicalLeft() - logicalLeftOverflow + (isHorizontal() ? tx : ty); int logicalExtent = logicalWidth() + logicalLeftOverflow + logicalRightOverflow; - int paintEnd = isHorizontal() ? paintInfo.rect.right() : paintInfo.rect.bottom(); + int paintEnd = isHorizontal() ? paintInfo.rect.maxX() : paintInfo.rect.maxY(); int paintStart = isHorizontal() ? paintInfo.rect.x() : paintInfo.rect.y(); if (logicalStart >= paintEnd || logicalStart + logicalExtent <= paintStart) @@ -492,13 +492,15 @@ void InlineTextBox::paint(PaintInfo& paintInfo, int tx, int ty) IntPoint boxOrigin = locationIncludingFlipping(); boxOrigin.move(tx, ty); IntRect boxRect(boxOrigin, IntSize(logicalWidth(), logicalHeight())); - IntPoint textOrigin = IntPoint(boxOrigin.x(), boxOrigin.y() + styleToUse->font().ascent()); + IntPoint textOrigin = IntPoint(boxOrigin.x(), boxOrigin.y() + styleToUse->fontMetrics().ascent()); - if (!isHorizontal()) { + RenderCombineText* combinedText = styleToUse->hasTextCombine() ? toRenderCombineText(textRenderer()) : 0; + bool shouldRotate = !isHorizontal() && (!combinedText || !combinedText->isCombined()); + if (shouldRotate) { context->save(); - context->translate(boxRect.x(), boxRect.bottom()); + context->translate(boxRect.x(), boxRect.maxY()); context->rotate(static_cast<float>(deg2rad(90.))); - context->translate(-boxRect.x(), -boxRect.bottom()); + context->translate(-boxRect.x(), -boxRect.maxY()); } @@ -510,6 +512,9 @@ void InlineTextBox::paint(PaintInfo& paintInfo, int tx, int ty) int d = styleToUse->textDecorationsInEffect(); const Font& font = styleToUse->font(); + if (combinedText) + combinedText->adjustTextOrigin(textOrigin, boxRect); + // 1. Paint backgrounds behind text if needed. Examples of such backgrounds include selection // and composition underlines. if (paintInfo.phase != PaintPhaseSelection && paintInfo.phase != PaintPhaseTextClip && !isPrinting) { @@ -609,13 +614,18 @@ void InlineTextBox::paint(PaintInfo& paintInfo, int tx, int ty) } } - const UChar* characters = textRenderer()->text()->characters() + m_start; int length = m_len; + const UChar* characters; + if (!combinedText) + characters = textRenderer()->text()->characters() + m_start; + else + combinedText->charactersToRender(m_start, characters, length); + BufferForAppendingHyphen charactersWithHyphen; if (hasHyphen()) adjustCharactersAndLengthForHyphen(charactersWithHyphen, styleToUse, characters, length); - TextRun textRun(characters, length, textRenderer()->allowTabs(), textPos(), m_toAdd, !isLeftToRightDirection(), m_dirOverride || styleToUse->visuallyOrdered()); + TextRun textRun(characters, length, textRenderer()->allowTabs(), textPos(), m_expansion, trailingExpansionBehavior(), !isLeftToRightDirection(), m_dirOverride || styleToUse->visuallyOrdered()); #ifdef ANDROID_DISABLE_ROUNDING_HACKS if (m_disableRoundingHacks) textRun.disableRoundingHacks(); @@ -637,7 +647,7 @@ void InlineTextBox::paint(PaintInfo& paintInfo, int tx, int ty) bool hasTextEmphasis = getEmphasisMarkPosition(styleToUse, emphasisMarkPosition); const AtomicString& emphasisMark = hasTextEmphasis ? styleToUse->textEmphasisMarkString() : nullAtom; if (!emphasisMark.isEmpty()) - emphasisMarkOffset = emphasisMarkPosition == TextEmphasisPositionOver ? -font.ascent() - font.emphasisMarkDescent(emphasisMark) : font.descent() + font.emphasisMarkAscent(emphasisMark); + emphasisMarkOffset = emphasisMarkPosition == TextEmphasisPositionOver ? -font.fontMetrics().ascent() - font.emphasisMarkDescent(emphasisMark) : font.fontMetrics().descent() + font.emphasisMarkAscent(emphasisMark); if (!paintSelectedTextOnly) { // For stroked painting, we have to change the text drawing mode. It's probably dangerous to leave that mutated as a side @@ -715,7 +725,7 @@ void InlineTextBox::paint(PaintInfo& paintInfo, int tx, int ty) } } - if (!isHorizontal()) + if (shouldRotate) context->restore(); } @@ -774,13 +784,13 @@ void InlineTextBox::paintSelection(GraphicsContext* context, const IntPoint& box IntPoint localOrigin(boxOrigin.x(), boxOrigin.y() - deltaY); context->clip(IntRect(localOrigin, IntSize(m_logicalWidth, selHeight))); #ifdef ANDROID_DISABLE_ROUNDING_HACKS - TextRun textRun = TextRun(characters, length, textRenderer()->allowTabs(), textPos(), m_toAdd, + TextRun textRun = TextRun(characters, length, textRenderer()->allowTabs(), textPos(), m_expansion, trailingExpansionBehavior(), !isLeftToRightDirection(), m_dirOverride || style->visuallyOrdered()); if (m_disableRoundingHacks) textRun.disableRoundingHacks(); context->drawHighlightForText(font, textRun, localOrigin, selHeight, c, style->colorSpace(), sPos, ePos); #else - context->drawHighlightForText(font, TextRun(characters, length, textRenderer()->allowTabs(), textPos(), m_toAdd, + context->drawHighlightForText(font, TextRun(characters, length, textRenderer()->allowTabs(), textPos(), m_expansion, trailingExpansionBehavior(), !isLeftToRightDirection(), m_dirOverride || style->visuallyOrdered()), localOrigin, selHeight, c, style->colorSpace(), sPos, ePos); #endif @@ -806,13 +816,13 @@ void InlineTextBox::paintCompositionBackground(GraphicsContext* context, const I int selHeight = selectionHeight(); 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_toAdd, + TextRun textRun = TextRun(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_expansion, trailingExpansionBehavior(), !isLeftToRightDirection(), m_dirOverride || style->visuallyOrdered()); if (m_disableRoundingHacks) textRun.disableRoundingHacks(); context->drawHighlightForText(font, textRun, localOrigin, selHeight, c, style->colorSpace(), sPos, ePos); #else - context->drawHighlightForText(font, TextRun(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_toAdd, + 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); #endif @@ -864,7 +874,7 @@ void InlineTextBox::paintDecoration(GraphicsContext* context, const IntPoint& bo bool linesAreOpaque = !isPrinting && (!(deco & UNDERLINE) || underline.alpha() == 255) && (!(deco & OVERLINE) || overline.alpha() == 255) && (!(deco & LINE_THROUGH) || linethrough.alpha() == 255); RenderStyle* styleToUse = renderer()->style(m_firstLine); - int baseline = styleToUse->font().ascent(); + int baseline = styleToUse->fontMetrics().ascent(); bool setClip = false; int extraOffset = 0; @@ -975,7 +985,7 @@ void InlineTextBox::paintSpellingOrGrammarMarker(GraphicsContext* pt, const IntP int deltaY = renderer()->style()->isFlippedLinesWritingMode() ? selectionBottom() - logicalBottom() : logicalTop() - selectionTop(); int selHeight = selectionHeight(); IntPoint startPoint(boxOrigin.x(), boxOrigin.y() - deltaY); - TextRun run(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_toAdd, !isLeftToRightDirection(), m_dirOverride || style->visuallyOrdered()); + TextRun run(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_expansion, trailingExpansionBehavior(), !isLeftToRightDirection(), m_dirOverride || style->visuallyOrdered()); #ifdef ANDROID_DISABLE_ROUNDING_HACKS if (m_disableRoundingHacks) run.disableRoundingHacks(); @@ -1001,7 +1011,7 @@ void InlineTextBox::paintSpellingOrGrammarMarker(GraphicsContext* pt, const IntP // So, we generally place the underline at the bottom of the text, but in larger fonts that's not so good so // we pin to two pixels under the baseline. int lineThickness = cMisspellingLineThickness; - int baseline = renderer()->style(m_firstLine)->font().ascent(); + int baseline = renderer()->style(m_firstLine)->fontMetrics().ascent(); int descent = logicalHeight() - baseline; int underlineOffset; if (descent <= (2 + lineThickness)) { @@ -1023,7 +1033,7 @@ void InlineTextBox::paintTextMatchMarker(GraphicsContext* pt, const IntPoint& bo int sPos = max(marker.startOffset - m_start, (unsigned)0); int ePos = min(marker.endOffset - m_start, (unsigned)m_len); - TextRun run(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_toAdd, !isLeftToRightDirection(), m_dirOverride || style->visuallyOrdered()); + TextRun run(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_expansion, trailingExpansionBehavior(), !isLeftToRightDirection(), m_dirOverride || style->visuallyOrdered()); #ifdef ANDROID_DISABLE_ROUNDING_HACKS if (m_disableRoundingHacks) run.disableRoundingHacks(); @@ -1055,7 +1065,7 @@ void InlineTextBox::computeRectForReplacementMarker(const DocumentMarker& marker int sPos = max(marker.startOffset - m_start, (unsigned)0); int ePos = min(marker.endOffset - m_start, (unsigned)m_len); - TextRun run(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_toAdd, !isLeftToRightDirection(), m_dirOverride || style->visuallyOrdered()); + TextRun run(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_expansion, trailingExpansionBehavior(), !isLeftToRightDirection(), m_dirOverride || style->visuallyOrdered()); #ifdef ANDROID_DISABLE_ROUNDING_HACKS if (m_disableRoundingHacks) run.disableRoundingHacks(); @@ -1085,9 +1095,7 @@ void InlineTextBox::paintDocumentMarkers(GraphicsContext* pt, const IntPoint& bo switch (marker.type) { case DocumentMarker::Grammar: case DocumentMarker::Spelling: - case DocumentMarker::Replacement: case DocumentMarker::CorrectionIndicator: - case DocumentMarker::RejectedCorrection: if (background) continue; break; @@ -1095,9 +1103,8 @@ void InlineTextBox::paintDocumentMarkers(GraphicsContext* pt, const IntPoint& bo if (!background) continue; break; - default: - ASSERT_NOT_REACHED(); + continue; } if (marker.endOffset <= start()) @@ -1124,9 +1131,6 @@ void InlineTextBox::paintDocumentMarkers(GraphicsContext* pt, const IntPoint& bo computeRectForReplacementMarker(marker, style, font); paintSpellingOrGrammarMarker(pt, boxOrigin, marker, style, font, false); break; - case DocumentMarker::Replacement: - case DocumentMarker::RejectedCorrection: - break; default: ASSERT_NOT_REACHED(); } @@ -1166,7 +1170,7 @@ void InlineTextBox::paintCompositionUnderline(GraphicsContext* ctx, const IntPoi // All other marked text underlines are 1px thick. // If there's not enough space the underline will touch or overlap characters. int lineThickness = 1; - int baseline = renderer()->style(m_firstLine)->font().ascent(); + int baseline = renderer()->style(m_firstLine)->fontMetrics().ascent(); if (underline.thick && logicalHeight() - baseline >= 2) lineThickness = 2; @@ -1224,13 +1228,13 @@ int InlineTextBox::offsetForPosition(int lineOffset, bool includePartialGlyphs) RenderStyle* style = text->style(m_firstLine); const Font* f = &style->font(); #ifdef ANDROID_DISABLE_ROUNDING_HACKS - TextRun textRun = TextRun(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_toAdd, !isLeftToRightDirection(), m_dirOverride || style->visuallyOrdered()); + TextRun textRun = TextRun(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_expansion, trailingExpansionBehavior(), !isLeftToRightDirection(), m_dirOverride || style->visuallyOrdered()); if (m_disableRoundingHacks) textRun.disableRoundingHacks(); int offset = f->offsetForPosition(textRun, lineOffset - logicalLeft(), includePartialGlyphs); #else int offset = f->offsetForPosition(TextRun(textRenderer()->text()->characters() + m_start, m_len, - textRenderer()->allowTabs(), textPos(), m_toAdd, !isLeftToRightDirection(), m_dirOverride || style->visuallyOrdered()), + textRenderer()->allowTabs(), textPos(), m_expansion, trailingExpansionBehavior(), !isLeftToRightDirection(), m_dirOverride || style->visuallyOrdered()), lineOffset - logicalLeft(), includePartialGlyphs); #endif if (blockIsInOppositeDirection && (!offset || offset == m_len)) @@ -1252,13 +1256,13 @@ int InlineTextBox::positionForOffset(int offset) const int to = !isLeftToRightDirection() ? m_len : offset - m_start; // FIXME: Do we need to add rightBearing here? #ifdef ANDROID_DISABLE_ROUNDING_HACKS - TextRun textRun = TextRun(text->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_toAdd, !isLeftToRightDirection(), m_dirOverride); + TextRun textRun = TextRun(text->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_expansion, trailingExpansionBehavior(), !isLeftToRightDirection(), m_dirOverride); if (m_disableRoundingHacks) textRun.disableRoundingHacks(); - return enclosingIntRect(f.selectionRectForText(textRun, IntPoint(logicalLeft(), 0), 0, from, to)).right(); + return enclosingIntRect(f.selectionRectForText(textRun, IntPoint(logicalLeft(), 0), 0, from, to)).maxX(); #else - return enclosingIntRect(f.selectionRectForText(TextRun(text->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_toAdd, !isLeftToRightDirection(), m_dirOverride), - IntPoint(logicalLeft(), 0), 0, from, to)).right(); + 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 } diff --git a/Source/WebCore/rendering/InlineTextBox.h b/Source/WebCore/rendering/InlineTextBox.h index ee75f06..095fa16 100644 --- a/Source/WebCore/rendering/InlineTextBox.h +++ b/Source/WebCore/rendering/InlineTextBox.h @@ -1,7 +1,7 @@ /* * (C) 1999 Lars Knoll (knoll@kde.org) * (C) 2000 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2004, 2005, 2006, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2004, 2005, 2006, 2009, 2010, 2011 Apple 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 @@ -25,6 +25,7 @@ #include "InlineBox.h" #include "RenderText.h" // so textRenderer() can be inline +#include "TextRun.h" namespace WebCore { @@ -88,7 +89,7 @@ private: int selectionHeight(); public: - virtual IntRect calculateBoundaries() const { return IntRect(x(), y(), logicalWidth(), logicalHeight()); } + virtual IntRect calculateBoundaries() const { return IntRect(x(), y(), width(), height()); } virtual IntRect selectionRect(int absx, int absy, int startPos, int endPos); bool isSelected(int startPos, int endPos) const; @@ -116,7 +117,7 @@ private: public: virtual bool isLineBreak() const; - void setSpaceAdd(int add) { m_logicalWidth -= m_toAdd; m_toAdd = add; m_logicalWidth += m_toAdd; } + void setExpansion(int expansion) { m_logicalWidth -= m_expansion; m_expansion = expansion; m_logicalWidth += m_expansion; } private: virtual bool isInlineTextBox() const { return true; } @@ -166,6 +167,8 @@ private: 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 computeRectForReplacementMarker(const DocumentMarker&, RenderStyle*, const Font&); + + TextRun::TrailingExpansionBehavior trailingExpansionBehavior() const { return m_expansion && nextLeafChild() ? TextRun::AllowTrailingExpansion : TextRun::ForbidTrailingExpansion; } }; inline RenderText* InlineTextBox::textRenderer() const diff --git a/Source/WebCore/rendering/LayoutState.cpp b/Source/WebCore/rendering/LayoutState.cpp index aeba416..8e4201e 100644 --- a/Source/WebCore/rendering/LayoutState.cpp +++ b/Source/WebCore/rendering/LayoutState.cpp @@ -167,11 +167,11 @@ int LayoutState::pageLogicalOffset(int childLogicalOffset) const return m_layoutOffset.height() + childLogicalOffset - m_pageOffset.height(); } -void LayoutState::addForcedColumnBreak(int childY) +void LayoutState::addForcedColumnBreak(int childLogicalOffset) { if (!m_columnInfo || m_columnInfo->columnHeight()) return; - m_columnInfo->addForcedBreak(pageLogicalOffset(childY)); + m_columnInfo->addForcedBreak(pageLogicalOffset(childLogicalOffset)); } } // namespace WebCore diff --git a/Source/WebCore/rendering/LayoutState.h b/Source/WebCore/rendering/LayoutState.h index c499435..f14c9ff 100644 --- a/Source/WebCore/rendering/LayoutState.h +++ b/Source/WebCore/rendering/LayoutState.h @@ -71,7 +71,7 @@ public: // direction (so an x-offset in vertical text and a y-offset for horizontal text). int pageLogicalOffset(int childLogicalOffset) const; - void addForcedColumnBreak(int childY); + void addForcedColumnBreak(int childLogicalOffset); bool pageLogicalHeight() const { return m_pageLogicalHeight; } bool pageLogicalHeightChanged() const { return m_pageLogicalHeightChanged; } diff --git a/Source/WebCore/rendering/MediaControlElements.cpp b/Source/WebCore/rendering/MediaControlElements.cpp index 1f66719..6defbb7 100644 --- a/Source/WebCore/rendering/MediaControlElements.cpp +++ b/Source/WebCore/rendering/MediaControlElements.cpp @@ -32,11 +32,13 @@ #include "MediaControlElements.h" +#include "CSSStyleSelector.h" #include "EventNames.h" #include "FloatConversion.h" #include "Frame.h" #include "HTMLNames.h" #include "LocalizedStrings.h" +#include "MediaControls.h" #include "MouseEvent.h" #include "Page.h" #include "RenderMedia.h" @@ -88,14 +90,6 @@ PassRefPtr<MediaControlShadowRootElement> MediaControlShadowRootElement::create( return element.release(); } -void MediaControlShadowRootElement::updateStyle() -{ - if (renderer()) { - RenderStyle* timelineContainerStyle = shadowHost()->renderer()->getCachedPseudoStyle(MEDIA_CONTROLS_TIMELINE_CONTAINER); - renderer()->setStyle(timelineContainerStyle); - } -} - void MediaControlShadowRootElement::detach() { HTMLDivElement::detach(); @@ -105,40 +99,11 @@ void MediaControlShadowRootElement::detach() // ---------------------------- -MediaControlElement::MediaControlElement(HTMLMediaElement* mediaElement, PseudoId pseudo) +MediaControlElement::MediaControlElement(HTMLMediaElement* mediaElement) : HTMLDivElement(divTag, mediaElement->document()) , m_mediaElement(mediaElement) - , m_pseudoStyleId(pseudo) { setInDocument(); - switch (pseudo) { - case MEDIA_CONTROLS_CURRENT_TIME_DISPLAY: - m_displayType = MediaCurrentTimeDisplay; - break; - case MEDIA_CONTROLS_TIME_REMAINING_DISPLAY: - m_displayType = MediaTimeRemainingDisplay; - break; - case MEDIA_CONTROLS_TIMELINE_CONTAINER: - m_displayType = MediaTimelineContainer; - break; - case MEDIA_CONTROLS_STATUS_DISPLAY: - m_displayType = MediaStatusDisplay; - break; - case MEDIA_CONTROLS_PANEL: - m_displayType = MediaControlsPanel; - break; - case MEDIA_CONTROLS_VOLUME_SLIDER_CONTAINER: - m_displayType = MediaVolumeSliderContainer; - break; - default: - ASSERT_NOT_REACHED(); - break; - } -} - -PassRefPtr<MediaControlElement> MediaControlElement::create(HTMLMediaElement* mediaElement, PseudoId pseudoStyleId) -{ - return adoptRef(new MediaControlElement(mediaElement, pseudoStyleId)); } void MediaControlElement::attachToParent(Element* parent) @@ -157,7 +122,8 @@ void MediaControlElement::update() PassRefPtr<RenderStyle> MediaControlElement::styleForElement() { - RenderStyle* style = m_mediaElement->renderer()->getCachedPseudoStyle(m_pseudoStyleId); + ASSERT(m_mediaElement->renderer()); + RefPtr<RenderStyle> style = document()->styleSelector()->styleForElement(this, m_mediaElement->renderer()->style(), true); if (!style) return 0; @@ -225,8 +191,31 @@ void MediaControlElement::updateStyle() // ---------------------------- +inline MediaControlPanelElement::MediaControlPanelElement(HTMLMediaElement* mediaElement) + : MediaControlElement(mediaElement) +{ +} + +PassRefPtr<MediaControlPanelElement> MediaControlPanelElement::create(HTMLMediaElement* mediaElement) +{ + return adoptRef(new MediaControlPanelElement(mediaElement)); +} + +MediaControlElementType MediaControlPanelElement::displayType() const +{ + return MediaControlsPanel; +} + +const AtomicString& MediaControlPanelElement::shadowPseudoId() const +{ + DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-panel")); + return id; +} + +// ---------------------------- + inline MediaControlTimelineContainerElement::MediaControlTimelineContainerElement(HTMLMediaElement* mediaElement) - : MediaControlElement(mediaElement, MEDIA_CONTROLS_TIMELINE_CONTAINER) + : MediaControlElement(mediaElement) { } @@ -240,20 +229,29 @@ bool MediaControlTimelineContainerElement::rendererIsNeeded(RenderStyle* style) if (!MediaControlElement::rendererIsNeeded(style)) return false; - // This is for MediaControllerThemeClassic: - // If there is no style for MediaControlStatusDisplayElement style, don't hide - // the timeline. - if (!mediaElement()->renderer()->getCachedPseudoStyle(MEDIA_CONTROLS_STATUS_DISPLAY)) + // Always show the timeline if the theme doesn't use status display (MediaControllerThemeClassic, for instance). + if (!document()->page()->theme()->usesMediaControlStatusDisplay()) return true; float duration = mediaElement()->duration(); return !isnan(duration) && !isinf(duration); } +MediaControlElementType MediaControlTimelineContainerElement::displayType() const +{ + return MediaTimelineContainer; +} + +const AtomicString& MediaControlTimelineContainerElement::shadowPseudoId() const +{ + DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-timeline-container")); + return id; +} + // ---------------------------- inline MediaControlVolumeSliderContainerElement::MediaControlVolumeSliderContainerElement(HTMLMediaElement* mediaElement) - : MediaControlElement(mediaElement, MEDIA_CONTROLS_VOLUME_SLIDER_CONTAINER) + : MediaControlElement(mediaElement) , m_isVisible(false) , m_x(0) , m_y(0) @@ -298,10 +296,21 @@ bool MediaControlVolumeSliderContainerElement::hitTest(const IntPoint& absPoint) return false; } +MediaControlElementType MediaControlVolumeSliderContainerElement::displayType() const +{ + return MediaVolumeSliderContainer; +} + +const AtomicString& MediaControlVolumeSliderContainerElement::shadowPseudoId() const +{ + DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-volume-slider-container")); + return id; +} + // ---------------------------- inline MediaControlStatusDisplayElement::MediaControlStatusDisplayElement(HTMLMediaElement* mediaElement) - : MediaControlElement(mediaElement, MEDIA_CONTROLS_STATUS_DISPLAY) + : MediaControlElement(mediaElement) , m_stateBeingDisplayed(Nothing) { } @@ -344,59 +353,30 @@ void MediaControlStatusDisplayElement::update() bool MediaControlStatusDisplayElement::rendererIsNeeded(RenderStyle* style) { - if (!MediaControlElement::rendererIsNeeded(style)) + if (!MediaControlElement::rendererIsNeeded(style) || !document()->page()->theme()->usesMediaControlStatusDisplay()) return false; float duration = mediaElement()->duration(); return (isnan(duration) || isinf(duration)); } +MediaControlElementType MediaControlStatusDisplayElement::displayType() const +{ + return MediaStatusDisplay; +} + +const AtomicString& MediaControlStatusDisplayElement::shadowPseudoId() const +{ + DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-status-display")); + return id; +} + // ---------------------------- -MediaControlInputElement::MediaControlInputElement(HTMLMediaElement* mediaElement, PseudoId pseudo) - : HTMLInputElement(inputTag, mediaElement->document()) +MediaControlInputElement::MediaControlInputElement(HTMLMediaElement* mediaElement, MediaControlElementType displayType) + : HTMLInputElement(inputTag, mediaElement->document(), 0, false) , m_mediaElement(mediaElement) - , m_pseudoStyleId(pseudo) + , m_displayType(displayType) { - setInDocument(); - - switch (pseudo) { - case MEDIA_CONTROLS_MUTE_BUTTON: - m_displayType = MediaMuteButton; - break; - case MEDIA_CONTROLS_PLAY_BUTTON: - m_displayType = MediaPlayButton; - break; - case MEDIA_CONTROLS_SEEK_FORWARD_BUTTON: - m_displayType = MediaSeekForwardButton; - break; - case MEDIA_CONTROLS_SEEK_BACK_BUTTON: - m_displayType = MediaSeekBackButton; - break; - case MEDIA_CONTROLS_FULLSCREEN_BUTTON: - m_displayType = MediaFullscreenButton; - break; - case MEDIA_CONTROLS_TIMELINE: - m_displayType = MediaSlider; - break; - case MEDIA_CONTROLS_RETURN_TO_REALTIME_BUTTON: - m_displayType = MediaReturnToRealtimeButton; - break; - case MEDIA_CONTROLS_REWIND_BUTTON: - m_displayType = MediaRewindButton; - break; - case MEDIA_CONTROLS_VOLUME_SLIDER: - m_displayType = MediaVolumeSlider; - break; - case MEDIA_CONTROLS_VOLUME_SLIDER_MUTE_BUTTON: - m_displayType = MediaVolumeSliderMuteButton; - break; - case MEDIA_CONTROLS_TOGGLE_CLOSED_CAPTIONS_BUTTON: - m_displayType = MediaShowClosedCaptionsButton; - break; - default: - ASSERT_NOT_REACHED(); - break; - } } void MediaControlInputElement::attachToParent(Element* parent) @@ -416,7 +396,7 @@ void MediaControlInputElement::update() PassRefPtr<RenderStyle> MediaControlInputElement::styleForElement() { - return mediaElement()->renderer()->getCachedPseudoStyle(m_pseudoStyleId); + return document()->styleSelector()->styleForElement(this, 0, true); } bool MediaControlInputElement::rendererIsNeeded(RenderStyle* style) @@ -481,7 +461,7 @@ void MediaControlInputElement::updateStyle() if (Node* shadowNode = shadowRoot()) shadowNode->recalcStyle(Node::Force); } - + bool MediaControlInputElement::hitTest(const IntPoint& absPoint) { if (renderer() && renderer()->style()->hasAppearance()) @@ -502,14 +482,14 @@ void MediaControlInputElement::setDisplayType(MediaControlElementType displayTyp // ---------------------------- -inline MediaControlMuteButtonElement::MediaControlMuteButtonElement(HTMLMediaElement* mediaElement, ButtonLocation location) - : MediaControlInputElement(mediaElement, location == Controller ? MEDIA_CONTROLS_MUTE_BUTTON : MEDIA_CONTROLS_VOLUME_SLIDER_MUTE_BUTTON) +inline MediaControlMuteButtonElement::MediaControlMuteButtonElement(HTMLMediaElement* mediaElement, MediaControlElementType displayType) + : MediaControlInputElement(mediaElement, displayType) { } -PassRefPtr<MediaControlMuteButtonElement> MediaControlMuteButtonElement::create(HTMLMediaElement* mediaElement, ButtonLocation location) +PassRefPtr<MediaControlMuteButtonElement> MediaControlMuteButtonElement::create(HTMLMediaElement* mediaElement) { - RefPtr<MediaControlMuteButtonElement> button = adoptRef(new MediaControlMuteButtonElement(mediaElement, location)); + RefPtr<MediaControlMuteButtonElement> button = adoptRef(new MediaControlMuteButtonElement(mediaElement, MediaMuteButton)); button->setType("button"); return button.release(); } @@ -523,15 +503,39 @@ void MediaControlMuteButtonElement::defaultEventHandler(Event* event) HTMLInputElement::defaultEventHandler(event); } +const AtomicString& MediaControlMuteButtonElement::shadowPseudoId() const +{ + DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-mute-button")); + return id; +} + void MediaControlMuteButtonElement::updateDisplayType() { setDisplayType(mediaElement()->muted() ? MediaUnMuteButton : MediaMuteButton); } +inline MediaControlVolumeSliderMuteButtonElement::MediaControlVolumeSliderMuteButtonElement(HTMLMediaElement* mediaElement) + : MediaControlMuteButtonElement(mediaElement, MediaVolumeSliderMuteButton) +{ +} + +PassRefPtr<MediaControlVolumeSliderMuteButtonElement> MediaControlVolumeSliderMuteButtonElement::create(HTMLMediaElement* mediaElement) +{ + RefPtr<MediaControlVolumeSliderMuteButtonElement> button = adoptRef(new MediaControlVolumeSliderMuteButtonElement(mediaElement)); + button->setType("button"); + return button.release(); +} + +const AtomicString& MediaControlVolumeSliderMuteButtonElement::shadowPseudoId() const +{ + DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-volume-slider-mute-button")); + return id; +} + // ---------------------------- inline MediaControlPlayButtonElement::MediaControlPlayButtonElement(HTMLMediaElement* mediaElement) - : MediaControlInputElement(mediaElement, MEDIA_CONTROLS_PLAY_BUTTON) + : MediaControlInputElement(mediaElement, MediaPlayButton) { } @@ -556,28 +560,22 @@ void MediaControlPlayButtonElement::updateDisplayType() setDisplayType(mediaElement()->canPlay() ? MediaPlayButton : MediaPauseButton); } +const AtomicString& MediaControlPlayButtonElement::shadowPseudoId() const +{ + DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-play-button")); + return id; +} + // ---------------------------- -inline MediaControlSeekButtonElement::MediaControlSeekButtonElement(HTMLMediaElement* mediaElement, PseudoId pseudoId) - : MediaControlInputElement(mediaElement, pseudoId) +inline MediaControlSeekButtonElement::MediaControlSeekButtonElement(HTMLMediaElement* mediaElement, MediaControlElementType displayType) + : MediaControlInputElement(mediaElement, displayType) , m_seeking(false) , m_capturing(false) , m_seekTimer(this, &MediaControlSeekButtonElement::seekTimerFired) { } -PassRefPtr<MediaControlSeekButtonElement> MediaControlSeekButtonElement::create(HTMLMediaElement* mediaElement, PseudoId pseudoStyleId) -{ - RefPtr<MediaControlSeekButtonElement> button = adoptRef(new MediaControlSeekButtonElement(mediaElement, pseudoStyleId)); - button->setType("button"); - return button.release(); -} - -inline bool MediaControlSeekButtonElement::isForwardButton() const -{ - return pseudoStyleId() == MEDIA_CONTROLS_SEEK_FORWARD_BUTTON; -} - void MediaControlSeekButtonElement::defaultEventHandler(Event* event) { if (event->type() == eventNames().mousedownEvent) { @@ -627,8 +625,48 @@ void MediaControlSeekButtonElement::detach() // ---------------------------- +inline MediaControlSeekForwardButtonElement::MediaControlSeekForwardButtonElement(HTMLMediaElement* mediaElement) + : MediaControlSeekButtonElement(mediaElement, MediaSeekForwardButton) +{ +} + +PassRefPtr<MediaControlSeekForwardButtonElement> MediaControlSeekForwardButtonElement::create(HTMLMediaElement* mediaElement) +{ + RefPtr<MediaControlSeekForwardButtonElement> button = adoptRef(new MediaControlSeekForwardButtonElement(mediaElement)); + button->setType("button"); + return button.release(); +} + +const AtomicString& MediaControlSeekForwardButtonElement::shadowPseudoId() const +{ + DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-seek-forward-button")); + return id; +} + +// ---------------------------- + +inline MediaControlSeekBackButtonElement::MediaControlSeekBackButtonElement(HTMLMediaElement* mediaElement) + : MediaControlSeekButtonElement(mediaElement, MediaSeekBackButton) +{ +} + +PassRefPtr<MediaControlSeekBackButtonElement> MediaControlSeekBackButtonElement::create(HTMLMediaElement* mediaElement) +{ + RefPtr<MediaControlSeekBackButtonElement> button = adoptRef(new MediaControlSeekBackButtonElement(mediaElement)); + button->setType("button"); + return button.release(); +} + +const AtomicString& MediaControlSeekBackButtonElement::shadowPseudoId() const +{ + DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-seek-back-button")); + return id; +} + +// ---------------------------- + inline MediaControlRewindButtonElement::MediaControlRewindButtonElement(HTMLMediaElement* element) - : MediaControlInputElement(element, MEDIA_CONTROLS_REWIND_BUTTON) + : MediaControlInputElement(element, MediaRewindButton) { } @@ -648,10 +686,16 @@ void MediaControlRewindButtonElement::defaultEventHandler(Event* event) HTMLInputElement::defaultEventHandler(event); } +const AtomicString& MediaControlRewindButtonElement::shadowPseudoId() const +{ + DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-rewind-button")); + return id; +} + // ---------------------------- inline MediaControlReturnToRealtimeButtonElement::MediaControlReturnToRealtimeButtonElement(HTMLMediaElement* mediaElement) - : MediaControlInputElement(mediaElement, MEDIA_CONTROLS_RETURN_TO_REALTIME_BUTTON) + : MediaControlInputElement(mediaElement, MediaReturnToRealtimeButton) { } @@ -671,11 +715,16 @@ void MediaControlReturnToRealtimeButtonElement::defaultEventHandler(Event* event HTMLInputElement::defaultEventHandler(event); } +const AtomicString& MediaControlReturnToRealtimeButtonElement::shadowPseudoId() const +{ + DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-return-to-realtime-button")); + return id; +} // ---------------------------- inline MediaControlToggleClosedCaptionsButtonElement::MediaControlToggleClosedCaptionsButtonElement(HTMLMediaElement* mediaElement) - : MediaControlInputElement(mediaElement, MEDIA_CONTROLS_TOGGLE_CLOSED_CAPTIONS_BUTTON) + : MediaControlInputElement(mediaElement, MediaShowClosedCaptionsButton) { } @@ -701,10 +750,16 @@ void MediaControlToggleClosedCaptionsButtonElement::updateDisplayType() setDisplayType(mediaElement()->closedCaptionsVisible() ? MediaHideClosedCaptionsButton : MediaShowClosedCaptionsButton); } +const AtomicString& MediaControlToggleClosedCaptionsButtonElement::shadowPseudoId() const +{ + DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-toggle-closed-captions-button")); + return id; +} + // ---------------------------- MediaControlTimelineElement::MediaControlTimelineElement(HTMLMediaElement* mediaElement) - : MediaControlInputElement(mediaElement, MEDIA_CONTROLS_TIMELINE) + : MediaControlInputElement(mediaElement, MediaSlider) { } @@ -740,9 +795,9 @@ void MediaControlTimelineElement::defaultEventHandler(Event* event) RenderSlider* slider = toRenderSlider(renderer()); if (slider && slider->inDragMode()) { - toRenderMedia(mediaElement()->renderer())->updateTimeDisplay(); + toRenderMedia(mediaElement()->renderer())->controls()->updateTimeDisplay(); #if PLATFORM(ANDROID) - toRenderMedia(mediaElement()->renderer())->updateLastTouch(); + toRenderMedia(mediaElement()->renderer())->controls()->updateLastTouch(); #endif } @@ -760,10 +815,16 @@ void MediaControlTimelineElement::update(bool updateDuration) MediaControlInputElement::update(); } +const AtomicString& MediaControlTimelineElement::shadowPseudoId() const +{ + DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-timeline")); + return id; +} + // ---------------------------- inline MediaControlVolumeSliderElement::MediaControlVolumeSliderElement(HTMLMediaElement* mediaElement) - : MediaControlInputElement(mediaElement, MEDIA_CONTROLS_VOLUME_SLIDER) + : MediaControlInputElement(mediaElement, MediaVolumeSlider) { } @@ -804,10 +865,16 @@ void MediaControlVolumeSliderElement::update() MediaControlInputElement::update(); } +const AtomicString& MediaControlVolumeSliderElement::shadowPseudoId() const +{ + DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-volume-slider")); + return id; +} + // ---------------------------- inline MediaControlFullscreenButtonElement::MediaControlFullscreenButtonElement(HTMLMediaElement* mediaElement) - : MediaControlInputElement(mediaElement, MEDIA_CONTROLS_FULLSCREEN_BUTTON) + : MediaControlInputElement(mediaElement, MediaFullscreenButton) { } @@ -840,20 +907,21 @@ void MediaControlFullscreenButtonElement::defaultEventHandler(Event* event) HTMLInputElement::defaultEventHandler(event); } +const AtomicString& MediaControlFullscreenButtonElement::shadowPseudoId() const +{ + DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-button")); + return id; +} + // ---------------------------- -inline MediaControlTimeDisplayElement::MediaControlTimeDisplayElement(HTMLMediaElement* mediaElement, PseudoId pseudo) - : MediaControlElement(mediaElement, pseudo) +inline MediaControlTimeDisplayElement::MediaControlTimeDisplayElement(HTMLMediaElement* mediaElement) + : MediaControlElement(mediaElement) , m_currentValue(0) , m_isVisible(true) { } -PassRefPtr<MediaControlTimeDisplayElement> MediaControlTimeDisplayElement::create(HTMLMediaElement* mediaElement, PseudoId pseudoStyleId) -{ - return adoptRef(new MediaControlTimeDisplayElement(mediaElement, pseudoStyleId)); -} - PassRefPtr<RenderStyle> MediaControlTimeDisplayElement::styleForElement() { RefPtr<RenderStyle> style = MediaControlElement::styleForElement(); @@ -884,6 +952,52 @@ void MediaControlTimeDisplayElement::setCurrentValue(float time) m_currentValue = time; } +// ---------------------------- + +PassRefPtr<MediaControlTimeRemainingDisplayElement> MediaControlTimeRemainingDisplayElement::create(HTMLMediaElement* mediaElement) +{ + return adoptRef(new MediaControlTimeRemainingDisplayElement(mediaElement)); +} + +MediaControlTimeRemainingDisplayElement::MediaControlTimeRemainingDisplayElement(HTMLMediaElement* mediaElement) + : MediaControlTimeDisplayElement(mediaElement) +{ +} + +MediaControlElementType MediaControlTimeRemainingDisplayElement::displayType() const +{ + return MediaTimeRemainingDisplay; +} + +const AtomicString& MediaControlTimeRemainingDisplayElement::shadowPseudoId() const +{ + DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-time-remaining-display")); + return id; +} + +// ---------------------------- + +PassRefPtr<MediaControlCurrentTimeDisplayElement> MediaControlCurrentTimeDisplayElement::create(HTMLMediaElement* mediaElement) +{ + return adoptRef(new MediaControlCurrentTimeDisplayElement(mediaElement)); +} + +MediaControlCurrentTimeDisplayElement::MediaControlCurrentTimeDisplayElement(HTMLMediaElement* mediaElement) + : MediaControlTimeDisplayElement(mediaElement) +{ +} + +MediaControlElementType MediaControlCurrentTimeDisplayElement::displayType() const +{ + return MediaCurrentTimeDisplay; +} + +const AtomicString& MediaControlCurrentTimeDisplayElement::shadowPseudoId() const +{ + DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-current-time-display")); + return id; +} + } // namespace WebCore #endif // ENABLE(VIDEO) diff --git a/Source/WebCore/rendering/MediaControlElements.h b/Source/WebCore/rendering/MediaControlElements.h index b2d063d..ff9541d 100644 --- a/Source/WebCore/rendering/MediaControlElements.h +++ b/Source/WebCore/rendering/MediaControlElements.h @@ -75,7 +75,6 @@ class MediaControlShadowRootElement : public HTMLDivElement { public: static PassRefPtr<MediaControlShadowRootElement> create(HTMLMediaElement*); - void updateStyle(); virtual void detach(); private: @@ -86,19 +85,17 @@ private: class MediaControlElement : public HTMLDivElement { public: - static PassRefPtr<MediaControlElement> create(HTMLMediaElement*, PseudoId); - virtual void attach(); void attachToParent(Element*); void update(); void updateStyle(); - MediaControlElementType displayType() const { return m_displayType; } + virtual MediaControlElementType displayType() const = 0; HTMLMediaElement* mediaElement() const { return m_mediaElement; } protected: - MediaControlElement(HTMLMediaElement*, PseudoId); + MediaControlElement(HTMLMediaElement*); virtual bool rendererIsNeeded(RenderStyle*); @@ -108,19 +105,32 @@ private: virtual bool isMediaControlElement() const { return true; } HTMLMediaElement* m_mediaElement; - PseudoId m_pseudoStyleId; - MediaControlElementType m_displayType; // some elements can show multiple types (e.g. play/pause) }; // ---------------------------- +class MediaControlPanelElement : public MediaControlElement { +public: + static PassRefPtr<MediaControlPanelElement> create(HTMLMediaElement*); + +private: + MediaControlPanelElement(HTMLMediaElement*); + virtual MediaControlElementType displayType() const; + virtual const AtomicString& shadowPseudoId() const; +}; + + +// ---------------------------- + class MediaControlTimelineContainerElement : public MediaControlElement { public: static PassRefPtr<MediaControlTimelineContainerElement> create(HTMLMediaElement*); private: MediaControlTimelineContainerElement(HTMLMediaElement*); + virtual MediaControlElementType displayType() const; virtual bool rendererIsNeeded(RenderStyle*); + virtual const AtomicString& shadowPseudoId() const; }; // ---------------------------- @@ -137,6 +147,8 @@ public: private: MediaControlVolumeSliderContainerElement(HTMLMediaElement*); + virtual MediaControlElementType displayType() const; + virtual const AtomicString& shadowPseudoId() const; bool m_isVisible; int m_x, m_y; @@ -153,7 +165,9 @@ public: private: MediaControlStatusDisplayElement(HTMLMediaElement*); + virtual MediaControlElementType displayType() const; virtual bool rendererIsNeeded(RenderStyle*); + virtual const AtomicString& shadowPseudoId() const; enum StateBeingDisplayed { Nothing, Loading, LiveBroadcast }; StateBeingDisplayed m_stateBeingDisplayed; @@ -174,12 +188,10 @@ public: HTMLMediaElement* mediaElement() const { return m_mediaElement; } protected: - MediaControlInputElement(HTMLMediaElement*, PseudoId); + MediaControlInputElement(HTMLMediaElement*, MediaControlElementType); void setDisplayType(MediaControlElementType); - PseudoId pseudoStyleId() const { return m_pseudoStyleId; } - private: virtual void attach(); virtual bool rendererIsNeeded(RenderStyle*); @@ -190,8 +202,7 @@ private: virtual void updateDisplayType() { } - HTMLMediaElement* m_mediaElement; - PseudoId m_pseudoStyleId; + HTMLMediaElement* m_mediaElement; MediaControlElementType m_displayType; }; @@ -199,17 +210,31 @@ private: class MediaControlMuteButtonElement : public MediaControlInputElement { public: - enum ButtonLocation { Controller, VolumeSlider }; - static PassRefPtr<MediaControlMuteButtonElement> create(HTMLMediaElement*, ButtonLocation); + static PassRefPtr<MediaControlMuteButtonElement> create(HTMLMediaElement*); virtual void defaultEventHandler(Event*); -private: - MediaControlMuteButtonElement(HTMLMediaElement*, ButtonLocation); +protected: + MediaControlMuteButtonElement(HTMLMediaElement*, MediaControlElementType); +private: virtual void updateDisplayType(); + virtual const AtomicString& shadowPseudoId() const; +}; + +// ---------------------------- + +class MediaControlVolumeSliderMuteButtonElement : public MediaControlMuteButtonElement { +public: + static PassRefPtr<MediaControlVolumeSliderMuteButtonElement> create(HTMLMediaElement*); + +private: + MediaControlVolumeSliderMuteButtonElement(HTMLMediaElement*); + + virtual const AtomicString& shadowPseudoId() const; }; + // ---------------------------- class MediaControlPlayButtonElement : public MediaControlInputElement { @@ -222,20 +247,20 @@ private: MediaControlPlayButtonElement(HTMLMediaElement*); virtual void updateDisplayType(); + virtual const AtomicString& shadowPseudoId() const; }; // ---------------------------- class MediaControlSeekButtonElement : public MediaControlInputElement { public: - static PassRefPtr<MediaControlSeekButtonElement> create(HTMLMediaElement*, PseudoId); - virtual void defaultEventHandler(Event*); -private: - MediaControlSeekButtonElement(HTMLMediaElement*, PseudoId); +protected: + MediaControlSeekButtonElement(HTMLMediaElement*, MediaControlElementType); - bool isForwardButton() const; +private: + virtual bool isForwardButton() const = 0; virtual void detach(); void seekTimerFired(Timer<MediaControlSeekButtonElement>*); @@ -244,7 +269,33 @@ private: bool m_capturing; Timer<MediaControlSeekButtonElement> m_seekTimer; }; - + +// ---------------------------- + +class MediaControlSeekForwardButtonElement : public MediaControlSeekButtonElement { +public: + static PassRefPtr<MediaControlSeekForwardButtonElement> create(HTMLMediaElement*); + +private: + MediaControlSeekForwardButtonElement(HTMLMediaElement*); + + virtual bool isForwardButton() const { return true; } + virtual const AtomicString& shadowPseudoId() const; +}; + +// ---------------------------- + +class MediaControlSeekBackButtonElement : public MediaControlSeekButtonElement { +public: + static PassRefPtr<MediaControlSeekBackButtonElement> create(HTMLMediaElement*); + +private: + MediaControlSeekBackButtonElement(HTMLMediaElement*); + + virtual bool isForwardButton() const { return false; } + virtual const AtomicString& shadowPseudoId() const; +}; + // ---------------------------- class MediaControlRewindButtonElement : public MediaControlInputElement { @@ -255,6 +306,8 @@ public: private: MediaControlRewindButtonElement(HTMLMediaElement*); + + virtual const AtomicString& shadowPseudoId() const; }; // ---------------------------- @@ -267,6 +320,8 @@ public: private: MediaControlReturnToRealtimeButtonElement(HTMLMediaElement*); + + virtual const AtomicString& shadowPseudoId() const; }; // ---------------------------- @@ -281,6 +336,7 @@ private: MediaControlToggleClosedCaptionsButtonElement(HTMLMediaElement*); virtual void updateDisplayType(); + virtual const AtomicString& shadowPseudoId() const; }; // ---------------------------- @@ -294,6 +350,8 @@ public: private: MediaControlTimelineElement(HTMLMediaElement*); + + virtual const AtomicString& shadowPseudoId() const; }; // ---------------------------- @@ -307,6 +365,8 @@ public: private: MediaControlVolumeSliderElement(HTMLMediaElement*); + + virtual const AtomicString& shadowPseudoId() const; }; // ---------------------------- @@ -319,22 +379,23 @@ public: private: MediaControlFullscreenButtonElement(HTMLMediaElement*); + + virtual const AtomicString& shadowPseudoId() const; }; // ---------------------------- class MediaControlTimeDisplayElement : public MediaControlElement { public: - static PassRefPtr<MediaControlTimeDisplayElement> create(HTMLMediaElement*, PseudoId); - void setVisible(bool); void setCurrentValue(float); float currentValue() const { return m_currentValue; } -private: - MediaControlTimeDisplayElement(HTMLMediaElement*, PseudoId); +protected: + MediaControlTimeDisplayElement(HTMLMediaElement*); +private: virtual PassRefPtr<RenderStyle> styleForElement(); float m_currentValue; bool m_isVisible; @@ -342,6 +403,32 @@ private: // ---------------------------- +class MediaControlTimeRemainingDisplayElement : public MediaControlTimeDisplayElement { +public: + static PassRefPtr<MediaControlTimeRemainingDisplayElement> create(HTMLMediaElement*); + +private: + MediaControlTimeRemainingDisplayElement(HTMLMediaElement*); + + virtual MediaControlElementType displayType() const; + virtual const AtomicString& shadowPseudoId() const; +}; + +// ---------------------------- + +class MediaControlCurrentTimeDisplayElement : public MediaControlTimeDisplayElement { +public: + static PassRefPtr<MediaControlCurrentTimeDisplayElement> create(HTMLMediaElement*); + +private: + MediaControlCurrentTimeDisplayElement(HTMLMediaElement*); + + virtual MediaControlElementType displayType() const; + virtual const AtomicString& shadowPseudoId() const; +}; + +// ---------------------------- + class RenderMediaControlShadowRoot : public RenderBlock { public: RenderMediaControlShadowRoot(Element* e) : RenderBlock(e) { } diff --git a/Source/WebCore/rendering/RenderBR.h b/Source/WebCore/rendering/RenderBR.h index 7216b5a..72a4514 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*/) const { return 0; } - virtual unsigned width(unsigned /*from*/, unsigned /*len*/, int /*xpos*/, bool /*firstLine = false*/) const { return 0; } + 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; } int lineHeight(bool firstLine) const; diff --git a/Source/WebCore/rendering/RenderBlock.cpp b/Source/WebCore/rendering/RenderBlock.cpp index 7275461..87aa630 100644 --- a/Source/WebCore/rendering/RenderBlock.cpp +++ b/Source/WebCore/rendering/RenderBlock.cpp @@ -36,6 +36,7 @@ #include "HitTestResult.h" #include "InlineTextBox.h" #include "PaintInfo.h" +#include "RenderCombineText.h" #include "RenderFlexibleBox.h" #include "RenderImage.h" #include "RenderInline.h" @@ -1267,7 +1268,7 @@ void RenderBlock::layoutBlock(bool relayoutChildren, int pageLogicalHeight) statePusher.pop(); if (view()->layoutState()->m_pageLogicalHeight) - setPageLogicalOffset(view()->layoutState()->pageLogicalOffset(y())); + setPageLogicalOffset(view()->layoutState()->pageLogicalOffset(logicalTop())); updateLayerTransform(); @@ -1330,10 +1331,18 @@ void RenderBlock::addOverflowFromChildren() ColumnInfo* colInfo = columnInfo(); if (columnCount(colInfo)) { IntRect lastRect = columnRectAt(colInfo, columnCount(colInfo) - 1); - int overflowLeft = !style()->isLeftToRightDirection() ? min(0, lastRect.x()) : 0; - int overflowRight = style()->isLeftToRightDirection() ? max(width(), lastRect.x() + lastRect.width()) : 0; - int overflowHeight = borderTop() + paddingTop() + colInfo->columnHeight(); - addLayoutOverflow(IntRect(overflowLeft, 0, overflowRight - overflowLeft, overflowHeight)); + if (style()->isHorizontalWritingMode()) { + int overflowLeft = !style()->isLeftToRightDirection() ? min(0, lastRect.x()) : 0; + int overflowRight = style()->isLeftToRightDirection() ? max(width(), lastRect.maxX()) : 0; + int overflowHeight = borderBefore() + paddingBefore() + colInfo->columnHeight(); + addLayoutOverflow(IntRect(overflowLeft, 0, overflowRight - overflowLeft, overflowHeight)); + } else { + IntRect lastRect = columnRectAt(colInfo, columnCount(colInfo) - 1); + int overflowTop = !style()->isLeftToRightDirection() ? min(0, lastRect.y()) : 0; + int overflowBottom = style()->isLeftToRightDirection() ? max(height(), lastRect.maxY()) : 0; + int overflowWidth = borderBefore() + paddingBefore() + colInfo->columnHeight(); + addLayoutOverflow(IntRect(0, overflowTop, overflowWidth, overflowBottom - overflowTop)); + } } } } @@ -1376,14 +1385,13 @@ void RenderBlock::addOverflowFromBlockChildren() void RenderBlock::addOverflowFromFloats() { - IntRect result; if (!m_floatingObjects) return; FloatingObject* r; DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); for (; (r = it.current()); ++it) { if (r->m_isDescendant) - addOverflowFromChild(r->m_renderer, IntSize(r->left() + r->m_renderer->marginLeft(), r->top() + r->m_renderer->marginTop())); + addOverflowFromChild(r->m_renderer, IntSize(xPositionForFloatIncludingMargin(r), yPositionForFloatIncludingMargin(r))); } return; } @@ -1649,7 +1657,7 @@ int RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo) bool paginated = view()->layoutState()->isPaginated(); if (paginated && logicalTop > beforeCollapseLogicalTop) { int oldLogicalTop = logicalTop; - logicalTop = min(logicalTop, nextPageTop(beforeCollapseLogicalTop)); + logicalTop = min(logicalTop, nextPageLogicalTop(beforeCollapseLogicalTop)); setLogicalHeight(logicalHeight() + (logicalTop - oldLogicalTop)); } return logicalTop; @@ -1719,7 +1727,7 @@ int RenderBlock::estimateLogicalTopPosition(RenderBox* child, const MarginInfo& // Adjust logicalTopEstimate down to the next page if the margins are so large that we don't fit on the current // page. if (paginated && logicalTopEstimate > logicalHeight()) - logicalTopEstimate = min(logicalTopEstimate, nextPageTop(logicalHeight())); + logicalTopEstimate = min(logicalTopEstimate, nextPageLogicalTop(logicalHeight())); logicalTopEstimate += getClearDelta(child, logicalTopEstimate); @@ -2062,7 +2070,7 @@ void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, int if (paginated) { // Check for an after page/column break. - int newHeight = applyAfterBreak(child, height(), marginInfo); + int newHeight = applyAfterBreak(child, logicalHeight(), marginInfo); if (newHeight != height()) setLogicalHeight(newHeight); } @@ -2166,7 +2174,7 @@ void RenderBlock::markForPaginationRelayoutIfNeeded() if (needsLayout()) return; - if (view()->layoutState()->pageLogicalHeightChanged() || (view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(y()) != pageLogicalOffset())) + if (view()->layoutState()->pageLogicalHeightChanged() || (view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(logicalTop()) != pageLogicalOffset())) setChildNeedsLayout(true, false); } @@ -2243,32 +2251,34 @@ void RenderBlock::paintColumnRules(PaintInfo& paintInfo, int tx, int ty) // We need to do multiple passes, breaking up our child painting into strips. ColumnInfo* colInfo = columnInfo(); unsigned colCount = columnCount(colInfo); - int currXOffset = style()->isLeftToRightDirection() ? 0 : contentWidth(); - int ruleAdd = borderLeft() + paddingLeft(); - int ruleX = style()->isLeftToRightDirection() ? 0 : contentWidth(); + int currLogicalLeftOffset = style()->isLeftToRightDirection() ? 0 : contentLogicalWidth(); + int ruleAdd = logicalLeftOffsetForContent(); + int ruleLogicalLeft = style()->isLeftToRightDirection() ? 0 : contentLogicalWidth(); for (unsigned i = 0; i < colCount; i++) { IntRect colRect = columnRectAt(colInfo, i); + int inlineDirectionSize = style()->isHorizontalWritingMode() ? colRect.width() : colRect.height(); + // Move to the next position. if (style()->isLeftToRightDirection()) { - ruleX += colRect.width() + colGap / 2; - currXOffset += colRect.width() + colGap; + ruleLogicalLeft += inlineDirectionSize + colGap / 2; + currLogicalLeftOffset += inlineDirectionSize + colGap; } else { - ruleX -= (colRect.width() + colGap / 2); - currXOffset -= (colRect.width() + colGap); + ruleLogicalLeft -= (inlineDirectionSize + colGap / 2); + currLogicalLeftOffset -= (inlineDirectionSize + colGap); } // Now paint the column rule. if (i < colCount - 1) { - int ruleStart = tx + ruleX - ruleWidth / 2 + ruleAdd; - int ruleEnd = ruleStart + ruleWidth; - int ruleTop = ty + borderTop() + paddingTop(); - int ruleBottom = ruleTop + contentHeight(); - drawLineForBoxSide(paintInfo.context, ruleStart, ruleTop, ruleEnd, ruleBottom, + int ruleLeft = style()->isHorizontalWritingMode() ? tx + ruleLogicalLeft - ruleWidth / 2 + ruleAdd : tx + borderBefore() + paddingBefore(); + int ruleRight = style()->isHorizontalWritingMode() ? ruleLeft + ruleWidth : ruleLeft + contentWidth(); + int ruleTop = style()->isHorizontalWritingMode() ? ty + borderTop() + paddingTop() : ty + ruleLogicalLeft - ruleWidth / 2 + ruleAdd; + int ruleBottom = style()->isHorizontalWritingMode() ? ruleTop + contentHeight() : ruleTop + ruleWidth; + drawLineForBoxSide(paintInfo.context, ruleLeft, ruleTop, ruleRight, ruleBottom, style()->isLeftToRightDirection() ? BSLeft : BSRight, ruleColor, ruleStyle, 0, 0); } - ruleX = currXOffset; + ruleLogicalLeft = currLogicalLeftOffset; } } @@ -2276,16 +2286,17 @@ void RenderBlock::paintColumnContents(PaintInfo& paintInfo, int tx, int ty, bool { // We need to do multiple passes, breaking up our child painting into strips. GraphicsContext* context = paintInfo.context; - int colGap = columnGap(); ColumnInfo* colInfo = columnInfo(); unsigned colCount = columnCount(colInfo); if (!colCount) return; - int currXOffset = style()->isLeftToRightDirection() ? 0 : contentWidth() - columnRectAt(colInfo, 0).width(); - int currYOffset = 0; + int currLogicalTopOffset = 0; for (unsigned i = 0; i < colCount; i++) { // For each rect, we clip to the rect, and then we adjust our coords. IntRect colRect = columnRectAt(colInfo, i); + flipForWritingMode(colRect); + int logicalLeftOffset = (style()->isHorizontalWritingMode() ? colRect.x() : colRect.y()) - logicalLeftOffsetForContent(); + IntSize offset = style()->isHorizontalWritingMode() ? IntSize(logicalLeftOffset, currLogicalTopOffset) : IntSize(currLogicalTopOffset, logicalLeftOffset); colRect.move(tx, ty); PaintInfo info(paintInfo); info.rect.intersect(colRect); @@ -2296,10 +2307,10 @@ void RenderBlock::paintColumnContents(PaintInfo& paintInfo, int tx, int ty, bool // Each strip pushes a clip, since column boxes are specified as being // like overflow:hidden. context->clip(colRect); - + // Adjust our x and y when painting. - int finalX = tx + currXOffset; - int finalY = ty + currYOffset; + int finalX = tx + offset.width(); + int finalY = ty + offset.height(); if (paintingFloats) paintFloats(info, finalX, finalY, paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip); else @@ -2307,14 +2318,12 @@ void RenderBlock::paintColumnContents(PaintInfo& paintInfo, int tx, int ty, bool context->restore(); } - - // Move to the next position. - if (style()->isLeftToRightDirection()) - currXOffset += colRect.width() + colGap; + + int blockDelta = (style()->isHorizontalWritingMode() ? colRect.height() : colRect.width()); + if (style()->isFlippedBlocksWritingMode()) + currLogicalTopOffset += blockDelta; else - currXOffset -= (colRect.width() + colGap); - - currYOffset -= colRect.height(); + currLogicalTopOffset -= blockDelta; } } @@ -2352,14 +2361,14 @@ void RenderBlock::paintChildren(PaintInfo& paintInfo, int tx, int ty) bool checkBeforeAlways = !childrenInline() && (usePrintRect && child->style()->pageBreakBefore() == PBALWAYS); if (checkBeforeAlways && (ty + child->y()) > paintInfo.rect.y() - && (ty + child->y()) < paintInfo.rect.bottom()) { + && (ty + child->y()) < paintInfo.rect.maxY()) { view()->setBestTruncatedAt(ty + child->y(), this, true); return; } if (!child->isFloating() && child->isReplaced() && usePrintRect && child->height() <= renderView->printRect().height()) { // Paginate block-level replaced elements. - if (ty + child->y() + child->height() > renderView->printRect().bottom()) { + if (ty + child->y() + child->height() > renderView->printRect().maxY()) { if (ty + child->y() < renderView->truncatedAt()) renderView->setBestTruncatedAt(ty + child->y(), child); // If we were able to truncate, don't paint. @@ -2376,7 +2385,7 @@ void RenderBlock::paintChildren(PaintInfo& paintInfo, int tx, int ty) bool checkAfterAlways = !childrenInline() && (usePrintRect && child->style()->pageBreakAfter() == PBALWAYS); if (checkAfterAlways && (ty + child->y() + child->height()) > paintInfo.rect.y() - && (ty + child->y() + child->height()) < paintInfo.rect.bottom()) { + && (ty + child->y() + child->height()) < paintInfo.rect.maxY()) { view()->setBestTruncatedAt(ty + child->y() + child->height() + max(0, child->collapsedMarginAfter()), this, true); return; } @@ -2491,6 +2500,19 @@ void RenderBlock::paintObject(PaintInfo& paintInfo, int tx, int ty) } } +IntPoint RenderBlock::flipFloatForWritingMode(const FloatingObject* child, const IntPoint& point) const +{ + if (!style()->isFlippedBlocksWritingMode()) + return point; + + // This is similar to the ParentToChildFlippingAdjustment in RenderBox::flipForWritingMode. We have to subtract out our left/top offsets twice, since + // it's going to get added back in. We hide this complication here so that the calling code looks normal for the unflipped + // case. + if (style()->isHorizontalWritingMode()) + return IntPoint(point.x(), point.y() + height() - child->renderer()->height() - 2 * yPositionForFloatIncludingMargin(child)); + return IntPoint(point.x() + width() - child->width() - 2 * xPositionForFloatIncludingMargin(child), point.y()); +} + void RenderBlock::paintFloats(PaintInfo& paintInfo, int tx, int ty, bool preservePhase) { if (!m_floatingObjects) @@ -2503,7 +2525,7 @@ void RenderBlock::paintFloats(PaintInfo& paintInfo, int tx, int ty, bool preserv if (r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer()) { PaintInfo currentPaintInfo(paintInfo); currentPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground; - IntPoint childPoint = flipForWritingMode(r->m_renderer, IntPoint(tx + r->left() + r->m_renderer->marginLeft() - r->m_renderer->x(), ty + r->top() + r->m_renderer->marginTop() - r->m_renderer->y()), ParentToChildFlippingAdjustment); + IntPoint childPoint = flipFloatForWritingMode(r, IntPoint(tx + xPositionForFloatIncludingMargin(r) - r->m_renderer->x(), ty + yPositionForFloatIncludingMargin(r) - r->m_renderer->y())); r->m_renderer->paint(currentPaintInfo, childPoint.x(), childPoint.y()); if (!preservePhase) { currentPaintInfo.phase = PaintPhaseChildBlockBackgrounds; @@ -2529,7 +2551,7 @@ void RenderBlock::paintEllipsisBoxes(PaintInfo& paintInfo, int tx, int ty) // intersect. int yPos = ty + firstLineBox()->y(); int h = lastLineBox()->y() + lastLineBox()->logicalHeight() - firstLineBox()->y(); - if (yPos >= paintInfo.rect.bottom() || yPos + h <= paintInfo.rect.y()) + if (yPos >= paintInfo.rect.maxY() || yPos + h <= paintInfo.rect.y()) return; // See if our boxes intersect with the dirty rect. If so, then we paint @@ -2538,7 +2560,7 @@ void RenderBlock::paintEllipsisBoxes(PaintInfo& paintInfo, int tx, int ty) for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) { yPos = ty + curr->y(); h = curr->logicalHeight(); - if (curr->ellipsisBox() && yPos < paintInfo.rect.bottom() && yPos + h > paintInfo.rect.y()) + if (curr->ellipsisBox() && yPos < paintInfo.rect.maxY() && yPos + h > paintInfo.rect.y()) curr->paintEllipsisBox(paintInfo, tx, ty); } } @@ -2737,8 +2759,8 @@ GapRects RenderBlock::selectionGaps(RenderBlock* rootBlock, const IntPoint& root if (m_floatingObjects) { for (DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); it.current(); ++it) { FloatingObject* r = it.current(); - IntRect floatBox = IntRect(offsetFromRootBlock.width() + r->left() + r->m_renderer->marginLeft(), - offsetFromRootBlock.height() + r->top() + r->m_renderer->marginTop(), + IntRect floatBox = IntRect(offsetFromRootBlock.width() + xPositionForFloatIncludingMargin(r), + offsetFromRootBlock.height() + yPositionForFloatIncludingMargin(r), r->m_renderer->width(), r->m_renderer->height()); rootBlock->flipForWritingMode(floatBox); floatBox.move(rootBlockPhysicalPosition.x(), rootBlockPhysicalPosition.y()); @@ -2808,8 +2830,8 @@ GapRects RenderBlock::inlineSelectionGaps(RenderBlock* rootBlock, const IntPoint IntRect logicalRect(curr->logicalLeft(), selTop, curr->logicalWidth(), selTop + selHeight); logicalRect.move(style()->isHorizontalWritingMode() ? offsetFromRootBlock : IntSize(offsetFromRootBlock.height(), offsetFromRootBlock.width())); IntRect physicalRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, logicalRect); - if (!paintInfo || (style()->isHorizontalWritingMode() && physicalRect.y() < paintInfo->rect.bottom() && physicalRect.bottom() > paintInfo->rect.y()) - || (!style()->isHorizontalWritingMode() && physicalRect.x() < paintInfo->rect.right() && physicalRect.right() > paintInfo->rect.x())) + if (!paintInfo || (style()->isHorizontalWritingMode() && physicalRect.y() < paintInfo->rect.maxY() && physicalRect.maxY() > paintInfo->rect.y()) + || (!style()->isHorizontalWritingMode() && physicalRect.x() < paintInfo->rect.maxX() && physicalRect.maxX() > paintInfo->rect.x())) result.unite(curr->lineSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, selTop, selHeight, paintInfo)); lastSelectedLine = curr; @@ -3098,7 +3120,7 @@ void RenderBlock::removeFloatingObject(RenderBox* o) // 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 + 1); + logicalBottom = max(logicalBottom, logicalTop == numeric_limits<int>::max() ? logicalTop : logicalTop + 1); markLinesDirtyInBlockRange(0, logicalBottom); } m_floatingObjects->removeRef(it.current()); @@ -3108,13 +3130,13 @@ void RenderBlock::removeFloatingObject(RenderBox* o) } } -void RenderBlock::removeFloatingObjectsBelow(FloatingObject* lastFloat, int y) +void RenderBlock::removeFloatingObjectsBelow(FloatingObject* lastFloat, int logicalOffset) { if (!m_floatingObjects) return; FloatingObject* curr = m_floatingObjects->last(); - while (curr != lastFloat && (!curr->isPlaced() || curr->top() >= y)) { + while (curr != lastFloat && (!curr->isPlaced() || logicalTopForFloat(curr) >= logicalOffset)) { m_floatingObjects->removeLast(); curr = m_floatingObjects->last(); } @@ -3460,7 +3482,7 @@ void RenderBlock::markLinesDirtyInBlockRange(int logicalTop, int logicalBottom, RootInlineBox* lowestDirtyLine = lastRootBox(); RootInlineBox* afterLowest = lowestDirtyLine; - while (lowestDirtyLine && lowestDirtyLine->blockLogicalHeight() >= logicalBottom) { + while (lowestDirtyLine && lowestDirtyLine->blockLogicalHeight() >= logicalBottom && logicalBottom < numeric_limits<int>::max()) { afterLowest = lowestDirtyLine; lowestDirtyLine = lowestDirtyLine->prevRootBox(); } @@ -3591,7 +3613,7 @@ int RenderBlock::addOverhangingFloats(RenderBlock* child, int logicalLeftOffset, if (!containsFloat(r->m_renderer)) { int leftOffset = style()->isHorizontalWritingMode() ? logicalLeftOffset : logicalTopOffset; int topOffset = style()->isHorizontalWritingMode() ? logicalTopOffset : logicalLeftOffset; - FloatingObject* floatingObj = new FloatingObject(r->type(), IntRect(r->left() - leftOffset, r->top() - topOffset, r->width(), r->height())); + FloatingObject* floatingObj = new FloatingObject(r->type(), IntRect(r->x() - leftOffset, r->y() - topOffset, r->width(), r->height())); floatingObj->m_renderer = r->m_renderer; // The nearest enclosing layer always paints the float (so that zindex and stacking @@ -3626,7 +3648,7 @@ int RenderBlock::addOverhangingFloats(RenderBlock* child, int logicalLeftOffset, // Since the float doesn't overhang, it didn't get put into our list. We need to go ahead and add its overflow in to the // child now. if (r->m_isDescendant) - child->addOverflowFromChild(r->m_renderer, IntSize(r->left() + r->m_renderer->marginLeft(), r->top() + r->m_renderer->marginTop())); + child->addOverflowFromChild(r->m_renderer, IntSize(xPositionForFloatIncludingMargin(r), yPositionForFloatIncludingMargin(r))); } } return lowestFloatLogicalBottom; @@ -3658,7 +3680,7 @@ void RenderBlock::addIntrudingFloats(RenderBlock* prev, int logicalLeftOffset, i int leftOffset = style()->isHorizontalWritingMode() ? logicalLeftOffset : logicalTopOffset; int topOffset = style()->isHorizontalWritingMode() ? logicalTopOffset : logicalLeftOffset; - FloatingObject* floatingObj = new FloatingObject(r->type(), IntRect(r->left() - leftOffset, r->top() - topOffset, r->width(), r->height())); + FloatingObject* floatingObj = new FloatingObject(r->type(), IntRect(r->x() - leftOffset, r->y() - topOffset, r->width(), r->height())); // Applying the child's margin makes no sense in the case where the child was passed in. // since this margin was added already through the modification of the |logicalLeftOffset| variable @@ -3667,9 +3689,9 @@ void RenderBlock::addIntrudingFloats(RenderBlock* prev, int logicalLeftOffset, i // will get applied twice. if (prev != parent()) { if (style()->isHorizontalWritingMode()) - floatingObj->setLeft(floatingObj->left() + prev->marginLeft()); + floatingObj->setX(floatingObj->x() + prev->marginLeft()); else - floatingObj->setTop(floatingObj->top() + prev->marginTop()); + floatingObj->setY(floatingObj->y() + prev->marginTop()); } floatingObj->m_shouldPaint = false; // We are not in the direct inheritance chain for this float. We will never paint it. @@ -3864,9 +3886,9 @@ bool RenderBlock::hitTestFloats(const HitTestRequest& request, HitTestResult& re DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); for (it.toLast(); (floatingObject = it.current()); --it) { if (floatingObject->m_shouldPaint && !floatingObject->m_renderer->hasSelfPaintingLayer()) { - int xOffset = floatingObject->left() + floatingObject->m_renderer->marginLeft() - floatingObject->m_renderer->x(); - int yOffset = floatingObject->top() + floatingObject->m_renderer->marginTop() - floatingObject->m_renderer->y(); - IntPoint childPoint = flipForWritingMode(floatingObject->m_renderer, IntPoint(tx + xOffset, ty + yOffset), ParentToChildFlippingAdjustment); + int xOffset = xPositionForFloatIncludingMargin(floatingObject) - floatingObject->m_renderer->x(); + int yOffset = yPositionForFloatIncludingMargin(floatingObject) - floatingObject->m_renderer->y(); + IntPoint childPoint = flipFloatForWritingMode(floatingObject, IntPoint(tx + xOffset, ty + yOffset)); if (floatingObject->m_renderer->hitTest(request, result, IntPoint(x, y), childPoint.x(), childPoint.y())) { updateHitTestResult(result, IntPoint(x - childPoint.x(), y - childPoint.y())); return true; @@ -3884,23 +3906,36 @@ bool RenderBlock::hitTestColumns(const HitTestRequest& request, HitTestResult& r int colCount = columnCount(colInfo); if (!colCount) return false; - int left = borderLeft() + paddingLeft(); - int currYOffset = 0; + int logicalLeft = logicalLeftOffsetForContent(); + int currLogicalTopOffset = 0; int i; - for (i = 0; i < colCount; i++) - currYOffset -= columnRectAt(colInfo, i).height(); + bool isHorizontal = style()->isHorizontalWritingMode(); + for (i = 0; i < colCount; i++) { + IntRect colRect = columnRectAt(colInfo, i); + int blockDelta = (isHorizontal ? colRect.height() : colRect.width()); + if (style()->isFlippedBlocksWritingMode()) + currLogicalTopOffset += blockDelta; + else + currLogicalTopOffset -= blockDelta; + } for (i = colCount - 1; i >= 0; i--) { IntRect colRect = columnRectAt(colInfo, i); - int currXOffset = colRect.x() - left; - currYOffset += colRect.height(); + flipForWritingMode(colRect); + int currLogicalLeftOffset = (isHorizontal ? colRect.x() : colRect.y()) - logicalLeft; + int blockDelta = (isHorizontal ? colRect.height() : colRect.width()); + if (style()->isFlippedBlocksWritingMode()) + currLogicalTopOffset -= blockDelta; + else + currLogicalTopOffset += blockDelta; colRect.move(tx, ty); if (colRect.intersects(result.rectForPoint(x, y))) { // The point is inside this column. // Adjust tx and ty to change where we hit test. - int finalX = tx + currXOffset; - int finalY = ty + currYOffset; + IntSize offset = isHorizontal ? IntSize(currLogicalLeftOffset, currLogicalTopOffset) : IntSize(currLogicalTopOffset, currLogicalLeftOffset); + int finalX = tx + offset.width(); + int finalY = ty + offset.height(); if (result.isRectBasedTest() && !colRect.contains(result.rectForPoint(x, y))) hitTestContents(request, result, x, y, finalX, finalY, hitTestAction); else @@ -3947,25 +3982,6 @@ Position RenderBlock::positionForBox(InlineBox *box, bool start) const return Position(box->renderer()->node(), start ? textBox->start() : textBox->start() + textBox->len()); } -Position RenderBlock::positionForRenderer(RenderObject* renderer, bool start) const -{ - if (!renderer) - return Position(node(), 0); - - Node* n = renderer->node() ? renderer->node() : node(); - if (!n) - return Position(); - - ASSERT(renderer == n->renderer()); - - int offset = start ? renderer->caretMinOffset() : renderer->caretMaxOffset(); - - // FIXME: This was a runtime check that seemingly couldn't fail; changed it to an assertion for now. - ASSERT(!n->isCharacterDataNode() || renderer->isText()); - - return Position(n, offset); -} - // FIXME: This function should go on RenderObject as an instance method. Then // all cases in which positionForPoint recurs could call this instead to // prevent crossing editable boundaries. This would require many tests. @@ -4139,7 +4155,7 @@ void RenderBlock::calcColumnWidth() { // Calculate our column width and column count. unsigned desiredColumnCount = 1; - int desiredColumnWidth = contentWidth(); + int desiredColumnWidth = contentLogicalWidth(); // For now, we don't support multi-column layouts when printing, since we have to do a lot of work for proper pagination. if (document()->paginated() || (style()->hasAutoColumnCount() && style()->hasAutoColumnWidth())) { @@ -4214,7 +4230,7 @@ void RenderBlock::setDesiredColumnCountAndWidth(int count, int width) int RenderBlock::desiredColumnWidth() const { if (!hasColumns()) - return contentWidth(); + return contentLogicalWidth(); return gColumnInfoMap->get(this)->desiredColumnWidth(); } @@ -4243,14 +4259,17 @@ IntRect RenderBlock::columnRectAt(ColumnInfo* colInfo, unsigned index) const ASSERT(hasColumns() && gColumnInfoMap->get(this) == colInfo); // Compute the appropriate rect based off our information. - int colWidth = colInfo->desiredColumnWidth(); - int colHeight = colInfo->columnHeight(); - int colTop = borderTop() + paddingTop(); + int colLogicalWidth = colInfo->desiredColumnWidth(); + int colLogicalHeight = colInfo->columnHeight(); + int colLogicalTop = borderBefore() + paddingBefore(); int colGap = columnGap(); - int colLeft = style()->isLeftToRightDirection() ? - borderLeft() + paddingLeft() + (index * (colWidth + colGap)) - : borderLeft() + paddingLeft() + contentWidth() - colWidth - (index * (colWidth + colGap)); - return IntRect(colLeft, colTop, colWidth, colHeight); + int colLogicalLeft = style()->isLeftToRightDirection() ? + logicalLeftOffsetForContent() + (index * (colLogicalWidth + colGap)) + : logicalLeftOffsetForContent() + contentLogicalWidth() - colLogicalWidth - (index * (colLogicalWidth + colGap)); + IntRect rect(colLogicalLeft, colLogicalTop, colLogicalWidth, colLogicalHeight); + if (style()->isHorizontalWritingMode()) + return IntRect(colLogicalLeft, colLogicalTop, colLogicalWidth, colLogicalHeight); + return IntRect(colLogicalTop, colLogicalLeft, colLogicalHeight, colLogicalWidth); } bool RenderBlock::layoutColumns(bool hasSpecifiedPageLogicalHeight, int pageLogicalHeight, LayoutStateMaintainer& statePusher) @@ -4270,12 +4289,12 @@ bool RenderBlock::layoutColumns(bool hasSpecifiedPageLogicalHeight, int pageLogi // maximum page break distance. if (!pageLogicalHeight) { int distanceBetweenBreaks = max(colInfo->maximumDistanceBetweenForcedBreaks(), - view()->layoutState()->pageLogicalOffset(borderTop() + paddingTop() + contentHeight()) - colInfo->forcedBreakOffset()); + view()->layoutState()->pageLogicalOffset(borderBefore() + paddingBefore() + contentLogicalHeight()) - colInfo->forcedBreakOffset()); columnHeight = max(colInfo->minimumColumnHeight(), distanceBetweenBreaks); } - } else if (contentHeight() > pageLogicalHeight * desiredColumnCount) { + } else if (contentLogicalHeight() > pageLogicalHeight * desiredColumnCount) { // Now that we know the intrinsic height of the columns, we have to rebalance them. - columnHeight = max(colInfo->minimumColumnHeight(), (int)ceilf((float)contentHeight() / desiredColumnCount)); + columnHeight = max(colInfo->minimumColumnHeight(), (int)ceilf((float)contentLogicalHeight() / desiredColumnCount)); } if (columnHeight && columnHeight != pageLogicalHeight) { @@ -4287,10 +4306,10 @@ bool RenderBlock::layoutColumns(bool hasSpecifiedPageLogicalHeight, int pageLogi } if (pageLogicalHeight) - colInfo->setColumnCountAndHeight(ceilf((float)contentHeight() / pageLogicalHeight), pageLogicalHeight); + colInfo->setColumnCountAndHeight(ceilf((float)contentLogicalHeight() / pageLogicalHeight), pageLogicalHeight); if (columnCount(colInfo)) { - setLogicalHeight(borderTop() + paddingTop() + colInfo->columnHeight() + borderBottom() + paddingBottom() + horizontalScrollbarHeight()); + setLogicalHeight(borderBefore() + paddingBefore() + colInfo->columnHeight() + borderAfter() + paddingAfter() + scrollbarLogicalHeight()); m_overflow.clear(); } @@ -4309,34 +4328,57 @@ void RenderBlock::adjustPointToColumnContents(IntPoint& point) const // Determine which columns we intersect. int colGap = columnGap(); - int leftGap = colGap / 2; + int halfColGap = colGap / 2; IntPoint columnPoint(columnRectAt(colInfo, 0).location()); - int yOffset = 0; + int logicalOffset = 0; for (unsigned i = 0; i < colInfo->columnCount(); i++) { // Add in half the column gap to the left and right of the rect. IntRect colRect = columnRectAt(colInfo, i); - IntRect gapAndColumnRect(colRect.x() - leftGap, colRect.y(), colRect.width() + colGap, colRect.height()); - - if (point.x() >= gapAndColumnRect.x() && point.x() < gapAndColumnRect.right()) { - // FIXME: The clamping that follows is not completely right for right-to-left - // content. - // Clamp everything above the column to its top left. - if (point.y() < gapAndColumnRect.y()) - point = gapAndColumnRect.location(); - // Clamp everything below the column to the next column's top left. If there is - // no next column, this still maps to just after this column. - else if (point.y() >= gapAndColumnRect.bottom()) { - point = gapAndColumnRect.location(); - point.move(0, gapAndColumnRect.height()); + if (style()->isHorizontalWritingMode()) { + IntRect gapAndColumnRect(colRect.x() - halfColGap, colRect.y(), colRect.width() + colGap, colRect.height()); + if (point.x() >= gapAndColumnRect.x() && point.x() < gapAndColumnRect.maxX()) { + // FIXME: The clamping that follows is not completely right for right-to-left + // content. + // Clamp everything above the column to its top left. + if (point.y() < gapAndColumnRect.y()) + point = gapAndColumnRect.location(); + // Clamp everything below the column to the next column's top left. If there is + // no next column, this still maps to just after this column. + else if (point.y() >= gapAndColumnRect.maxY()) { + point = gapAndColumnRect.location(); + point.move(0, gapAndColumnRect.height()); + } + + // We're inside the column. Translate the x and y into our column coordinate space. + point.move(columnPoint.x() - colRect.x(), logicalOffset); + return; } + + // Move to the next position. + logicalOffset += colRect.height(); + } else { + IntRect gapAndColumnRect(colRect.x(), colRect.y() - halfColGap, colRect.width(), colRect.height() + colGap); + if (point.y() >= gapAndColumnRect.y() && point.y() < gapAndColumnRect.maxY()) { + // FIXME: The clamping that follows is not completely right for right-to-left + // content. + // Clamp everything above the column to its top left. + if (point.x() < gapAndColumnRect.x()) + point = gapAndColumnRect.location(); + // Clamp everything below the column to the next column's top left. If there is + // no next column, this still maps to just after this column. + else if (point.x() >= gapAndColumnRect.maxX()) { + point = gapAndColumnRect.location(); + point.move(gapAndColumnRect.width(), 0); + } - // We're inside the column. Translate the x and y into our column coordinate space. - point.move(columnPoint.x() - colRect.x(), yOffset); - return; + // We're inside the column. Translate the x and y into our column coordinate space. + point.move(logicalOffset, columnPoint.y() - colRect.y()); + return; + } + + // Move to the next position. + logicalOffset += colRect.width(); } - - // Move to the next position. - yOffset += colRect.height(); } } @@ -4356,27 +4398,56 @@ void RenderBlock::adjustRectForColumns(IntRect& r) const if (!colCount) return; - int left = borderLeft() + paddingLeft(); - - int currYOffset = 0; + int logicalLeft = logicalLeftOffsetForContent(); + int currLogicalOffset = 0; + for (unsigned i = 0; i < colCount; i++) { IntRect colRect = columnRectAt(colInfo, i); - int currXOffset = colRect.x() - left; - IntRect repaintRect = r; - repaintRect.move(currXOffset, currYOffset); - + if (style()->isHorizontalWritingMode()) { + int currXOffset = colRect.x() - logicalLeft; + repaintRect.move(currXOffset, currLogicalOffset); + currLogicalOffset -= colRect.height(); + } else { + int currYOffset = colRect.y() - logicalLeft; + repaintRect.move(currLogicalOffset, currYOffset); + currLogicalOffset -= colRect.width(); + } repaintRect.intersect(colRect); - result.unite(repaintRect); - - // Move to the next position. - currYOffset -= colRect.height(); } r = result; } +IntPoint RenderBlock::flipForWritingModeIncludingColumns(const IntPoint& point) const +{ + ASSERT(hasColumns()); + if (!hasColumns() || !style()->isFlippedBlocksWritingMode()) + return point; + ColumnInfo* colInfo = columnInfo(); + int columnLogicalHeight = colInfo->columnHeight(); + int expandedLogicalHeight = borderBefore() + paddingBefore() + columnCount(colInfo) * columnLogicalHeight + borderAfter() + paddingAfter() + scrollbarLogicalHeight(); + if (style()->isHorizontalWritingMode()) + return IntPoint(point.x(), expandedLogicalHeight - point.y()); + return IntPoint(expandedLogicalHeight - point.x(), point.y()); +} + +void RenderBlock::flipForWritingModeIncludingColumns(IntRect& rect) const +{ + ASSERT(hasColumns()); + if (!hasColumns() || !style()->isFlippedBlocksWritingMode()) + return; + + ColumnInfo* colInfo = columnInfo(); + int columnLogicalHeight = colInfo->columnHeight(); + int expandedLogicalHeight = borderBefore() + paddingBefore() + columnCount(colInfo) * columnLogicalHeight + borderAfter() + paddingAfter() + scrollbarLogicalHeight(); + if (style()->isHorizontalWritingMode()) + rect.setY(expandedLogicalHeight - rect.maxY()); + else + rect.setX(expandedLogicalHeight - rect.maxX()); +} + void RenderBlock::adjustForColumns(IntSize& offset, const IntPoint& point) const { if (!hasColumns()) @@ -4384,18 +4455,34 @@ void RenderBlock::adjustForColumns(IntSize& offset, const IntPoint& point) const ColumnInfo* colInfo = columnInfo(); - int left = borderLeft() + paddingLeft(); - int yOffset = 0; + int logicalLeft = logicalLeftOffsetForContent(); size_t colCount = columnCount(colInfo); + int colLogicalWidth = colInfo->desiredColumnWidth(); + int colLogicalHeight = colInfo->columnHeight(); + for (size_t i = 0; i < colCount; ++i) { - IntRect columnRect = columnRectAt(colInfo, i); - int xOffset = columnRect.x() - left; - if (point.y() < columnRect.bottom() + yOffset) { - offset.expand(xOffset, -yOffset); - return; - } + // Compute the edges for a given column in the block progression direction. + IntRect sliceRect = IntRect(logicalLeft, borderBefore() + paddingBefore() + i * colLogicalHeight, colLogicalWidth, colLogicalHeight); + if (!style()->isHorizontalWritingMode()) + sliceRect = sliceRect.transposedRect(); + + // If we have a flipped blocks writing mode, then convert the column so that it's coming from the after edge (either top or left edge). + flipForWritingModeIncludingColumns(sliceRect); + + int logicalOffset = style()->isFlippedBlocksWritingMode() ? (colCount - 1 - i) * colLogicalHeight : i * colLogicalHeight; - yOffset += columnRect.height(); + // Now we're in the same coordinate space as the point. See if it is inside the rectangle. + if (style()->isHorizontalWritingMode()) { + if (point.y() >= sliceRect.y() && point.y() < sliceRect.maxY()) { + offset.expand(columnRectAt(colInfo, i).x() - logicalLeft, -logicalOffset); + return; + } + } else { + if (point.x() >= sliceRect.x() && point.x() < sliceRect.maxX()) { + offset.expand(-logicalOffset, columnRectAt(colInfo, i).y() - logicalLeft); + return; + } + } } } @@ -4535,16 +4622,13 @@ static int getBPMWidth(int childValue, Length cssUnit) static int getBorderPaddingMargin(const RenderBoxModelObject* child, bool endOfInline) { RenderStyle* cstyle = child->style(); - int result = 0; - bool leftSide = (cstyle->isLeftToRightDirection()) ? !endOfInline : endOfInline; - result += getBPMWidth((leftSide ? child->marginLeft() : child->marginRight()), - (leftSide ? cstyle->marginLeft() : - cstyle->marginRight())); - result += getBPMWidth((leftSide ? child->paddingLeft() : child->paddingRight()), - (leftSide ? cstyle->paddingLeft() : - cstyle->paddingRight())); - result += leftSide ? child->borderLeft() : child->borderRight(); - return result; + if (endOfInline) + return getBPMWidth(child->marginEnd(), cstyle->marginEnd()) + + getBPMWidth(child->paddingEnd(), cstyle->paddingEnd()) + + child->borderEnd(); + return getBPMWidth(child->marginStart(), cstyle->marginStart()) + + getBPMWidth(child->paddingStart(), cstyle->paddingStart()) + + child->borderStart(); } static inline void stripTrailingSpace(int& inlineMax, int& inlineMin, @@ -4567,7 +4651,7 @@ void RenderBlock::computeInlinePreferredLogicalWidths() int inlineMax = 0; int inlineMin = 0; - int cw = containingBlock()->contentWidth(); + int cw = containingBlock()->contentLogicalWidth(); // If we are at the start of a line, we want to ignore all white-space. // Also strip spaces if we previously had text that ended in a trailing space. @@ -4577,7 +4661,7 @@ void RenderBlock::computeInlinePreferredLogicalWidths() // Firefox and Opera will allow a table cell to grow to fit an image inside it under // very specific cirucumstances (in order to match common WinIE renderings). // Not supporting the quirk has caused us to mis-render some real sites. (See Bugzilla 10517.) - bool allowImagesToBreak = !document()->inQuirksMode() || !isTableCell() || !style()->width().isIntrinsicOrAuto(); + bool allowImagesToBreak = !document()->inQuirksMode() || !isTableCell() || !style()->logicalWidth().isIntrinsicOrAuto(); bool autoWrap, oldAutoWrap; autoWrap = oldAutoWrap = style()->autoWrap(); @@ -4645,12 +4729,12 @@ void RenderBlock::computeInlinePreferredLogicalWidths() } else { // Inline replaced elts add in their margins to their min/max values. int margins = 0; - Length leftMargin = cstyle->marginLeft(); - Length rightMargin = cstyle->marginRight(); - if (leftMargin.isFixed()) - margins += leftMargin.value(); - if (rightMargin.isFixed()) - margins += rightMargin.value(); + Length startMargin = cstyle->marginStart(); + Length endMargin = cstyle->marginEnd(); + if (startMargin.isFixed()) + margins += startMargin.value(); + if (endMargin.isFixed()) + margins += endMargin.value(); childMin += margins; childMax += margins; } @@ -4689,8 +4773,8 @@ void RenderBlock::computeInlinePreferredLogicalWidths() if (!addedTextIndent) { addedTextIndent = true; ti = style()->textIndent().calcMinValue(cw); - childMin+=ti; - childMax+=ti; + childMin += ti; + childMax += ti; } // Add our width to the max. @@ -4725,6 +4809,9 @@ void RenderBlock::computeInlinePreferredLogicalWidths() continue; } + if (t->style()->hasTextCombine()) + toRenderCombineText(t)->combineText(); + // Determine if we have a breakable character. Pass in // whether or not we should ignore any spaces at the front // of the string. If those are going to be stripped out, @@ -4852,14 +4939,16 @@ void RenderBlock::computeBlockPreferredLogicalWidths() // A margin basically has three types: fixed, percentage, and auto (variable). // Auto and percentage margins simply become 0 when computing min/max width. // Fixed margins can be added in as is. - Length ml = child->style()->marginLeft(); - Length mr = child->style()->marginRight(); - int margin = 0, marginLeft = 0, marginRight = 0; - if (ml.isFixed()) - marginLeft += ml.value(); - if (mr.isFixed()) - marginRight += mr.value(); - margin = marginLeft + marginRight; + Length startMarginLength = child->style()->marginStart(); + Length endMarginLength = child->style()->marginEnd(); + int margin = 0; + int marginStart = 0; + int marginEnd = 0; + if (startMarginLength.isFixed()) + marginStart += startMarginLength.value(); + if (endMarginLength.isFixed()) + marginEnd += endMarginLength.value(); + margin = marginStart + marginEnd; int w = child->minPreferredLogicalWidth() + margin; m_minPreferredLogicalWidth = max(w, m_minPreferredLogicalWidth); @@ -4875,8 +4964,11 @@ void RenderBlock::computeBlockPreferredLogicalWidths() // Determine a left and right max value based off whether or not the floats can fit in the // margins of the object. For negative margins, we will attempt to overlap the float if the negative margin // is smaller than the float width. - int maxLeft = marginLeft > 0 ? max(floatLeftWidth, marginLeft) : floatLeftWidth + marginLeft; - int maxRight = marginRight > 0 ? max(floatRightWidth, marginRight) : floatRightWidth + marginRight; + bool ltr = containingBlock()->style()->isLeftToRightDirection(); + int marginLogicalLeft = ltr ? marginStart : marginEnd; + int marginLogicalRight = ltr ? marginEnd : marginStart; + int maxLeft = marginLogicalLeft > 0 ? max(floatLeftWidth, marginLogicalLeft) : floatLeftWidth + marginLogicalLeft; + int maxRight = marginLogicalRight > 0 ? max(floatRightWidth, marginLogicalRight) : floatRightWidth + marginLogicalRight; w = child->maxPreferredLogicalWidth() + maxLeft + maxRight; w = max(w, floatLeftWidth + floatRightWidth); } @@ -4906,7 +4998,7 @@ void RenderBlock::computeBlockPreferredLogicalWidths() // of 100px because of the table. // We can achieve this effect by making the maxwidth of blocks that contain tables // with percentage widths be infinite (as long as they are not inside a table cell). - if (document()->inQuirksMode() && child->style()->width().isPercent() && + if (document()->inQuirksMode() && child->style()->logicalWidth().isPercent() && !isTableCell() && child->isTable() && m_maxPreferredLogicalWidth < BLOCK_MAX_WIDTH) { RenderBlock* cb = containingBlock(); while (!cb->isRenderView() && !cb->isTableCell()) @@ -4992,8 +5084,8 @@ int RenderBlock::baselinePosition(FontBaseline baselineType, bool firstLine, Lin return RenderBox::baselinePosition(baselineType, firstLine, direction, linePositionMode); } - const Font& f = style(firstLine)->font(); - return f.ascent(baselineType) + (lineHeight(firstLine, direction, linePositionMode) - f.height()) / 2; + const FontMetrics& fontMetrics = style(firstLine)->fontMetrics(); + return fontMetrics.ascent(baselineType) + (lineHeight(firstLine, direction, linePositionMode) - fontMetrics.height()) / 2; } int RenderBlock::firstLineBoxBaseline() const @@ -5003,7 +5095,7 @@ int RenderBlock::firstLineBoxBaseline() const if (childrenInline()) { if (firstLineBox()) - return firstLineBox()->logicalTop() + style(true)->font().ascent(firstRootBox()->baselineType()); + return firstLineBox()->logicalTop() + style(true)->fontMetrics().ascent(firstRootBox()->baselineType()); else return -1; } @@ -5029,11 +5121,13 @@ int RenderBlock::lastLineBoxBaseline() const if (childrenInline()) { if (!firstLineBox() && hasLineIfEmpty()) { - const Font& f = firstLineStyle()->font(); - return f.ascent() + (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - f.height()) / 2 + (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight()); + const FontMetrics& fontMetrics = firstLineStyle()->fontMetrics(); + return fontMetrics.ascent() + + (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - fontMetrics.height()) / 2 + + (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight()); } if (lastLineBox()) - return lastLineBox()->logicalTop() + style(lastLineBox() == firstLineBox())->font().ascent(lastRootBox()->baselineType()); + return lastLineBox()->logicalTop() + style(lastLineBox() == firstLineBox())->fontMetrics().ascent(lastRootBox()->baselineType()); return -1; } else { bool haveNormalFlowChild = false; @@ -5046,8 +5140,10 @@ int RenderBlock::lastLineBoxBaseline() const } } if (!haveNormalFlowChild && hasLineIfEmpty()) { - const Font& f = firstLineStyle()->font(); - return f.ascent() + (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - f.height()) / 2 + (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight()); + const FontMetrics& fontMetrics = firstLineStyle()->fontMetrics(); + return fontMetrics.ascent() + + (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - fontMetrics.height()) / 2 + + (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight()); } } @@ -5400,7 +5496,7 @@ void RenderBlock::adjustForBorderFit(int x, int& left, int& right) const for (; (r = it.current()); ++it) { // Only examine the object if our m_shouldPaint flag is set. if (r->m_shouldPaint) { - int floatLeft = r->left() - r->m_renderer->x() + r->m_renderer->marginLeft(); + int floatLeft = xPositionForFloatIncludingMargin(r) - r->m_renderer->x(); int floatRight = floatLeft + r->m_renderer->width(); left = min(left, floatLeft); right = max(right, floatRight); @@ -5755,16 +5851,18 @@ RenderBlock* RenderBlock::createAnonymousColumnSpanBlock() const return newBox; } -int RenderBlock::nextPageTop(int yPos) const +int RenderBlock::nextPageLogicalTop(int logicalOffset) const { LayoutState* layoutState = view()->layoutState(); if (!layoutState->m_pageLogicalHeight) - return yPos; + return logicalOffset; - // The yPos is in our coordinate space. We can add in our pushed offset. + // The logicalOffset is in our coordinate space. We can add in our pushed offset. int pageLogicalHeight = layoutState->m_pageLogicalHeight; - int remainingHeight = (pageLogicalHeight - ((layoutState->m_layoutOffset - layoutState->m_pageOffset).height() + yPos) % pageLogicalHeight) % pageLogicalHeight; - return yPos + remainingHeight; + IntSize delta = layoutState->m_layoutOffset - layoutState->m_pageOffset; + int offset = style()->isHorizontalWritingMode() ? delta.height() : delta.width(); + int remainingLogicalHeight = (pageLogicalHeight - (offset + logicalOffset) % pageLogicalHeight) % pageLogicalHeight; + return logicalOffset + remainingLogicalHeight; } static bool inNormalFlow(RenderBox* child) @@ -5781,7 +5879,7 @@ static bool inNormalFlow(RenderBox* child) return true; } -int RenderBlock::applyBeforeBreak(RenderBox* child, int yPos) +int RenderBlock::applyBeforeBreak(RenderBox* child, int logicalOffset) { // FIXME: Add page break checking here when we support printing. bool checkColumnBreaks = view()->layoutState()->isPaginatingColumns(); @@ -5789,13 +5887,13 @@ int RenderBlock::applyBeforeBreak(RenderBox* child, int yPos) bool checkBeforeAlways = (checkColumnBreaks && child->style()->columnBreakBefore() == PBALWAYS) || (checkPageBreaks && child->style()->pageBreakBefore() == PBALWAYS); if (checkBeforeAlways && inNormalFlow(child)) { if (checkColumnBreaks) - view()->layoutState()->addForcedColumnBreak(yPos); - return nextPageTop(yPos); + view()->layoutState()->addForcedColumnBreak(logicalOffset); + return nextPageLogicalTop(logicalOffset); } - return yPos; + return logicalOffset; } -int RenderBlock::applyAfterBreak(RenderBox* child, int yPos, MarginInfo& marginInfo) +int RenderBlock::applyAfterBreak(RenderBox* child, int logicalOffset, MarginInfo& marginInfo) { // FIXME: Add page break checking here when we support printing. bool checkColumnBreaks = view()->layoutState()->isPaginatingColumns(); @@ -5804,28 +5902,30 @@ int RenderBlock::applyAfterBreak(RenderBox* child, int yPos, MarginInfo& marginI if (checkAfterAlways && inNormalFlow(child)) { marginInfo.setMarginAfterQuirk(true); // Cause margins to be discarded for any following content. if (checkColumnBreaks) - view()->layoutState()->addForcedColumnBreak(yPos); - return nextPageTop(yPos); + view()->layoutState()->addForcedColumnBreak(logicalOffset); + return nextPageLogicalTop(logicalOffset); } - return yPos; + return logicalOffset; } -int RenderBlock::adjustForUnsplittableChild(RenderBox* child, int yPos, bool includeMargins) +int RenderBlock::adjustForUnsplittableChild(RenderBox* child, int logicalOffset, bool includeMargins) { bool isUnsplittable = child->isReplaced() || child->scrollsOverflow(); if (!isUnsplittable) - return yPos; - int childHeight = child->height() + (includeMargins ? child->marginTop() + child->marginBottom() : 0); + return logicalOffset; + int childLogicalHeight = logicalHeightForChild(child) + (includeMargins ? marginBeforeForChild(child) + marginAfterForChild(child) : 0); LayoutState* layoutState = view()->layoutState(); if (layoutState->m_columnInfo) - layoutState->m_columnInfo->updateMinimumColumnHeight(childHeight); + layoutState->m_columnInfo->updateMinimumColumnHeight(childLogicalHeight); int pageLogicalHeight = layoutState->m_pageLogicalHeight; - if (!pageLogicalHeight || childHeight > pageLogicalHeight) - return yPos; - int remainingHeight = (pageLogicalHeight - ((layoutState->m_layoutOffset - layoutState->m_pageOffset).height() + yPos) % pageLogicalHeight) % pageLogicalHeight; - if (remainingHeight < childHeight) - return yPos + remainingHeight; - return yPos; + if (!pageLogicalHeight || childLogicalHeight > pageLogicalHeight) + return logicalOffset; + IntSize delta = layoutState->m_layoutOffset - layoutState->m_pageOffset; + int offset = style()->isHorizontalWritingMode() ? delta.height() : delta.width(); + int remainingLogicalHeight = (pageLogicalHeight - (offset + logicalOffset) % pageLogicalHeight) % pageLogicalHeight; + if (remainingLogicalHeight < childLogicalHeight) + return logicalOffset + remainingLogicalHeight; + return logicalOffset; } void RenderBlock::adjustLinePositionForPagination(RootInlineBox* lineBox, int& delta) @@ -5848,22 +5948,24 @@ void RenderBlock::adjustLinePositionForPagination(RootInlineBox* lineBox, int& d // line and all following lines. LayoutState* layoutState = view()->layoutState(); int pageLogicalHeight = layoutState->m_pageLogicalHeight; - int yPos = lineBox->topVisualOverflow(); - int lineHeight = lineBox->bottomVisualOverflow() - yPos; + int logicalOffset = lineBox->logicalTopVisualOverflow(); + int lineHeight = lineBox->logicalBottomVisualOverflow() - logicalOffset; if (layoutState->m_columnInfo) layoutState->m_columnInfo->updateMinimumColumnHeight(lineHeight); - yPos += delta; + logicalOffset += delta; lineBox->setPaginationStrut(0); if (!pageLogicalHeight || lineHeight > pageLogicalHeight) return; - int remainingHeight = pageLogicalHeight - ((layoutState->m_layoutOffset - layoutState->m_pageOffset).height() + yPos) % pageLogicalHeight; - if (remainingHeight < lineHeight) { - int totalHeight = lineHeight + max(0, yPos); - if (lineBox == firstRootBox() && totalHeight < pageLogicalHeight && !isPositioned() && !isTableCell()) - setPaginationStrut(remainingHeight + max(0, yPos)); + IntSize offsetDelta = layoutState->m_layoutOffset - layoutState->m_pageOffset; + int offset = style()->isHorizontalWritingMode() ? offsetDelta.height() : offsetDelta.width(); + int remainingLogicalHeight = pageLogicalHeight - (offset + logicalOffset) % pageLogicalHeight; + if (remainingLogicalHeight < lineHeight) { + int totalLogicalHeight = lineHeight + max(0, logicalOffset); + if (lineBox == firstRootBox() && totalLogicalHeight < pageLogicalHeight && !isPositioned() && !isTableCell()) + setPaginationStrut(remainingLogicalHeight + max(0, logicalOffset)); else { - delta += remainingHeight; - lineBox->setPaginationStrut(remainingHeight); + delta += remainingLogicalHeight; + lineBox->setPaginationStrut(remainingLogicalHeight); } } } diff --git a/Source/WebCore/rendering/RenderBlock.h b/Source/WebCore/rendering/RenderBlock.h index f8829ee..2c61331 100644 --- a/Source/WebCore/rendering/RenderBlock.h +++ b/Source/WebCore/rendering/RenderBlock.h @@ -106,6 +106,9 @@ public: // Block flows subclass availableWidth to handle multi column layout (shrinking the width available to children when laying out.) virtual int availableLogicalWidth() const; + IntPoint flipForWritingModeIncludingColumns(const IntPoint&) const; + void flipForWritingModeIncludingColumns(IntRect&) const; + RootInlineBox* firstRootBox() const { return static_cast<RootInlineBox*>(firstLineBox()); } RootInlineBox* lastRootBox() const { return static_cast<RootInlineBox*>(lastLineBox()); } @@ -212,6 +215,9 @@ public: virtual void scrollbarsChanged(bool /*horizontalScrollbarChanged*/, bool /*verticalScrollbarChanged*/) { }; + int logicalRightOffsetForContent() const { return style()->isHorizontalWritingMode() ? borderLeft() + paddingLeft() + availableLogicalWidth() : borderTop() + paddingTop() + availableLogicalWidth(); } + int logicalLeftOffsetForContent() const { return style()->isHorizontalWritingMode() ? borderLeft() + paddingLeft() : borderTop() + paddingTop(); } + protected: // These functions are only used internally to manipulate the render tree structure via remove/insert/appendChildNode. // Since they are typically called only to move objects around within anonymous blocks (which only have layers in @@ -261,8 +267,6 @@ protected: virtual void paint(PaintInfo&, int tx, int ty); virtual void paintObject(PaintInfo&, int tx, int ty); - int logicalRightOffsetForContent() const { return style()->isHorizontalWritingMode() ? borderLeft() + paddingLeft() + availableLogicalWidth() : borderTop() + paddingTop() + availableLogicalWidth(); } - int logicalLeftOffsetForContent() const { return style()->isHorizontalWritingMode() ? borderLeft() + paddingLeft() : borderTop() + paddingTop(); } 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; @@ -393,15 +397,15 @@ private: bool isPlaced() const { return m_isPlaced; } void setIsPlaced(bool placed = true) { m_isPlaced = placed; } - int left() const { ASSERT(isPlaced()); return m_frameRect.x(); } - int right() const { ASSERT(isPlaced()); return m_frameRect.right(); } - int top() const { ASSERT(isPlaced()); return m_frameRect.y(); } - int bottom() const { ASSERT(isPlaced()); return m_frameRect.bottom(); } + int x() const { ASSERT(isPlaced()); return m_frameRect.x(); } + int maxX() const { ASSERT(isPlaced()); return m_frameRect.maxX(); } + int y() const { ASSERT(isPlaced()); return m_frameRect.y(); } + int maxY() const { ASSERT(isPlaced()); return m_frameRect.maxY(); } int width() const { return m_frameRect.width(); } int height() const { return m_frameRect.height(); } - - void setLeft(int left) { m_frameRect.setX(left); } - void setTop(int top) { m_frameRect.setY(top); } + + void setX(int x) { m_frameRect.setX(x); } + void setY(int y) { m_frameRect.setY(y); } void setWidth(int width) { m_frameRect.setWidth(width); } void setHeight(int height) { m_frameRect.setHeight(height); } @@ -417,24 +421,26 @@ private: bool m_isPlaced : 1; }; - int logicalTopForFloat(FloatingObject* child) const { return style()->isHorizontalWritingMode() ? child->top() : child->left(); } - int logicalBottomForFloat(FloatingObject* child) const { return style()->isHorizontalWritingMode() ? child->bottom() : child->right(); } - int logicalLeftForFloat(FloatingObject* child) const { return style()->isHorizontalWritingMode() ? child->left() : child->top(); } - int logicalRightForFloat(FloatingObject* child) const { return style()->isHorizontalWritingMode() ? child->right() : child->bottom(); } - int logicalWidthForFloat(FloatingObject* child) const { return style()->isHorizontalWritingMode() ? child->width() : child->height(); } + IntPoint flipFloatForWritingMode(const FloatingObject*, const IntPoint&) const; + + int logicalTopForFloat(const FloatingObject* child) const { return style()->isHorizontalWritingMode() ? child->y() : child->x(); } + int logicalBottomForFloat(const FloatingObject* child) const { return style()->isHorizontalWritingMode() ? child->maxY() : child->maxX(); } + int logicalLeftForFloat(const FloatingObject* child) const { return style()->isHorizontalWritingMode() ? child->x() : child->y(); } + int logicalRightForFloat(const FloatingObject* child) const { return style()->isHorizontalWritingMode() ? child->maxX() : child->maxY(); } + int logicalWidthForFloat(const FloatingObject* child) const { return style()->isHorizontalWritingMode() ? child->width() : child->height(); } void setLogicalTopForFloat(FloatingObject* child, int logicalTop) { if (style()->isHorizontalWritingMode()) - child->setTop(logicalTop); + child->setY(logicalTop); else - child->setLeft(logicalTop); + child->setX(logicalTop); } void setLogicalLeftForFloat(FloatingObject* child, int logicalLeft) { if (style()->isHorizontalWritingMode()) - child->setLeft(logicalLeft); + child->setX(logicalLeft); else - child->setTop(logicalLeft); + child->setY(logicalLeft); } void setLogicalHeightForFloat(FloatingObject* child, int logicalHeight) { @@ -451,6 +457,22 @@ private: child->setHeight(logicalWidth); } + int xPositionForFloatIncludingMargin(const FloatingObject* child) const + { + if (style()->isHorizontalWritingMode()) + return child->x() + child->renderer()->marginLeft(); + else + return child->x() + marginBeforeForChild(child->renderer()); + } + + int yPositionForFloatIncludingMargin(const FloatingObject* child) const + { + if (style()->isHorizontalWritingMode()) + return child->y() + marginBeforeForChild(child->renderer()); + else + return child->y() + child->renderer()->marginTop(); + } + // The following functions' implementations are in RenderBlockLineLayout.cpp. RootInlineBox* determineStartPosition(bool& firstLine, bool& fullLayout, bool& previousLineBrokeCleanly, InlineBidiResolver&, Vector<FloatWithRect>& floats, unsigned& numCleanFloats, @@ -488,7 +510,7 @@ private: FloatingObject* insertFloatingObject(RenderBox*); void removeFloatingObject(RenderBox*); - void removeFloatingObjectsBelow(FloatingObject*, int y); + void removeFloatingObjectsBelow(FloatingObject*, int logicalOffset); // Called from lineWidth, to position the floats added in the last line. // Returns true if and only if it has positioned any floats. @@ -568,7 +590,6 @@ private: void newLine(EClear); Position positionForBox(InlineBox*, bool start = true) const; - Position positionForRenderer(RenderObject*, bool start = true) const; VisiblePosition positionForPointWithInlineChildren(const IntPoint&); // Adjust tx and ty from painting offsets to the local coords of this renderer @@ -668,11 +689,11 @@ private: // End helper functions and structs used by layoutBlockChildren. // Pagination routines. - int nextPageTop(int yPos) const; // Returns the top of the next page following yPos. - int applyBeforeBreak(RenderBox* child, int yPos); // If the child has a before break, then return a new yPos that shifts to the top of the next page/column. - int applyAfterBreak(RenderBox* child, int yPos, MarginInfo& marginInfo); // If the child has an after break, then return a new yPos that shifts to the top of the next page/column. - int adjustForUnsplittableChild(RenderBox* child, int yPos, 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& deltaY); // Computes a deltaY value that put a line at the top of the next page if it doesn't fit on the current page. + int nextPageLogicalTop(int logicalOffset) const; // Returns the top of the next page following logicalOffset. + int applyBeforeBreak(RenderBox* child, int logicalOffset); // If the child has a before break, then return a new yPos that shifts to the top of the next page/column. + int applyAfterBreak(RenderBox* child, int logicalOffset, MarginInfo& marginInfo); // If the child has an after break, then return a new offset that shifts to the top of the next page/column. + 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; diff --git a/Source/WebCore/rendering/RenderBlockLineLayout.cpp b/Source/WebCore/rendering/RenderBlockLineLayout.cpp index 5e16931..5e2b52d 100644 --- a/Source/WebCore/rendering/RenderBlockLineLayout.cpp +++ b/Source/WebCore/rendering/RenderBlockLineLayout.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2000 Lars Knoll (knoll@kde.org) - * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009, 2010 Apple Inc. All right reserved. + * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All right reserved. * Copyright (C) 2010 Google Inc. All rights reserved. * * This library is free software; you can redistribute it and/or @@ -23,12 +23,12 @@ #include "config.h" #include "BidiResolver.h" -#include "CharacterNames.h" #include "Hyphenation.h" #include "InlineIterator.h" #include "InlineTextBox.h" #include "Logging.h" #include "RenderArena.h" +#include "RenderCombineText.h" #include "RenderInline.h" #include "RenderLayer.h" #include "RenderListMarker.h" @@ -42,6 +42,13 @@ #include <wtf/RefCountedLeakCounter.h> #include <wtf/StdLibExtras.h> #include <wtf/Vector.h> +#include <wtf/unicode/CharacterNames.h> + +#if ENABLE(SVG) +#include "RenderSVGInlineText.h" +#include "SVGRootInlineBox.h" +#endif + #ifdef ANDROID_LAYOUT #include "Frame.h" #include "FrameTree.h" @@ -50,11 +57,6 @@ #include "HTMLNames.h" #endif // ANDROID_LAYOUT -#if ENABLE(SVG) -#include "RenderSVGInlineText.h" -#include "SVGRootInlineBox.h" -#endif - using namespace std; using namespace WTF; using namespace Unicode; @@ -190,6 +192,16 @@ static inline void dirtyLineBoxesForRenderer(RenderObject* o, bool fullLayout) toRenderInline(o)->dirtyLineBoxes(fullLayout); } +static bool parentIsConstructedOrHaveNext(InlineFlowBox* parentBox) +{ + do { + if (parentBox->isConstructed() || parentBox->nextOnLine()) + return true; + parentBox = parentBox->parent(); + } while (parentBox); + return false; +} + InlineFlowBox* RenderBlock::createLineBoxes(RenderObject* obj, bool firstLine) { // See if we have an unconstructed line box for this object that is also @@ -204,13 +216,13 @@ InlineFlowBox* RenderBlock::createLineBoxes(RenderObject* obj, bool firstLine) // Get the last box we made for this render object. parentBox = obj->isRenderInline() ? toRenderInline(obj)->lastLineBox() : toRenderBlock(obj)->lastLineBox(); - // If this box is constructed then it is from a previous line, and we need - // to make a new box for our line. If this box is unconstructed but it has + // If this box or its ancestor is constructed then it is from a previous line, and we need + // to make a new box for our line. If this box or its ancestor is unconstructed but it has // something following it on the line, then we know we have to make a new box // as well. In this situation our inline has actually been split in two on // the same line (this can happen with very fancy language mixtures). bool constructedNewBox = false; - if (!parentBox || parentBox->isConstructed() || parentBox->nextOnLine()) { + if (!parentBox || parentIsConstructedOrHaveNext(parentBox)) { // We need to make a new box for this render object. Once // made, we need to place it at the end of the current line. InlineBox* newBox = createInlineBoxForRenderer(obj, obj == this); @@ -317,7 +329,9 @@ void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox, int availableLogicalWidth = availableLogicalWidthForLine(logicalHeight(), firstLine); int totalLogicalWidth = lineBox->getFlowSpacingLogicalWidth(); bool needsWordSpacing = false; - unsigned numSpaces = 0; + unsigned expansionOpportunityCount = 0; + bool isAfterExpansion = true; + Vector<unsigned, 16> expansionOpportunities; ETextAlign textAlign = style()->textAlign(); for (BidiRun* r = firstRun; r; r = r->next()) { @@ -329,12 +343,9 @@ void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox, RenderText* rt = toRenderText(r->m_object); if (textAlign == JUSTIFY && r != trailingSpaceRun) { - const UChar* characters = rt->characters(); - for (int i = r->m_start; i < r->m_stop; i++) { - UChar c = characters[i]; - if (c == ' ' || c == '\n' || c == '\t') - numSpaces++; - } + unsigned opportunitiesInRun = Font::expansionOpportunityCount(rt->characters() + r->m_start, r->m_stop - r->m_start, r->m_box->direction(), isAfterExpansion); + expansionOpportunities.append(opportunitiesInRun); + expansionOpportunityCount += opportunitiesInRun; } if (int length = rt->textLength()) { @@ -361,16 +372,24 @@ void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox, GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.add(static_cast<InlineTextBox*>(r->m_box), make_pair(Vector<const SimpleFontData*>(), GlyphOverflow())).first; it->second.second = glyphOverflow; } - } else if (!r->m_object->isRenderInline()) { - RenderBox* renderBox = toRenderBox(r->m_object); - renderBox->computeLogicalWidth(); - r->m_box->setLogicalWidth(logicalWidthForChild(renderBox)); - totalLogicalWidth += marginStartForChild(renderBox) + marginEndForChild(renderBox); + } else { + isAfterExpansion = false; + if (!r->m_object->isRenderInline()) { + RenderBox* renderBox = toRenderBox(r->m_object); + renderBox->computeLogicalWidth(); + r->m_box->setLogicalWidth(logicalWidthForChild(renderBox)); + totalLogicalWidth += marginStartForChild(renderBox) + marginEndForChild(renderBox); + } } totalLogicalWidth += r->m_box->logicalWidth(); } + if (isAfterExpansion && !expansionOpportunities.isEmpty()) { + expansionOpportunities.last()--; + expansionOpportunityCount--; + } + // Armed with the total width of the line (without justification), // 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 @@ -392,7 +411,7 @@ void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox, } break; case JUSTIFY: - if (numSpaces && !reachedEnd && !lineBox->endsWithBreak()) { + if (expansionOpportunityCount && !reachedEnd && !lineBox->endsWithBreak()) { if (trailingSpaceRun) { totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth(); trailingSpaceRun->m_box->setLogicalWidth(0); @@ -401,7 +420,7 @@ void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox, } // fall through case TAAUTO: - numSpaces = 0; + expansionOpportunityCount = 0; // for right to left fall through to right aligned if (style()->isLeftToRightDirection()) { if (totalLogicalWidth > availableLogicalWidth && trailingSpaceRun) @@ -443,31 +462,26 @@ void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox, break; } - if (numSpaces) { + if (expansionOpportunityCount) { + size_t i = 0; for (BidiRun* r = firstRun; r; r = r->next()) { if (!r->m_box || r == trailingSpaceRun) continue; - int spaceAdd = 0; if (r->m_object->isText()) { - unsigned spaces = 0; - const UChar* characters = toRenderText(r->m_object)->characters(); - for (int i = r->m_start; i < r->m_stop; i++) { - UChar c = characters[i]; - if (c == ' ' || c == '\n' || c == '\t') - spaces++; - } + unsigned opportunitiesInRun = expansionOpportunities[i++]; - ASSERT(spaces <= numSpaces); + ASSERT(opportunitiesInRun <= expansionOpportunityCount); // Only justify text if whitespace is collapsed. if (r->m_object->style()->collapseWhiteSpace()) { - spaceAdd = (availableLogicalWidth - totalLogicalWidth) * spaces / numSpaces; - static_cast<InlineTextBox*>(r->m_box)->setSpaceAdd(spaceAdd); - totalLogicalWidth += spaceAdd; + InlineTextBox* textBox = static_cast<InlineTextBox*>(r->m_box); + int expansion = (availableLogicalWidth - totalLogicalWidth) * opportunitiesInRun / expansionOpportunityCount; + textBox->setExpansion(expansion); + totalLogicalWidth += expansion; } - numSpaces -= spaces; - if (!numSpaces) + expansionOpportunityCount -= opportunitiesInRun; + if (!expansionOpportunityCount) break; } } @@ -909,7 +923,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogica adjustLinePositionForPagination(lineBox, adjustment); if (adjustment) { int oldLineWidth = availableLogicalWidthForLine(oldLogicalHeight, firstLine); - lineBox->adjustPosition(0, adjustment); + lineBox->adjustBlockDirectionPosition(adjustment); if (useRepaintBounds) // This can only be a positive adjustment, so no need to update repaintTop. repaintLogicalBottom = max(repaintLogicalBottom, afterSideVisualOverflowForLine(lineBox)); @@ -967,7 +981,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogica if (delta) { repaintLogicalTop = min(repaintLogicalTop, beforeSideVisualOverflowForLine(line) + min(delta, 0)); repaintLogicalBottom = max(repaintLogicalBottom, afterSideVisualOverflowForLine(line) + max(delta, 0)); - line->adjustPosition(0, delta); + line->adjustBlockDirectionPosition(delta); } if (Vector<RenderBox*>* cleanLineFloats = line->floatsPtr()) { Vector<RenderBox*>::iterator end = cleanLineFloats->end(); @@ -1084,7 +1098,7 @@ RootInlineBox* RenderBlock::determineStartPosition(bool& firstLine, bool& fullLa repaintLogicalTop = min(repaintLogicalTop, beforeSideVisualOverflowForLine(curr) + min(paginationDelta, 0)); repaintLogicalBottom = max(repaintLogicalBottom, afterSideVisualOverflowForLine(curr) + max(paginationDelta, 0)); - curr->adjustPosition(0, paginationDelta); + curr->adjustBlockDirectionPosition(paginationDelta); } } @@ -1500,7 +1514,7 @@ 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) { - if (isFixedPitch || (!from && len == text->textLength())) + 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)); } @@ -1752,11 +1766,14 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool bool isSVGText = t->isSVGInlineText(); #endif + RenderStyle* style = t->style(firstLine); + if (style->hasTextCombine()) + toRenderCombineText(o)->combineText(); + int strlen = t->textLength(); int len = strlen - pos; const UChar* str = t->characters(); - RenderStyle* style = t->style(firstLine); const Font& f = style->font(); bool isFixedPitch = f.isFixedPitch(); bool canHyphenate = style->hyphens() == HyphensAuto && WebCore::canHyphenate(style->hyphenationLocale()); @@ -2169,38 +2186,34 @@ void RenderBlock::addOverflowFromInlineChildren() int RenderBlock::beforeSideVisualOverflowForLine(RootInlineBox* line) const { - // Overflow is in the block's coordinate space, which means it isn't purely physical. For flipped blocks (rl and bt), - // we continue to use top and left overflow even though physically it's bottom and right. + // Overflow is in the block's coordinate space, which means it isn't purely physical. if (style()->isHorizontalWritingMode()) - return line->topVisualOverflow(); - return line->leftVisualOverflow(); + return line->minYVisualOverflow(); + return line->minXVisualOverflow(); } int RenderBlock::afterSideVisualOverflowForLine(RootInlineBox* line) const { - // Overflow is in the block's coordinate space, which means it isn't purely physical. For flipped blocks (rl and bt), - // we continue to use bottom and right overflow even though physically it's top and left. + // Overflow is in the block's coordinate space, which means it isn't purely physical. if (style()->isHorizontalWritingMode()) - return line->bottomVisualOverflow(); - return line->rightVisualOverflow(); + return line->maxYVisualOverflow(); + return line->maxXVisualOverflow(); } int RenderBlock::beforeSideLayoutOverflowForLine(RootInlineBox* line) const { - // Overflow is in the block's coordinate space, which means it isn't purely physical. For flipped blocks (rl and bt), - // we continue to use top and left overflow even though physically it's bottom and right. + // Overflow is in the block's coordinate space, which means it isn't purely physical. if (style()->isHorizontalWritingMode()) - return line->topLayoutOverflow(); - return line->leftLayoutOverflow(); + return line->minYLayoutOverflow(); + return line->minXLayoutOverflow(); } int RenderBlock::afterSideLayoutOverflowForLine(RootInlineBox* line) const { - // Overflow is in the block's coordinate space, which means it isn't purely physical. For flipped blocks (rl and bt), - // we continue to use bottom and right overflow even though physically it's top and left. + // Overflow is in the block's coordinate space, which means it isn't purely physical. if (style()->isHorizontalWritingMode()) - return line->bottomLayoutOverflow(); - return line->rightLayoutOverflow(); + return line->maxYLayoutOverflow(); + return line->maxXLayoutOverflow(); } void RenderBlock::deleteEllipsisLineBoxes() diff --git a/Source/WebCore/rendering/RenderBox.cpp b/Source/WebCore/rendering/RenderBox.cpp index 265c46a..39c80d4 100644 --- a/Source/WebCore/rendering/RenderBox.cpp +++ b/Source/WebCore/rendering/RenderBox.cpp @@ -425,8 +425,8 @@ int RenderBox::scrollWidth() const // For objects with visible overflow, this matches IE. // FIXME: Need to work right with writing modes. if (style()->isLeftToRightDirection()) - return max(clientWidth(), rightLayoutOverflow() - borderLeft()); - return clientWidth() - min(0, leftLayoutOverflow() - borderLeft()); + return max(clientWidth(), maxXLayoutOverflow() - borderLeft()); + return clientWidth() - min(0, minXLayoutOverflow() - borderLeft()); } int RenderBox::scrollHeight() const @@ -435,7 +435,7 @@ int RenderBox::scrollHeight() const return layer()->scrollHeight(); // For objects with visible overflow, this matches IE. // FIXME: Need to work right with writing modes. - return max(clientHeight(), bottomLayoutOverflow() - borderTop()); + return max(clientHeight(), maxYLayoutOverflow() - borderTop()); } int RenderBox::scrollLeft() const @@ -559,16 +559,16 @@ IntRect RenderBox::reflectedRect(const IntRect& r) const IntRect result = r; switch (style()->boxReflect()->direction()) { case ReflectionBelow: - result.setY(box.bottom() + reflectionOffset() + (box.bottom() - r.bottom())); + result.setY(box.maxY() + reflectionOffset() + (box.maxY() - r.maxY())); break; case ReflectionAbove: - result.setY(box.y() - reflectionOffset() - box.height() + (box.bottom() - r.bottom())); + result.setY(box.y() - reflectionOffset() - box.height() + (box.maxY() - r.maxY())); break; case ReflectionLeft: - result.setX(box.x() - reflectionOffset() - box.width() + (box.right() - r.right())); + result.setX(box.x() - reflectionOffset() - box.width() + (box.maxX() - r.maxX())); break; case ReflectionRight: - result.setX(box.right() + reflectionOffset() + (box.right() - r.right())); + result.setX(box.maxX() + reflectionOffset() + (box.maxX() - r.maxX())); break; } return result; @@ -1279,8 +1279,14 @@ IntSize RenderBox::offsetFromContainer(RenderObject* o, const IntPoint& point) c if (!isInline() || isReplaced()) { if (style()->position() != AbsolutePosition && style()->position() != FixedPosition) { - o->adjustForColumns(offset, IntPoint(point.x() + x(), point.y() + y())); - offset += locationOffsetIncludingFlipping(); + if (o->hasColumns()) { + IntRect columnRect(frameRect()); + toRenderBlock(o)->flipForWritingModeIncludingColumns(columnRect); + offset += IntSize(columnRect.location().x(), columnRect.location().y()); + columnRect.move(point.x(), point.y()); + o->adjustForColumns(offset, columnRect.location()); + } else + offset += locationOffsetIncludingFlipping(); } else offset += locationOffset(); } @@ -3067,12 +3073,12 @@ IntRect RenderBox::localCaretRect(InlineBox* box, int caretOffset, int* extraWid // <rdar://problem/3777804> Deleting all content in a document can result in giant tall-as-window insertion point // // FIXME: ignoring :first-line, missing good reason to take care of - int fontHeight = style()->font().height(); + int fontHeight = style()->fontMetrics().height(); if (fontHeight > rect.height() || (!isReplaced() && !isTable())) rect.setHeight(fontHeight); if (extraWidthToEndOfLine) - *extraWidthToEndOfLine = x() + width() - rect.right(); + *extraWidthToEndOfLine = x() + width() - rect.maxX(); // Move to local coords rect.move(-x(), -y()); @@ -3193,9 +3199,9 @@ void RenderBox::addShadowOverflow() style()->getBoxShadowExtent(shadowTop, shadowRight, shadowBottom, shadowLeft); IntRect borderBox = borderBoxRect(); int overflowLeft = borderBox.x() + shadowLeft; - int overflowRight = borderBox.right() + shadowRight; + int overflowRight = borderBox.maxX() + shadowRight; int overflowTop = borderBox.y() + shadowTop; - int overflowBottom = borderBox.bottom() + shadowBottom; + int overflowBottom = borderBox.maxY() + shadowBottom; addVisualOverflow(IntRect(overflowLeft, overflowTop, overflowRight - overflowLeft, overflowBottom - overflowTop)); } @@ -3234,13 +3240,13 @@ void RenderBox::addLayoutOverflow(const IntRect& rect) bool hasLeftOverflow = !style()->isLeftToRightDirection() && style()->isHorizontalWritingMode(); if (!hasTopOverflow) - overflowRect.shiftTopEdgeTo(max(overflowRect.y(), clientBox.y())); + overflowRect.shiftYEdgeTo(max(overflowRect.y(), clientBox.y())); else - overflowRect.shiftBottomEdgeTo(min(overflowRect.bottom(), clientBox.bottom())); + overflowRect.shiftMaxYEdgeTo(min(overflowRect.maxY(), clientBox.maxY())); if (!hasLeftOverflow) - overflowRect.shiftLeftEdgeTo(max(overflowRect.x(), clientBox.x())); + overflowRect.shiftXEdgeTo(max(overflowRect.x(), clientBox.x())); else - overflowRect.shiftRightEdgeTo(min(overflowRect.right(), clientBox.right())); + overflowRect.shiftMaxXEdgeTo(min(overflowRect.maxX(), clientBox.maxX())); // Now re-test with the adjusted rectangle and see if it has become unreachable or fully // contained. @@ -3329,9 +3335,9 @@ IntRect RenderBox::visualOverflowRectForPropagation(RenderStyle* parentStyle) co // We are putting ourselves into our parent's coordinate space. If there is a flipped block mismatch // in a particular axis, then we have to flip the rect along that axis. if (style()->writingMode() == RightToLeftWritingMode || parentStyle->writingMode() == RightToLeftWritingMode) - rect.setX(width() - rect.right()); + rect.setX(width() - rect.maxX()); else if (style()->writingMode() == BottomToTopWritingMode || parentStyle->writingMode() == BottomToTopWritingMode) - rect.setY(height() - rect.bottom()); + rect.setY(height() - rect.maxY()); return rect; } @@ -3375,9 +3381,9 @@ IntRect RenderBox::layoutOverflowRectForPropagation(RenderStyle* parentStyle) co // We are putting ourselves into our parent's coordinate space. If there is a flipped block mismatch // in a particular axis, then we have to flip the rect along that axis. if (style()->writingMode() == RightToLeftWritingMode || parentStyle->writingMode() == RightToLeftWritingMode) - rect.setX(width() - rect.right()); + rect.setX(width() - rect.maxX()); else if (style()->writingMode() == BottomToTopWritingMode || parentStyle->writingMode() == BottomToTopWritingMode) - rect.setY(height() - rect.bottom()); + rect.setY(height() - rect.maxY()); return rect; } @@ -3400,9 +3406,9 @@ void RenderBox::flipForWritingMode(IntRect& rect) const return; if (style()->isHorizontalWritingMode()) - rect.setY(height() - rect.bottom()); + rect.setY(height() - rect.maxY()); else - rect.setX(width() - rect.right()); + rect.setX(width() - rect.maxX()); } int RenderBox::flipForWritingMode(int position) const @@ -3419,6 +3425,13 @@ IntPoint RenderBox::flipForWritingMode(const IntPoint& position) const return style()->isHorizontalWritingMode() ? IntPoint(position.x(), height() - position.y()) : IntPoint(width() - position.x(), position.y()); } +IntPoint RenderBox::flipForWritingModeIncludingColumns(const IntPoint& point) const +{ + if (!hasColumns() || !style()->isFlippedBlocksWritingMode()) + return flipForWritingMode(point); + return toRenderBlock(this)->flipForWritingModeIncludingColumns(point); +} + IntSize RenderBox::flipForWritingMode(const IntSize& offset) const { if (!style()->isFlippedBlocksWritingMode()) diff --git a/Source/WebCore/rendering/RenderBox.h b/Source/WebCore/rendering/RenderBox.h index acbcc29..7241ed1 100644 --- a/Source/WebCore/rendering/RenderBox.h +++ b/Source/WebCore/rendering/RenderBox.h @@ -127,21 +127,25 @@ public: RenderBox* nextSiblingBox() const; RenderBox* parentBox() const; + // Visual and layout overflow are in the coordinate space of the box. This means that they aren't purely physical directions. + // 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. IntRect layoutOverflowRect() const { return m_overflow ? m_overflow->layoutOverflowRect() : clientBoxRect(); } - int topLayoutOverflow() const { return m_overflow? m_overflow->topLayoutOverflow() : borderTop(); } - int bottomLayoutOverflow() const { return m_overflow ? m_overflow->bottomLayoutOverflow() : borderTop() + clientHeight(); } - int leftLayoutOverflow() const { return m_overflow ? m_overflow->leftLayoutOverflow() : borderLeft(); } - int rightLayoutOverflow() const { return m_overflow ? m_overflow->rightLayoutOverflow() : borderLeft() + clientWidth(); } - int logicalLeftLayoutOverflow() const { return style()->isHorizontalWritingMode() ? leftLayoutOverflow() : topLayoutOverflow(); } - int logicalRightLayoutOverflow() const { return style()->isHorizontalWritingMode() ? rightLayoutOverflow() : bottomLayoutOverflow(); } + int minYLayoutOverflow() const { return m_overflow? m_overflow->minYLayoutOverflow() : borderTop(); } + int maxYLayoutOverflow() const { return m_overflow ? m_overflow->maxYLayoutOverflow() : borderTop() + clientHeight(); } + int minXLayoutOverflow() const { return m_overflow ? m_overflow->minXLayoutOverflow() : borderLeft(); } + int maxXLayoutOverflow() const { return m_overflow ? m_overflow->maxXLayoutOverflow() : borderLeft() + clientWidth(); } + int logicalLeftLayoutOverflow() const { return style()->isHorizontalWritingMode() ? minXLayoutOverflow() : minYLayoutOverflow(); } + int logicalRightLayoutOverflow() const { return style()->isHorizontalWritingMode() ? maxXLayoutOverflow() : maxYLayoutOverflow(); } IntRect visualOverflowRect() const { return m_overflow ? m_overflow->visualOverflowRect() : borderBoxRect(); } - int topVisualOverflow() const { return m_overflow? m_overflow->topVisualOverflow() : 0; } - int bottomVisualOverflow() const { return m_overflow ? m_overflow->bottomVisualOverflow() : height(); } - int leftVisualOverflow() const { return m_overflow ? m_overflow->leftVisualOverflow() : 0; } - int rightVisualOverflow() const { return m_overflow ? m_overflow->rightVisualOverflow() : width(); } - int logicalLeftVisualOverflow() const { return style()->isHorizontalWritingMode() ? leftVisualOverflow() : topVisualOverflow(); } - int logicalRightVisualOverflow() const { return style()->isHorizontalWritingMode() ? rightVisualOverflow() : bottomVisualOverflow(); } + int minYVisualOverflow() const { return m_overflow? m_overflow->minYVisualOverflow() : 0; } + int maxYVisualOverflow() const { return m_overflow ? m_overflow->maxYVisualOverflow() : height(); } + int minXVisualOverflow() const { return m_overflow ? m_overflow->minXVisualOverflow() : 0; } + int maxXVisualOverflow() const { return m_overflow ? m_overflow->maxXVisualOverflow() : width(); } + int logicalLeftVisualOverflow() const { return style()->isHorizontalWritingMode() ? minXVisualOverflow() : minYVisualOverflow(); } + int logicalRightVisualOverflow() const { return style()->isHorizontalWritingMode() ? maxXVisualOverflow() : maxYVisualOverflow(); } void addLayoutOverflow(const IntRect&); void addVisualOverflow(const IntRect&); @@ -172,7 +176,7 @@ public: int clientTop() const { return borderTop(); } int clientWidth() const; int clientHeight() const; - int clientLogicalBottom() const { return style()->isHorizontalWritingMode() ? clientTop() + clientHeight() : clientLeft() + clientWidth(); } + int clientLogicalBottom() const { return borderBefore() + (style()->isHorizontalWritingMode() ? clientHeight() : clientWidth()); } IntRect clientBoxRect() const { return IntRect(clientLeft(), clientTop(), clientWidth(), clientHeight()); } // scrollWidth/scrollHeight will be the same as clientWidth/clientHeight unless the @@ -378,6 +382,7 @@ public: IntPoint flipForWritingMode(const RenderBox* child, const IntPoint&, FlippingAdjustment) const; int flipForWritingMode(int position) const; // The offset is in the block direction (y for horizontal writing modes, x for vertical writing modes). IntPoint flipForWritingMode(const IntPoint&) const; + IntPoint flipForWritingModeIncludingColumns(const IntPoint&) const; IntSize flipForWritingMode(const IntSize&) const; void flipForWritingMode(IntRect&) const; IntSize locationOffsetIncludingFlipping() const; diff --git a/Source/WebCore/rendering/RenderBoxModelObject.cpp b/Source/WebCore/rendering/RenderBoxModelObject.cpp index f2412a1..ffbecce 100644 --- a/Source/WebCore/rendering/RenderBoxModelObject.cpp +++ b/Source/WebCore/rendering/RenderBoxModelObject.cpp @@ -50,8 +50,8 @@ bool RenderBoxModelObject::s_layerWasSelfPainting = false; static const double cInterpolationCutoff = 800. * 800.; static const double cLowQualityTimeThreshold = 0.500; // 500 ms -typedef pair<RenderBoxModelObject*, const void*> LastPaintSizeMapKey; -typedef HashMap<LastPaintSizeMapKey, IntSize> LastPaintSizeMap; +typedef HashMap<const void*, IntSize> LayerSizeMap; +typedef HashMap<RenderBoxModelObject*, LayerSizeMap> ObjectLayerSizeMap; // The HashMap for storing continuation pointers. // An inline can be split with blocks occuring in between the inline content. @@ -68,14 +68,16 @@ class ImageQualityController { public: ImageQualityController(); bool shouldPaintAtLowQuality(GraphicsContext*, RenderBoxModelObject*, Image*, const void* layer, const IntSize&); - void keyDestroyed(LastPaintSizeMapKey key); + void removeLayer(RenderBoxModelObject*, LayerSizeMap* innerMap, const void* layer); + void set(RenderBoxModelObject*, LayerSizeMap* innerMap, const void* layer, const IntSize&); void objectDestroyed(RenderBoxModelObject*); + bool isEmpty() { return m_objectLayerSizeMap.isEmpty(); } private: void highQualityRepaintTimerFired(Timer<ImageQualityController>*); void restartTimer(); - LastPaintSizeMap m_lastPaintSizeMap; + ObjectLayerSizeMap m_objectLayerSizeMap; Timer<ImageQualityController> m_timer; bool m_animatedResizeIsActive; }; @@ -86,31 +88,41 @@ ImageQualityController::ImageQualityController() { } -void ImageQualityController::keyDestroyed(LastPaintSizeMapKey key) +void ImageQualityController::removeLayer(RenderBoxModelObject* object, LayerSizeMap* innerMap, const void* layer) { - m_lastPaintSizeMap.remove(key); - if (m_lastPaintSizeMap.isEmpty()) { - m_animatedResizeIsActive = false; - m_timer.stop(); + if (innerMap) { + innerMap->remove(layer); + if (innerMap->isEmpty()) + objectDestroyed(object); } } -void ImageQualityController::objectDestroyed(RenderBoxModelObject* object) +void ImageQualityController::set(RenderBoxModelObject* object, LayerSizeMap* innerMap, const void* layer, const IntSize& size) { - Vector<LastPaintSizeMapKey> keysToDie; - for (LastPaintSizeMap::iterator it = m_lastPaintSizeMap.begin(); it != m_lastPaintSizeMap.end(); ++it) - if (it->first.first == object) - keysToDie.append(it->first); - for (Vector<LastPaintSizeMapKey>::iterator it = keysToDie.begin(); it != keysToDie.end(); ++it) - keyDestroyed(*it); + if (innerMap) + innerMap->set(layer, size); + else { + LayerSizeMap newInnerMap; + newInnerMap.set(layer, size); + m_objectLayerSizeMap.set(object, newInnerMap); + } } +void ImageQualityController::objectDestroyed(RenderBoxModelObject* object) +{ + m_objectLayerSizeMap.remove(object); + if (m_objectLayerSizeMap.isEmpty()) { + m_animatedResizeIsActive = false; + m_timer.stop(); + } +} + void ImageQualityController::highQualityRepaintTimerFired(Timer<ImageQualityController>*) { if (m_animatedResizeIsActive) { m_animatedResizeIsActive = false; - for (LastPaintSizeMap::iterator it = m_lastPaintSizeMap.begin(); it != m_lastPaintSizeMap.end(); ++it) - it->first.first->repaint(); + for (ObjectLayerSizeMap::iterator it = m_objectLayerSizeMap.begin(); it != m_objectLayerSizeMap.end(); ++it) + it->first->repaint(); } } @@ -130,17 +142,24 @@ bool ImageQualityController::shouldPaintAtLowQuality(GraphicsContext* context, R // is actually being scaled. IntSize imageSize(image->width(), image->height()); - // Look ourselves up in the hashtable. - LastPaintSizeMapKey key(object, layer); - LastPaintSizeMap::iterator i = m_lastPaintSizeMap.find(key); + // Look ourselves up in the hashtables. + ObjectLayerSizeMap::iterator i = m_objectLayerSizeMap.find(object); + LayerSizeMap* innerMap = i != m_objectLayerSizeMap.end() ? &i->second : 0; + IntSize oldSize; + bool isFirstResize = true; + if (innerMap) { + LayerSizeMap::iterator j = innerMap->find(layer); + if (j != innerMap->end()) { + isFirstResize = false; + oldSize = j->second; + } + } const AffineTransform& currentTransform = context->getCTM(); bool contextIsScaled = !currentTransform.isIdentityOrTranslationOrFlipped(); if (!contextIsScaled && imageSize == size) { // There is no scale in effect. If we had a scale in effect before, we can just remove this object from the list. - if (i != m_lastPaintSizeMap.end()) - m_lastPaintSizeMap.remove(key); - + removeLayer(object, innerMap, layer); return false; } @@ -150,39 +169,44 @@ bool ImageQualityController::shouldPaintAtLowQuality(GraphicsContext* context, R if (totalPixels > cInterpolationCutoff) return true; } + // If an animated resize is active, paint in low quality and kick the timer ahead. if (m_animatedResizeIsActive) { - m_lastPaintSizeMap.set(key, size); + set(object, innerMap, layer, size); restartTimer(); return true; } // If this is the first time resizing this image, or its size is the // same as the last resize, draw at high res, but record the paint // size and set the timer. - if (i == m_lastPaintSizeMap.end() || size == i->second) { + if (isFirstResize || oldSize == size) { restartTimer(); - m_lastPaintSizeMap.set(key, size); + set(object, innerMap, layer, size); return false; } // If the timer is no longer active, draw at high quality and don't // set the timer. if (!m_timer.isActive()) { - keyDestroyed(key); + removeLayer(object, innerMap, layer); return false; } // This object has been resized to two different sizes while the timer // is active, so draw at low quality, set the flag for animated resizes and // the object to the list for high quality redraw. - m_lastPaintSizeMap.set(key, size); + set(object, innerMap, layer, size); m_animatedResizeIsActive = true; restartTimer(); return true; } +static ImageQualityController* gImageQualityController = 0; + static ImageQualityController* imageQualityController() { - static ImageQualityController* controller = new ImageQualityController; - return controller; + if (!gImageQualityController) + gImageQualityController = new ImageQualityController; + + return gImageQualityController; } void RenderBoxModelObject::setSelectionState(SelectionState s) @@ -223,7 +247,13 @@ RenderBoxModelObject::~RenderBoxModelObject() // Our layer should have been destroyed and cleared by now ASSERT(!hasLayer()); ASSERT(!m_layer); - imageQualityController()->objectDestroyed(this); + if (gImageQualityController) { + gImageQualityController->objectDestroyed(this); + if (gImageQualityController->isEmpty()) { + delete gImageQualityController; + gImageQualityController = 0; + } + } } void RenderBoxModelObject::destroyLayer() @@ -351,7 +381,7 @@ int RenderBoxModelObject::relativePositionOffsetX() const // call availableWidth on our containing block. if (!style()->left().isAuto()) { RenderBlock* cb = containingBlock(); - if (!style()->right().isAuto() && !containingBlock()->style()->isLeftToRightDirection()) + if (!style()->right().isAuto() && !cb->style()->isLeftToRightDirection()) return -style()->right().calcValue(cb->availableWidth()); return style()->left().calcValue(cb->availableWidth()); } @@ -693,9 +723,9 @@ void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co phase += destRect.location() - destOrigin; CompositeOperator compositeOp = op == CompositeSourceOver ? bgLayer->composite() : op; RenderObject* clientForBackgroundImage = backgroundObject ? backgroundObject : this; - Image* image = bg->image(clientForBackgroundImage, tileSize); - bool useLowQualityScaling = shouldPaintAtLowQuality(context, image, bgLayer, tileSize); - context->drawTiledImage(image, style()->colorSpace(), destRect, phase, tileSize, compositeOp, useLowQualityScaling); + RefPtr<Image> image = bg->image(clientForBackgroundImage, tileSize); + bool useLowQualityScaling = shouldPaintAtLowQuality(context, image.get(), bgLayer, tileSize); + context->drawTiledImage(image.get(), style()->colorSpace(), destRect, phase, tileSize, compositeOp, useLowQualityScaling); } } @@ -897,7 +927,7 @@ bool RenderBoxModelObject::paintNinePieceImage(GraphicsContext* graphicsContext, bool drawMiddle = (imageWidth - leftSlice - rightSlice) > 0 && (w - leftWidth - rightWidth) > 0 && (imageHeight - topSlice - bottomSlice) > 0 && (h - topWidth - bottomWidth) > 0; - Image* image = styleImage->image(this, imageSize); + RefPtr<Image> image = styleImage->image(this, imageSize); ColorSpace colorSpace = style->colorSpace(); if (drawLeft) { @@ -906,18 +936,18 @@ bool RenderBoxModelObject::paintNinePieceImage(GraphicsContext* graphicsContext, // The top left corner rect is (tx, ty, leftWidth, topWidth) // The rect to use from within the image is obtained from our slice, and is (0, 0, leftSlice, topSlice) if (drawTop) - graphicsContext->drawImage(image, colorSpace, IntRect(tx, ty, leftWidth, topWidth), + graphicsContext->drawImage(image.get(), colorSpace, IntRect(tx, ty, leftWidth, topWidth), IntRect(0, 0, leftSlice, topSlice), op); // The bottom left corner rect is (tx, ty + h - bottomWidth, leftWidth, bottomWidth) // The rect to use from within the image is (0, imageHeight - bottomSlice, leftSlice, botomSlice) if (drawBottom) - graphicsContext->drawImage(image, colorSpace, IntRect(tx, ty + h - bottomWidth, leftWidth, bottomWidth), + graphicsContext->drawImage(image.get(), colorSpace, IntRect(tx, ty + h - bottomWidth, leftWidth, bottomWidth), IntRect(0, imageHeight - bottomSlice, leftSlice, bottomSlice), op); // Paint the left edge. // Have to scale and tile into the border rect. - graphicsContext->drawTiledImage(image, colorSpace, IntRect(tx, ty + topWidth, leftWidth, + graphicsContext->drawTiledImage(image.get(), colorSpace, IntRect(tx, ty + topWidth, leftWidth, h - topWidth - bottomWidth), IntRect(0, topSlice, leftSlice, imageHeight - topSlice - bottomSlice), Image::StretchTile, (Image::TileRule)vRule, op); @@ -928,17 +958,17 @@ bool RenderBoxModelObject::paintNinePieceImage(GraphicsContext* graphicsContext, // The top right corner rect is (tx + w - rightWidth, ty, rightWidth, topWidth) // The rect to use from within the image is obtained from our slice, and is (imageWidth - rightSlice, 0, rightSlice, topSlice) if (drawTop) - graphicsContext->drawImage(image, colorSpace, IntRect(tx + w - rightWidth, ty, rightWidth, topWidth), + graphicsContext->drawImage(image.get(), colorSpace, IntRect(tx + w - rightWidth, ty, rightWidth, topWidth), IntRect(imageWidth - rightSlice, 0, rightSlice, topSlice), op); // The bottom right corner rect is (tx + w - rightWidth, ty + h - bottomWidth, rightWidth, bottomWidth) // The rect to use from within the image is (imageWidth - rightSlice, imageHeight - bottomSlice, rightSlice, bottomSlice) if (drawBottom) - graphicsContext->drawImage(image, colorSpace, IntRect(tx + w - rightWidth, ty + h - bottomWidth, rightWidth, bottomWidth), + graphicsContext->drawImage(image.get(), colorSpace, IntRect(tx + w - rightWidth, ty + h - bottomWidth, rightWidth, bottomWidth), IntRect(imageWidth - rightSlice, imageHeight - bottomSlice, rightSlice, bottomSlice), op); // Paint the right edge. - graphicsContext->drawTiledImage(image, colorSpace, IntRect(tx + w - rightWidth, ty + topWidth, rightWidth, + graphicsContext->drawTiledImage(image.get(), colorSpace, IntRect(tx + w - rightWidth, ty + topWidth, rightWidth, h - topWidth - bottomWidth), IntRect(imageWidth - rightSlice, topSlice, rightSlice, imageHeight - topSlice - bottomSlice), Image::StretchTile, (Image::TileRule)vRule, op); @@ -946,20 +976,20 @@ bool RenderBoxModelObject::paintNinePieceImage(GraphicsContext* graphicsContext, // Paint the top edge. if (drawTop) - graphicsContext->drawTiledImage(image, colorSpace, IntRect(tx + leftWidth, ty, w - leftWidth - rightWidth, topWidth), + graphicsContext->drawTiledImage(image.get(), colorSpace, IntRect(tx + leftWidth, ty, w - leftWidth - rightWidth, topWidth), IntRect(leftSlice, 0, imageWidth - rightSlice - leftSlice, topSlice), (Image::TileRule)hRule, Image::StretchTile, op); // Paint the bottom edge. if (drawBottom) - graphicsContext->drawTiledImage(image, colorSpace, IntRect(tx + leftWidth, ty + h - bottomWidth, + graphicsContext->drawTiledImage(image.get(), colorSpace, IntRect(tx + leftWidth, ty + h - bottomWidth, w - leftWidth - rightWidth, bottomWidth), IntRect(leftSlice, imageHeight - bottomSlice, imageWidth - rightSlice - leftSlice, bottomSlice), (Image::TileRule)hRule, Image::StretchTile, op); // Paint the middle. if (drawMiddle) - graphicsContext->drawTiledImage(image, colorSpace, IntRect(tx + leftWidth, ty + topWidth, w - leftWidth - rightWidth, + graphicsContext->drawTiledImage(image.get(), colorSpace, IntRect(tx + leftWidth, ty + topWidth, w - leftWidth - rightWidth, h - topWidth - bottomWidth), IntRect(leftSlice, topSlice, imageWidth - rightSlice - leftSlice, imageHeight - topSlice - bottomSlice), (Image::TileRule)hRule, (Image::TileRule)vRule, op); @@ -1545,6 +1575,20 @@ void RenderBoxModelObject::clipBorderSidePolygon(GraphicsContext* graphicsContex graphicsContext->clipConvexPolygon(4, secondQuad, !secondEdgeMatches); } +static inline IntRect areaCastingShadowInHole(const IntRect& holeRect, int shadowBlur, int shadowSpread, const IntSize& shadowOffset) +{ + IntRect bounds(holeRect); + + bounds.inflate(shadowBlur); + + if (shadowSpread < 0) + bounds.inflate(-shadowSpread); + + IntRect offsetBounds = bounds; + offsetBounds.move(-shadowOffset); + return unionRect(bounds, offsetBounds); +} + void RenderBoxModelObject::paintBoxShadow(GraphicsContext* context, int tx, int ty, int w, int h, const RenderStyle* s, ShadowStyle shadowStyle, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) { // FIXME: Deal with border-image. Would be great to use border-image as a mask. @@ -1555,17 +1599,18 @@ void RenderBoxModelObject::paintBoxShadow(GraphicsContext* context, int tx, int RoundedIntRect border(tx, ty, w, h); bool hasBorderRadius = s->hasBorderRadius(); bool isHorizontal = s->isHorizontalWritingMode(); - if (hasBorderRadius && (includeLogicalLeftEdge || includeLogicalRightEdge)) { - RoundedIntRect::Radii radii = ((shadowStyle == Inset) ? s->getRoundedInnerBorderWithBorderWidths(border.rect(), borderTop(), borderBottom(), borderLeft(), borderRight()) : s->getRoundedBorderFor(border.rect())).radii(); - border.includeLogicalEdges(radii, isHorizontal, includeLogicalLeftEdge, includeLogicalRightEdge); - } - + if (shadowStyle == Inset) border.setRect(IntRect(border.rect().x() + (includeLogicalLeftEdge || !isHorizontal ? borderLeft() : 0), border.rect().y() + (includeLogicalLeftEdge || isHorizontal ? borderTop() : 0), border.rect().width() - ((includeLogicalLeftEdge || !isHorizontal) ? borderLeft() : 0) - ((includeLogicalRightEdge || !isHorizontal) ? borderRight() : 0), border.rect().height() - ((includeLogicalLeftEdge || isHorizontal) ? borderTop() : 0) - ((includeLogicalRightEdge || isHorizontal) ? borderBottom() : 0))); + if (hasBorderRadius && (includeLogicalLeftEdge || includeLogicalRightEdge)) { + RoundedIntRect::Radii radii = ((shadowStyle == Inset) ? s->getRoundedInnerBorderWithBorderWidths(border.rect(), borderTop(), borderBottom(), borderLeft(), borderRight()) : s->getRoundedBorderFor(border.rect())).radii(); + border.includeLogicalEdges(radii, isHorizontal, includeLogicalLeftEdge, includeLogicalRightEdge); + } + bool hasOpaqueBackground = s->visitedDependentColor(CSSPropertyBackgroundColor).isValid() && s->visitedDependentColor(CSSPropertyBackgroundColor).alpha() == 255; for (const ShadowData* shadow = s->boxShadow(); shadow; shadow = shadow->next()) { if (shadow->style() != shadowStyle) @@ -1595,7 +1640,11 @@ void RenderBoxModelObject::paintBoxShadow(GraphicsContext* context, int tx, int shadowOffset -= extraOffset; fillRect.move(extraOffset); - context->setShadow(shadowOffset, shadowBlur, shadowColor, s->colorSpace()); + if (shadow->isWebkitBoxShadow()) + context->setLegacyShadow(shadowOffset, shadowBlur, shadowColor, s->colorSpace()); + else + context->setShadow(shadowOffset, shadowBlur, shadowColor, s->colorSpace()); + if (hasBorderRadius) { RoundedIntRect rectToClipOut = border; @@ -1611,6 +1660,7 @@ void RenderBoxModelObject::paintBoxShadow(GraphicsContext* context, int tx, int if (shadowSpread < 0) fillRect.expandRadii(shadowSpread); + context->fillRoundedRect(fillRect, Color::black, s->colorSpace()); } else { IntRect rectToClipOut = border.rect(); @@ -1663,17 +1713,14 @@ void RenderBoxModelObject::paintBoxShadow(GraphicsContext* context, int tx, int Color fillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), 255); - IntRect outerRect(border.rect()); - outerRect.inflateX(w - 2 * shadowSpread); - outerRect.inflateY(h - 2 * shadowSpread); - + IntRect outerRect = areaCastingShadowInHole(border.rect(), shadowBlur, shadowSpread, shadowOffset); context->save(); Path path; if (hasBorderRadius) { + Path path; path.addRoundedRect(border.rect(), border.radii().topLeft(), border.radii().topRight(), border.radii().bottomLeft(), border.radii().bottomRight()); context->clip(path); - path.clear(); } else context->clip(border.rect()); @@ -1681,19 +1728,16 @@ void RenderBoxModelObject::paintBoxShadow(GraphicsContext* context, int tx, int context->translate(extraOffset.width(), extraOffset.height()); shadowOffset -= extraOffset; - path.addRect(outerRect); - - if (hasBorderRadius) { - if (shadowSpread > 0) - border.shrinkRadii(shadowSpread); - path.addRoundedRect(holeRect, border.radii().topLeft(), border.radii().topRight(), border.radii().bottomLeft(), border.radii().bottomRight()); - } else - path.addRect(holeRect); + if (hasBorderRadius && shadowSpread > 0) + border.shrinkRadii(shadowSpread); + + if (shadow->isWebkitBoxShadow()) + context->setLegacyShadow(shadowOffset, shadowBlur, shadowColor, s->colorSpace()); + else + context->setShadow(shadowOffset, shadowBlur, shadowColor, s->colorSpace()); - context->setFillRule(RULE_EVENODD); - context->setFillColor(fillColor, s->colorSpace()); - context->setShadow(shadowOffset, shadowBlur, shadowColor, s->colorSpace()); - context->fillPath(path); + RoundedIntRect roundedHole(holeRect, border.radii()); + context->fillRectWithRoundedHole(outerRect, roundedHole, fillColor, s->colorSpace()); context->restore(); } diff --git a/Source/WebCore/rendering/RenderCombineText.cpp b/Source/WebCore/rendering/RenderCombineText.cpp new file mode 100644 index 0000000..1b20bd8 --- /dev/null +++ b/Source/WebCore/rendering/RenderCombineText.cpp @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2011 Apple 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 "RenderCombineText.h" + +#include "TextRun.h" + +namespace WebCore { + +const float textCombineMargin = 1.1f; // Allow em + 10% margin + +RenderCombineText::RenderCombineText(Node* node, PassRefPtr<StringImpl> string) + : RenderText(node, string) + , m_combinedTextWidth(0) + , m_isCombined(false) + , m_needsFontUpdate(false) +{ +} + +void RenderCombineText::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) +{ + RenderText::styleDidChange(diff, oldStyle); + + if (m_isCombined) + RenderText::setTextInternal(originalText()); // This RenderCombineText has been combined once. Restore the original text for the next combineText(). + + m_needsFontUpdate = true; +} + +void RenderCombineText::setTextInternal(PassRefPtr<StringImpl> text) +{ + RenderText::setTextInternal(text); + + m_needsFontUpdate = true; +} + +unsigned RenderCombineText::width(unsigned from, unsigned length, const Font& font, int xPosition, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const +{ + if (!characters()) + return 0; + + if (m_isCombined) + return font.size(); + + return RenderText::width(from, length, font, xPosition, fallbackFonts, glyphOverflow); +} + +void RenderCombineText::adjustTextOrigin(IntPoint& textOrigin, const IntRect& boxRect) const +{ + if (m_isCombined) + textOrigin.move(boxRect.height() / 2 - ceilf(m_combinedTextWidth) / 2, style()->font().pixelSize()); +} + +void RenderCombineText::charactersToRender(int start, const UChar*& characters, int& length) const +{ + if (m_isCombined) { + length = originalText()->length(); + characters = originalText()->characters(); + return; + } + + characters = text()->characters() + start; +} + +void RenderCombineText::combineText() +{ + if (!m_needsFontUpdate) + return; + + m_isCombined = false; + m_needsFontUpdate = false; + + // CSS3 spec says text-combine works only in vertical writing mode. + if (style()->isHorizontalWritingMode()) + return; + + TextRun run = TextRun(String(text())); + FontDescription description = style()->font().fontDescription(); + float emWidth = description.computedSize() * textCombineMargin; + bool shouldUpdateFont = false; + + description.setOrientation(Horizontal); // We are going to draw combined text horizontally. + m_combinedTextWidth = style()->font().floatWidth(run); + m_isCombined = m_combinedTextWidth <= emWidth; + + if (m_isCombined) + shouldUpdateFont = style()->setFontDescription(description); // Need to change font orientation to horizontal. + else { + // Need to try compressed glyphs. + static const FontWidthVariant widthVariants[] = { HalfWidth, ThirdWidth, QuarterWidth }; + for (size_t i = 0 ; i < WTF_ARRAY_LENGTH(widthVariants) ; ++i) { + description.setWidthVariant(widthVariants[i]); + Font compressedFont = Font(description, style()->font().letterSpacing(), style()->font().wordSpacing()); + compressedFont.update(style()->font().fontSelector()); + float runWidth = compressedFont.floatWidth(run); + if (runWidth <= emWidth) { + m_combinedTextWidth = runWidth; + m_isCombined = true; + + // Replace my font with the new one. + shouldUpdateFont = style()->setFontDescription(description); + break; + } + } + } + + if (shouldUpdateFont) + style()->font().update(style()->font().fontSelector()); + + if (m_isCombined) { + static const UChar newCharacter = objectReplacementCharacter; + DEFINE_STATIC_LOCAL(String, objectReplacementCharacterString, (&newCharacter, 1)); + RenderText::setTextInternal(objectReplacementCharacterString.impl()); + } +} + +} // namespace WebCore diff --git a/Source/WebCore/rendering/RenderCombineText.h b/Source/WebCore/rendering/RenderCombineText.h new file mode 100644 index 0000000..582cbd6 --- /dev/null +++ b/Source/WebCore/rendering/RenderCombineText.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2011 Apple 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 RenderCombineText_h +#define RenderCombineText_h + +#include "RenderText.h" + +namespace WebCore { + +class RenderCombineText : public RenderText { +public: + RenderCombineText(Node*, PassRefPtr<StringImpl>); + + void combineText(); + void adjustTextOrigin(IntPoint& textOrigin, const IntRect& 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(); } + +private: + virtual unsigned width(unsigned from, unsigned length, const Font&, int 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>); + + float m_combinedTextWidth; + bool m_isCombined : 1; + bool m_needsFontUpdate : 1; +}; + +inline RenderCombineText* toRenderCombineText(RenderObject* object) +{ + ASSERT(!object || object->isText()); + return static_cast<RenderCombineText*>(object); +} + +inline const RenderCombineText* toRenderCombineText(const RenderObject* object) +{ + ASSERT(!object || object->isText()); + return static_cast<const RenderCombineText*>(object); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderCombineText(const RenderCombineText*); + +} // namespace WebCore + +#endif // RenderCombineText_h diff --git a/Source/WebCore/rendering/RenderCounter.cpp b/Source/WebCore/rendering/RenderCounter.cpp index 57c54f8..fbd5545 100644 --- a/Source/WebCore/rendering/RenderCounter.cpp +++ b/Source/WebCore/rendering/RenderCounter.cpp @@ -24,6 +24,7 @@ #include "CounterNode.h" #include "Document.h" +#include "Element.h" #include "HTMLNames.h" #include "HTMLOListElement.h" #include "RenderListItem.h" @@ -46,11 +47,157 @@ static CounterMaps& counterMaps() return staticCounterMaps; } -static inline RenderObject* previousSiblingOrParent(RenderObject* object) +// This function processes the renderer tree in the order of the DOM tree +// including pseudo elements as defined in CSS 2.1. +// Anonymous renderers are skipped except for those representing pseudo elements. +static RenderObject* previousInPreOrder(const RenderObject* object) { - if (RenderObject* sibling = object->previousSibling()) - return sibling; - return object->parent(); + Element* parent; + Element* sibling; + switch (object->style()->styleType()) { + case NOPSEUDO: + ASSERT(!object->isAnonymous()); + parent = toElement(object->node()); + sibling = parent->previousElementSibling(); + parent = parent->parentElement(); + break; + case BEFORE: + return object->generatingNode()->renderer(); // It is always the generating node's renderer + case AFTER: + parent = toElement(object->generatingNode()); + sibling = parent->lastElementChild(); + break; + default: + ASSERT_NOT_REACHED(); + return 0; + } + while (sibling) { + if (RenderObject* renderer = sibling->renderer()) { + if (RenderObject* after = renderer->afterPseudoElementRenderer()) + return after; + parent = sibling; + sibling = sibling->lastElementChild(); + if (!sibling) { + if (RenderObject* before = renderer->beforePseudoElementRenderer()) + return before; + return renderer; + } + } else + sibling = sibling->previousElementSibling(); + } + if (!parent) + return 0; + RenderObject* renderer = parent->renderer(); // Should never be null + if (RenderObject* before = renderer->beforePseudoElementRenderer()) + return before; + return renderer; +} + +// This function processes the renderer tree in the order of the DOM tree +// including pseudo elements as defined in CSS 2.1. +// Anonymous renderers are skipped except for those representing pseudo elements. +static RenderObject* previousSiblingOrParent(const RenderObject* object) +{ + Element* parent; + Element* sibling; + switch (object->style()->styleType()) { + case NOPSEUDO: + ASSERT(!object->isAnonymous()); + parent = toElement(object->node()); + sibling = parent->previousElementSibling(); + parent = parent->parentElement(); + break; + case BEFORE: + return object->generatingNode()->renderer(); // It is always the generating node's renderer + case AFTER: + parent = toElement(object->generatingNode()); + sibling = parent->lastElementChild(); + break; + default: + ASSERT_NOT_REACHED(); + return 0; + } + while (sibling) { + if (RenderObject* renderer = sibling->renderer()) // This skips invisible nodes + return renderer; + sibling = sibling->previousElementSibling(); + } + if (parent) { + RenderObject* renderer = parent->renderer(); + if (RenderObject* before = renderer->virtualChildren()->beforePseudoElementRenderer(renderer)) + return before; + return renderer; + } + return 0; +} + +static Element* parentElement(RenderObject* object) +{ + switch (object->style()->styleType()) { + case NOPSEUDO: + ASSERT(!object->isAnonymous()); + return toElement(object->node())->parentElement(); + case BEFORE: + case AFTER: + return toElement(object->generatingNode()); + default: + ASSERT_NOT_REACHED(); + return 0; + } +} + +static inline bool areRenderersElementsSiblings(RenderObject* first, RenderObject* second) +{ + return parentElement(first) == parentElement(second); +} + +// This function processes the renderer tree in the order of the DOM tree +// including pseudo elements as defined in CSS 2.1. +// Anonymous renderers are skipped except for those representing pseudo elements. +static RenderObject* nextInPreOrder(const RenderObject* object, const Element* stayWithin, bool skipDescendants = false) +{ + Element* self; + Element* child; + RenderObject* result; + self = toElement(object->generatingNode()); + if (skipDescendants) + goto nextsibling; + switch (object->style()->styleType()) { + case NOPSEUDO: + ASSERT(!object->isAnonymous()); + result = object->beforePseudoElementRenderer(); + if (result) + return result; + break; + case BEFORE: + break; + case AFTER: + goto nextsibling; + default: + ASSERT_NOT_REACHED(); + return 0; + } + child = self->firstElementChild(); + while (true) { + while (child) { + result = child->renderer(); + if (result) + return result; + child = child->nextElementSibling(); + } + result = self->renderer()->afterPseudoElementRenderer(); + if (result) + return result; +nextsibling: + if (self == stayWithin) + return 0; + child = self->nextElementSibling(); + self = self->parentElement(); + if (!self) { + ASSERT(!child); // We can only reach this if we are searching beyond the root element + return 0; // which cannot have siblings + } + } } static bool planCounter(RenderObject* object, const AtomicString& identifier, bool& isReset, int& value) @@ -61,10 +208,27 @@ static bool planCounter(RenderObject* object, const AtomicString& identifier, bo // We can't even look at their styles or we'll see extra resets and increments! if (object->isText() && !object->isBR()) return false; - + Node* generatingNode = object->generatingNode(); + // We must have a generating node or else we cannot have a counter. + if (!generatingNode) + return false; RenderStyle* style = object->style(); ASSERT(style); + switch (style->styleType()) { + case NOPSEUDO: + // Sometimes nodes have more then one renderer. Only the first one gets the counter + // LayoutTests/http/tests/css/counter-crash.html + if (generatingNode->renderer() != object) + return false; + break; + case BEFORE: + case AFTER: + break; + default: + return false; // Counters are forbidden from all other pseudo elements. + } + if (const CounterDirectiveMap* directivesMap = style->counterDirectives()) { CounterDirectives directives = directivesMap->get(identifier.impl()); if (directives.m_reset) { @@ -133,14 +297,9 @@ static bool findPlaceForCounter(RenderObject* counterOwner, const AtomicString& // We check renderers in preOrder from the renderer that our counter is attached to // towards the begining of the document for counters with the same identifier as the one // we are trying to find a place for. This is the next renderer to be checked. - RenderObject* currentRenderer = counterOwner->previousInPreOrder(); + RenderObject* currentRenderer = previousInPreOrder(counterOwner); previousSibling = 0; while (currentRenderer) { - // A sibling without a parent means that the counter node tree was not constructed correctly so we stop - // traversing. In the future RenderCounter should handle RenderObjects that are not connected to the - // render tree at counter node creation. See bug 43812. - if (previousSibling && !previousSibling->parent()) - return false; CounterNode* currentCounter = makeCounterNode(currentRenderer, identifier, false); if (searchEndRenderer == currentRenderer) { // We may be at the end of our search. @@ -149,7 +308,7 @@ static bool findPlaceForCounter(RenderObject* counterOwner, const AtomicString& if (previousSibling) { // But we already found another counter that we come after. if (currentCounter->actsAsReset()) { // We found a reset counter that is on a renderer that is a sibling of ours or a parent. - if (isReset && currentRenderer->parent() == counterOwner->parent()) { + if (isReset && areRenderersElementsSiblings(currentRenderer, counterOwner)) { // We are also a reset counter and the previous reset was on a sibling renderer // hence we are the next sibling of that counter if that reset is not a root or // we are a root node if that reset is a root. @@ -164,7 +323,7 @@ static bool findPlaceForCounter(RenderObject* counterOwner, const AtomicString& return true; } // CurrentCounter, the counter at the EndSearchRenderer, is not reset. - if (!isReset || currentRenderer->parent() != counterOwner->parent()) { + if (!isReset || !areRenderersElementsSiblings(currentRenderer, counterOwner)) { // If the node we are placing is not reset or we have found a counter that is attached // to an ancestor of the placed counter's renderer we know we are a sibling of that node. ASSERT(currentCounter->parent() == previousSibling->parent()); @@ -177,7 +336,7 @@ static bool findPlaceForCounter(RenderObject* counterOwner, const AtomicString& // previousSibling, and when we are a sibling of the end counter we must set previousSibling // to currentCounter. if (currentCounter->actsAsReset()) { - if (isReset && currentRenderer->parent() == counterOwner->parent()) { + if (isReset && areRenderersElementsSiblings(currentRenderer, counterOwner)) { parent = currentCounter->parent(); previousSibling = currentCounter; return parent; @@ -185,7 +344,7 @@ static bool findPlaceForCounter(RenderObject* counterOwner, const AtomicString& parent = currentCounter; return true; } - if (!isReset || currentRenderer->parent() != counterOwner->parent()) { + if (!isReset || !areRenderersElementsSiblings(currentRenderer, counterOwner)) { parent = currentCounter->parent(); previousSibling = currentCounter; return true; @@ -210,7 +369,7 @@ static bool findPlaceForCounter(RenderObject* counterOwner, const AtomicString& previousSibling = currentCounter; // We are no longer interested in previous siblings of the currentRenderer or their children // as counters they may have attached cannot be the previous sibling of the counter we are placing. - currentRenderer = currentRenderer->parent(); + currentRenderer = parentElement(currentRenderer)->renderer(); continue; } } else @@ -261,28 +420,28 @@ static CounterNode* makeCounterNode(RenderObject* object, const AtomicString& id object->m_hasCounterNodeMap = true; } nodeMap->set(identifier.impl(), newNode); - if (newNode->parent() || !object->nextInPreOrder(object->parent())) + if (newNode->parent()) return newNode.get(); // Checking if some nodes that were previously counter tree root nodes // should become children of this node now. CounterMaps& maps = counterMaps(); - RenderObject* stayWithin = object->parent(); - for (RenderObject* currentRenderer = object->nextInPreOrder(stayWithin); currentRenderer; currentRenderer = currentRenderer->nextInPreOrder(stayWithin)) { + Element* stayWithin = parentElement(object); + bool skipDescendants; + for (RenderObject* currentRenderer = nextInPreOrder(object, stayWithin); currentRenderer; currentRenderer = nextInPreOrder(currentRenderer, stayWithin, skipDescendants)) { + skipDescendants = false; if (!currentRenderer->m_hasCounterNodeMap) continue; CounterNode* currentCounter = maps.get(currentRenderer)->get(identifier.impl()).get(); if (!currentCounter) continue; + skipDescendants = true; if (currentCounter->parent()) { ASSERT(newNode->firstChild()); - if (currentRenderer->lastChild()) - currentRenderer = currentRenderer->lastChild(); continue; } - if (stayWithin != currentRenderer->parent() || !currentCounter->hasResetType()) - newNode->insertAfter(currentCounter, newNode->lastChild(), identifier); - if (currentRenderer->lastChild()) - currentRenderer = currentRenderer->lastChild(); + if (stayWithin == parentElement(currentRenderer) && currentCounter->hasResetType()) + break; + newNode->insertAfter(currentCounter, newNode->lastChild(), identifier); } return newNode.get(); } @@ -449,12 +608,22 @@ static void updateCounters(RenderObject* renderer) void RenderCounter::rendererSubtreeAttached(RenderObject* renderer) { + Node* node = renderer->node(); + if (node) + node = node->parentNode(); + else + node = renderer->generatingNode(); + if (node && !node->attached()) + return; // No need to update if the parent is not attached yet for (RenderObject* descendant = renderer; descendant; descendant = descendant->nextInPreOrder(renderer)) updateCounters(descendant); } void RenderCounter::rendererStyleChanged(RenderObject* renderer, const RenderStyle* oldStyle, const RenderStyle* newStyle) { + Node* node = renderer->generatingNode(); + if (!node || !node->attached()) + return; // cannot have generated content or if it can have, it will be handled during attaching const CounterDirectiveMap* newCounterDirectives; const CounterDirectiveMap* oldCounterDirectives; if (oldStyle && (oldCounterDirectives = oldStyle->counterDirectives())) { @@ -494,3 +663,27 @@ void RenderCounter::rendererStyleChanged(RenderObject* renderer, const RenderSty } } // namespace WebCore + +#ifndef NDEBUG + +void showCounterRendererTree(const WebCore::RenderObject* renderer, const char* counterName) +{ + if (!renderer) + return; + const WebCore::RenderObject* root = renderer; + while (root->parent()) + root = root->parent(); + + AtomicString identifier(counterName); + for (const WebCore::RenderObject* current = root; current; current = current->nextInPreOrder()) { + fprintf(stderr, "%c", (current == renderer) ? '*' : ' '); + for (const WebCore::RenderObject* parent = current; parent && parent != root; parent = parent->parent()) + fprintf(stderr, " "); + fprintf(stderr, "%p N:%p P:%p PS:%p NS:%p C:%p\n", + current, current->node(), current->parent(), current->previousSibling(), + current->nextSibling(), current->m_hasCounterNodeMap? + counterName ? WebCore::counterMaps().get(current)->get(identifier.impl()).get() : (WebCore::CounterNode*)1 : (WebCore::CounterNode*)0); + } +} + +#endif // NDEBUG diff --git a/Source/WebCore/rendering/RenderCounter.h b/Source/WebCore/rendering/RenderCounter.h index 9373193..de0ee1b 100644 --- a/Source/WebCore/rendering/RenderCounter.h +++ b/Source/WebCore/rendering/RenderCounter.h @@ -67,4 +67,9 @@ void toRenderCounter(const RenderCounter*); } // namespace WebCore +#ifndef NDEBUG +// Outside the WebCore namespace for ease of invocation from gdb. +void showCounterRendererTree(const WebCore::RenderObject*, const char* counterName = 0); +#endif + #endif // RenderCounter_h diff --git a/Source/WebCore/rendering/RenderEmbeddedObject.cpp b/Source/WebCore/rendering/RenderEmbeddedObject.cpp index 5486d51..cdd6c55 100644 --- a/Source/WebCore/rendering/RenderEmbeddedObject.cpp +++ b/Source/WebCore/rendering/RenderEmbeddedObject.cpp @@ -172,8 +172,9 @@ void RenderEmbeddedObject::paintReplaced(PaintInfo& paintInfo, int tx, int ty) context->setFillColor(m_missingPluginIndicatorIsPressed ? replacementTextRoundedRectPressedColor() : Color::white, style()->colorSpace()); context->fillPath(path); + const FontMetrics& fontMetrics = font.fontMetrics(); float labelX = roundf(replacementTextRect.location().x() + (replacementTextRect.size().width() - textWidth) / 2); - float labelY = roundf(replacementTextRect.location().y() + (replacementTextRect.size().height() - font.height()) / 2 + font.ascent()); + float labelY = roundf(replacementTextRect.location().y() + (replacementTextRect.size().height() - fontMetrics.height()) / 2 + fontMetrics.ascent()); context->setAlpha(m_missingPluginIndicatorIsPressed ? replacementTextPressedTextOpacity : replacementTextTextOpacity); context->setFillColor(Color::black, style()->colorSpace()); context->drawBidiText(font, run, FloatPoint(labelX, labelY)); diff --git a/Source/WebCore/rendering/RenderFileUploadControl.cpp b/Source/WebCore/rendering/RenderFileUploadControl.cpp index aec55a8..f72edad 100644 --- a/Source/WebCore/rendering/RenderFileUploadControl.cpp +++ b/Source/WebCore/rendering/RenderFileUploadControl.cpp @@ -216,7 +216,7 @@ void RenderFileUploadControl::paintObject(PaintInfo& paintInfo, int tx, int ty) const String& displayedFilename = fileTextValue(); unsigned length = displayedFilename.length(); const UChar* string = displayedFilename.characters(); - TextRun textRun(string, length, false, 0, 0, !style()->isLeftToRightDirection(), style()->unicodeBidi() == Override); + TextRun textRun(string, length, false, 0, 0, TextRun::AllowTrailingExpansion, !style()->isLeftToRightDirection(), style()->unicodeBidi() == Override); // Determine where the filename should be placed int contentLeft = tx + borderLeft() + paddingLeft(); @@ -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, false, false, false)); + float charWidth = style()->font().floatWidth(TextRun(&ch, 1, false, 0, 0, TextRun::AllowTrailingExpansion, false, false, false)); m_maxPreferredLogicalWidth = (int)ceilf(charWidth * defaultWidthNumChars); } @@ -297,6 +297,11 @@ void RenderFileUploadControl::computePreferredLogicalWidths() setPreferredLogicalWidthsDirty(false); } +VisiblePosition RenderFileUploadControl::positionForPoint(const IntPoint&) +{ + return VisiblePosition(); +} + void RenderFileUploadControl::receiveDroppedFiles(const Vector<String>& paths) { if (allowsMultipleFiles()) diff --git a/Source/WebCore/rendering/RenderFileUploadControl.h b/Source/WebCore/rendering/RenderFileUploadControl.h index c96800c..22974fe 100644 --- a/Source/WebCore/rendering/RenderFileUploadControl.h +++ b/Source/WebCore/rendering/RenderFileUploadControl.h @@ -28,7 +28,7 @@ namespace WebCore { class Chrome; class HTMLInputElement; - + // Each RenderFileUploadControl contains a RenderButton (for opening the file chooser), and // sufficient space to draw a file icon and filename. The RenderButton has a shadow node // associated with it to receive click/hover events. @@ -71,6 +71,8 @@ private: Chrome* chrome() const; int maxFilenameWidth() const; PassRefPtr<RenderStyle> createButtonStyle(const RenderStyle* parentStyle) const; + + virtual VisiblePosition positionForPoint(const IntPoint&); RefPtr<HTMLInputElement> m_button; RefPtr<FileChooser> m_fileChooser; diff --git a/Source/WebCore/rendering/RenderFlexibleBox.cpp b/Source/WebCore/rendering/RenderFlexibleBox.cpp index 5af5733..9ab3c3f 100644 --- a/Source/WebCore/rendering/RenderFlexibleBox.cpp +++ b/Source/WebCore/rendering/RenderFlexibleBox.cpp @@ -25,11 +25,11 @@ #include "config.h" #include "RenderFlexibleBox.h" -#include "CharacterNames.h" #include "RenderLayer.h" #include "RenderView.h" #include "TextRun.h" #include <wtf/StdLibExtras.h> +#include <wtf/unicode/CharacterNames.h> #ifdef ANDROID_LAYOUT #include "Document.h" @@ -288,7 +288,7 @@ void RenderFlexibleBox::layoutBlock(bool relayoutChildren, int /*pageHeight FIXM updateLayerTransform(); if (view()->layoutState()->pageLogicalHeight()) - setPageLogicalOffset(view()->layoutState()->pageLogicalOffset(y())); + setPageLogicalOffset(view()->layoutState()->pageLogicalOffset(logicalTop())); // Update our scrollbars if we're overflow:auto/scroll/hidden now that we know if // we overflow or not. diff --git a/Source/WebCore/rendering/RenderFrameSet.cpp b/Source/WebCore/rendering/RenderFrameSet.cpp index 06b2a7a..e4eee6e 100644 --- a/Source/WebCore/rendering/RenderFrameSet.cpp +++ b/Source/WebCore/rendering/RenderFrameSet.cpp @@ -96,8 +96,8 @@ void RenderFrameSet::paintColumnBorder(const PaintInfo& paintInfo, const IntRect // Now stroke the edges but only if we have enough room to paint both edges with a little // bit of the fill color showing through. if (borderRect.width() >= 3) { - context->fillRect(IntRect(borderRect.topLeft(), IntSize(1, height())), borderStartEdgeColor(), colorSpace); - context->fillRect(IntRect(borderRect.topRight(), IntSize(1, height())), borderEndEdgeColor(), colorSpace); + context->fillRect(IntRect(borderRect.location(), IntSize(1, height())), borderStartEdgeColor(), colorSpace); + context->fillRect(IntRect(IntPoint(borderRect.maxX() - 1, borderRect.y()), IntSize(1, height())), borderEndEdgeColor(), colorSpace); } } @@ -116,8 +116,8 @@ void RenderFrameSet::paintRowBorder(const PaintInfo& paintInfo, const IntRect& b // Now stroke the edges but only if we have enough room to paint both edges with a little // bit of the fill color showing through. if (borderRect.height() >= 3) { - context->fillRect(IntRect(borderRect.topLeft(), IntSize(width(), 1)), borderStartEdgeColor(), colorSpace); - context->fillRect(IntRect(borderRect.bottomLeft(), IntSize(width(), 1)), borderEndEdgeColor(), colorSpace); + context->fillRect(IntRect(borderRect.location(), IntSize(width(), 1)), borderStartEdgeColor(), colorSpace); + context->fillRect(IntRect(IntPoint(borderRect.x(), borderRect.maxY() - 1), IntSize(width(), 1)), borderEndEdgeColor(), colorSpace); } } diff --git a/Source/WebCore/rendering/RenderImage.cpp b/Source/WebCore/rendering/RenderImage.cpp index 839328e..7369f4e 100644 --- a/Source/WebCore/rendering/RenderImage.cpp +++ b/Source/WebCore/rendering/RenderImage.cpp @@ -4,7 +4,7 @@ * (C) 2000 Dirk Mueller (mueller@kde.org) * (C) 2006 Allan Sandfeld Jensen (kde@carewolf.com) * (C) 2006 Samuel Weinig (sam.weinig@gmail.com) - * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved. * Copyright (C) 2010 Google Inc. All rights reserved. * * This library is free software; you can redistribute it and/or @@ -30,7 +30,6 @@ #include "Frame.h" #include "GraphicsContext.h" #include "HTMLAreaElement.h" -#include "HTMLCollection.h" #include "HTMLImageElement.h" #include "HTMLInputElement.h" #include "HTMLMapElement.h" @@ -38,11 +37,9 @@ #include "HitTestResult.h" #include "Page.h" #include "RenderLayer.h" -#include "RenderTheme.h" #include "RenderView.h" #include "SelectionController.h" #include "TextRun.h" -#include <wtf/CurrentTime.h> #include <wtf/UnusedParam.h> #ifdef ANDROID_LAYOUT @@ -116,7 +113,7 @@ bool RenderImage::setImageSizeForAltText(CachedImage* newImage /* = 0 */) // we have an alt and the user meant it (its not a text we invented) if (!m_altText.isEmpty()) { const Font& font = style()->font(); - IntSize textSize(min(font.width(TextRun(m_altText.characters(), m_altText.length())), maxAltTextWidth), min(font.height(), maxAltTextHeight)); + IntSize textSize(min(font.width(TextRun(m_altText.characters(), m_altText.length())), maxAltTextWidth), min(font.fontMetrics().height(), maxAltTextHeight)); imageSize = imageSize.expandedTo(textSize); } @@ -277,7 +274,7 @@ void RenderImage::paintReplaced(PaintInfo& paintInfo, int tx, int ty) int usableWidth = cWidth - 2; int usableHeight = cHeight - 2; - Image* image = m_imageResource->image(); + RefPtr<Image> image = m_imageResource->image(); if (m_imageResource->errorOccurred() && !image->isNull() && usableWidth >= image->width() && usableHeight >= image->height()) { // Center the error image, accounting for border and padding. @@ -289,7 +286,7 @@ void RenderImage::paintReplaced(PaintInfo& paintInfo, int tx, int ty) centerY = 0; imageX = leftBorder + leftPad + centerX + 1; imageY = topBorder + topPad + centerY + 1; - context->drawImage(image, style()->colorSpace(), IntPoint(tx + imageX, ty + imageY)); + context->drawImage(image.get(), style()->colorSpace(), IntPoint(tx + imageX, ty + imageY)); errorPictureDrawn = true; } @@ -299,21 +296,22 @@ void RenderImage::paintReplaced(PaintInfo& paintInfo, int tx, int ty) int ax = tx + leftBorder + leftPad; int ay = ty + topBorder + topPad; const Font& font = style()->font(); - int ascent = font.ascent(); + const FontMetrics& fontMetrics = font.fontMetrics(); + int ascent = fontMetrics.ascent(); // Only draw the alt text if it'll fit within the content box, // and only if it fits above the error image. TextRun textRun(text.characters(), text.length()); int textWidth = font.width(textRun); if (errorPictureDrawn) { - if (usableWidth >= textWidth && font.height() <= imageY) - context->drawText(style()->font(), textRun, IntPoint(ax, ay + ascent)); - } else if (usableWidth >= textWidth && cHeight >= font.height()) - context->drawText(style()->font(), textRun, IntPoint(ax, ay + ascent)); + if (usableWidth >= textWidth && fontMetrics.height() <= imageY) + context->drawText(font, textRun, IntPoint(ax, ay + ascent)); + } else if (usableWidth >= textWidth && cHeight >= fontMetrics.height()) + context->drawText(font, textRun, IntPoint(ax, ay + ascent)); } } } else if (m_imageResource->hasImage() && cWidth > 0 && cHeight > 0) { - Image* img = m_imageResource->image(cWidth, cHeight); + RefPtr<Image> img = m_imageResource->image(cWidth, cHeight); if (!img || img->isNull()) return; @@ -333,60 +331,65 @@ void RenderImage::paint(PaintInfo& paintInfo, int tx, int ty) RenderReplaced::paint(paintInfo, tx, ty); if (paintInfo.phase == PaintPhaseOutline) - paintFocusRing(paintInfo, style()); + paintAreaElementFocusRing(paintInfo); } -void RenderImage::paintFocusRing(PaintInfo& paintInfo, const RenderStyle*) +void RenderImage::paintAreaElementFocusRing(PaintInfo& paintInfo) { - // Don't draw focus rings if printing. - if (document()->printing() || !frame()->selection()->isFocusedAndActive()) + Document* document = this->document(); + + if (document->printing() || !document->frame()->selection()->isFocusedAndActive()) return; if (paintInfo.context->paintingDisabled() && !paintInfo.context->updatingControlTints()) return; - HTMLMapElement* mapElement = imageMap(); - if (!mapElement) + Node* focusedNode = document->focusedNode(); + if (!focusedNode || !focusedNode->hasTagName(areaTag)) return; - - Document* document = mapElement->document(); - if (!document) + + HTMLAreaElement* areaElement = static_cast<HTMLAreaElement*>(focusedNode); + if (areaElement->imageElement() != node()) return; - - Node* focusedNode = document->focusedNode(); - if (!focusedNode) + + // Even if the theme handles focus ring drawing for entire elements, it won't do it for + // an area within an image, so we don't call RenderTheme::supportsFocusRing here. + + Path path = areaElement->computePath(this); + if (path.isEmpty()) return; - - RefPtr<HTMLCollection> areas = mapElement->areas(); - unsigned numAreas = areas->length(); - - // FIXME: Clip the paths to the image bounding box. - for (unsigned k = 0; k < numAreas; ++k) { - HTMLAreaElement* areaElement = static_cast<HTMLAreaElement*>(areas->item(k)); - if (focusedNode != areaElement) - continue; - - RenderStyle* styleToUse = areaElement->computedStyle(); - if (theme()->supportsFocusRing(styleToUse)) - return; // The theme draws the focus ring. - paintInfo.context->drawFocusRing(areaElement->getPath(this), styleToUse->outlineWidth(), styleToUse->outlineOffset(), styleToUse->visitedDependentColor(CSSPropertyOutlineColor)); - break; - } + + // FIXME: Do we need additional code to clip the path to the image's bounding box? + + RenderStyle* areaElementStyle = areaElement->computedStyle(); + paintInfo.context->drawFocusRing(path, areaElementStyle->outlineWidth(), areaElementStyle->outlineOffset(), + areaElementStyle->visitedDependentColor(CSSPropertyOutlineColor)); } - + +void RenderImage::areaElementFocusChanged(HTMLAreaElement* element) +{ + ASSERT_UNUSED(element, element->imageElement() == node()); + + // It would be more efficient to only repaint the focus ring rectangle + // for the passed-in area element. That would require adding functions + // to the area element class. + repaint(); +} + void RenderImage::paintIntoRect(GraphicsContext* context, const IntRect& rect) { if (!m_imageResource->hasImage() || m_imageResource->errorOccurred() || rect.width() <= 0 || rect.height() <= 0) return; - Image* img = m_imageResource->image(rect.width(), rect.height()); + RefPtr<Image> img = m_imageResource->image(rect.width(), rect.height()); if (!img || img->isNull()) return; HTMLImageElement* imageElt = (node() && node()->hasTagName(imgTag)) ? static_cast<HTMLImageElement*>(node()) : 0; CompositeOperator compositeOperator = imageElt ? imageElt->compositeOperator() : CompositeSourceOver; - bool useLowQualityScaling = shouldPaintAtLowQuality(context, m_imageResource->image(), 0, rect.size()); - context->drawImage(m_imageResource->image(rect.width(), rect.height()), style()->colorSpace(), rect, compositeOperator, useLowQualityScaling); + Image* image = m_imageResource->image().get(); + bool useLowQualityScaling = shouldPaintAtLowQuality(context, image, image, rect.size()); + context->drawImage(m_imageResource->image(rect.width(), rect.height()).get(), style()->colorSpace(), rect, compositeOperator, useLowQualityScaling); } int RenderImage::minimumReplacedHeight() const diff --git a/Source/WebCore/rendering/RenderImage.h b/Source/WebCore/rendering/RenderImage.h index 16ae7ec..e3f743c 100644 --- a/Source/WebCore/rendering/RenderImage.h +++ b/Source/WebCore/rendering/RenderImage.h @@ -3,7 +3,7 @@ * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2006 Allan Sandfeld Jensen (kde@carewolf.com) * (C) 2006 Samuel Weinig (sam.weinig@gmail.com) - * Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010, 2011 Apple 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 @@ -30,6 +30,7 @@ namespace WebCore { +class HTMLAreaElement; class HTMLMapElement; class RenderImage : public RenderReplaced { @@ -48,6 +49,7 @@ public: void updateAltText(); HTMLMapElement* imageMap() const; + void areaElementFocusChanged(HTMLAreaElement*); void highQualityRepaintTimerFired(Timer<RenderImage>*); @@ -57,7 +59,6 @@ protected: virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); virtual void paintIntoRect(GraphicsContext*, const IntRect&); - void paintFocusRing(PaintInfo&, const RenderStyle*); virtual void paint(PaintInfo&, int tx, int ty); bool isLogicalWidthSpecified() const; @@ -91,6 +92,8 @@ private: int calcAspectRatioLogicalWidth() const; int calcAspectRatioLogicalHeight() const; + void paintAreaElementFocusRing(PaintInfo&); + // Text to display as long as the image isn't available. String m_altText; OwnPtr<RenderImageResource> m_imageResource; diff --git a/Source/WebCore/rendering/RenderImageResource.h b/Source/WebCore/rendering/RenderImageResource.h index a20c55a..f1ec75b 100644 --- a/Source/WebCore/rendering/RenderImageResource.h +++ b/Source/WebCore/rendering/RenderImageResource.h @@ -28,6 +28,7 @@ #include "CachedImage.h" #include "CachedResourceHandle.h" +#include "Image.h" #include "StyleImage.h" namespace WebCore { @@ -53,7 +54,7 @@ public: void resetAnimation(); - virtual Image* image(int /* width */ = 0, int /* height */ = 0) { return m_cachedImage ? m_cachedImage->image() : nullImage(); } + virtual PassRefPtr<Image> image(int /* width */ = 0, int /* height */ = 0) const { return m_cachedImage ? m_cachedImage->image() : nullImage(); } virtual bool errorOccurred() const { return m_cachedImage && m_cachedImage->errorOccurred(); } virtual void setImageContainerSize(const IntSize& size) const; diff --git a/Source/WebCore/rendering/RenderImageResourceStyleImage.h b/Source/WebCore/rendering/RenderImageResourceStyleImage.h index d91aaa8..278a82c 100644 --- a/Source/WebCore/rendering/RenderImageResourceStyleImage.h +++ b/Source/WebCore/rendering/RenderImageResourceStyleImage.h @@ -46,7 +46,7 @@ public: virtual void shutdown(); virtual bool hasImage() const { return true; } - virtual Image* image(int width = 0, int height = 0) { return m_styleImage->image(m_renderer, IntSize(width, height)); } + virtual PassRefPtr<Image> image(int width = 0, int height = 0) const { return m_styleImage->image(m_renderer, IntSize(width, height)); } virtual bool errorOccurred() const { return m_styleImage->errorOccurred(); } virtual void setImageContainerSize(const IntSize& size) const { m_styleImage->setImageContainerSize(size); } diff --git a/Source/WebCore/rendering/RenderIndicator.cpp b/Source/WebCore/rendering/RenderIndicator.cpp index b03dfba..8f34a40 100644 --- a/Source/WebCore/rendering/RenderIndicator.cpp +++ b/Source/WebCore/rendering/RenderIndicator.cpp @@ -25,12 +25,51 @@ #include "RenderIndicator.h" #include "RenderTheme.h" -#include "ShadowElement.h" +#include "RenderView.h" using namespace std; namespace WebCore { +RenderIndicatorPart::RenderIndicatorPart(Node* node) + : RenderBlock(node) + , m_originalVisibility(HIDDEN) +{ +} + +RenderIndicatorPart::~RenderIndicatorPart() +{ +} + +void RenderIndicatorPart::layout() +{ + RenderBox* parentRenderer = toRenderBox(parent()); + IntRect oldRect = frameRect(); + IntRect newRect = preferredFrameRect(); + + LayoutStateMaintainer statePusher(parentRenderer->view(), parentRenderer, parentRenderer->size(), parentRenderer->style()->isFlippedBlocksWritingMode()); + + if (oldRect.size() != newRect.size()) + setChildNeedsLayout(true, false); + if (needsLayout()) + RenderBlock::layout(); + setFrameRect(newRect); + + if (checkForRepaintDuringLayout()) + repaintDuringLayoutIfMoved(oldRect); + + statePusher.pop(); + parentRenderer->addOverflowFromChild(this); + style()->setVisibility(shouldBeHidden() ? HIDDEN : originalVisibility()); +} + +void RenderIndicatorPart::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) +{ + m_originalVisibility = style()->visibility(); + RenderBlock::styleDidChange(diff, oldStyle); +} + + RenderIndicator::RenderIndicator(Node* node) : RenderBlock(node) { diff --git a/Source/WebCore/rendering/RenderIndicator.h b/Source/WebCore/rendering/RenderIndicator.h index 50d819d..7c2a346 100644 --- a/Source/WebCore/rendering/RenderIndicator.h +++ b/Source/WebCore/rendering/RenderIndicator.h @@ -26,6 +26,24 @@ namespace WebCore { +class RenderIndicatorPart : public RenderBlock { +public: + RenderIndicatorPart(Node*); + virtual ~RenderIndicatorPart(); + +protected: + EVisibility originalVisibility() const { return m_originalVisibility; } + virtual IntRect preferredFrameRect() = 0; + virtual bool shouldBeHidden() = 0; +private: + virtual void layout(); + virtual bool requiresForcedStyleRecalcPropagation() const { return true; } + virtual bool canHaveChildren() const { return false; } + virtual void styleDidChange(StyleDifference, const RenderStyle*); + + EVisibility m_originalVisibility; +}; + class RenderIndicator : public RenderBlock { public: RenderIndicator(Node*); diff --git a/Source/WebCore/rendering/RenderInline.cpp b/Source/WebCore/rendering/RenderInline.cpp index 7466ace..3768774 100644 --- a/Source/WebCore/rendering/RenderInline.cpp +++ b/Source/WebCore/rendering/RenderInline.cpp @@ -595,10 +595,10 @@ IntRect RenderInline::linesVisualOverflowBoundingBox() const bool isHorizontal = style()->isHorizontalWritingMode(); - int x = isHorizontal ? logicalLeftSide : firstLineBox()->leftVisualOverflow(); - int y = isHorizontal ? firstLineBox()->topVisualOverflow() : logicalLeftSide; - int width = isHorizontal ? logicalRightSide - logicalLeftSide : lastLineBox()->rightVisualOverflow() - firstLineBox()->leftVisualOverflow(); - int height = isHorizontal ? lastLineBox()->bottomVisualOverflow() - firstLineBox()->topVisualOverflow() : logicalRightSide - logicalLeftSide; + 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); } @@ -749,7 +749,7 @@ void RenderInline::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntSize RenderInline::offsetFromContainer(RenderObject* container, const IntPoint& point) const { ASSERT(container == this->container()); - + IntSize offset; if (isRelPositioned()) offset += relativePositionOffset(); @@ -783,6 +783,10 @@ void RenderInline::mapLocalToContainer(RenderBoxModelObject* repaintContainer, b if (!o) return; + IntPoint centerPoint = roundedIntPoint(transformState.mappedPoint()); + if (o->isBox() && o->style()->isFlippedBlocksWritingMode()) + transformState.move(toRenderBox(o)->flipForWritingModeIncludingColumns(roundedIntPoint(transformState.mappedPoint())) - centerPoint); + IntSize containerOffset = offsetFromContainer(o, roundedIntPoint(transformState.mappedPoint())); bool preserve3D = useTransforms && (o->style()->preserves3D() || style()->preserves3D()); @@ -905,8 +909,8 @@ int RenderInline::lineHeight(bool firstLine, LineDirectionMode /*direction*/, Li int RenderInline::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const { - const Font& f = style(firstLine)->font(); - return f.ascent(baselineType) + (lineHeight(firstLine, direction, linePositionMode) - f.height()) / 2; + const FontMetrics& fontMetrics = style(firstLine)->fontMetrics(); + return fontMetrics.ascent(baselineType) + (lineHeight(firstLine, direction, linePositionMode) - fontMetrics.height()) / 2; } IntSize RenderInline::relativePositionedInlineOffset(const RenderBox* child) const @@ -1033,30 +1037,30 @@ void RenderInline::paintOutlineForLine(GraphicsContext* graphicsContext, int tx, int t = ty + thisline.y() - offset; int l = tx + thisline.x() - offset; - int b = ty + thisline.bottom() + offset; - int r = tx + thisline.right() + offset; + int b = ty + thisline.maxY() + offset; + int r = tx + thisline.maxX() + offset; // left edge drawLineForBoxSide(graphicsContext, l - ow, - t - (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.right() - 1) <= thisline.x() ? ow : 0), + t - (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.maxX() - 1) <= thisline.x() ? ow : 0), l, - b + (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.right() - 1) <= thisline.x() ? ow : 0), + b + (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.maxX() - 1) <= thisline.x() ? ow : 0), BSLeft, oc, os, - (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.right() - 1) <= thisline.x() ? ow : -ow), - (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.right() - 1) <= thisline.x() ? ow : -ow)); + (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.maxX() - 1) <= thisline.x() ? ow : -ow), + (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.maxX() - 1) <= thisline.x() ? ow : -ow)); // right edge drawLineForBoxSide(graphicsContext, r, - t - (lastline.isEmpty() || lastline.right() < thisline.right() || (thisline.right() - 1) <= lastline.x() ? ow : 0), + t - (lastline.isEmpty() || lastline.maxX() < thisline.maxX() || (thisline.maxX() - 1) <= lastline.x() ? ow : 0), r + ow, - b + (nextline.isEmpty() || nextline.right() <= thisline.right() || (thisline.right() - 1) <= nextline.x() ? ow : 0), + b + (nextline.isEmpty() || nextline.maxX() <= thisline.maxX() || (thisline.maxX() - 1) <= nextline.x() ? ow : 0), BSRight, oc, os, - (lastline.isEmpty() || lastline.right() < thisline.right() || (thisline.right() - 1) <= lastline.x() ? ow : -ow), - (nextline.isEmpty() || nextline.right() <= thisline.right() || (thisline.right() - 1) <= nextline.x() ? ow : -ow)); + (lastline.isEmpty() || lastline.maxX() < thisline.maxX() || (thisline.maxX() - 1) <= lastline.x() ? ow : -ow), + (nextline.isEmpty() || nextline.maxX() <= thisline.maxX() || (thisline.maxX() - 1) <= nextline.x() ? ow : -ow)); // upper edge if (thisline.x() < lastline.x()) drawLineForBoxSide(graphicsContext, @@ -1068,14 +1072,14 @@ void RenderInline::paintOutlineForLine(GraphicsContext* graphicsContext, int tx, ow, (!lastline.isEmpty() && tx + lastline.x() + 1 < r + ow) ? -ow : ow); - if (lastline.right() < thisline.right()) + if (lastline.maxX() < thisline.maxX()) drawLineForBoxSide(graphicsContext, - max(lastline.isEmpty() ? -1000000 : tx + lastline.right(), l - ow), + max(lastline.isEmpty() ? -1000000 : tx + lastline.maxX(), l - ow), t - ow, r + ow, t , BSTop, oc, os, - (!lastline.isEmpty() && l - ow < tx + lastline.right()) ? -ow : ow, + (!lastline.isEmpty() && l - ow < tx + lastline.maxX()) ? -ow : ow, ow); // lower edge @@ -1089,14 +1093,14 @@ void RenderInline::paintOutlineForLine(GraphicsContext* graphicsContext, int tx, ow, (!nextline.isEmpty() && tx + nextline.x() + 1 < r + ow) ? -ow : ow); - if (nextline.right() < thisline.right()) + if (nextline.maxX() < thisline.maxX()) drawLineForBoxSide(graphicsContext, - max(!nextline.isEmpty() ? tx + nextline.right() : -1000000, l - ow), + max(!nextline.isEmpty() ? tx + nextline.maxX() : -1000000, l - ow), b, r + ow, b + ow, BSBottom, oc, os, - (!nextline.isEmpty() && l - ow < tx + nextline.right()) ? -ow : ow, + (!nextline.isEmpty() && l - ow < tx + nextline.maxX()) ? -ow : ow, ow); } diff --git a/Source/WebCore/rendering/RenderLayer.cpp b/Source/WebCore/rendering/RenderLayer.cpp index 29a6fc9..e278c75 100644 --- a/Source/WebCore/rendering/RenderLayer.cpp +++ b/Source/WebCore/rendering/RenderLayer.cpp @@ -188,6 +188,8 @@ RenderLayer::RenderLayer(RenderBoxModelObject* renderer) , m_scrollCorner(0) , m_resizer(0) { + ScrollableArea::setConstrainsScrollingToContentEdge(false); + if (!renderer->firstChild() && renderer->style()) { m_visibleContentStatusDirty = false; m_hasVisibleContent = renderer->style()->visibility() == VISIBLE; @@ -960,7 +962,7 @@ static IntRect transparencyClipBox(const RenderLayer* l, const RenderLayer* root TransformationMatrix transform; transform.translate(x, y); - transform = *l->transform() * transform; + transform = transform * *l->transform(); IntRect clipRect = l->boundingBox(l); expandClipRectForDescendantsAndReflection(clipRect, l, l, paintBehavior); @@ -1532,7 +1534,7 @@ IntRect RenderLayer::getRectToExpose(const IntRect &visibleRect, const IntRect & scrollX = ScrollAlignment::getHiddenBehavior(alignX); // If we're trying to align to the closest edge, and the exposeRect is further right // than the visibleRect, and not bigger than the visible area, then align with the right. - if (scrollX == alignToClosestEdge && exposeRect.right() > visibleRect.right() && exposeRect.width() < visibleRect.width()) + if (scrollX == alignToClosestEdge && exposeRect.maxX() > visibleRect.maxX() && exposeRect.width() < visibleRect.width()) scrollX = alignRight; // Given the X behavior, compute the X coordinate. @@ -1540,7 +1542,7 @@ IntRect RenderLayer::getRectToExpose(const IntRect &visibleRect, const IntRect & if (scrollX == noScroll) x = visibleRect.x(); else if (scrollX == alignRight) - x = exposeRect.right() - visibleRect.width(); + x = exposeRect.maxX() - visibleRect.width(); else if (scrollX == alignCenter) x = exposeRect.x() + (exposeRect.width() - visibleRect.width()) / 2; else @@ -1565,7 +1567,7 @@ IntRect RenderLayer::getRectToExpose(const IntRect &visibleRect, const IntRect & scrollY = ScrollAlignment::getHiddenBehavior(alignY); // If we're trying to align to the closest edge, and the exposeRect is further down // than the visibleRect, and not bigger than the visible area, then align with the bottom. - if (scrollY == alignToClosestEdge && exposeRect.bottom() > visibleRect.bottom() && exposeRect.height() < visibleRect.height()) + if (scrollY == alignToClosestEdge && exposeRect.maxY() > visibleRect.maxY() && exposeRect.height() < visibleRect.height()) scrollY = alignBottom; // Given the Y behavior, compute the Y coordinate. @@ -1573,7 +1575,7 @@ IntRect RenderLayer::getRectToExpose(const IntRect &visibleRect, const IntRect & if (scrollY == noScroll) y = visibleRect.y(); else if (scrollY == alignBottom) - y = exposeRect.bottom() - visibleRect.height(); + y = exposeRect.maxY() - visibleRect.height(); else if (scrollY == alignCenter) y = exposeRect.y() + (exposeRect.height() - visibleRect.height()) / 2; else @@ -1681,7 +1683,7 @@ int RenderLayer::scrollPosition(Scrollbar* scrollbar) const if (scrollbar->orientation() == HorizontalScrollbar) return scrollXOffset(); if (scrollbar->orientation() == VerticalScrollbar) - return m_scrollY; + return scrollYOffset(); return 0; } @@ -1710,8 +1712,8 @@ static IntRect cornerRect(const RenderLayer* layer, const IntRect& bounds) horizontalThickness = layer->verticalScrollbar()->width(); verticalThickness = layer->horizontalScrollbar()->height(); } - return IntRect(bounds.right() - horizontalThickness - layer->renderer()->style()->borderRightWidth(), - bounds.bottom() - verticalThickness - layer->renderer()->style()->borderBottomWidth(), + return IntRect(bounds.maxX() - horizontalThickness - layer->renderer()->style()->borderRightWidth(), + bounds.maxY() - verticalThickness - layer->renderer()->style()->borderBottomWidth(), horizontalThickness, verticalThickness); } @@ -1789,6 +1791,21 @@ IntPoint RenderLayer::convertFromContainingViewToScrollbar(const Scrollbar* scro return point; } +IntSize RenderLayer::contentsSize() const +{ + return IntSize(const_cast<RenderLayer*>(this)->scrollWidth(), const_cast<RenderLayer*>(this)->scrollHeight()); +} + +int RenderLayer::visibleHeight() const +{ + return m_height; +} + +int RenderLayer::visibleWidth() const +{ + return m_width; +} + IntSize RenderLayer::scrollbarOffset(const Scrollbar* scrollbar) const { RenderBox* box = renderBox(); @@ -1846,10 +1863,13 @@ void RenderLayer::setHasHorizontalScrollbar(bool hasScrollbar) if (hasScrollbar == (m_hBar != 0)) return; - if (hasScrollbar) + if (hasScrollbar) { m_hBar = createScrollbar(HorizontalScrollbar); - else + ScrollableArea::didAddHorizontalScrollbar(m_hBar.get()); + } else { + ScrollableArea::willRemoveHorizontalScrollbar(m_hBar.get()); 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) @@ -1869,10 +1889,13 @@ void RenderLayer::setHasVerticalScrollbar(bool hasScrollbar) if (hasScrollbar == (m_vBar != 0)) return; - if (hasScrollbar) + if (hasScrollbar) { m_vBar = createScrollbar(VerticalScrollbar); - else + ScrollableArea::didAddVerticalScrollbar(m_vBar.get()); + } else { + ScrollableArea::willRemoveVerticalScrollbar(m_vBar.get()); 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) @@ -1936,14 +1959,14 @@ void RenderLayer::positionOverflowControls(int tx, int ty) IntRect scrollCorner(scrollCornerRect(this, borderBox)); IntRect absBounds(borderBox.x() + tx, borderBox.y() + ty, borderBox.width(), borderBox.height()); if (m_vBar) - m_vBar->setFrameRect(IntRect(absBounds.right() - box->borderRight() - m_vBar->width(), + m_vBar->setFrameRect(IntRect(absBounds.maxX() - box->borderRight() - m_vBar->width(), absBounds.y() + box->borderTop(), m_vBar->width(), absBounds.height() - (box->borderTop() + box->borderBottom()) - scrollCorner.height())); if (m_hBar) m_hBar->setFrameRect(IntRect(absBounds.x() + box->borderLeft(), - absBounds.bottom() - box->borderBottom() - m_hBar->height(), + absBounds.maxY() - box->borderBottom() - m_hBar->height(), absBounds.width() - (box->borderLeft() + box->borderRight()) - scrollCorner.width(), m_hBar->height())); @@ -2000,7 +2023,7 @@ int RenderLayer::overflowBottom() const RenderBox* box = renderBox(); IntRect overflowRect(box->layoutOverflowRect()); box->flipForWritingMode(overflowRect); - return overflowRect.bottom(); + return overflowRect.maxY(); } int RenderLayer::overflowLeft() const @@ -2016,7 +2039,7 @@ int RenderLayer::overflowRight() const RenderBox* box = renderBox(); IntRect overflowRect(box->layoutOverflowRect()); box->flipForWritingMode(overflowRect); - return overflowRect.right(); + return overflowRect.maxX(); } void RenderLayer::computeScrollDimensions(bool* needHBar, bool* needVBar) @@ -2078,8 +2101,8 @@ void RenderLayer::updateScrollInfoAfterLayout() // Layout may cause us to be in an invalid scroll position. In this case we need // to pull our scroll offsets back to the max (or push them up to the min). int newX = max(0, min(scrollXOffset(), scrollWidth() - box->clientWidth())); - int newY = max(0, min(m_scrollY, scrollHeight() - box->clientHeight())); - if (newX != scrollXOffset() || newY != m_scrollY) { + int newY = max(0, min(scrollYOffset(), scrollHeight() - box->clientHeight())); + if (newX != scrollXOffset() || newY != scrollYOffset()) { RenderView* view = renderer()->view(); ASSERT(view); // scrollToOffset() may call updateLayerPositions(), which doesn't work @@ -2163,7 +2186,10 @@ void RenderLayer::updateScrollInfoAfterLayout() m_vBar->setProportion(clientHeight, m_scrollHeight); } + RenderView* view = renderer()->view(); + view->disableLayoutState(); scrollToOffset(scrollXOffset(), scrollYOffset()); + view->enableLayoutState(); if (renderer()->node() && renderer()->document()->hasListenerType(Document::OVERFLOWCHANGED_LISTENER)) updateOverflowStatus(horizontalOverflow, verticalOverflow); @@ -2256,7 +2282,7 @@ void RenderLayer::paintResizer(GraphicsContext* context, int tx, int ty, const I // Paint the resizer control. DEFINE_STATIC_LOCAL(RefPtr<Image>, resizeCornerImage, (Image::loadPlatformResource("textAreaResizeCorner"))); - IntPoint imagePoint(absRect.right() - resizeCornerImage->width(), absRect.bottom() - resizeCornerImage->height()); + IntPoint imagePoint(absRect.maxX() - resizeCornerImage->width(), absRect.maxY() - resizeCornerImage->height()); context->drawImage(resizeCornerImage.get(), box->style()->colorSpace(), imagePoint); // Draw a frame around the resizer (1px grey line) if there are any scrollbars present. @@ -2634,13 +2660,18 @@ void RenderLayer::paintChildLayerIntoColumns(RenderLayer* childLayer, RenderLaye int layerY = 0; columnBlock->layer()->convertToLayerCoords(rootLayer, layerX, layerY); + bool isHorizontal = columnBlock->style()->isHorizontalWritingMode(); + ColumnInfo* colInfo = columnBlock->columnInfo(); unsigned colCount = columnBlock->columnCount(colInfo); - int currYOffset = 0; + int currLogicalTopOffset = 0; for (unsigned i = 0; i < colCount; i++) { // For each rect, we clip to the rect, and then we adjust our coords. IntRect colRect = columnBlock->columnRectAt(colInfo, i); - int currXOffset = colRect.x() - (columnBlock->borderLeft() + columnBlock->paddingLeft()); + columnBlock->flipForWritingMode(colRect); + int logicalLeftOffset = (isHorizontal ? colRect.x() : colRect.y()) - columnBlock->logicalLeftOffsetForContent(); + IntSize offset = isHorizontal ? IntSize(logicalLeftOffset, currLogicalTopOffset) : IntSize(currLogicalTopOffset, logicalLeftOffset); + colRect.move(layerX, layerY); IntRect localDirtyRect(paintDirtyRect); @@ -2660,7 +2691,7 @@ void RenderLayer::paintChildLayerIntoColumns(RenderLayer* childLayer, RenderLaye if (oldHasTransform) oldTransform = *childLayer->transform(); TransformationMatrix newTransform(oldTransform); - newTransform.translateRight(currXOffset, currYOffset); + newTransform.translateRight(offset.width(), offset.height()); childLayer->m_transform.set(new TransformationMatrix(newTransform)); childLayer->paintLayer(rootLayer, context, localDirtyRect, paintBehavior, paintingRoot, overlapTestRequests, paintFlags); @@ -2675,7 +2706,7 @@ void RenderLayer::paintChildLayerIntoColumns(RenderLayer* childLayer, RenderLaye int childY = 0; columnLayers[colIndex - 1]->convertToLayerCoords(rootLayer, childX, childY); TransformationMatrix transform; - transform.translateRight(childX + currXOffset, childY + currYOffset); + transform.translateRight(childX + offset.width(), childY + offset.height()); // Apply the transform. context->concatCTM(transform.toAffineTransform()); @@ -2690,7 +2721,11 @@ void RenderLayer::paintChildLayerIntoColumns(RenderLayer* childLayer, RenderLaye } // Move to the next position. - currYOffset -= colRect.height(); + int blockDelta = isHorizontal ? colRect.height() : colRect.width(); + if (columnBlock->style()->isFlippedBlocksWritingMode()) + currLogicalTopOffset += blockDelta; + else + currLogicalTopOffset -= blockDelta; } } @@ -3111,21 +3146,35 @@ RenderLayer* RenderLayer::hitTestChildLayerColumns(RenderLayer* childLayer, Rend int colCount = columnBlock->columnCount(colInfo); // We have to go backwards from the last column to the first. - int left = columnBlock->borderLeft() + columnBlock->paddingLeft(); - int currYOffset = 0; + bool isHorizontal = columnBlock->style()->isHorizontalWritingMode(); + int logicalLeft = columnBlock->logicalLeftOffsetForContent(); + int currLogicalTopOffset = 0; int i; - for (i = 0; i < colCount; i++) - currYOffset -= columnBlock->columnRectAt(colInfo, i).height(); + for (i = 0; i < colCount; i++) { + IntRect colRect = columnBlock->columnRectAt(colInfo, i); + int blockDelta = (isHorizontal ? colRect.height() : colRect.width()); + if (columnBlock->style()->isFlippedBlocksWritingMode()) + currLogicalTopOffset += blockDelta; + else + currLogicalTopOffset -= blockDelta; + } for (i = colCount - 1; i >= 0; i--) { // For each rect, we clip to the rect, and then we adjust our coords. IntRect colRect = columnBlock->columnRectAt(colInfo, i); - int currXOffset = colRect.x() - left; - currYOffset += colRect.height(); + columnBlock->flipForWritingMode(colRect); + int currLogicalLeftOffset = (isHorizontal ? colRect.x() : colRect.y()) - logicalLeft; + int blockDelta = (isHorizontal ? colRect.height() : colRect.width()); + if (columnBlock->style()->isFlippedBlocksWritingMode()) + currLogicalTopOffset -= blockDelta; + else + currLogicalTopOffset += blockDelta; colRect.move(layerX, layerY); IntRect localClipRect(hitTestRect); localClipRect.intersect(colRect); + IntSize offset = isHorizontal ? IntSize(currLogicalLeftOffset, currLogicalTopOffset) : IntSize(currLogicalTopOffset, currLogicalLeftOffset); + if (!localClipRect.isEmpty() && localClipRect.intersects(result.rectForPoint(hitTestPoint))) { RenderLayer* hitLayer = 0; if (!columnIndex) { @@ -3135,7 +3184,7 @@ RenderLayer* RenderLayer::hitTestChildLayerColumns(RenderLayer* childLayer, Rend if (oldHasTransform) oldTransform = *childLayer->transform(); TransformationMatrix newTransform(oldTransform); - newTransform.translateRight(currXOffset, currYOffset); + newTransform.translateRight(offset.width(), offset.height()); childLayer->m_transform.set(new TransformationMatrix(newTransform)); hitLayer = childLayer->hitTestLayer(rootLayer, columnLayers[0], request, result, localClipRect, hitTestPoint, false, transformState, zOffset); @@ -3148,7 +3197,7 @@ RenderLayer* RenderLayer::hitTestChildLayerColumns(RenderLayer* childLayer, Rend // This involves subtracting out the position of the layer in our current coordinate space. RenderLayer* nextLayer = columnLayers[columnIndex - 1]; RefPtr<HitTestingTransformState> newTransformState = nextLayer->createLocalTransformState(rootLayer, nextLayer, localClipRect, hitTestPoint, transformState); - newTransformState->translate(currXOffset, currYOffset, HitTestingTransformState::AccumulateTransform); + newTransformState->translate(offset.width(), offset.height(), HitTestingTransformState::AccumulateTransform); IntPoint localPoint = roundedIntPoint(newTransformState->mappedPoint()); IntRect localHitTestRect = newTransformState->mappedQuad().enclosingBoundingBox(); newTransformState->flatten(); @@ -3437,19 +3486,9 @@ IntRect RenderLayer::localBoundingBox() const // as part of our bounding box. We do this because we are the responsible layer for both hit testing and painting those // floats. IntRect result; - if (renderer()->isRenderInline()) { - // Go from our first line box to our last line box. - RenderInline* inlineFlow = toRenderInline(renderer()); - InlineFlowBox* firstBox = inlineFlow->firstLineBox(); - if (!firstBox) - return result; - int top = firstBox->topVisualOverflow(); - int bottom = inlineFlow->lastLineBox()->bottomVisualOverflow(); - int left = firstBox->x(); - for (InlineFlowBox* curr = firstBox->nextLineBox(); curr; curr = curr->nextLineBox()) - left = min(left, curr->x()); - result = IntRect(left, top, width(), bottom - top); - } else if (renderer()->isTableRow()) { + if (renderer()->isRenderInline()) + result = toRenderInline(renderer())->linesVisualOverflowBoundingBox(); + else if (renderer()->isTableRow()) { // Our bounding box is just the union of all of our cells' border/overflow rects. for (RenderObject* child = renderer()->firstChild(); child; child = child->nextSibling()) { if (child->isTableCell()) { @@ -3485,7 +3524,10 @@ IntRect RenderLayer::localBoundingBox() const IntRect RenderLayer::boundingBox(const RenderLayer* ancestorLayer) const { IntRect result = localBoundingBox(); - + if (renderer()->isBox()) + renderBox()->flipForWritingMode(result); + else + renderer()->containingBlock()->flipForWritingMode(result); int deltaX = 0, deltaY = 0; convertToLayerCoords(ancestorLayer, deltaX, deltaY); result.move(deltaX, deltaY); @@ -3538,6 +3580,26 @@ 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 57cb4de..66281ce 100644 --- a/Source/WebCore/rendering/RenderLayer.h +++ b/Source/WebCore/rendering/RenderLayer.h @@ -483,6 +483,7 @@ public: bool isComposited() const { return false; } bool hasCompositedMask() const { return false; } #endif + virtual bool scrollbarWillRenderIntoCompositingLayer() const; bool paintsWithTransparency(PaintBehavior paintBehavior) const { @@ -495,7 +496,6 @@ private: // The normal operator new is disallowed on all render objects. void* operator new(size_t) throw(); -private: void setNextSibling(RenderLayer* next) { m_next = next; } void setPreviousSibling(RenderLayer* prev) { m_previous = prev; } void setParent(RenderLayer* parent); @@ -571,6 +571,9 @@ private: virtual IntRect convertFromContainingViewToScrollbar(const Scrollbar*, const IntRect&) const; virtual IntPoint convertFromScrollbarToContainingView(const Scrollbar*, const IntPoint&) const; virtual IntPoint convertFromContainingViewToScrollbar(const Scrollbar*, const IntPoint&) const; + virtual IntSize contentsSize() const; + virtual int visibleHeight() const; + virtual int visibleWidth() const; // NOTE: This should only be called by the overriden setScrollOffset from ScrollableArea. void scrollTo(int x, int y); @@ -624,7 +627,6 @@ private: void updateContentsScale(float); -private: friend class RenderLayerBacking; friend class RenderLayerCompositor; friend class RenderBoxModelObject; diff --git a/Source/WebCore/rendering/RenderLayerBacking.cpp b/Source/WebCore/rendering/RenderLayerBacking.cpp index 8001c42..d0a36c7 100644 --- a/Source/WebCore/rendering/RenderLayerBacking.cpp +++ b/Source/WebCore/rendering/RenderLayerBacking.cpp @@ -70,7 +70,7 @@ static IntRect clipBox(RenderBox* renderer); static inline bool isAcceleratedCanvas(RenderObject* renderer) { -#if ENABLE(3D_CANVAS) || ENABLE(ACCELERATED_2D_CANVAS) +#if ENABLE(WEBGL) || ENABLE(ACCELERATED_2D_CANVAS) if (renderer->isCanvas()) { HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(renderer->node()); if (CanvasRenderingContext* context = canvas->renderingContext()) @@ -287,7 +287,7 @@ bool RenderLayerBacking::updateGraphicsLayerConfiguration() m_graphicsLayer->setContentsToMedia(mediaElement->platformLayer()); } #endif -#if ENABLE(3D_CANVAS) || ENABLE(ACCELERATED_2D_CANVAS) +#if ENABLE(WEBGL) || ENABLE(ACCELERATED_2D_CANVAS) else if (isAcceleratedCanvas(renderer)) { HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(renderer->node()); if (CanvasRenderingContext* context = canvas->renderingContext()) @@ -803,7 +803,7 @@ bool RenderLayerBacking::containsPaintedContent() const return hasBoxDecorationsOrBackground(renderer()); #endif #if PLATFORM(MAC) && PLATFORM(CA) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) -#elif ENABLE(3D_CANVAS) || ENABLE(ACCELERATED_2D_CANVAS) +#elif ENABLE(WEBGL) || ENABLE(ACCELERATED_2D_CANVAS) if (isAcceleratedCanvas(renderer())) return hasBoxDecorationsOrBackground(renderer()); #endif @@ -843,7 +843,7 @@ void RenderLayerBacking::contentChanged(RenderLayer::ContentChangeType changeTyp updateAfterLayout(CompositingChildren, isUpdateRoot); } -#if ENABLE(3D_CANVAS) || ENABLE(ACCELERATED_2D_CANVAS) +#if ENABLE(WEBGL) || ENABLE(ACCELERATED_2D_CANVAS) if ((changeType == RenderLayer::CanvasChanged) && isAcceleratedCanvas(renderer())) { m_graphicsLayer->setContentsNeedsDisplay(); return; diff --git a/Source/WebCore/rendering/RenderLayerCompositor.cpp b/Source/WebCore/rendering/RenderLayerCompositor.cpp index 9a5dda7..f9c0f32 100644 --- a/Source/WebCore/rendering/RenderLayerCompositor.cpp +++ b/Source/WebCore/rendering/RenderLayerCompositor.cpp @@ -1483,7 +1483,7 @@ void RenderLayerCompositor::ensureRootPlatformLayer() #ifndef NDEBUG m_rootPlatformLayer->setName("Root platform"); #endif - m_rootPlatformLayer->setSize(FloatSize(m_renderView->rightLayoutOverflow(), m_renderView->bottomLayoutOverflow())); + m_rootPlatformLayer->setSize(FloatSize(m_renderView->maxXLayoutOverflow(), m_renderView->maxYLayoutOverflow())); m_rootPlatformLayer->setPosition(FloatPoint()); // Need to clip to prevent transformed content showing outside this frame diff --git a/Source/WebCore/rendering/RenderLineBoxList.cpp b/Source/WebCore/rendering/RenderLineBoxList.cpp index 1488ecc..274905e 100644 --- a/Source/WebCore/rendering/RenderLineBoxList.cpp +++ b/Source/WebCore/rendering/RenderLineBoxList.cpp @@ -160,11 +160,11 @@ bool RenderLineBoxList::rangeIntersectsRect(RenderBoxModelObject* renderer, int if (renderer->style()->isHorizontalWritingMode()) { physicalStart += ty; - if (physicalStart >= rect.bottom() || physicalStart + physicalExtent <= rect.y()) + if (physicalStart >= rect.maxY() || physicalStart + physicalExtent <= rect.y()) return false; } else { physicalStart += tx; - if (physicalStart >= rect.right() || physicalStart + physicalExtent <= rect.x()) + if (physicalStart >= rect.maxX() || physicalStart + physicalExtent <= rect.x()) return false; } @@ -231,19 +231,19 @@ void RenderLineBoxList::paint(RenderBoxModelObject* renderer, PaintInfo& paintIn // FIXME: This is the deprecated pagination model that is still needed // for embedded views inside AppKit. AppKit is incapable of paginating vertical // text pages, so we don't have to deal with vertical lines at all here. - int topForPaginationCheck = curr->topVisualOverflow(); - int bottomForPaginationCheck = curr->bottomVisualOverflow(); + int topForPaginationCheck = curr->minYVisualOverflow(); + int bottomForPaginationCheck = curr->maxYVisualOverflow(); if (!curr->parent()) { // We're a root box. Use lineTop and lineBottom as well here. topForPaginationCheck = min(topForPaginationCheck, curr->root()->lineTop()); bottomForPaginationCheck = max(bottomForPaginationCheck, curr->root()->lineBottom()); } if (bottomForPaginationCheck - topForPaginationCheck <= v->printRect().height()) { - if (ty + bottomForPaginationCheck > v->printRect().bottom()) { + if (ty + bottomForPaginationCheck > v->printRect().maxY()) { if (RootInlineBox* nextRootBox = curr->root()->nextRootBox()) - bottomForPaginationCheck = min(bottomForPaginationCheck, min(nextRootBox->topVisualOverflow(), nextRootBox->lineTop())); + bottomForPaginationCheck = min(bottomForPaginationCheck, min(nextRootBox->minYVisualOverflow(), nextRootBox->lineTop())); } - if (ty + bottomForPaginationCheck > v->printRect().bottom()) { + if (ty + bottomForPaginationCheck > v->printRect().maxY()) { if (ty + topForPaginationCheck < v->truncatedAt()) v->setBestTruncatedAt(ty + topForPaginationCheck, renderer); // If we were able to truncate, don't paint. diff --git a/Source/WebCore/rendering/RenderListBox.cpp b/Source/WebCore/rendering/RenderListBox.cpp index 90f13da..13e8e58 100644 --- a/Source/WebCore/rendering/RenderListBox.cpp +++ b/Source/WebCore/rendering/RenderListBox.cpp @@ -1,7 +1,5 @@ /* - * This file is part of the select element renderer in WebCore. - * - * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2008, 2011 Apple Inc. All rights reserved. * 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) * * Redistribution and use in source and binary forms, with or without @@ -48,6 +46,7 @@ #include "OptionElement.h" #include "Page.h" #include "PaintInfo.h" +#include "RenderLayer.h" #include "RenderScrollbar.h" #include "RenderTheme.h" #include "RenderView.h" @@ -112,7 +111,7 @@ void RenderListBox::updateFromElement() } if (!text.isEmpty()) { - float textWidth = itemFont.floatWidth(TextRun(text.impl(), 0, 0, 0, false, false, false, false)); + float textWidth = itemFont.floatWidth(TextRun(text.impl(), false, 0, 0, TextRun::AllowTrailingExpansion, false, false, false, false)); width = max(width, textWidth); } } @@ -142,8 +141,11 @@ void RenderListBox::selectionChanged() void RenderListBox::layout() { RenderBlock::layout(); - if (m_scrollToRevealSelectionAfterLayout) + if (m_scrollToRevealSelectionAfterLayout) { + view()->disableLayoutState(); scrollToRevealSelection(); + view()->enableLayoutState(); + } } void RenderListBox::scrollToRevealSelection() @@ -303,7 +305,7 @@ void RenderListBox::paintItemForeground(PaintInfo& paintInfo, int tx, int ty, in // Determine where the item text should be placed IntRect r = itemBoundingBoxRect(tx, ty, listIndex); - r.move(optionsSpacingHorizontal, style()->font().ascent()); + r.move(optionsSpacingHorizontal, style()->fontMetrics().ascent()); RenderStyle* itemStyle = element->renderStyle(); if (!itemStyle) @@ -331,7 +333,7 @@ void RenderListBox::paintItemForeground(PaintInfo& paintInfo, int tx, int ty, in unsigned length = itemText.length(); const UChar* string = itemText.characters(); - TextRun textRun(string, length, 0, 0, 0, !itemStyle->isLeftToRightDirection(), itemStyle->unicodeBidi() == Override, false, false); + TextRun textRun(string, length, false, 0, 0, TextRun::AllowTrailingExpansion, !itemStyle->isLeftToRightDirection(), itemStyle->unicodeBidi() == Override, false, false); // Draw the item text if (itemStyle->visibility() != HIDDEN) @@ -550,7 +552,7 @@ void RenderListBox::scrollTo(int newOffset) int RenderListBox::itemHeight() const { - return style()->font().height() + rowSpacing; + return style()->fontMetrics().height() + rowSpacing; } int RenderListBox::verticalScrollbarWidth() const @@ -696,6 +698,37 @@ IntPoint RenderListBox::convertFromContainingViewToScrollbar(const Scrollbar* sc return point; } +IntSize RenderListBox::contentsSize() const +{ + return IntSize(scrollWidth(), scrollHeight()); +} + +int RenderListBox::visibleHeight() const +{ + return height(); +} + +int RenderListBox::visibleWidth() const +{ + return width(); +} + +IntPoint RenderListBox::currentMousePosition() const +{ + RenderView* view = this->view(); + if (!view) + return IntPoint(); + 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; @@ -723,10 +756,13 @@ void RenderListBox::setHasVerticalScrollbar(bool hasScrollbar) if (hasScrollbar == (m_vBar != 0)) return; - if (hasScrollbar) + if (hasScrollbar) { m_vBar = createScrollbar(); - else + ScrollableArea::didAddVerticalScrollbar(m_vBar.get()); + } else { + ScrollableArea::willRemoveVerticalScrollbar(m_vBar.get()); destroyScrollbar(); + } if (m_vBar) m_vBar->styleChanged(); diff --git a/Source/WebCore/rendering/RenderListBox.h b/Source/WebCore/rendering/RenderListBox.h index 1ba2b94..1eb2036 100644 --- a/Source/WebCore/rendering/RenderListBox.h +++ b/Source/WebCore/rendering/RenderListBox.h @@ -106,6 +106,11 @@ private: virtual IntPoint convertFromScrollbarToContainingView(const Scrollbar*, const IntPoint&) const; virtual IntPoint convertFromContainingViewToScrollbar(const Scrollbar*, const IntPoint&) const; virtual Scrollbar* verticalScrollbar() const { return m_vBar.get(); } + virtual IntSize contentsSize() const; + 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/RenderListItem.cpp b/Source/WebCore/rendering/RenderListItem.cpp index 65606f3..5cfb522 100644 --- a/Source/WebCore/rendering/RenderListItem.cpp +++ b/Source/WebCore/rendering/RenderListItem.cpp @@ -297,12 +297,12 @@ void RenderListItem::positionListMarker() for (InlineFlowBox* box = m_marker->inlineBoxWrapper()->parent(); box; box = box->parent()) { IntRect newLogicalVisualOverflowRect = box->logicalVisualOverflowRect(); IntRect newLogicalLayoutOverflowRect = box->logicalLayoutOverflowRect(); - if (markerLogicalLeft + m_marker->logicalWidth() > newLogicalVisualOverflowRect.right() && !hitSelfPaintingLayer) { + if (markerLogicalLeft + m_marker->logicalWidth() > newLogicalVisualOverflowRect.maxX() && !hitSelfPaintingLayer) { newLogicalVisualOverflowRect.setWidth(markerLogicalLeft + m_marker->logicalWidth() - box->logicalLeftVisualOverflow()); if (box == root) adjustOverflow = true; } - if (markerLogicalLeft + m_marker->logicalWidth() > newLogicalLayoutOverflowRect.right()) { + if (markerLogicalLeft + m_marker->logicalWidth() > newLogicalLayoutOverflowRect.maxX()) { newLogicalLayoutOverflowRect.setWidth(markerLogicalLeft + m_marker->logicalWidth() - box->logicalLeftLayoutOverflow()); if (box == root) adjustOverflow = true; diff --git a/Source/WebCore/rendering/RenderListMarker.cpp b/Source/WebCore/rendering/RenderListMarker.cpp index cd41c75..c1c7245 100644 --- a/Source/WebCore/rendering/RenderListMarker.cpp +++ b/Source/WebCore/rendering/RenderListMarker.cpp @@ -26,13 +26,13 @@ #include "RenderListMarker.h" #include "CachedImage.h" -#include "CharacterNames.h" #include "Document.h" #include "GraphicsContext.h" #include "RenderLayer.h" #include "RenderListItem.h" #include "RenderView.h" #include "TextRun.h" +#include <wtf/unicode/CharacterNames.h> using namespace std; using namespace WTF; @@ -1130,7 +1130,7 @@ void RenderListMarker::paint(PaintInfo& paintInfo, int tx, int ty) if (style()->highlight() != nullAtom && !paintInfo.context->paintingDisabled()) paintCustomHighlight(tx, ty, style()->highlight(), true); #endif - context->drawImage(m_image->image(this, marker.size()), style()->colorSpace(), marker); + context->drawImage(m_image->image(this, marker.size()).get(), style()->colorSpace(), marker); if (selectionState() != SelectionNone) { IntRect selRect = localSelectionRect(); selRect.move(boxOrigin.x(), boxOrigin.y()); @@ -1260,12 +1260,12 @@ void RenderListMarker::paint(PaintInfo& paintInfo, int tx, int ty) marker = marker.transposedRect(); marker.move(box.x(), box.y() - logicalHeight()); context->save(); - context->translate(marker.x(), marker.bottom()); + context->translate(marker.x(), marker.maxY()); context->rotate(static_cast<float>(deg2rad(90.))); - context->translate(-marker.x(), -marker.bottom()); + context->translate(-marker.x(), -marker.maxY()); } - IntPoint textOrigin = IntPoint(marker.x(), marker.y() + style()->font().ascent()); + IntPoint textOrigin = IntPoint(marker.x(), marker.y() + style()->fontMetrics().ascent()); if (type == Asterisks || type == Footnotes) context->drawText(style()->font(), textRun, textOrigin); @@ -1311,7 +1311,7 @@ void RenderListMarker::layout() setHeight(m_image->imageSize(this, style()->effectiveZoom()).height()); } else { setLogicalWidth(minPreferredLogicalWidth()); - setLogicalHeight(style()->font().height()); + setLogicalHeight(style()->fontMetrics().height()); } setMarginStart(0); @@ -1346,11 +1346,12 @@ void RenderListMarker::computePreferredLogicalWidths() m_text = ""; const Font& font = style()->font(); + const FontMetrics& fontMetrics = font.fontMetrics(); if (isImage()) { // FIXME: This is a somewhat arbitrary width. Generated images for markers really won't become particularly useful // until we support the CSS3 marker pseudoclass to allow control over the width and height of the marker box. - int bulletWidth = font.ascent() / 2; + int bulletWidth = fontMetrics.ascent() / 2; m_image->setImageContainerSize(IntSize(bulletWidth, bulletWidth)); IntSize imageSize = m_image->imageSize(this, style()->effectiveZoom()); m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = style()->isHorizontalWritingMode() ? imageSize.width() : imageSize.height(); @@ -1373,7 +1374,7 @@ void RenderListMarker::computePreferredLogicalWidths() case Disc: case Square: m_text = listMarkerText(type, 0); // value is ignored for these types - logicalWidth = (font.ascent() * 2 / 3 + 1) / 2 + 2; + logicalWidth = (fontMetrics.ascent() * 2 / 3 + 1) / 2 + 2; break; case Afar: case Amharic: @@ -1472,7 +1473,7 @@ void RenderListMarker::computePreferredLogicalWidths() void RenderListMarker::updateMargins() { - const Font& font = style()->font(); + const FontMetrics& fontMetrics = style()->fontMetrics(); int marginStart = 0; int marginEnd = 0; @@ -1485,7 +1486,7 @@ void RenderListMarker::updateMargins() case Circle: case Square: marginStart = -1; - marginEnd = font.ascent() - minPreferredLogicalWidth() + 1; + marginEnd = fontMetrics.ascent() - minPreferredLogicalWidth() + 1; break; default: break; @@ -1495,7 +1496,7 @@ void RenderListMarker::updateMargins() if (isImage()) marginStart = -minPreferredLogicalWidth() - cMarkerPadding; else { - int offset = font.ascent() * 2 / 3; + int offset = fontMetrics.ascent() * 2 / 3; switch (style()->listStyleType()) { case Disc: case Circle: @@ -1513,7 +1514,7 @@ void RenderListMarker::updateMargins() if (isImage()) marginEnd = cMarkerPadding; else { - int offset = font.ascent() * 2 / 3; + int offset = fontMetrics.ascent() * 2 / 3; switch (style()->listStyleType()) { case Disc: case Circle: @@ -1584,15 +1585,15 @@ IntRect RenderListMarker::getRelativeMarkerRect() case Asterisks: case Footnotes: { const Font& font = style()->font(); - relativeRect = IntRect(0, 0, font.width(m_text), font.height()); + relativeRect = IntRect(0, 0, font.width(m_text), font.fontMetrics().height()); break; } case Disc: case Circle: case Square: { // FIXME: Are these particular rounding rules necessary? - const Font& font = style()->font(); - int ascent = font.ascent(); + const FontMetrics& fontMetrics = style()->fontMetrics(); + int ascent = fontMetrics.ascent(); int bulletWidth = (ascent * 2 / 3 + 1) / 2; relativeRect = IntRect(1, 3 * (ascent - ascent * 2 / 3) / 2, bulletWidth, bulletWidth); break; @@ -1680,7 +1681,7 @@ IntRect RenderListMarker::getRelativeMarkerRect() int itemWidth = font.width(m_text); UChar suffixSpace[2] = { listMarkerSuffix(type, m_listItem->value()), ' ' }; int suffixSpaceWidth = font.width(TextRun(suffixSpace, 2)); - relativeRect = IntRect(0, 0, itemWidth + suffixSpaceWidth, font.height()); + relativeRect = IntRect(0, 0, itemWidth + suffixSpaceWidth, font.fontMetrics().height()); } if (!style()->isHorizontalWritingMode()) { diff --git a/Source/WebCore/rendering/RenderMarquee.cpp b/Source/WebCore/rendering/RenderMarquee.cpp index 9b58118..6f59340 100644 --- a/Source/WebCore/rendering/RenderMarquee.cpp +++ b/Source/WebCore/rendering/RenderMarquee.cpp @@ -116,7 +116,7 @@ int RenderMarquee::computePosition(EMarqueeDirection dir, bool stopAtContentEdge if (isHorizontal()) { bool ltr = s->isLeftToRightDirection(); int clientWidth = box->clientWidth(); - int contentWidth = ltr ? box->rightLayoutOverflow() : box->leftLayoutOverflow(); + int contentWidth = ltr ? box->maxXLayoutOverflow() : box->minXLayoutOverflow(); if (ltr) contentWidth += (box->paddingRight() - box->borderLeft()); else { @@ -137,7 +137,7 @@ int RenderMarquee::computePosition(EMarqueeDirection dir, bool stopAtContentEdge } } else { - int contentHeight = box->bottomLayoutOverflow() - box->borderTop() + box->paddingBottom(); + int contentHeight = box->maxYLayoutOverflow() - box->borderTop() + box->paddingBottom(); int clientHeight = box->clientHeight(); if (dir == MUP) { if (stopAtContentEdge) diff --git a/Source/WebCore/rendering/RenderMedia.cpp b/Source/WebCore/rendering/RenderMedia.cpp index 0b913ee..16cd874 100644 --- a/Source/WebCore/rendering/RenderMedia.cpp +++ b/Source/WebCore/rendering/RenderMedia.cpp @@ -28,59 +28,22 @@ #if ENABLE(VIDEO) #include "RenderMedia.h" -#include "EventNames.h" -#include "FloatConversion.h" -#include "HTMLNames.h" +#include "HTMLMediaElement.h" #include "MediaControlElements.h" -#include "MouseEvent.h" -#include "Page.h" -#include "RenderLayer.h" -#include "RenderTheme.h" -#include <wtf/CurrentTime.h> -#include <wtf/MathExtras.h> - -#if PLATFORM(ANDROID) && ENABLE(TOUCH_EVENTS) -#include "TouchEvent.h" -#define TOUCH_DELAY 4 -#endif - -using namespace std; +#include "MediaControls.h" namespace WebCore { -using namespace HTMLNames; - -static const double cTimeUpdateRepeatDelay = 0.2; -static const double cOpacityAnimationRepeatDelay = 0.05; - RenderMedia::RenderMedia(HTMLMediaElement* video) : RenderImage(video) - , m_timeUpdateTimer(this, &RenderMedia::timeUpdateTimerFired) - , m_opacityAnimationTimer(this, &RenderMedia::opacityAnimationTimerFired) - , m_mouseOver(false) - , m_opacityAnimationStartTime(0) - , m_opacityAnimationDuration(0) - , m_opacityAnimationFrom(0) - , m_opacityAnimationTo(1.0f) -#if PLATFORM(ANDROID) - , m_lastTouch(0) -#endif + , m_controls(new MediaControls(video)) { setImageResource(RenderImageResource::create()); } RenderMedia::RenderMedia(HTMLMediaElement* video, const IntSize& intrinsicSize) : RenderImage(video) - , m_timeUpdateTimer(this, &RenderMedia::timeUpdateTimerFired) - , m_opacityAnimationTimer(this, &RenderMedia::opacityAnimationTimerFired) - , m_mouseOver(false) - , m_opacityAnimationStartTime(0) - , m_opacityAnimationDuration(0) - , m_opacityAnimationFrom(0) - , m_opacityAnimationTo(1.0f) -#if PLATFORM(ANDROID) - , m_lastTouch(0) -#endif + , m_controls(new MediaControls(video)) { setImageResource(RenderImageResource::create()); setIntrinsicSize(intrinsicSize); @@ -92,16 +55,7 @@ RenderMedia::~RenderMedia() void RenderMedia::destroy() { - if (m_controlsShadowRoot && m_controlsShadowRoot->renderer()) { - - // detach the panel before removing the shadow renderer to prevent a crash in m_controlsShadowRoot->detach() - // when display: style changes - m_panel->detach(); - - removeChild(m_controlsShadowRoot->renderer()); - m_controlsShadowRoot->detach(); - m_controlsShadowRoot = 0; - } + m_controls->destroy(); RenderImage::destroy(); } @@ -110,51 +64,10 @@ HTMLMediaElement* RenderMedia::mediaElement() const return static_cast<HTMLMediaElement*>(node()); } -MediaPlayer* RenderMedia::player() const -{ - return mediaElement()->player(); -} - void RenderMedia::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { RenderImage::styleDidChange(diff, oldStyle); - - if (m_controlsShadowRoot) { - if (m_panel) - m_panel->updateStyle(); - if (m_muteButton) - m_muteButton->updateStyle(); - if (m_playButton) - m_playButton->updateStyle(); - if (m_seekBackButton) - m_seekBackButton->updateStyle(); - if (m_seekForwardButton) - m_seekForwardButton->updateStyle(); - if (m_rewindButton) - m_rewindButton->updateStyle(); - if (m_returnToRealtimeButton) - m_returnToRealtimeButton->updateStyle(); - if (m_toggleClosedCaptionsButton) - m_toggleClosedCaptionsButton->updateStyle(); - if (m_statusDisplay) - m_statusDisplay->updateStyle(); - if (m_timelineContainer) - m_timelineContainer->updateStyle(); - if (m_timeline) - m_timeline->updateStyle(); - if (m_fullscreenButton) - m_fullscreenButton->updateStyle(); - if (m_currentTimeDisplay) - m_currentTimeDisplay->updateStyle(); - if (m_timeRemainingDisplay) - m_timeRemainingDisplay->updateStyle(); - if (m_volumeSliderContainer) - m_volumeSliderContainer->updateStyle(); - if (m_volumeSliderMuteButton) - m_volumeSliderMuteButton->updateStyle(); - if (m_volumeSlider) - m_volumeSlider->updateStyle(); - } + m_controls->updateStyle(); } void RenderMedia::layout() @@ -163,17 +76,13 @@ void RenderMedia::layout() RenderImage::layout(); - RenderBox* controlsRenderer = m_controlsShadowRoot ? m_controlsShadowRoot->renderBox() : 0; + RenderBox* controlsRenderer = m_controls->renderBox(); if (!controlsRenderer) return; IntSize newSize = contentBoxRect().size(); if (newSize != oldSize || controlsRenderer->needsLayout()) { - if (m_currentTimeDisplay && m_timeRemainingDisplay) { - bool shouldShowTimeDisplays = shouldShowTimeDisplayControls(); - m_currentTimeDisplay->setVisible(shouldShowTimeDisplays); - m_timeRemainingDisplay->setVisible(shouldShowTimeDisplays); - } + m_controls->updateTimeDisplayVisibility(); controlsRenderer->setLocation(borderLeft() + paddingLeft(), borderTop() + paddingTop()); controlsRenderer->style()->setHeight(Length(newSize.height(), Fixed)); @@ -184,480 +93,9 @@ void RenderMedia::layout() } } -void RenderMedia::createControlsShadowRoot() -{ - ASSERT(!m_controlsShadowRoot); - m_controlsShadowRoot = MediaControlShadowRootElement::create(mediaElement()); - addChild(m_controlsShadowRoot->renderer()); -} - -void RenderMedia::createPanel() -{ - ASSERT(!m_panel); - m_panel = MediaControlElement::create(mediaElement(), MEDIA_CONTROLS_PANEL); - m_panel->attachToParent(m_controlsShadowRoot.get()); -} - -void RenderMedia::createMuteButton() -{ - ASSERT(!m_muteButton); - m_muteButton = MediaControlMuteButtonElement::create(mediaElement(), MediaControlMuteButtonElement::Controller); - m_muteButton->attachToParent(m_panel.get()); -} - -void RenderMedia::createPlayButton() -{ - ASSERT(!m_playButton); - m_playButton = MediaControlPlayButtonElement::create(mediaElement()); - m_playButton->attachToParent(m_panel.get()); -} - -void RenderMedia::createSeekBackButton() -{ - ASSERT(!m_seekBackButton); - m_seekBackButton = MediaControlSeekButtonElement::create(mediaElement(), MEDIA_CONTROLS_SEEK_BACK_BUTTON); - m_seekBackButton->attachToParent(m_panel.get()); -} - -void RenderMedia::createSeekForwardButton() -{ - ASSERT(!m_seekForwardButton); - m_seekForwardButton = MediaControlSeekButtonElement::create(mediaElement(), MEDIA_CONTROLS_SEEK_FORWARD_BUTTON); - m_seekForwardButton->attachToParent(m_panel.get()); -} - -void RenderMedia::createRewindButton() -{ - ASSERT(!m_rewindButton); - m_rewindButton = MediaControlRewindButtonElement::create(mediaElement()); - m_rewindButton->attachToParent(m_panel.get()); -} - -void RenderMedia::createReturnToRealtimeButton() -{ - ASSERT(!m_returnToRealtimeButton); - m_returnToRealtimeButton = MediaControlReturnToRealtimeButtonElement::create(mediaElement()); - m_returnToRealtimeButton->attachToParent(m_panel.get()); -} - -void RenderMedia::createToggleClosedCaptionsButton() -{ - ASSERT(!m_toggleClosedCaptionsButton); - m_toggleClosedCaptionsButton = MediaControlToggleClosedCaptionsButtonElement::create(mediaElement()); - m_toggleClosedCaptionsButton->attachToParent(m_panel.get()); -} - -void RenderMedia::createStatusDisplay() -{ - ASSERT(!m_statusDisplay); - m_statusDisplay = MediaControlStatusDisplayElement::create(mediaElement()); - m_statusDisplay->attachToParent(m_panel.get()); -} - -void RenderMedia::createTimelineContainer() -{ - ASSERT(!m_timelineContainer); - m_timelineContainer = MediaControlTimelineContainerElement::create(mediaElement()); - m_timelineContainer->attachToParent(m_panel.get()); -} - -void RenderMedia::createTimeline() -{ - ASSERT(!m_timeline); - m_timeline = MediaControlTimelineElement::create(mediaElement()); - m_timeline->setAttribute(precisionAttr, "float"); - m_timeline->attachToParent(m_timelineContainer.get()); -} - -void RenderMedia::createVolumeSliderContainer() -{ - ASSERT(!m_volumeSliderContainer); - m_volumeSliderContainer = MediaControlVolumeSliderContainerElement::create(mediaElement()); - m_volumeSliderContainer->attachToParent(m_panel.get()); -} - -void RenderMedia::createVolumeSlider() -{ - ASSERT(!m_volumeSlider); - m_volumeSlider = MediaControlVolumeSliderElement::create(mediaElement()); - m_volumeSlider->setAttribute(precisionAttr, "float"); - m_volumeSlider->setAttribute(maxAttr, "1"); - m_volumeSlider->setAttribute(valueAttr, String::number(mediaElement()->volume())); - m_volumeSlider->attachToParent(m_volumeSliderContainer.get()); -} - -void RenderMedia::createVolumeSliderMuteButton() -{ - ASSERT(!m_volumeSliderMuteButton); - m_volumeSliderMuteButton = MediaControlMuteButtonElement::create(mediaElement(), MediaControlMuteButtonElement::VolumeSlider); - m_volumeSliderMuteButton->attachToParent(m_volumeSliderContainer.get()); - -} - -void RenderMedia::createCurrentTimeDisplay() -{ - ASSERT(!m_currentTimeDisplay); - m_currentTimeDisplay = MediaControlTimeDisplayElement::create(mediaElement(), MEDIA_CONTROLS_CURRENT_TIME_DISPLAY); - m_currentTimeDisplay->attachToParent(m_timelineContainer.get()); -} - -void RenderMedia::createTimeRemainingDisplay() -{ - ASSERT(!m_timeRemainingDisplay); - m_timeRemainingDisplay = MediaControlTimeDisplayElement::create(mediaElement(), MEDIA_CONTROLS_TIME_REMAINING_DISPLAY); - m_timeRemainingDisplay->attachToParent(m_timelineContainer.get()); -} - -void RenderMedia::createFullscreenButton() -{ - ASSERT(!m_fullscreenButton); - m_fullscreenButton = MediaControlFullscreenButtonElement::create(mediaElement()); - m_fullscreenButton->attachToParent(m_panel.get()); -} - void RenderMedia::updateFromElement() { - updateControls(); -} - -void RenderMedia::updateControls() -{ - HTMLMediaElement* media = mediaElement(); - if (!media->controls() || !media->inActiveDocument()) { - if (m_controlsShadowRoot) { - m_controlsShadowRoot->detach(); - m_panel = 0; - m_muteButton = 0; - m_playButton = 0; - m_statusDisplay = 0; - m_timelineContainer = 0; - m_timeline = 0; - m_seekBackButton = 0; - m_seekForwardButton = 0; - m_rewindButton = 0; - m_returnToRealtimeButton = 0; - m_currentTimeDisplay = 0; - m_timeRemainingDisplay = 0; - m_fullscreenButton = 0; - m_volumeSliderContainer = 0; - m_volumeSlider = 0; - m_volumeSliderMuteButton = 0; - m_controlsShadowRoot = 0; - m_toggleClosedCaptionsButton = 0; - } - m_opacityAnimationTo = 1.0f; - m_opacityAnimationTimer.stop(); - m_timeUpdateTimer.stop(); - return; - } - - if (!m_controlsShadowRoot) { - createControlsShadowRoot(); - createPanel(); - if (m_panel) { - createRewindButton(); - createPlayButton(); - createReturnToRealtimeButton(); - createStatusDisplay(); - createTimelineContainer(); - if (m_timelineContainer) { - createCurrentTimeDisplay(); - createTimeline(); - createTimeRemainingDisplay(); - } - createSeekBackButton(); - createSeekForwardButton(); - createToggleClosedCaptionsButton(); - createFullscreenButton(); - createMuteButton(); - createVolumeSliderContainer(); - if (m_volumeSliderContainer) { - createVolumeSlider(); - createVolumeSliderMuteButton(); - } - m_panel->attach(); - } - } - - if (media->canPlay()) { - if (m_timeUpdateTimer.isActive()) - m_timeUpdateTimer.stop(); - } else if (style()->visibility() == VISIBLE && m_timeline && m_timeline->renderer() && m_timeline->renderer()->style()->display() != NONE) { - m_timeUpdateTimer.startRepeating(cTimeUpdateRepeatDelay); - } - - - if (m_panel) { - // update() might alter the opacity of the element, especially if we are in the middle - // of an animation. This is the only element concerned as we animate only this element. - float opacityBeforeChangingStyle = m_panel->renderer() ? m_panel->renderer()->style()->opacity() : 0; - m_panel->update(); - changeOpacity(m_panel.get(), opacityBeforeChangingStyle); - } - if (m_muteButton) - m_muteButton->update(); - if (m_playButton) - m_playButton->update(); - if (m_timelineContainer) - m_timelineContainer->update(); - if (m_volumeSliderContainer) - m_volumeSliderContainer->update(); - if (m_timeline) - m_timeline->update(); - if (m_currentTimeDisplay) - m_currentTimeDisplay->update(); - if (m_timeRemainingDisplay) - m_timeRemainingDisplay->update(); - if (m_seekBackButton) - m_seekBackButton->update(); - if (m_seekForwardButton) - m_seekForwardButton->update(); - if (m_rewindButton) - m_rewindButton->update(); - if (m_returnToRealtimeButton) - m_returnToRealtimeButton->update(); - if (m_toggleClosedCaptionsButton) - m_toggleClosedCaptionsButton->update(); - if (m_statusDisplay) - m_statusDisplay->update(); - if (m_fullscreenButton) - m_fullscreenButton->update(); - if (m_volumeSlider) - m_volumeSlider->update(); - if (m_volumeSliderMuteButton) - m_volumeSliderMuteButton->update(); - - updateTimeDisplay(); - updateControlVisibility(); -} - -void RenderMedia::timeUpdateTimerFired(Timer<RenderMedia>*) -{ - if (m_timeline) - m_timeline->update(false); - updateTimeDisplay(); -} - -void RenderMedia::updateTimeDisplay() -{ - if (!m_currentTimeDisplay || !m_currentTimeDisplay->renderer() || m_currentTimeDisplay->renderer()->style()->display() == NONE || style()->visibility() != VISIBLE) - return; - - float now = mediaElement()->currentTime(); - float duration = mediaElement()->duration(); - - // Allow the theme to format the time - ExceptionCode ec; - m_currentTimeDisplay->setInnerText(theme()->formatMediaControlsCurrentTime(now, duration), ec); - m_currentTimeDisplay->setCurrentValue(now); - m_timeRemainingDisplay->setInnerText(theme()->formatMediaControlsRemainingTime(now, duration), ec); - m_timeRemainingDisplay->setCurrentValue(now - duration); -} - -void RenderMedia::updateControlVisibility() -{ - if (!m_panel || !m_panel->renderer()) - return; - - // Don't fade for audio controls. - HTMLMediaElement* media = mediaElement(); - if (!media->hasVideo()) - return; - - // Don't fade if the media element is not visible - if (style()->visibility() != VISIBLE) - return; - -#if PLATFORM(ANDROID) && ENABLE(TOUCH_EVENTS) - if (WTF::currentTime() - m_lastTouch > TOUCH_DELAY) - m_mouseOver = false; - else - m_mouseOver = true; -#endif - - bool shouldHideController = !m_mouseOver && !media->canPlay(); - - // Do fading manually, css animations don't work with shadow trees - - float animateFrom = m_panel->renderer()->style()->opacity(); - float animateTo = shouldHideController ? 0.0f : 1.0f; - - if (animateFrom == animateTo) - return; - - if (m_opacityAnimationTimer.isActive()) { - if (m_opacityAnimationTo == animateTo) - return; - m_opacityAnimationTimer.stop(); - } - - if (animateFrom < animateTo) - m_opacityAnimationDuration = m_panel->renderer()->theme()->mediaControlsFadeInDuration(); - else - m_opacityAnimationDuration = m_panel->renderer()->theme()->mediaControlsFadeOutDuration(); - - m_opacityAnimationFrom = animateFrom; - m_opacityAnimationTo = animateTo; - - m_opacityAnimationStartTime = currentTime(); - m_opacityAnimationTimer.startRepeating(cOpacityAnimationRepeatDelay); -} - -void RenderMedia::changeOpacity(HTMLElement* e, float opacity) -{ - if (!e || !e->renderer() || !e->renderer()->style()) - return; - RefPtr<RenderStyle> s = RenderStyle::clone(e->renderer()->style()); - s->setOpacity(opacity); - // z-index can't be auto if opacity is used - s->setZIndex(0); - e->renderer()->setStyle(s.release()); -} - -void RenderMedia::opacityAnimationTimerFired(Timer<RenderMedia>*) -{ - double time = currentTime() - m_opacityAnimationStartTime; - if (time >= m_opacityAnimationDuration) { - time = m_opacityAnimationDuration; - m_opacityAnimationTimer.stop(); - } - float opacity = narrowPrecisionToFloat(m_opacityAnimationFrom + (m_opacityAnimationTo - m_opacityAnimationFrom) * time / m_opacityAnimationDuration); - changeOpacity(m_panel.get(), opacity); -} - -void RenderMedia::updateVolumeSliderContainer(bool visible) -{ - if (!mediaElement()->hasAudio() || !m_volumeSliderContainer || !m_volumeSlider) - return; - - if (visible && !m_volumeSliderContainer->isVisible()) { - if (!m_muteButton || !m_muteButton->renderer() || !m_muteButton->renderBox()) - return; - - RefPtr<RenderStyle> s = m_volumeSliderContainer->styleForElement(); - int height = s->height().isPercent() ? 0 : s->height().value(); - int width = s->width().isPercent() ? 0 : s->width().value(); - IntPoint offset = document()->page()->theme()->volumeSliderOffsetFromMuteButton(m_muteButton->renderer()->node(), IntSize(width, height)); - int x = offset.x() + m_muteButton->renderBox()->offsetLeft(); - int y = offset.y() + m_muteButton->renderBox()->offsetTop(); - - m_volumeSliderContainer->setPosition(x, y); - m_volumeSliderContainer->setVisible(true); - m_volumeSliderContainer->update(); - m_volumeSlider->update(); - } else if (!visible && m_volumeSliderContainer->isVisible()) { - m_volumeSliderContainer->setVisible(false); - m_volumeSliderContainer->updateStyle(); - } -} - -#if PLATFORM(ANDROID) -void RenderMedia::updateLastTouch() -{ - m_lastTouch = WTF::currentTime(); -} -#endif - -void RenderMedia::forwardEvent(Event* event) -{ -#if PLATFORM(ANDROID) - if (event->isMouseEvent()) - updateLastTouch(); -#if ENABLE(TOUCH_EVENTS) - if (event->isTouchEvent()) - updateLastTouch(); -#endif -#endif - - if (event->isMouseEvent() && m_controlsShadowRoot) { - MouseEvent* mouseEvent = static_cast<MouseEvent*>(event); - IntPoint point(mouseEvent->absoluteLocation()); - - bool defaultHandled = false; - if (m_volumeSliderMuteButton && m_volumeSliderMuteButton->hitTest(point)) { - m_volumeSliderMuteButton->defaultEventHandler(event); - defaultHandled = event->defaultHandled(); - } - - bool showVolumeSlider = false; - if (!defaultHandled && m_muteButton && m_muteButton->hitTest(point)) { - m_muteButton->defaultEventHandler(event); - if (event->type() != eventNames().mouseoutEvent) - showVolumeSlider = true; - } - - if (m_volumeSliderContainer && m_volumeSliderContainer->hitTest(point)) - showVolumeSlider = true; - - if (m_volumeSlider && m_volumeSlider->hitTest(point)) { - m_volumeSlider->defaultEventHandler(event); - showVolumeSlider = true; - } - - updateVolumeSliderContainer(showVolumeSlider); - - if (m_playButton && m_playButton->hitTest(point)) - m_playButton->defaultEventHandler(event); - - if (m_seekBackButton && m_seekBackButton->hitTest(point)) - m_seekBackButton->defaultEventHandler(event); - - if (m_seekForwardButton && m_seekForwardButton->hitTest(point)) - m_seekForwardButton->defaultEventHandler(event); - - if (m_rewindButton && m_rewindButton->hitTest(point)) - m_rewindButton->defaultEventHandler(event); - - if (m_returnToRealtimeButton && m_returnToRealtimeButton->hitTest(point)) - m_returnToRealtimeButton->defaultEventHandler(event); - - if (m_toggleClosedCaptionsButton && m_toggleClosedCaptionsButton->hitTest(point)) - m_toggleClosedCaptionsButton->defaultEventHandler(event); - - if (m_timeline && m_timeline->hitTest(point)) - m_timeline->defaultEventHandler(event); - - if (m_fullscreenButton && m_fullscreenButton->hitTest(point)) - m_fullscreenButton->defaultEventHandler(event); - - if (event->type() == eventNames().mouseoverEvent) { - m_mouseOver = true; - updateControlVisibility(); - } - if (event->type() == eventNames().mouseoutEvent) { - // When the scrollbar thumb captures mouse events, we should treat the mouse as still being over our renderer if the new target is a descendant - Node* mouseOverNode = mouseEvent->relatedTarget() ? mouseEvent->relatedTarget()->toNode() : 0; - RenderObject* mouseOverRenderer = mouseOverNode ? mouseOverNode->renderer() : 0; - m_mouseOver = mouseOverRenderer && mouseOverRenderer->isDescendantOf(this); - updateControlVisibility(); - } - } -#if PLATFORM(ANDROID) && ENABLE(TOUCH_EVENTS) - // We want to process touch events landing on the timeline so that the user - // can drag the scrollbar thumb with their finger. - else if (event->isTouchEvent() && m_controlsShadowRoot) { - TouchEvent* touchEvent = static_cast<TouchEvent*>(event); - if (touchEvent->touches() && touchEvent->touches()->item(0)) { - IntPoint point; - point.setX(touchEvent->touches()->item(0)->pageX()); - point.setY(touchEvent->touches()->item(0)->pageY()); - if (m_timeline && m_timeline->hitTest(point)) - m_timeline->defaultEventHandler(event); - } - } -#endif -} - -// We want the timeline slider to be at least 100 pixels wide. -static const int minWidthToDisplayTimeDisplays = 16 + 16 + 45 + 100 + 45 + 16 + 1; - -bool RenderMedia::shouldShowTimeDisplayControls() const -{ - if (!m_currentTimeDisplay && !m_timeRemainingDisplay) - return false; - - int width = mediaElement()->renderBox()->width(); - return width >= minWidthToDisplayTimeDisplays * style()->effectiveZoom(); + m_controls->update(); } } // namespace WebCore diff --git a/Source/WebCore/rendering/RenderMedia.h b/Source/WebCore/rendering/RenderMedia.h index 817252d..7658ef6 100644 --- a/Source/WebCore/rendering/RenderMedia.h +++ b/Source/WebCore/rendering/RenderMedia.h @@ -29,27 +29,11 @@ #if ENABLE(VIDEO) #include "RenderImage.h" -#include "Timer.h" namespace WebCore { - -class HTMLInputElement; + class HTMLMediaElement; -class MediaControlMuteButtonElement; -class MediaControlPlayButtonElement; -class MediaControlSeekButtonElement; -class MediaControlRewindButtonElement; -class MediaControlReturnToRealtimeButtonElement; -class MediaControlToggleClosedCaptionsButtonElement; -class MediaControlTimelineElement; -class MediaControlVolumeSliderElement; -class MediaControlFullscreenButtonElement; -class MediaControlTimeDisplayElement; -class MediaControlStatusDisplayElement; -class MediaControlTimelineContainerElement; -class MediaControlVolumeSliderContainerElement; -class MediaControlElement; -class MediaPlayer; +class MediaControls; class RenderMedia : public RenderImage { public: @@ -61,19 +45,9 @@ public: RenderObjectChildList* children() { return &m_children; } HTMLMediaElement* mediaElement() const; - MediaPlayer* player() const; + MediaControls* controls() const; - bool shouldShowTimeDisplayControls() const; - - void updateFromElement(); - void updatePlayer(); - void updateControls(); - void updateTimeDisplay(); - - void forwardEvent(Event*); -#if PLATFORM(ANDROID) - void updateLastTouch(); -#endif + virtual void updateFromElement(); protected: virtual void layout(); @@ -88,70 +62,13 @@ private: virtual bool isMedia() const { return true; } virtual bool isImage() const { return false; } - void createControlsShadowRoot(); - void destroyControlsShadowRoot(); - void createPanel(); - void createMuteButton(); - void createPlayButton(); - void createSeekBackButton(); - void createSeekForwardButton(); - void createRewindButton(); - void createReturnToRealtimeButton(); - void createToggleClosedCaptionsButton(); - void createStatusDisplay(); - void createTimelineContainer(); - void createTimeline(); - void createVolumeSliderContainer(); - void createVolumeSlider(); - void createVolumeSliderMuteButton(); - void createCurrentTimeDisplay(); - void createTimeRemainingDisplay(); - void createFullscreenButton(); - - void timeUpdateTimerFired(Timer<RenderMedia>*); - - void updateControlVisibility(); - void changeOpacity(HTMLElement*, float opacity); - void opacityAnimationTimerFired(Timer<RenderMedia>*); - - void updateVolumeSliderContainer(bool visible); virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); virtual bool requiresForcedStyleRecalcPropagation() const { return true; } - RefPtr<HTMLElement> m_controlsShadowRoot; - RefPtr<MediaControlElement> m_panel; - RefPtr<MediaControlMuteButtonElement> m_muteButton; - RefPtr<MediaControlPlayButtonElement> m_playButton; - RefPtr<MediaControlSeekButtonElement> m_seekBackButton; - RefPtr<MediaControlSeekButtonElement> m_seekForwardButton; - RefPtr<MediaControlRewindButtonElement> m_rewindButton; - RefPtr<MediaControlReturnToRealtimeButtonElement> m_returnToRealtimeButton; - RefPtr<MediaControlToggleClosedCaptionsButtonElement> m_toggleClosedCaptionsButton; - RefPtr<MediaControlTimelineElement> m_timeline; - RefPtr<MediaControlVolumeSliderElement> m_volumeSlider; - RefPtr<MediaControlMuteButtonElement> m_volumeSliderMuteButton; - RefPtr<MediaControlFullscreenButtonElement> m_fullscreenButton; - RefPtr<MediaControlTimelineContainerElement> m_timelineContainer; - RefPtr<MediaControlVolumeSliderContainerElement> m_volumeSliderContainer; - RefPtr<MediaControlTimeDisplayElement> m_currentTimeDisplay; - RefPtr<MediaControlTimeDisplayElement> m_timeRemainingDisplay; - RefPtr<MediaControlStatusDisplayElement> m_statusDisplay; + OwnPtr<MediaControls> m_controls; RenderObjectChildList m_children; - Node* m_lastUnderNode; - Node* m_nodeUnderMouse; - - Timer<RenderMedia> m_timeUpdateTimer; - Timer<RenderMedia> m_opacityAnimationTimer; - bool m_mouseOver; - double m_opacityAnimationStartTime; - double m_opacityAnimationDuration; - float m_opacityAnimationFrom; - float m_opacityAnimationTo; -#if PLATFORM(ANDROID) - double m_lastTouch; -#endif }; inline RenderMedia* toRenderMedia(RenderObject* object) @@ -160,6 +77,11 @@ inline RenderMedia* toRenderMedia(RenderObject* object) return static_cast<RenderMedia*>(object); } +inline MediaControls* RenderMedia::controls() const +{ + return m_controls.get(); +} + // This will catch anyone doing an unnecessary cast. void toRenderMedia(const RenderMedia*); diff --git a/Source/WebCore/rendering/RenderMenuList.cpp b/Source/WebCore/rendering/RenderMenuList.cpp index e55b5ca..3e9d198 100644 --- a/Source/WebCore/rendering/RenderMenuList.cpp +++ b/Source/WebCore/rendering/RenderMenuList.cpp @@ -2,7 +2,7 @@ * This file is part of the select element renderer in WebCore. * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). - * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved. * 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) * * This library is free software; you can redistribute it and/or @@ -55,7 +55,6 @@ RenderMenuList::RenderMenuList(Element* element) , m_optionsChanged(true) , m_optionsWidth(0) , m_lastSelectedIndex(-1) - , m_popup(0) , m_popupIsVisible(false) { } @@ -84,19 +83,26 @@ void RenderMenuList::createInnerBlock() void RenderMenuList::adjustInnerStyle() { - m_innerBlock->style()->setBoxFlex(1.0f); + RenderStyle* innerStyle = m_innerBlock->style(); + innerStyle->setBoxFlex(1); - m_innerBlock->style()->setPaddingLeft(Length(theme()->popupInternalPaddingLeft(style()), Fixed)); - m_innerBlock->style()->setPaddingRight(Length(theme()->popupInternalPaddingRight(style()), Fixed)); - m_innerBlock->style()->setPaddingTop(Length(theme()->popupInternalPaddingTop(style()), Fixed)); - m_innerBlock->style()->setPaddingBottom(Length(theme()->popupInternalPaddingBottom(style()), Fixed)); + innerStyle->setPaddingLeft(Length(theme()->popupInternalPaddingLeft(style()), Fixed)); + innerStyle->setPaddingRight(Length(theme()->popupInternalPaddingRight(style()), Fixed)); + innerStyle->setPaddingTop(Length(theme()->popupInternalPaddingTop(style()), Fixed)); + innerStyle->setPaddingBottom(Length(theme()->popupInternalPaddingBottom(style()), Fixed)); if (document()->page()->chrome()->selectItemWritingDirectionIsNatural()) { // Items in the popup will not respect the CSS text-align and direction properties, // so we must adjust our own style to match. - m_innerBlock->style()->setTextAlign(LEFT); + innerStyle->setTextAlign(LEFT); TextDirection direction = (m_buttonText && m_buttonText->text()->defaultWritingDirection() == WTF::Unicode::RightToLeft) ? RTL : LTR; - m_innerBlock->style()->setDirection(direction); + innerStyle->setDirection(direction); + } else if (m_optionStyle && document()->page()->chrome()->selectItemAlignmentFollowsMenuWritingDirection()) { + if ((m_optionStyle->direction() != innerStyle->direction() || m_optionStyle->unicodeBidi() != innerStyle->unicodeBidi())) + m_innerBlock->setNeedsLayoutAndPrefWidthsRecalc(); + innerStyle->setTextAlign(style()->isLeftToRightDirection() ? LEFT : RIGHT); + innerStyle->setDirection(m_optionStyle->direction()); + innerStyle->setUnicodeBidi(m_optionStyle->unicodeBidi()); } } @@ -184,8 +190,11 @@ void RenderMenuList::setTextFromOption(int optionIndex) int i = select->optionToListIndex(optionIndex); String text = ""; if (i >= 0 && i < size) { - if (OptionElement* optionElement = toOptionElement(listItems[i])) + Element* element = listItems[i]; + if (OptionElement* optionElement = toOptionElement(element)) { text = optionElement->textIndentedToRespectGroupLabel(); + m_optionStyle = element->renderStyle(); + } } setText(text.stripWhiteSpace()); @@ -418,7 +427,7 @@ PopupMenuStyle RenderMenuList::itemStyle(unsigned listIndex) const Element* element = listItems[listIndex]; RenderStyle* style = element->renderStyle() ? element->renderStyle() : element->computedStyle(); - return style ? PopupMenuStyle(style->visitedDependentColor(CSSPropertyColor), itemBackgroundColor(listIndex), style->font(), style->visibility() == VISIBLE, style->display() == NONE, style->textIndent(), style->direction()) : menuStyle(); + return style ? PopupMenuStyle(style->visitedDependentColor(CSSPropertyColor), itemBackgroundColor(listIndex), style->font(), style->visibility() == VISIBLE, style->display() == NONE, style->textIndent(), style->direction(), style->unicodeBidi() == Override) : menuStyle(); } Color RenderMenuList::itemBackgroundColor(unsigned listIndex) const @@ -448,7 +457,7 @@ Color RenderMenuList::itemBackgroundColor(unsigned listIndex) const PopupMenuStyle RenderMenuList::menuStyle() const { RenderStyle* s = m_innerBlock ? m_innerBlock->style() : style(); - return PopupMenuStyle(s->visitedDependentColor(CSSPropertyColor), s->visitedDependentColor(CSSPropertyBackgroundColor), s->font(), s->visibility() == VISIBLE, s->display() == NONE, s->textIndent(), s->direction()); + return PopupMenuStyle(s->visitedDependentColor(CSSPropertyColor), s->visitedDependentColor(CSSPropertyBackgroundColor), s->font(), s->visibility() == VISIBLE, s->display() == NONE, s->textIndent(), style()->direction(), style()->unicodeBidi() == Override); } HostWindow* RenderMenuList::hostWindow() const @@ -479,7 +488,7 @@ int RenderMenuList::clientInsetRight() const int RenderMenuList::clientPaddingLeft() const { - return paddingLeft(); + return paddingLeft() + m_innerBlock->paddingLeft(); } const int endOfLinePadding = 2; @@ -495,7 +504,7 @@ int RenderMenuList::clientPaddingRight() const // If the appearance isn't MenulistPart, then the select is styled (non-native), so // we want to return the user specified padding. - return paddingRight(); + return paddingRight() + m_innerBlock->paddingRight(); } int RenderMenuList::listSize() const diff --git a/Source/WebCore/rendering/RenderMenuList.h b/Source/WebCore/rendering/RenderMenuList.h index b84b799..cd6e561 100644 --- a/Source/WebCore/rendering/RenderMenuList.h +++ b/Source/WebCore/rendering/RenderMenuList.h @@ -2,7 +2,7 @@ * This file is part of the select element renderer in WebCore. * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). - * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple 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 @@ -132,6 +132,8 @@ private: int m_lastSelectedIndex; + RefPtr<RenderStyle> m_optionStyle; + RefPtr<PopupMenu> m_popup; bool m_popupIsVisible; }; diff --git a/Source/WebCore/rendering/RenderMeter.cpp b/Source/WebCore/rendering/RenderMeter.cpp index 6439651..f3ada0b 100644 --- a/Source/WebCore/rendering/RenderMeter.cpp +++ b/Source/WebCore/rendering/RenderMeter.cpp @@ -107,7 +107,7 @@ RenderMeter::~RenderMeter() PassRefPtr<MeterPartElement> RenderMeter::createPart(PseudoId pseudoId) { - RefPtr<MeterPartElement> element = MeterPartElement::createForPart(static_cast<HTMLElement*>(node()), pseudoId); + RefPtr<MeterPartElement> element = MeterPartElement::createForPart(toHTMLElement(node()), pseudoId); if (element->renderer()) addChild(element->renderer()); return element; diff --git a/Source/WebCore/rendering/RenderObject.cpp b/Source/WebCore/rendering/RenderObject.cpp index 9a1233e..ebab355 100644 --- a/Source/WebCore/rendering/RenderObject.cpp +++ b/Source/WebCore/rendering/RenderObject.cpp @@ -3,7 +3,7 @@ * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2000 Dirk Mueller (mueller@kde.org) * (C) 2004 Allan Sandfeld Jensen (kde@carewolf.com) - * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2011 Apple Inc. All rights reserved. * Copyright (C) 2009 Google Inc. All rights reserved. * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) * @@ -31,6 +31,7 @@ #include "CSSStyleSelector.h" #include "Chrome.h" #include "ContentData.h" +#include "CursorList.h" #include "DashArray.h" #include "EditingBoundary.h" #include "FloatQuad.h" @@ -319,7 +320,6 @@ void RenderObject::addChild(RenderObject* newChild, RenderObject* beforeChild) // Just add it... children->insertChildNode(this, newChild, beforeChild); } - RenderCounter::rendererSubtreeAttached(newChild); if (newChild->isText() && newChild->style()->textTransform() == CAPITALIZE) { RefPtr<StringImpl> textToTransform = toRenderText(newChild)->originalText(); if (textToTransform) @@ -1381,11 +1381,11 @@ bool RenderObject::repaintAfterLayoutIfNeeded(RenderBoxModelObject* repaintConta else if (deltaLeft < 0) repaintUsingContainer(repaintContainer, IntRect(newBounds.x(), newBounds.y(), -deltaLeft, newBounds.height())); - int deltaRight = newBounds.right() - oldBounds.right(); + int deltaRight = newBounds.maxX() - oldBounds.maxX(); if (deltaRight > 0) - repaintUsingContainer(repaintContainer, IntRect(oldBounds.right(), newBounds.y(), deltaRight, newBounds.height())); + repaintUsingContainer(repaintContainer, IntRect(oldBounds.maxX(), newBounds.y(), deltaRight, newBounds.height())); else if (deltaRight < 0) - repaintUsingContainer(repaintContainer, IntRect(newBounds.right(), oldBounds.y(), -deltaRight, oldBounds.height())); + repaintUsingContainer(repaintContainer, IntRect(newBounds.maxX(), oldBounds.y(), -deltaRight, oldBounds.height())); int deltaTop = newBounds.y() - oldBounds.y(); if (deltaTop > 0) @@ -1393,11 +1393,11 @@ bool RenderObject::repaintAfterLayoutIfNeeded(RenderBoxModelObject* repaintConta else if (deltaTop < 0) repaintUsingContainer(repaintContainer, IntRect(newBounds.x(), newBounds.y(), newBounds.width(), -deltaTop)); - int deltaBottom = newBounds.bottom() - oldBounds.bottom(); + int deltaBottom = newBounds.maxY() - oldBounds.maxY(); if (deltaBottom > 0) - repaintUsingContainer(repaintContainer, IntRect(newBounds.x(), oldBounds.bottom(), newBounds.width(), deltaBottom)); + repaintUsingContainer(repaintContainer, IntRect(newBounds.x(), oldBounds.maxY(), newBounds.width(), deltaBottom)); else if (deltaBottom < 0) - repaintUsingContainer(repaintContainer, IntRect(oldBounds.x(), newBounds.bottom(), oldBounds.width(), -deltaBottom)); + repaintUsingContainer(repaintContainer, IntRect(oldBounds.x(), newBounds.maxY(), oldBounds.width(), -deltaBottom)); if (newOutlineBox == oldOutlineBox) return false; @@ -1419,7 +1419,7 @@ bool RenderObject::repaintAfterLayoutIfNeeded(RenderBoxModelObject* repaintConta newOutlineBox.y(), width + borderWidth, max(newOutlineBox.height(), oldOutlineBox.height())); - int right = min(newBounds.right(), oldBounds.right()); + int right = min(newBounds.maxX(), oldBounds.maxX()); if (rightRect.x() < right) { rightRect.setWidth(min(rightRect.width(), right - rightRect.x())); repaintUsingContainer(repaintContainer, rightRect); @@ -1435,10 +1435,10 @@ bool RenderObject::repaintAfterLayoutIfNeeded(RenderBoxModelObject* repaintConta int boxHeight = isBox() ? toRenderBox(this)->height() : 0; int borderHeight = max(-outlineStyle->outlineOffset(), max(borderBottom, max(style()->borderBottomLeftRadius().height().calcValue(boxHeight), style()->borderBottomRightRadius().height().calcValue(boxHeight)))) + max(ow, shadowBottom); IntRect bottomRect(newOutlineBox.x(), - min(newOutlineBox.bottom(), oldOutlineBox.bottom()) - borderHeight, + min(newOutlineBox.maxY(), oldOutlineBox.maxY()) - borderHeight, max(newOutlineBox.width(), oldOutlineBox.width()), height + borderHeight); - int bottom = min(newBounds.bottom(), oldBounds.bottom()); + int bottom = min(newBounds.maxY(), oldBounds.maxY()); if (bottomRect.y() < bottom) { bottomRect.setHeight(min(bottomRect.height(), bottom - bottomRect.y())); repaintUsingContainer(repaintContainer, bottomRect); @@ -1863,6 +1863,17 @@ void RenderObject::styleWillChange(StyleDifference diff, const RenderStyle* newS } } +static bool areNonIdenticalCursorListsEqual(const RenderStyle* a, const RenderStyle* b) +{ + ASSERT(a->cursors() != b->cursors()); + return a->cursors() && b->cursors() && *a->cursors() == *b->cursors(); +} + +static inline bool areCursorsEqual(const RenderStyle* a, const RenderStyle* b) +{ + return a->cursor() == b->cursor() && (a->cursors() == b->cursors() || areNonIdenticalCursorListsEqual(a, b)); +} + void RenderObject::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { if (s_affectsParentBlock) @@ -1888,6 +1899,11 @@ void RenderObject::styleDidChange(StyleDifference diff, const RenderStyle* oldSt // Don't check for repaint here; we need to wait until the layer has been // updated by subclasses before we know if we have to repaint (in setStyle()). + + if (oldStyle && !areCursorsEqual(oldStyle, style())) { + if (Frame* frame = this->frame()) + frame->eventHandler()->dispatchFakeMouseMoveEventSoon(); + } } void RenderObject::updateFillImages(const FillLayer* oldLayers, const FillLayer* newLayers) @@ -1950,6 +1966,10 @@ void RenderObject::mapLocalToContainer(RenderBoxModelObject* repaintContainer, b if (!o) return; + IntPoint centerPoint = roundedIntPoint(transformState.mappedPoint()); + if (o->isBox() && o->style()->isFlippedBlocksWritingMode()) + transformState.move(toRenderBox(o)->flipForWritingModeIncludingColumns(roundedIntPoint(transformState.mappedPoint())) - centerPoint); + IntSize columnOffset; o->adjustForColumns(columnOffset, roundedIntPoint(transformState.mappedPoint())); if (!columnOffset.isZero()) @@ -1989,7 +2009,7 @@ void RenderObject::getTransformFromContainer(const RenderObject* containerObject transform.translate(offsetInContainer.width(), offsetInContainer.height()); RenderLayer* layer; if (hasLayer() && (layer = toRenderBoxModelObject(this)->layer()) && layer->transform()) - transform.multLeft(layer->currentTransform()); + transform.multiply(layer->currentTransform()); #if ENABLE(3D_RENDERING) if (containerObject && containerObject->hasLayer() && containerObject->style()->hasPerspective()) { @@ -2001,7 +2021,7 @@ void RenderObject::getTransformFromContainer(const RenderObject* containerObject perspectiveMatrix.applyPerspective(containerObject->style()->perspective()); transform.translateRight3d(-perspectiveOrigin.x(), -perspectiveOrigin.y(), 0); - transform.multiply(perspectiveMatrix); + transform = perspectiveMatrix * transform; transform.translateRight3d(perspectiveOrigin.x(), perspectiveOrigin.y(), 0); } #else @@ -2157,9 +2177,6 @@ void RenderObject::destroy() if (frame() && frame()->eventHandler()->autoscrollRenderer() == this) frame()->eventHandler()->stopAutoscrollTimer(true); - if (m_hasCounterNodeMap) - RenderCounter::destroyCounterNodes(this); - if (AXObjectCache::accessibilityEnabled()) { document()->axObjectCache()->childrenChanged(this->parent()); document()->axObjectCache()->remove(this); @@ -2172,6 +2189,14 @@ void RenderObject::destroy() remove(); + // If this renderer had a parent, remove should have destroyed any counters + // attached to this renderer and marked the affected other counters for + // reevaluation. This apparently redundant check is here for the case when + // this renderer had no parent at the time remove() was called. + + if (m_hasCounterNodeMap) + RenderCounter::destroyCounterNodes(this); + // FIXME: Would like to do this in RenderBoxModelObject, but the timing is so complicated that this can't easily // be moved into RenderBoxModelObject::destroy. if (hasLayer()) { diff --git a/Source/WebCore/rendering/RenderObject.h b/Source/WebCore/rendering/RenderObject.h index f2e7f13..43e6bea 100644 --- a/Source/WebCore/rendering/RenderObject.h +++ b/Source/WebCore/rendering/RenderObject.h @@ -143,6 +143,18 @@ public: return children->lastChild(); return 0; } + RenderObject* beforePseudoElementRenderer() const + { + if (const RenderObjectChildList* children = virtualChildren()) + return children->beforePseudoElementRenderer(this); + return 0; + } + RenderObject* afterPseudoElementRenderer() const + { + if (const RenderObjectChildList* children = virtualChildren()) + return children->afterPseudoElementRenderer(this); + return 0; + } virtual RenderObjectChildList* virtualChildren() { return 0; } virtual const RenderObjectChildList* virtualChildren() const { return 0; } @@ -332,6 +344,7 @@ public: virtual bool isSVGImage() const { return false; } virtual bool isSVGForeignObject() const { return false; } virtual bool isSVGResourceContainer() const { return false; } + virtual bool isSVGResourceFilter() const { return false; } virtual bool isSVGResourceFilterPrimitive() const { return false; } virtual bool isSVGShadowTreeRootContainer() const { return false; } @@ -444,6 +457,11 @@ public: bool isRooted(RenderView** = 0); Node* node() const { return m_isAnonymous ? 0 : m_node; } + + // Returns the styled node that caused the generation of this renderer. + // This is the same as node() except for renderers of :before and :after + // pseudo elements for which their parent node is returned. + Node* generatingNode() const { return m_node == document() ? 0 : m_node; } void setNode(Node* node) { m_node = node; } Document* document() const { return m_node->document(); } diff --git a/Source/WebCore/rendering/RenderObjectChildList.cpp b/Source/WebCore/rendering/RenderObjectChildList.cpp index fa4f902..6a773dc 100644 --- a/Source/WebCore/rendering/RenderObjectChildList.cpp +++ b/Source/WebCore/rendering/RenderObjectChildList.cpp @@ -128,6 +128,9 @@ RenderObject* RenderObjectChildList::removeChildNode(RenderObject* owner, Render oldChild->setNextSibling(0); oldChild->setParent(0); + if (oldChild->m_hasCounterNodeMap) + RenderCounter::destroyCounterNodes(oldChild); + if (AXObjectCache::accessibilityEnabled()) owner->document()->axObjectCache()->childrenChanged(owner); @@ -175,6 +178,7 @@ void RenderObjectChildList::appendChildNode(RenderObject* owner, RenderObject* n owner->dirtyLinesFromChangedChild(newChild); } + RenderCounter::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. @@ -234,6 +238,7 @@ void RenderObjectChildList::insertChildNode(RenderObject* owner, RenderObject* c owner->dirtyLinesFromChangedChild(child); } + RenderCounter::rendererSubtreeAttached(child); child->setNeedsLayoutAndPrefWidthsRecalc(); if (!owner->normalChildNeedsLayout()) owner->setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child. @@ -242,59 +247,6 @@ void RenderObjectChildList::insertChildNode(RenderObject* owner, RenderObject* c owner->document()->axObjectCache()->childrenChanged(owner); } -static RenderObject* beforeAfterContainer(RenderObject* container, PseudoId type) -{ - if (type == BEFORE) { - // An anonymous (generated) inline run-in that has PseudoId BEFORE must come from a grandparent. - // Therefore we should skip these generated run-ins when checking our immediate children. - // If we don't find our :before child immediately, then we should check if we own a - // generated inline run-in in the next level of children. - RenderObject* first = container; - do { - // Skip list markers and generated run-ins - first = first->firstChild(); - while (first && (first->isListMarker() || (first->isRenderInline() && first->isRunIn() && first->isAnonymous()))) - first = first->nextSibling(); - } while (first && first->isAnonymous() && first->style()->styleType() == NOPSEUDO); - - if (!first) - return 0; - - if (first->style()->styleType() == type) - return first; - - // Check for a possible generated run-in, using run-in positioning rules. - // Skip inlines and floating / positioned blocks, and place as the first child. - first = container->firstChild(); - if (!first->isRenderBlock()) - return 0; - while (first && first->isFloatingOrPositioned()) - first = first->nextSibling(); - if (first) { - first = first->firstChild(); - // We still need to skip any list markers that could exist before the run-in. - while (first && first->isListMarker()) - first = first->nextSibling(); - if (first && first->style()->styleType() == type && first->isRenderInline() && first->isRunIn() && first->isAnonymous()) - return first; - } - return 0; - } - - if (type == AFTER) { - RenderObject* last = container; - do { - last = last->lastChild(); - } while (last && last->isAnonymous() && last->style()->styleType() == NOPSEUDO && !last->isListMarker()); - if (last && last->style()->styleType() != type) - return 0; - return last; - } - - ASSERT_NOT_REACHED(); - return 0; -} - static RenderObject* findBeforeAfterParent(RenderObject* object) { // Only table parts need to search for the :before or :after parent @@ -325,14 +277,63 @@ static void invalidateCountersInContainer(RenderObject* container, const AtomicS } } -void RenderObjectChildList::invalidateCounters(RenderObject* owner, const AtomicString& identifier) +void RenderObjectChildList::invalidateCounters(const RenderObject* owner, const AtomicString& identifier) { ASSERT(!owner->documentBeingDestroyed()); - invalidateCountersInContainer(beforeAfterContainer(owner, BEFORE), identifier); - invalidateCountersInContainer(beforeAfterContainer(owner, AFTER), identifier); + invalidateCountersInContainer(beforePseudoElementRenderer(owner), identifier); + invalidateCountersInContainer(afterPseudoElementRenderer(owner), identifier); } -void RenderObjectChildList::updateBeforeAfterContent(RenderObject* owner, PseudoId type, RenderObject* styledObject) +RenderObject* RenderObjectChildList::beforePseudoElementRenderer(const RenderObject* owner) const +{ + // An anonymous (generated) inline run-in that has PseudoId BEFORE must come from a grandparent. + // Therefore we should skip these generated run-ins when checking our immediate children. + // If we don't find our :before child immediately, then we should check if we own a + // generated inline run-in in the next level of children. + RenderObject* first = const_cast<RenderObject*>(owner); + do { + // Skip list markers and generated run-ins + first = first->firstChild(); + while (first && (first->isListMarker() || (first->isRenderInline() && first->isRunIn() && first->isAnonymous()))) + first = first->nextSibling(); + } while (first && first->isAnonymous() && first->style()->styleType() == NOPSEUDO); + + if (!first) + return 0; + + if (first->style()->styleType() == BEFORE) + return first; + + // Check for a possible generated run-in, using run-in positioning rules. + // Skip inlines and floating / positioned blocks, and place as the first child. + first = owner->firstChild(); + if (!first->isRenderBlock()) + return 0; + while (first && first->isFloatingOrPositioned()) + first = first->nextSibling(); + if (first) { + first = first->firstChild(); + // We still need to skip any list markers that could exist before the run-in. + while (first && first->isListMarker()) + first = first->nextSibling(); + if (first && first->style()->styleType() == BEFORE && first->isRenderInline() && first->isRunIn() && first->isAnonymous()) + return first; + } + return 0; +} + +RenderObject* RenderObjectChildList::afterPseudoElementRenderer(const RenderObject* owner) const +{ + RenderObject* last = const_cast<RenderObject*>(owner); + do { + last = last->lastChild(); + } while (last && last->isAnonymous() && last->style()->styleType() == NOPSEUDO && !last->isListMarker()); + if (last && last->style()->styleType() != AFTER) + return 0; + return last; +} + +void RenderObjectChildList::updateBeforeAfterContent(RenderObject* owner, PseudoId type, const RenderObject* styledObject) { // Double check that the document did in fact use generated content rules. Otherwise we should not have been called. ASSERT(owner->document()->usesBeforeAfterRules()); @@ -345,7 +346,18 @@ void RenderObjectChildList::updateBeforeAfterContent(RenderObject* owner, Pseudo styledObject = owner; RenderStyle* pseudoElementStyle = styledObject->getCachedPseudoStyle(type); - RenderObject* child = beforeAfterContainer(owner, type); + RenderObject* child; + switch (type) { + case BEFORE: + child = beforePseudoElementRenderer(owner); + break; + case AFTER: + child = afterPseudoElementRenderer(owner); + break; + default: + ASSERT_NOT_REACHED(); + return; + } // Whether or not we currently have generated content attached. bool oldContentPresent = child; @@ -459,6 +471,8 @@ void RenderObjectChildList::updateBeforeAfterContent(RenderObject* owner, Pseudo // Make a generated box that might be any display type now that we are able to drill down into children // to find the original content properly. generatedContentContainer = RenderObject::createObject(owner->document(), pseudoElementStyle); + ASSERT(styledObject->node()); // The styled object cannot be anonymous or else it could not have ':before' or ':after' pseudo elements. + generatedContentContainer->setNode(styledObject->node()); // This allows access to the generatingNode. generatedContentContainer->setStyle(pseudoElementStyle); owner->addChild(generatedContentContainer, insertBefore); } diff --git a/Source/WebCore/rendering/RenderObjectChildList.h b/Source/WebCore/rendering/RenderObjectChildList.h index 8b80f37..087adfb 100644 --- a/Source/WebCore/rendering/RenderObjectChildList.h +++ b/Source/WebCore/rendering/RenderObjectChildList.h @@ -55,8 +55,10 @@ public: void appendChildNode(RenderObject* owner, RenderObject*, bool fullAppend = true); void insertChildNode(RenderObject* owner, RenderObject* child, RenderObject* before, bool fullInsert = true); - void updateBeforeAfterContent(RenderObject* owner, PseudoId type, RenderObject* styledObject = 0); - void invalidateCounters(RenderObject* owner, const AtomicString& identifier); + void updateBeforeAfterContent(RenderObject* owner, PseudoId type, const RenderObject* styledObject = 0); + RenderObject* beforePseudoElementRenderer(const RenderObject* owner) const; + RenderObject* afterPseudoElementRenderer(const RenderObject* owner) const; + void invalidateCounters(const RenderObject* owner, const AtomicString& identifier); private: RenderObject* m_firstChild; diff --git a/Source/WebCore/rendering/RenderOverflow.h b/Source/WebCore/rendering/RenderOverflow.h index 33e8cff..48fe2bb 100644 --- a/Source/WebCore/rendering/RenderOverflow.h +++ b/Source/WebCore/rendering/RenderOverflow.h @@ -41,38 +41,38 @@ class RenderOverflow { WTF_MAKE_NONCOPYABLE(RenderOverflow); WTF_MAKE_FAST_ALLOCATED; public: RenderOverflow(const IntRect& layoutRect, const IntRect& visualRect) - : m_topLayoutOverflow(layoutRect.y()) - , m_bottomLayoutOverflow(layoutRect.bottom()) - , m_leftLayoutOverflow(layoutRect.x()) - , m_rightLayoutOverflow(layoutRect.right()) - , m_topVisualOverflow(visualRect.y()) - , m_bottomVisualOverflow(visualRect.bottom()) - , m_leftVisualOverflow(visualRect.x()) - , m_rightVisualOverflow(visualRect.right()) + : m_minYLayoutOverflow(layoutRect.y()) + , m_maxYLayoutOverflow(layoutRect.maxY()) + , m_minXLayoutOverflow(layoutRect.x()) + , m_maxXLayoutOverflow(layoutRect.maxX()) + , m_minYVisualOverflow(visualRect.y()) + , m_maxYVisualOverflow(visualRect.maxY()) + , m_minXVisualOverflow(visualRect.x()) + , m_maxXVisualOverflow(visualRect.maxX()) { } - int topLayoutOverflow() const { return m_topLayoutOverflow; } - int bottomLayoutOverflow() const { return m_bottomLayoutOverflow; } - int leftLayoutOverflow() const { return m_leftLayoutOverflow; } - int rightLayoutOverflow() const { return m_rightLayoutOverflow; } + int minYLayoutOverflow() const { return m_minYLayoutOverflow; } + int maxYLayoutOverflow() const { return m_maxYLayoutOverflow; } + int minXLayoutOverflow() const { return m_minXLayoutOverflow; } + int maxXLayoutOverflow() const { return m_maxXLayoutOverflow; } IntRect layoutOverflowRect() const; - int topVisualOverflow() const { return m_topVisualOverflow; } - int bottomVisualOverflow() const { return m_bottomVisualOverflow; } - int leftVisualOverflow() const { return m_leftVisualOverflow; } - int rightVisualOverflow() const { return m_rightVisualOverflow; } + int minYVisualOverflow() const { return m_minYVisualOverflow; } + int maxYVisualOverflow() const { return m_maxYVisualOverflow; } + int minXVisualOverflow() const { return m_minXVisualOverflow; } + int maxXVisualOverflow() const { return m_maxXVisualOverflow; } IntRect visualOverflowRect() const; - void setTopLayoutOverflow(int overflow) { m_topLayoutOverflow = overflow; } - void setBottomLayoutOverflow(int overflow) { m_bottomLayoutOverflow = overflow; } - void setLeftLayoutOverflow(int overflow) { m_leftLayoutOverflow = overflow; } - void setRightLayoutOverflow(int overflow) { m_rightLayoutOverflow = overflow; } + void setMinYLayoutOverflow(int overflow) { m_minYLayoutOverflow = overflow; } + void setMaxYLayoutOverflow(int overflow) { m_maxYLayoutOverflow = overflow; } + void setMinXLayoutOverflow(int overflow) { m_minXLayoutOverflow = overflow; } + void setMaxXLayoutOverflow(int overflow) { m_maxXLayoutOverflow = overflow; } - void setTopVisualOverflow(int overflow) { m_topVisualOverflow = overflow; } - void setBottomVisualOverflow(int overflow) { m_bottomVisualOverflow = overflow; } - void setLeftVisualOverflow(int overflow) { m_leftVisualOverflow = overflow; } - void setRightVisualOverflow(int overflow) { m_rightVisualOverflow = overflow; } + void setMinYVisualOverflow(int overflow) { m_minYVisualOverflow = overflow; } + void setMaxYVisualOverflow(int overflow) { m_maxYVisualOverflow = overflow; } + void setMinXVisualOverflow(int overflow) { m_minXVisualOverflow = overflow; } + void setMaxXVisualOverflow(int overflow) { m_maxXVisualOverflow = overflow; } void move(int dx, int dy); @@ -85,78 +85,78 @@ public: void resetLayoutOverflow(const IntRect& defaultRect); private: - int m_topLayoutOverflow; - int m_bottomLayoutOverflow; - int m_leftLayoutOverflow; - int m_rightLayoutOverflow; - - int m_topVisualOverflow; - int m_bottomVisualOverflow; - int m_leftVisualOverflow; - int m_rightVisualOverflow; + int m_minYLayoutOverflow; + int m_maxYLayoutOverflow; + int m_minXLayoutOverflow; + int m_maxXLayoutOverflow; + + int m_minYVisualOverflow; + int m_maxYVisualOverflow; + int m_minXVisualOverflow; + int m_maxXVisualOverflow; }; inline IntRect RenderOverflow::layoutOverflowRect() const { - return IntRect(m_leftLayoutOverflow, m_topLayoutOverflow, m_rightLayoutOverflow - m_leftLayoutOverflow, m_bottomLayoutOverflow - m_topLayoutOverflow); + return IntRect(m_minXLayoutOverflow, m_minYLayoutOverflow, m_maxXLayoutOverflow - m_minXLayoutOverflow, m_maxYLayoutOverflow - m_minYLayoutOverflow); } inline IntRect RenderOverflow::visualOverflowRect() const { - return IntRect(m_leftVisualOverflow, m_topVisualOverflow, m_rightVisualOverflow - m_leftVisualOverflow, m_bottomVisualOverflow - m_topVisualOverflow); + return IntRect(m_minXVisualOverflow, m_minYVisualOverflow, m_maxXVisualOverflow - m_minXVisualOverflow, m_maxYVisualOverflow - m_minYVisualOverflow); } inline void RenderOverflow::move(int dx, int dy) { - m_topLayoutOverflow += dy; - m_bottomLayoutOverflow += dy; - m_leftLayoutOverflow += dx; - m_rightLayoutOverflow += dx; + m_minYLayoutOverflow += dy; + m_maxYLayoutOverflow += dy; + m_minXLayoutOverflow += dx; + m_maxXLayoutOverflow += dx; - m_topVisualOverflow += dy; - m_bottomVisualOverflow += dy; - m_leftVisualOverflow += dx; - m_rightVisualOverflow += dx; + m_minYVisualOverflow += dy; + m_maxYVisualOverflow += dy; + m_minXVisualOverflow += dx; + m_maxXVisualOverflow += dx; } inline void RenderOverflow::addLayoutOverflow(const IntRect& rect) { - m_topLayoutOverflow = std::min(rect.y(), m_topLayoutOverflow); - m_bottomLayoutOverflow = std::max(rect.bottom(), m_bottomLayoutOverflow); - m_leftLayoutOverflow = std::min(rect.x(), m_leftLayoutOverflow); - m_rightLayoutOverflow = std::max(rect.right(), m_rightLayoutOverflow); + m_minYLayoutOverflow = std::min(rect.y(), m_minYLayoutOverflow); + m_maxYLayoutOverflow = std::max(rect.maxY(), m_maxYLayoutOverflow); + m_minXLayoutOverflow = std::min(rect.x(), m_minXLayoutOverflow); + m_maxXLayoutOverflow = std::max(rect.maxX(), m_maxXLayoutOverflow); } inline void RenderOverflow::addVisualOverflow(const IntRect& rect) { - m_topVisualOverflow = std::min(rect.y(), m_topVisualOverflow); - m_bottomVisualOverflow = std::max(rect.bottom(), m_bottomVisualOverflow); - m_leftVisualOverflow = std::min(rect.x(), m_leftVisualOverflow); - m_rightVisualOverflow = std::max(rect.right(), m_rightVisualOverflow); + m_minYVisualOverflow = std::min(rect.y(), m_minYVisualOverflow); + m_maxYVisualOverflow = std::max(rect.maxY(), m_maxYVisualOverflow); + m_minXVisualOverflow = std::min(rect.x(), m_minXVisualOverflow); + m_maxXVisualOverflow = std::max(rect.maxX(), m_maxXVisualOverflow); } inline void RenderOverflow::setLayoutOverflow(const IntRect& rect) { - m_topLayoutOverflow = rect.y(); - m_bottomLayoutOverflow = rect.bottom(); - m_leftLayoutOverflow = rect.x(); - m_rightLayoutOverflow = rect.right(); + m_minYLayoutOverflow = rect.y(); + m_maxYLayoutOverflow = rect.maxY(); + m_minXLayoutOverflow = rect.x(); + m_maxXLayoutOverflow = rect.maxX(); } inline void RenderOverflow::setVisualOverflow(const IntRect& rect) { - m_topVisualOverflow = rect.y(); - m_bottomVisualOverflow = rect.bottom(); - m_leftVisualOverflow = rect.x(); - m_rightVisualOverflow = rect.right(); + m_minYVisualOverflow = rect.y(); + m_maxYVisualOverflow = rect.maxY(); + m_minXVisualOverflow = rect.x(); + m_maxXVisualOverflow = rect.maxX(); } inline void RenderOverflow::resetLayoutOverflow(const IntRect& rect) { - m_topLayoutOverflow = rect.y(); - m_bottomLayoutOverflow = rect.bottom(); - m_leftLayoutOverflow = rect.x(); - m_rightLayoutOverflow = rect.right(); + m_minYLayoutOverflow = rect.y(); + m_maxYLayoutOverflow = rect.maxY(); + m_minXLayoutOverflow = rect.x(); + m_maxXLayoutOverflow = rect.maxX(); } } // namespace WebCore diff --git a/Source/WebCore/rendering/RenderProgress.cpp b/Source/WebCore/rendering/RenderProgress.cpp index 4194e2b..2a8e6f3 100644 --- a/Source/WebCore/rendering/RenderProgress.cpp +++ b/Source/WebCore/rendering/RenderProgress.cpp @@ -36,6 +36,16 @@ using namespace std; namespace WebCore { +IntRect RenderProgressBarValuePart::preferredFrameRect() +{ + return toRenderProgress(parent())->valuePartRect(); +} + +bool RenderProgressBarValuePart::shouldBeHidden() +{ + return !toRenderProgress(parent())->shouldHaveParts(); +} + RenderProgress::RenderProgress(HTMLProgressElement* element) : RenderIndicator(element) , m_position(-1) @@ -49,23 +59,10 @@ RenderProgress::RenderProgress(HTMLProgressElement* element) RenderProgress::~RenderProgress() { - if (m_valuePart) - m_valuePart->detach(); } void RenderProgress::updateFromElement() { - if (!m_valuePart) { - m_valuePart = ShadowBlockElement::createForPart(static_cast<HTMLElement*>(node()), PROGRESS_BAR_VALUE); - if (m_valuePart->renderer()) - addChild(m_valuePart->renderer()); - } - - if (shouldHaveParts()) - style()->setAppearance(NoControlPart); - else if (m_valuePart->renderer()) - m_valuePart->renderer()->style()->setVisibility(HIDDEN); - HTMLProgressElement* element = progressElement(); if (m_position == element->position()) return; @@ -102,7 +99,8 @@ void RenderProgress::paint(PaintInfo& paintInfo, int tx, int ty) void RenderProgress::layoutParts() { - m_valuePart->layoutAsPart(valuePartRect()); + for (RenderObject* child = firstChild(); child; child = child->nextSibling()) + child->layout(); updateAnimationState(); } @@ -110,8 +108,6 @@ bool RenderProgress::shouldHaveParts() const { if (!style()->hasAppearance()) return true; - if (ShadowBlockElement::partShouldHaveStyle(this, PROGRESS_BAR_VALUE)) - return true; return false; } diff --git a/Source/WebCore/rendering/RenderProgress.h b/Source/WebCore/rendering/RenderProgress.h index 9ed5741..78cf359 100644 --- a/Source/WebCore/rendering/RenderProgress.h +++ b/Source/WebCore/rendering/RenderProgress.h @@ -28,7 +28,14 @@ namespace WebCore { class HTMLProgressElement; -class ShadowBlockElement; + +class RenderProgressBarValuePart : public RenderIndicatorPart { +public: + RenderProgressBarValuePart(Node* node) : RenderIndicatorPart(node) {} +private: + virtual IntRect preferredFrameRect(); + virtual bool shouldBeHidden(); +}; class RenderProgress : public RenderIndicator { public: @@ -40,6 +47,8 @@ public: double animationStartTime() const { return m_animationStartTime; } bool isDeterminate() const; + IntRect valuePartRect() const; + bool shouldHaveParts() const; HTMLProgressElement* progressElement() const; @@ -48,12 +57,8 @@ private: virtual bool isProgress() const { return true; } virtual void updateFromElement(); virtual void paint(PaintInfo&, int tx, int ty); - virtual void layoutParts(); - IntRect valuePartRect() const; - bool shouldHaveParts() const; - void animationTimerFired(Timer<RenderProgress>*); void updateAnimationState(); @@ -63,7 +68,6 @@ private: double m_animationDuration; bool m_animating; Timer<RenderProgress> m_animationTimer; - RefPtr<ShadowBlockElement> m_valuePart; }; inline RenderProgress* toRenderProgress(RenderObject* object) diff --git a/Source/WebCore/rendering/RenderReplaced.cpp b/Source/WebCore/rendering/RenderReplaced.cpp index 0d72f95..c27d336 100644 --- a/Source/WebCore/rendering/RenderReplaced.cpp +++ b/Source/WebCore/rendering/RenderReplaced.cpp @@ -172,8 +172,8 @@ bool RenderReplaced::shouldPaint(PaintInfo& paintInfo, int& tx, int& ty) int currentTY = ty + y(); // Early exit if the element touches the edges. - int top = currentTY + topVisualOverflow(); - int bottom = currentTY + bottomVisualOverflow(); + int top = currentTY + minYVisualOverflow(); + int bottom = currentTY + maxYVisualOverflow(); if (isSelected() && m_inlineBoxWrapper) { int selTop = ty + m_inlineBoxWrapper->root()->selectionTop(); int selBottom = ty + selTop + m_inlineBoxWrapper->root()->selectionHeight(); @@ -182,9 +182,9 @@ bool RenderReplaced::shouldPaint(PaintInfo& paintInfo, int& tx, int& ty) } int os = 2 * maximalOutlineSize(paintInfo.phase); - if (currentTX + leftVisualOverflow() >= paintInfo.rect.right() + os || currentTX + rightVisualOverflow() <= paintInfo.rect.x() - os) + if (currentTX + minXVisualOverflow() >= paintInfo.rect.maxX() + os || currentTX + maxXVisualOverflow() <= paintInfo.rect.x() - os) return false; - if (top >= paintInfo.rect.bottom() + os || bottom <= paintInfo.rect.y() - os) + if (top >= paintInfo.rect.maxY() + os || bottom <= paintInfo.rect.y() - os) return false; return true; diff --git a/Source/WebCore/rendering/RenderRubyRun.cpp b/Source/WebCore/rendering/RenderRubyRun.cpp index c12e543..f2e30eb 100644 --- a/Source/WebCore/rendering/RenderRubyRun.cpp +++ b/Source/WebCore/rendering/RenderRubyRun.cpp @@ -42,7 +42,6 @@ namespace WebCore { RenderRubyRun::RenderRubyRun(Node* node) : RenderBlock(node) - , m_beingDestroyed(false) { setReplaced(true); setInline(true); @@ -52,13 +51,6 @@ RenderRubyRun::~RenderRubyRun() { } -void RenderRubyRun::destroy() -{ - // Mark if the run is being destroyed to avoid trouble in removeChild(). - m_beingDestroyed = true; - RenderBlock::destroy(); -} - bool RenderRubyRun::hasRubyText() const { // The only place where a ruby text can be is in the first position @@ -165,7 +157,7 @@ void RenderRubyRun::removeChild(RenderObject* child) { // If the child is a ruby text, then merge the ruby base with the base of // the right sibling run, if possible. - if (!m_beingDestroyed && !documentBeingDestroyed() && child->isRubyText()) { + if (!beingDestroyed() && !documentBeingDestroyed() && child->isRubyText()) { RenderRubyBase* base = rubyBase(); RenderObject* rightNeighbour = nextSibling(); if (base && rightNeighbour && rightNeighbour->isRubyRun()) { @@ -184,7 +176,7 @@ void RenderRubyRun::removeChild(RenderObject* child) RenderBlock::removeChild(child); - if (!m_beingDestroyed && !documentBeingDestroyed()) { + if (!beingDestroyed() && !documentBeingDestroyed()) { // Check if our base (if any) is now empty. If so, destroy it. RenderBlock* base = rubyBase(); if (base && !base->firstChild()) { diff --git a/Source/WebCore/rendering/RenderRubyRun.h b/Source/WebCore/rendering/RenderRubyRun.h index d844bff..53209bc 100644 --- a/Source/WebCore/rendering/RenderRubyRun.h +++ b/Source/WebCore/rendering/RenderRubyRun.h @@ -46,8 +46,6 @@ public: RenderRubyRun(Node*); virtual ~RenderRubyRun(); - virtual void destroy(); - bool hasRubyText() const; bool hasRubyBase() const; bool isEmpty() const; @@ -75,8 +73,6 @@ private: virtual const char* renderName() const { return "RenderRubyRun (anonymous)"; } virtual bool createsAnonymousWrapper() const { return true; } virtual void removeLeftoverAnonymousBlock(RenderBlock*) { } - - bool m_beingDestroyed; }; } // namespace WebCore diff --git a/Source/WebCore/rendering/RenderScrollbarTheme.cpp b/Source/WebCore/rendering/RenderScrollbarTheme.cpp index e32d87a..87309d4 100644 --- a/Source/WebCore/rendering/RenderScrollbarTheme.cpp +++ b/Source/WebCore/rendering/RenderScrollbarTheme.cpp @@ -98,10 +98,10 @@ IntRect RenderScrollbarTheme::constrainTrackRectToTrackPieces(Scrollbar* scrollb IntRect result = rect; if (scrollbar->orientation() == HorizontalScrollbar) { result.setX(backRect.x()); - result.setWidth(forwardRect.right() - backRect.x()); + result.setWidth(forwardRect.maxX() - backRect.x()); } else { result.setY(backRect.y()); - result.setHeight(forwardRect.bottom() - backRect.y()); + result.setHeight(forwardRect.maxY() - backRect.y()); } return result; } diff --git a/Source/WebCore/rendering/RenderTable.cpp b/Source/WebCore/rendering/RenderTable.cpp index 3fc1c72..bb90e97 100644 --- a/Source/WebCore/rendering/RenderTable.cpp +++ b/Source/WebCore/rendering/RenderTable.cpp @@ -168,7 +168,7 @@ void RenderTable::addChild(RenderObject* child, RenderObject* beforeChild) if (!wrapInAnonymousSection) { // If the next renderer is actually wrapped in an anonymous table section, we need to go up and find that. - while (beforeChild && !beforeChild->isTableSection() && !beforeChild->isTableCol() && beforeChild->style()->display() != TABLE_CAPTION) + while (beforeChild && beforeChild->parent() != this) beforeChild = beforeChild->parent(); RenderBox::addChild(child, beforeChild); @@ -419,7 +419,7 @@ void RenderTable::layout() while (section) { if (!sectionMoved && section->logicalTop() != logicalHeight()) { sectionMoved = true; - movedSectionLogicalTop = min(logicalHeight(), section->logicalTop()) + (style()->isHorizontalWritingMode() ? section->topVisualOverflow() : section->leftVisualOverflow()); + movedSectionLogicalTop = min(logicalHeight(), section->logicalTop()) + (style()->isHorizontalWritingMode() ? section->minYVisualOverflow() : section->minXVisualOverflow()); } section->setLogicalLocation(sectionLogicalLeft, logicalHeight()); @@ -453,15 +453,15 @@ void RenderTable::layout() statePusher.pop(); if (view()->layoutState()->pageLogicalHeight()) - setPageLogicalOffset(view()->layoutState()->pageLogicalOffset(y())); + setPageLogicalOffset(view()->layoutState()->pageLogicalOffset(logicalTop())); bool didFullRepaint = repainter.repaintAfterLayout(); // Repaint with our new bounds if they are different from our old bounds. if (!didFullRepaint && sectionMoved) { if (style()->isHorizontalWritingMode()) - repaintRectangle(IntRect(leftVisualOverflow(), movedSectionLogicalTop, rightVisualOverflow() - leftVisualOverflow(), bottomVisualOverflow() - movedSectionLogicalTop)); + repaintRectangle(IntRect(minXVisualOverflow(), movedSectionLogicalTop, maxXVisualOverflow() - minXVisualOverflow(), maxYVisualOverflow() - movedSectionLogicalTop)); else - repaintRectangle(IntRect(movedSectionLogicalTop, topVisualOverflow(), rightVisualOverflow() - movedSectionLogicalTop, bottomVisualOverflow() - topVisualOverflow())); + repaintRectangle(IntRect(movedSectionLogicalTop, minYVisualOverflow(), maxXVisualOverflow() - movedSectionLogicalTop, maxYVisualOverflow() - minYVisualOverflow())); } setNeedsLayout(false); @@ -513,9 +513,9 @@ void RenderTable::paint(PaintInfo& paintInfo, int tx, int ty) PaintPhase paintPhase = paintInfo.phase; int os = 2 * maximalOutlineSize(paintPhase); - if (ty + topVisualOverflow() >= paintInfo.rect.bottom() + os || ty + bottomVisualOverflow() <= paintInfo.rect.y() - os) + if (ty + minYVisualOverflow() >= paintInfo.rect.maxY() + os || ty + maxYVisualOverflow() <= paintInfo.rect.y() - os) return; - if (tx + leftVisualOverflow() >= paintInfo.rect.right() + os || tx + rightVisualOverflow() <= paintInfo.rect.x() - os) + if (tx + minXVisualOverflow() >= paintInfo.rect.maxX() + os || tx + maxXVisualOverflow() <= paintInfo.rect.x() - os) return; bool pushedClip = pushContentsClip(paintInfo, tx, ty); @@ -1185,6 +1185,8 @@ int RenderTable::firstLineBoxBaseline() const if (isWritingModeRoot()) return -1; + recalcSectionsIfNeeded(); + RenderTableSection* firstNonEmptySection = m_head ? m_head : (m_firstBody ? m_firstBody : m_foot); if (firstNonEmptySection && !firstNonEmptySection->numRows()) firstNonEmptySection = sectionBelow(firstNonEmptySection, true); diff --git a/Source/WebCore/rendering/RenderTableCell.cpp b/Source/WebCore/rendering/RenderTableCell.cpp index 8549f49..1593a5c 100644 --- a/Source/WebCore/rendering/RenderTableCell.cpp +++ b/Source/WebCore/rendering/RenderTableCell.cpp @@ -276,9 +276,9 @@ IntRect RenderTableCell::clippedOverflowRectForRepaint(RenderBoxModelObject* rep right = max(right, below->borderHalfRight(true)); } } - left = max(left, -leftVisualOverflow()); - top = max(top, -topVisualOverflow()); - IntRect r(-left, - top, left + max(width() + right, rightVisualOverflow()), top + max(height() + bottom, bottomVisualOverflow())); + left = max(left, -minXVisualOverflow()); + top = max(top, -minYVisualOverflow()); + IntRect r(-left, - top, left + max(width() + right, maxXVisualOverflow()), top + max(height() + bottom, maxYVisualOverflow())); if (RenderView* v = view()) { // FIXME: layoutDelta needs to be applied in parts before/after transforms and @@ -812,8 +812,8 @@ void RenderTableCell::paint(PaintInfo& paintInfo, int tx, int ty) tx += x(); ty += y(); int os = 2 * maximalOutlineSize(paintInfo.phase); - if (ty - table()->outerBorderTop() < paintInfo.rect.bottom() + os && - ty + height() + table()->outerBorderBottom() > paintInfo.rect.y() - os) + if (ty - table()->outerBorderTop() < paintInfo.rect.maxY() + os + && ty + height() + table()->outerBorderBottom() > paintInfo.rect.y() - os) paintCollapsedBorder(paintInfo.context, tx, ty, width(), height()); return; } diff --git a/Source/WebCore/rendering/RenderTableRow.cpp b/Source/WebCore/rendering/RenderTableRow.cpp index 595e156..7300c19 100644 --- a/Source/WebCore/rendering/RenderTableRow.cpp +++ b/Source/WebCore/rendering/RenderTableRow.cpp @@ -125,7 +125,7 @@ void RenderTableRow::layout() for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { if (child->isTableCell()) { RenderTableCell* cell = toRenderTableCell(child); - if (!cell->needsLayout() && paginated && view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(cell->y()) != cell->pageLogicalOffset()) + if (!cell->needsLayout() && paginated && view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(cell->logicalTop()) != cell->pageLogicalOffset()) cell->setChildNeedsLayout(true, false); if (child->needsLayout()) { diff --git a/Source/WebCore/rendering/RenderTableSection.cpp b/Source/WebCore/rendering/RenderTableSection.cpp index 265d2ef..f20c236 100644 --- a/Source/WebCore/rendering/RenderTableSection.cpp +++ b/Source/WebCore/rendering/RenderTableSection.cpp @@ -704,7 +704,7 @@ int RenderTableSection::layoutRows(int toAdd) if (intrinsicPaddingBefore != oldIntrinsicPaddingBefore || intrinsicPaddingAfter != oldIntrinsicPaddingAfter) cell->setNeedsLayout(true, false); - if (!cell->needsLayout() && view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(cell->y()) != cell->pageLogicalOffset()) + if (!cell->needsLayout() && view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(cell->logicalTop()) != cell->pageLogicalOffset()) cell->setChildNeedsLayout(true, false); cell->layoutIfNeeded(); @@ -1068,9 +1068,9 @@ void RenderTableSection::paintObject(PaintInfo& paintInfo, int tx, int ty) localRepaintRect.move(-tx, -ty); if (style()->isFlippedBlocksWritingMode()) { if (style()->isHorizontalWritingMode()) - localRepaintRect.setY(height() - localRepaintRect.bottom()); + localRepaintRect.setY(height() - localRepaintRect.maxY()); else - localRepaintRect.setX(width() - localRepaintRect.right()); + localRepaintRect.setX(width() - localRepaintRect.maxX()); } // If some cell overflows, just paint all of them. @@ -1085,7 +1085,7 @@ void RenderTableSection::paintObject(PaintInfo& paintInfo, int tx, int ty) if (startrow == m_rowPos.size() || (startrow > 0 && (m_rowPos[startrow] > before))) --startrow; - int after = (style()->isHorizontalWritingMode() ? localRepaintRect.bottom() : localRepaintRect.right()) + os; + int after = (style()->isHorizontalWritingMode() ? localRepaintRect.maxY() : localRepaintRect.maxX()) + os; endrow = std::lower_bound(m_rowPos.begin(), m_rowPos.end(), after) - m_rowPos.begin(); if (endrow == m_rowPos.size()) --endrow; @@ -1104,7 +1104,7 @@ void RenderTableSection::paintObject(PaintInfo& paintInfo, int tx, int ty) if ((startcol == columnPos.size()) || (startcol > 0 && (columnPos[startcol] > start))) --startcol; - int end = (style()->isHorizontalWritingMode() ? localRepaintRect.right() : localRepaintRect.bottom()) + os; + int end = (style()->isHorizontalWritingMode() ? localRepaintRect.maxX() : localRepaintRect.maxY()) + os; endcol = std::lower_bound(columnPos.begin(), columnPos.end(), end) - columnPos.begin(); if (endcol == columnPos.size()) --endcol; diff --git a/Source/WebCore/rendering/RenderText.cpp b/Source/WebCore/rendering/RenderText.cpp index 86b32d5..1b05af2 100644 --- a/Source/WebCore/rendering/RenderText.cpp +++ b/Source/WebCore/rendering/RenderText.cpp @@ -26,7 +26,6 @@ #include "RenderText.h" #include "AXObjectCache.h" -#include "CharacterNames.h" #include "EllipsisBox.h" #include "FloatQuad.h" #include "FontTranscoder.h" @@ -35,6 +34,7 @@ #include "Range.h" #include "RenderArena.h" #include "RenderBlock.h" +#include "RenderCombineText.h" #include "RenderLayer.h" #include "RenderView.h" #include "Text.h" @@ -45,6 +45,7 @@ #include "break_lines.h" #include <wtf/AlwaysInline.h> #include <wtf/text/StringBuffer.h> +#include <wtf/unicode/CharacterNames.h> using namespace std; using namespace WTF; @@ -345,8 +346,12 @@ void RenderText::absoluteQuads(Vector<FloatQuad>& quads, ClippingOption option) // Shorten the width of this text box if it ends in an ellipsis. IntRect ellipsisRect = (option == ClipToEllipsis) ? ellipsisRectForBox(box, 0, textLength()) : IntRect(); - if (!ellipsisRect.isEmpty()) - boundaries.setWidth(ellipsisRect.right() - boundaries.x()); + if (!ellipsisRect.isEmpty()) { + if (style()->isHorizontalWritingMode()) + boundaries.setWidth(ellipsisRect.maxX() - boundaries.x()); + else + boundaries.setHeight(ellipsisRect.maxY() - boundaries.y()); + } quads.append(localToAbsoluteQuad(FloatRect(boundaries))); } } @@ -374,8 +379,13 @@ void RenderText::absoluteQuadsForRange(Vector<FloatQuad>& quads, unsigned start, IntRect r(box->calculateBoundaries()); if (useSelectionHeight) { IntRect selectionRect = box->selectionRect(0, 0, start, end); - r.setHeight(selectionRect.height()); - r.setY(selectionRect.y()); + if (box->isHorizontal()) { + r.setHeight(selectionRect.height()); + r.setY(selectionRect.y()); + } else { + r.setWidth(selectionRect.width()); + r.setX(selectionRect.x()); + } } quads.append(localToAbsoluteQuad(FloatRect(r))); } else { @@ -384,8 +394,13 @@ void RenderText::absoluteQuadsForRange(Vector<FloatQuad>& quads, unsigned start, if (r.height()) { if (!useSelectionHeight) { // change the height and y position because selectionRect uses selection-specific values - r.setHeight(box->logicalHeight()); - r.setY(box->y()); + if (box->isHorizontal()) { + r.setHeight(box->logicalHeight()); + r.setY(box->y()); + } else { + r.setWidth(box->logicalHeight()); + r.setX(box->x()); + } } quads.append(localToAbsoluteQuad(FloatRect(r))); } @@ -547,6 +562,12 @@ IntRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, int* e ALWAYS_INLINE int RenderText::widthFromCache(const Font& f, int start, int len, int xPos, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const { + if (style()->hasTextCombine()) { + const RenderCombineText* combineText = toRenderCombineText(this); + if (combineText->isCombined()) + return combineText->combinedTextWidth(f); + } + if (f.isFixedPitch() && !f.isSmallCaps() && m_isAllASCII) { int monospaceCharacterWidth = f.spaceWidth(); int tabWidth = allowTabs() ? monospaceCharacterWidth * 8 : 0; diff --git a/Source/WebCore/rendering/RenderTextControl.cpp b/Source/WebCore/rendering/RenderTextControl.cpp index cac8113..72b20ec 100644 --- a/Source/WebCore/rendering/RenderTextControl.cpp +++ b/Source/WebCore/rendering/RenderTextControl.cpp @@ -23,7 +23,6 @@ #include "RenderTextControl.h" #include "AXObjectCache.h" -#include "CharacterNames.h" #include "Editor.h" #include "Event.h" #include "EventNames.h" @@ -42,6 +41,7 @@ #include "TextControlInnerElements.h" #include "TextIterator.h" #include "TextRun.h" +#include <wtf/unicode/CharacterNames.h> using namespace std; @@ -146,7 +146,7 @@ void RenderTextControl::createSubtreeIfNeeded(TextControlInnerElement* innerBloc // For non-search fields, there is no intermediate innerBlock as the shadow node. // m_innerText will be the shadow node in that case. RenderStyle* parentStyle = innerBlock ? innerBlock->renderer()->style() : style(); - m_innerText = TextControlInnerTextElement::create(document(), innerBlock ? 0 : static_cast<HTMLElement*>(node())); + m_innerText = TextControlInnerTextElement::create(document(), innerBlock ? 0 : toHTMLElement(node())); m_innerText->attachInnerElement(innerBlock ? innerBlock : node(), createInnerTextStyle(parentStyle), renderArena()); } } @@ -544,7 +544,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, false, false, false)); + return style()->font().floatWidth(TextRun(&ch, 1, false, 0, 0, TextRun::AllowTrailingExpansion, false, false, false)); } float RenderTextControl::scaleEmToUnits(int x) const @@ -639,12 +639,12 @@ 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(), 0, 0, 0, !placeholderStyle->isLeftToRightDirection(), placeholderStyle->unicodeBidi() == Override, false, false); + TextRun textRun(placeholderText.characters(), placeholderText.length(), false, 0, 0, TextRun::AllowTrailingExpansion, !placeholderStyle->isLeftToRightDirection(), placeholderStyle->unicodeBidi() == Override, false, false); RenderBox* textRenderer = innerTextElement() ? innerTextElement()->renderBox() : 0; if (textRenderer) { IntPoint textPoint; - textPoint.setY(ty + textBlockInsetTop() + placeholderStyle->font().ascent()); + textPoint.setY(ty + textBlockInsetTop() + placeholderStyle->fontMetrics().ascent()); if (placeholderStyle->isLeftToRightDirection()) textPoint.setX(tx + textBlockInsetLeft()); else diff --git a/Source/WebCore/rendering/RenderTextControlMultiLine.cpp b/Source/WebCore/rendering/RenderTextControlMultiLine.cpp index d0b0cbc..cf32f68 100644 --- a/Source/WebCore/rendering/RenderTextControlMultiLine.cpp +++ b/Source/WebCore/rendering/RenderTextControlMultiLine.cpp @@ -41,7 +41,7 @@ RenderTextControlMultiLine::RenderTextControlMultiLine(Node* node, bool placehol RenderTextControlMultiLine::~RenderTextControlMultiLine() { - if (node()) + if (node() && node()->inDocument()) static_cast<HTMLTextAreaElement*>(node())->rendererWillBeDestroyed(); } diff --git a/Source/WebCore/rendering/RenderTextControlSingleLine.cpp b/Source/WebCore/rendering/RenderTextControlSingleLine.cpp index 95f209a..de8fb0d 100644 --- a/Source/WebCore/rendering/RenderTextControlSingleLine.cpp +++ b/Source/WebCore/rendering/RenderTextControlSingleLine.cpp @@ -397,7 +397,7 @@ void RenderTextControlSingleLine::forwardEvent(Event* event) #endif FloatPoint localPoint = innerTextRenderer->absoluteToLocal(static_cast<MouseEvent*>(event)->absoluteLocation(), false, true); - int textRight = innerTextRenderer->borderBoxRect().right(); + int textRight = innerTextRenderer->borderBoxRect().maxX(); if (m_resultsButton && localPoint.x() < innerTextRenderer->borderBoxRect().x()) m_resultsButton->defaultEventHandler(event); @@ -564,9 +564,6 @@ int RenderTextControlSingleLine::preferredContentWidth(float charWidth) const result += cancelRenderer->borderLeft() + cancelRenderer->borderRight() + cancelRenderer->paddingLeft() + cancelRenderer->paddingRight(); - if (RenderBox* spinRenderer = m_innerSpinButton ? m_innerSpinButton->renderBox() : 0) - result += spinRenderer->minPreferredLogicalWidth(); - #if ENABLE(INPUT_SPEECH) if (RenderBox* speechRenderer = m_speechButton ? m_speechButton->renderBox() : 0) { result += speechRenderer->borderLeft() + speechRenderer->borderRight() + @@ -618,17 +615,17 @@ void RenderTextControlSingleLine::createSubtreeIfNeeded() #if ENABLE(INPUT_SPEECH) if (inputElement()->isSpeechEnabled() && !m_speechButton) { // Create the speech button element. - m_speechButton = InputFieldSpeechButtonElement::create(static_cast<HTMLElement*>(node())); + 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(static_cast<HTMLElement*>(node())); + m_innerSpinButton = SpinButtonElement::create(toHTMLElement(node())); m_innerSpinButton->attachInnerElement(node(), createInnerSpinButtonStyle(), renderArena()); } if (hasSpinButton && !m_outerSpinButton) { - m_outerSpinButton = SpinButtonElement::create(static_cast<HTMLElement*>(node())); + m_outerSpinButton = SpinButtonElement::create(toHTMLElement(node())); m_outerSpinButton->attachInnerElement(node(), createOuterSpinButtonStyle(), renderArena()); } return; @@ -636,18 +633,18 @@ void RenderTextControlSingleLine::createSubtreeIfNeeded() if (!m_innerBlock) { // Create the inner block element - m_innerBlock = TextControlInnerElement::create(static_cast<HTMLElement*>(node())); + 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(static_cast<HTMLElement*>(node())); + m_speechButton = InputFieldSpeechButtonElement::create(toHTMLElement(node())); m_speechButton->attachInnerElement(node(), createSpeechButtonStyle(), renderArena()); } #endif if (inputElement()->hasSpinButton() && !m_outerSpinButton) { - m_outerSpinButton = SpinButtonElement::create(static_cast<HTMLElement*>(node())); + m_outerSpinButton = SpinButtonElement::create(toHTMLElement(node())); m_outerSpinButton->attachInnerElement(node(), createOuterSpinButtonStyle(), renderArena()); } @@ -687,7 +684,7 @@ void RenderTextControlSingleLine::updateFromElement() // flag is false. It protects an unacceptable renderer value from // being overwritten with the DOM value. if (!static_cast<HTMLInputElement*>(node())->formControlValueMatchesRenderer()) - setInnerTextValue(inputElement()->value()); + setInnerTextValue(inputElement()->visibleValue()); } } @@ -712,7 +709,7 @@ PassRefPtr<RenderStyle> RenderTextControlSingleLine::createInnerTextStyle(const textBlockStyle->setOverflowY(OHIDDEN); // Do not allow line-height to be smaller than our default. - if (textBlockStyle->font().lineSpacing() > lineHeight(true, HorizontalLine, PositionOfInteriorLineBoxes)) + if (textBlockStyle->fontMetrics().lineSpacing() > lineHeight(true, HorizontalLine, PositionOfInteriorLineBoxes)) textBlockStyle->setLineHeight(Length(-100.0f, Percent)); WebCore::EDisplay display = (m_innerBlock || inputElement()->hasSpinButton() ? INLINE_BLOCK : BLOCK); @@ -931,7 +928,7 @@ PopupMenuStyle RenderTextControlSingleLine::itemStyle(unsigned) const PopupMenuStyle RenderTextControlSingleLine::menuStyle() const { - return PopupMenuStyle(style()->visitedDependentColor(CSSPropertyColor), style()->visitedDependentColor(CSSPropertyBackgroundColor), style()->font(), style()->visibility() == VISIBLE, style()->display() == NONE, style()->textIndent(), style()->direction()); + return PopupMenuStyle(style()->visitedDependentColor(CSSPropertyColor), style()->visitedDependentColor(CSSPropertyBackgroundColor), style()->font(), style()->visibility() == VISIBLE, style()->display() == NONE, style()->textIndent(), style()->direction(), style()->unicodeBidi() == Override); } int RenderTextControlSingleLine::clientInsetLeft() const diff --git a/Source/WebCore/rendering/RenderTheme.h b/Source/WebCore/rendering/RenderTheme.h index 13c69e6..e2b9c78 100644 --- a/Source/WebCore/rendering/RenderTheme.h +++ b/Source/WebCore/rendering/RenderTheme.h @@ -180,6 +180,7 @@ public: // Media controls virtual bool hitTestMediaControlPart(RenderObject*, const IntPoint& absPoint); virtual bool shouldRenderMediaControlPart(ControlPart, Element*); + virtual bool usesMediaControlStatusDisplay() { return false; } virtual double mediaControlsFadeInDuration() { return 0.1; } virtual double mediaControlsFadeOutDuration() { return 0.3; } virtual String formatMediaControlsTime(float time) const; @@ -194,6 +195,8 @@ public: virtual IntSize meterSizeForBounds(const RenderMeter*, const IntRect&) const; virtual bool supportsMeter(ControlPart, bool isHorizontal) const; #endif + + virtual bool shouldShowPlaceholderWhenFocused() const { return false; } protected: // The platform selection color. diff --git a/Source/WebCore/rendering/RenderThemeChromiumMac.h b/Source/WebCore/rendering/RenderThemeChromiumMac.h index d1875fc..80bbae4 100644 --- a/Source/WebCore/rendering/RenderThemeChromiumMac.h +++ b/Source/WebCore/rendering/RenderThemeChromiumMac.h @@ -46,6 +46,7 @@ protected: virtual bool paintMediaVolumeSliderTrack(RenderObject*, const PaintInfo&, const IntRect&); virtual bool paintMediaVolumeSliderThumb(RenderObject*, const PaintInfo&, const IntRect&); virtual IntPoint volumeSliderOffsetFromMuteButton(Node*, const IntSize&) const; + virtual bool usesMediaControlStatusDisplay() { return false; } #endif diff --git a/Source/WebCore/rendering/RenderThemeChromiumWin.cpp b/Source/WebCore/rendering/RenderThemeChromiumWin.cpp index bba0520..d538050 100644 --- a/Source/WebCore/rendering/RenderThemeChromiumWin.cpp +++ b/Source/WebCore/rendering/RenderThemeChromiumWin.cpp @@ -479,15 +479,15 @@ bool RenderThemeChromiumWin::paintMenuList(RenderObject* o, const PaintInfo& i, int spacingBottom = borderBottom + box->paddingBottom(); int buttonX; - if (r.right() - r.x() < buttonWidth) + if (r.maxX() - r.x() < buttonWidth) buttonX = r.x(); else - buttonX = o->style()->direction() == LTR ? r.right() - spacingRight - buttonWidth : r.x() + spacingLeft; + buttonX = o->style()->direction() == LTR ? r.maxX() - spacingRight - buttonWidth : r.x() + spacingLeft; // Compute the rectangle of the button in the destination image. IntRect rect(buttonX, r.y() + spacingTop, - std::min(buttonWidth, r.right() - r.x()), + std::min(buttonWidth, r.maxX() - r.x()), r.height() - (spacingTop + spacingBottom)); // Get the correct theme data for a textfield and paint the menu. diff --git a/Source/WebCore/rendering/RenderThemeMac.h b/Source/WebCore/rendering/RenderThemeMac.h index 95661b8..9837c2a 100644 --- a/Source/WebCore/rendering/RenderThemeMac.h +++ b/Source/WebCore/rendering/RenderThemeMac.h @@ -164,9 +164,12 @@ protected: virtual String extraMediaControlsStyleSheet(); virtual bool shouldRenderMediaControlPart(ControlPart, Element*); + virtual bool usesMediaControlStatusDisplay(); virtual void adjustMediaSliderThumbSize(RenderObject*) const; virtual IntPoint volumeSliderOffsetFromMuteButton(Node*, const IntSize&) const; #endif + + virtual bool shouldShowPlaceholderWhenFocused() const; private: diff --git a/Source/WebCore/rendering/RenderThemeMac.mm b/Source/WebCore/rendering/RenderThemeMac.mm index 605e958..e3c75c5 100644 --- a/Source/WebCore/rendering/RenderThemeMac.mm +++ b/Source/WebCore/rendering/RenderThemeMac.mm @@ -1041,20 +1041,20 @@ void RenderThemeMac::paintMenuListButtonGradients(RenderObject* o, const PaintIn FloatRect topGradient(r.x(), r.y(), r.width(), r.height() / 2.0f); struct CGFunctionCallbacks topCallbacks = { 0, TopGradientInterpolate, NULL }; RetainPtr<CGFunctionRef> topFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &topCallbacks)); - RetainPtr<CGShadingRef> topShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(topGradient.x(), topGradient.y()), CGPointMake(topGradient.x(), topGradient.bottom()), topFunction.get(), false, false)); + RetainPtr<CGShadingRef> topShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(topGradient.x(), topGradient.y()), CGPointMake(topGradient.x(), topGradient.maxY()), topFunction.get(), false, false)); FloatRect bottomGradient(r.x() + radius, r.y() + r.height() / 2.0f, r.width() - 2.0f * radius, r.height() / 2.0f); struct CGFunctionCallbacks bottomCallbacks = { 0, BottomGradientInterpolate, NULL }; RetainPtr<CGFunctionRef> bottomFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &bottomCallbacks)); - RetainPtr<CGShadingRef> bottomShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(bottomGradient.x(), bottomGradient.y()), CGPointMake(bottomGradient.x(), bottomGradient.bottom()), bottomFunction.get(), false, false)); + RetainPtr<CGShadingRef> bottomShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(bottomGradient.x(), bottomGradient.y()), CGPointMake(bottomGradient.x(), bottomGradient.maxY()), bottomFunction.get(), false, false)); struct CGFunctionCallbacks mainCallbacks = { 0, MainGradientInterpolate, NULL }; RetainPtr<CGFunctionRef> mainFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks)); - RetainPtr<CGShadingRef> mainShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(r.x(), r.y()), CGPointMake(r.x(), r.bottom()), mainFunction.get(), false, false)); + RetainPtr<CGShadingRef> mainShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(r.x(), r.y()), CGPointMake(r.x(), r.maxY()), mainFunction.get(), false, false)); RetainPtr<CGShadingRef> leftShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(r.x(), r.y()), CGPointMake(r.x() + radius, r.y()), mainFunction.get(), false, false)); - RetainPtr<CGShadingRef> rightShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(r.right(), r.y()), CGPointMake(r.right() - radius, r.y()), mainFunction.get(), false, false)); + RetainPtr<CGShadingRef> rightShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(r.maxX(), r.y()), CGPointMake(r.maxX() - radius, r.y()), mainFunction.get(), false, false)); paintInfo.context->save(); CGContextClipToRect(context, r); paintInfo.context->addRoundedRectClip(border); @@ -1099,7 +1099,7 @@ bool RenderThemeMac::paintMenuListButton(RenderObject* o, const PaintInfo& paint float centerY = bounds.y() + bounds.height() / 2.0f; float arrowHeight = baseArrowHeight * fontScale; float arrowWidth = baseArrowWidth * fontScale; - float leftEdge = bounds.right() - arrowPaddingRight * o->style()->effectiveZoom() - arrowWidth; + float leftEdge = bounds.maxX() - arrowPaddingRight * o->style()->effectiveZoom() - arrowWidth; float spaceBetweenArrows = baseSpaceBetweenArrows * fontScale; if (bounds.width() < arrowWidth + arrowPaddingLeft * o->style()->effectiveZoom()) @@ -1138,11 +1138,11 @@ bool RenderThemeMac::paintMenuListButton(RenderObject* o, const PaintInfo& paint paintInfo.context->setStrokeStyle(SolidStroke); paintInfo.context->setStrokeColor(leftSeparatorColor, ColorSpaceDeviceRGB); paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator, bounds.y()), - IntPoint(leftEdgeOfSeparator, bounds.bottom())); + IntPoint(leftEdgeOfSeparator, bounds.maxY())); paintInfo.context->setStrokeColor(rightSeparatorColor, ColorSpaceDeviceRGB); paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.y()), - IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.bottom())); + IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.maxY())); paintInfo.context->restore(); return false; @@ -1293,9 +1293,9 @@ bool RenderThemeMac::paintSliderTrack(RenderObject* o, const PaintInfo& paintInf RetainPtr<CGFunctionRef> mainFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks)); RetainPtr<CGShadingRef> mainShading; if (o->style()->appearance() == SliderVerticalPart) - mainShading.adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bounds.x(), bounds.bottom()), CGPointMake(bounds.right(), bounds.bottom()), mainFunction.get(), false, false)); + mainShading.adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bounds.x(), bounds.maxY()), CGPointMake(bounds.maxX(), bounds.maxY()), mainFunction.get(), false, false)); else - mainShading.adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bounds.x(), bounds.y()), CGPointMake(bounds.x(), bounds.bottom()), mainFunction.get(), false, false)); + mainShading.adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bounds.x(), bounds.y()), CGPointMake(bounds.x(), bounds.maxY()), mainFunction.get(), false, false)); IntSize radius(trackRadius, trackRadius); paintInfo.context->addRoundedRectClip(RoundedIntRect(bounds, radius, radius, radius, radius)); @@ -1981,6 +1981,11 @@ bool RenderThemeMac::shouldRenderMediaControlPart(ControlPart part, Element* ele return RenderTheme::shouldRenderMediaControlPart(part, element); } +bool RenderThemeMac::usesMediaControlStatusDisplay() +{ + return mediaControllerTheme() == MediaControllerThemeQuickTime; +} + IntPoint RenderThemeMac::volumeSliderOffsetFromMuteButton(Node* muteButton, const IntSize& size) const { static const int xOffset = -4; @@ -1994,6 +1999,15 @@ IntPoint RenderThemeMac::volumeSliderOffsetFromMuteButton(Node* muteButton, cons return IntPoint(xOffset * zoomLevel, y); } +bool RenderThemeMac::shouldShowPlaceholderWhenFocused() const +{ +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) + return true; +#else + return false; +#endif +} + #endif // ENABLE(VIDEO) NSPopUpButtonCell* RenderThemeMac::popupButton() const diff --git a/Source/WebCore/rendering/RenderThemeSafari.cpp b/Source/WebCore/rendering/RenderThemeSafari.cpp index 47f627e..a2f9ed1 100644 --- a/Source/WebCore/rendering/RenderThemeSafari.cpp +++ b/Source/WebCore/rendering/RenderThemeSafari.cpp @@ -760,20 +760,20 @@ void RenderThemeSafari::paintMenuListButtonGradients(RenderObject* o, const Pain FloatRect topGradient(r.x(), r.y(), r.width(), r.height() / 2.0f); struct CGFunctionCallbacks topCallbacks = { 0, TopGradientInterpolate, NULL }; RetainPtr<CGFunctionRef> topFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &topCallbacks)); - RetainPtr<CGShadingRef> topShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(topGradient.x(), topGradient.y()), CGPointMake(topGradient.x(), topGradient.bottom()), topFunction.get(), false, false)); + RetainPtr<CGShadingRef> topShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(topGradient.x(), topGradient.y()), CGPointMake(topGradient.x(), topGradient.maxY()), topFunction.get(), false, false)); FloatRect bottomGradient(r.x() + radius, r.y() + r.height() / 2.0f, r.width() - 2.0f * radius, r.height() / 2.0f); struct CGFunctionCallbacks bottomCallbacks = { 0, BottomGradientInterpolate, NULL }; RetainPtr<CGFunctionRef> bottomFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &bottomCallbacks)); - RetainPtr<CGShadingRef> bottomShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(bottomGradient.x(), bottomGradient.y()), CGPointMake(bottomGradient.x(), bottomGradient.bottom()), bottomFunction.get(), false, false)); + RetainPtr<CGShadingRef> bottomShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(bottomGradient.x(), bottomGradient.y()), CGPointMake(bottomGradient.x(), bottomGradient.maxY()), bottomFunction.get(), false, false)); struct CGFunctionCallbacks mainCallbacks = { 0, MainGradientInterpolate, NULL }; RetainPtr<CGFunctionRef> mainFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks)); - RetainPtr<CGShadingRef> mainShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(r.x(), r.y()), CGPointMake(r.x(), r.bottom()), mainFunction.get(), false, false)); + RetainPtr<CGShadingRef> mainShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(r.x(), r.y()), CGPointMake(r.x(), r.maxY()), mainFunction.get(), false, false)); RetainPtr<CGShadingRef> leftShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(r.x(), r.y()), CGPointMake(r.x() + radius, r.y()), mainFunction.get(), false, false)); - RetainPtr<CGShadingRef> rightShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(r.right(), r.y()), CGPointMake(r.right() - radius, r.y()), mainFunction.get(), false, false)); + RetainPtr<CGShadingRef> rightShading(AdoptCF, CGShadingCreateAxial(cspace, CGPointMake(r.maxX(), r.y()), CGPointMake(r.maxX() - radius, r.y()), mainFunction.get(), false, false)); paintInfo.context->save(); CGContextClipToRect(context, bound.rect()); paintInfo.context->addRoundedRectClip(bound); @@ -818,7 +818,7 @@ bool RenderThemeSafari::paintMenuListButton(RenderObject* o, const PaintInfo& pa float centerY = bounds.y() + bounds.height() / 2.0f; float arrowHeight = baseArrowHeight * fontScale; float arrowWidth = baseArrowWidth * fontScale; - float leftEdge = bounds.right() - arrowPaddingRight - arrowWidth; + float leftEdge = bounds.maxX() - arrowPaddingRight - arrowWidth; if (bounds.width() < arrowWidth + arrowPaddingLeft) return false; @@ -848,11 +848,11 @@ bool RenderThemeSafari::paintMenuListButton(RenderObject* o, const PaintInfo& pa paintInfo.context->setStrokeStyle(SolidStroke); paintInfo.context->setStrokeColor(leftSeparatorColor, ColorSpaceDeviceRGB); paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator, bounds.y()), - IntPoint(leftEdgeOfSeparator, bounds.bottom())); + IntPoint(leftEdgeOfSeparator, bounds.maxY())); paintInfo.context->setStrokeColor(rightSeparatorColor, ColorSpaceDeviceRGB); paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.y()), - IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.bottom())); + IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.maxY())); paintInfo.context->restore(); return false; @@ -976,9 +976,9 @@ bool RenderThemeSafari::paintSliderTrack(RenderObject* o, const PaintInfo& paint RetainPtr<CGFunctionRef> mainFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks)); RetainPtr<CGShadingRef> mainShading; if (o->style()->appearance() == SliderVerticalPart) - mainShading.adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bounds.rect().x(), bounds.rect().bottom()), CGPointMake(bounds.rect().right(), bounds.rect().bottom()), mainFunction.get(), false, false)); + mainShading.adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bounds.rect().x(), bounds.rect().maxY()), CGPointMake(bounds.rect().maxX(), bounds.rect().maxY()), mainFunction.get(), false, false)); else - mainShading.adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bounds.rect().x(), bounds.rect().y()), CGPointMake(bounds.rect().x(), bounds.rect().bottom()), mainFunction.get(), false, false)); + mainShading.adoptCF(CGShadingCreateAxial(cspace, CGPointMake(bounds.rect().x(), bounds.rect().y()), CGPointMake(bounds.rect().x(), bounds.rect().maxY()), mainFunction.get(), false, false)); paintInfo.context->addRoundedRectClip(bounds); CGContextDrawShading(context, mainShading.get()); diff --git a/Source/WebCore/rendering/RenderThemeWin.cpp b/Source/WebCore/rendering/RenderThemeWin.cpp index f0f8268..5581db8 100644 --- a/Source/WebCore/rendering/RenderThemeWin.cpp +++ b/Source/WebCore/rendering/RenderThemeWin.cpp @@ -27,6 +27,7 @@ #include "Frame.h" #include "GraphicsContext.h" #include "LocalWindowsContext.h" +#include "PaintInfo.h" #include "RenderSlider.h" #include "Settings.h" #include "SoftLinking.h" @@ -694,7 +695,7 @@ bool RenderThemeWin::paintInnerSpinButton(RenderObject* o, const PaintInfo& i, c IntRect upRect(r); upRect.setHeight(r.height() / 2); IntRect downRect(r); - downRect.setY(upRect.bottom()); + downRect.setY(upRect.maxY()); downRect.setHeight(r.height() - upRect.height()); drawControl(i.context, o, spinButtonTheme(), getThemeData(o, SpinButtonUp), upRect); drawControl(i.context, o, spinButtonTheme(), getThemeData(o, SpinButtonDown), downRect); @@ -769,7 +770,7 @@ void RenderThemeWin::adjustMenuListButtonStyle(CSSStyleSelector* selector, Rende style->setHeight(Length(Auto)); // Calculate our min-height - int minHeight = style->font().height(); + int minHeight = style->fontMetrics().height(); minHeight = max(minHeight, dropDownBoxMinHeight); style->setMinHeight(Length(minHeight, Fixed)); @@ -788,7 +789,7 @@ bool RenderThemeWin::paintMenuListButton(RenderObject* o, const PaintInfo& i, co IntRect buttonRect(r); buttonRect.inflate(-borderThickness); if (o->style()->direction() == LTR) - buttonRect.setX(buttonRect.right() - dropDownButtonWidth); + buttonRect.setX(buttonRect.maxX() - dropDownButtonWidth); buttonRect.setWidth(dropDownButtonWidth); if (isRunningOnVistaOrLater()) { diff --git a/Source/WebCore/rendering/RenderThemeWinCE.cpp b/Source/WebCore/rendering/RenderThemeWinCE.cpp index d4bff96..a56ab3e 100644 --- a/Source/WebCore/rendering/RenderThemeWinCE.cpp +++ b/Source/WebCore/rendering/RenderThemeWinCE.cpp @@ -250,7 +250,7 @@ bool RenderThemeWinCE::paintMenuList(RenderObject* o, const PaintInfo& i, const bool RenderThemeWinCE::paintMenuListButton(RenderObject* o, const PaintInfo& i, const IntRect& r) { - IntRect buttonRect(r.right() - dropDownButtonWidth - 1, r.y(), dropDownButtonWidth, r.height()); + IntRect buttonRect(r.maxX() - dropDownButtonWidth - 1, r.y(), dropDownButtonWidth, r.height()); buttonRect.inflateY(-1); i.context->drawFrameControl(buttonRect, DFC_SCROLL, DFCS_SCROLLCOMBOBOX | determineClassicState(o)); return true; @@ -386,7 +386,7 @@ bool RenderThemeWinCE::paintSearchFieldCancelButton(RenderObject* o, const Paint IntRect xBounds(cancelBounds.location() + IntSize(3, 3), xSize); paintInfo.context->setStrokeColor(Color::white, ColorSpaceDeviceRGB); paintInfo.context->drawLine(xBounds.location(), xBounds.location() + xBounds.size()); - paintInfo.context->drawLine(IntPoint(xBounds.right(), xBounds.y()), IntPoint(xBounds.x(), xBounds.bottom())); + paintInfo.context->drawLine(IntPoint(xBounds.maxX(), xBounds.y()), IntPoint(xBounds.x(), xBounds.maxY())); paintInfo.context->restore(); return false; @@ -452,7 +452,7 @@ void RenderThemeWinCE::adjustMenuListButtonStyle(CSSStyleSelector* selector, Ren style->setHeight(Length(Auto)); // Calculate our min-height - int minHeight = style->font().height(); + int minHeight = style->fontMetrics().height(); minHeight = max(minHeight, dropDownBoxMinHeight); style->setMinHeight(Length(minHeight, Fixed)); @@ -489,7 +489,7 @@ static HTMLMediaElement* mediaElementParent(Node* node) bool RenderThemeWinCE::paintSliderTrack(RenderObject* o, const PaintInfo& i, const IntRect& r) { bool rc = RenderTheme::paintSliderTrack(o, i, r); - IntPoint left = IntPoint(r.x() + 2, (r.y() + r.bottom()) / 2); + IntPoint left = IntPoint(r.x() + 2, (r.y() + r.maxY()) / 2); i.context->save(); i.context->setStrokeColor(Color::gray, ColorSpaceDeviceRGB); i.context->setFillColor(Color::gray, ColorSpaceDeviceRGB); @@ -498,13 +498,13 @@ bool RenderThemeWinCE::paintSliderTrack(RenderObject* o, const PaintInfo& i, con HTMLMediaElement* mediaElement = mediaElementParent(o->node()); if (mediaElement) { i.context->setStrokeColor(Color(0, 0xff, 0)); - IntPoint right = IntPoint(left.x() + mediaElement->percentLoaded() * (r.right() - r.x() - 4), (r.y() + r.bottom()) / 2); + IntPoint right = IntPoint(left.x() + mediaElement->percentLoaded() * (r.maxX() - r.x() - 4), (r.y() + r.maxY()) / 2); i.context->drawLine(left, right); left = right; } #endif i.context->setStrokeColor(Color::black, ColorSpaceDeviceRGB); - i.context->drawLine(left, IntPoint(r.right() - 2, left.y())); + i.context->drawLine(left, IntPoint(r.maxX() - 2, left.y())); i.context->restore(); return rc; } @@ -566,14 +566,14 @@ bool RenderThemeWinCE::paintMediaMuteButton(RenderObject* o, const PaintInfo& pa FloatPoint pts[6] = { FloatPoint(imRect.x() + 1, imRect.y() + imRect.height() / 3.0), FloatPoint(imRect.x() + 1 + imRect.width() / 2.0, imRect.y() + imRect.height() / 3.0), - FloatPoint(imRect.right() - 1, imRect.y()), - FloatPoint(imRect.right() - 1, imRect.bottom()), + FloatPoint(imRect.maxX() - 1, imRect.y()), + FloatPoint(imRect.maxX() - 1, imRect.maxY()), FloatPoint(imRect.x() + 1 + imRect.width() / 2.0, imRect.y() + 2.0 * imRect.height() / 3.0), FloatPoint(imRect.x() + 1, imRect.y() + 2.0 * imRect.height() / 3.0) }; paintInfo.context->drawConvexPolygon(6, pts); if (muted) - paintInfo.context->drawLine(IntPoint(imRect.right(), imRect.y()), IntPoint(imRect.x(), imRect.bottom())); + paintInfo.context->drawLine(IntPoint(imRect.maxX(), imRect.y()), IntPoint(imRect.x(), imRect.maxY())); paintInfo.context->restore(); return rc; } @@ -595,7 +595,7 @@ bool RenderThemeWinCE::paintMediaPlayButton(RenderObject* o, const PaintInfo& pa imRect.move(2.0 * width / 3.0, 0); paintInfo.context->fillRect(imRect); } else { - FloatPoint pts[3] = { FloatPoint(imRect.x(), imRect.y()), FloatPoint(imRect.right(), (imRect.y() + imRect.bottom()) / 2.0), FloatPoint(imRect.x(), imRect.bottom()) }; + FloatPoint pts[3] = { FloatPoint(imRect.x(), imRect.y()), FloatPoint(imRect.maxX(), (imRect.y() + imRect.maxY()) / 2.0), FloatPoint(imRect.x(), imRect.maxY()) }; paintInfo.context->drawConvexPolygon(3, pts); } paintInfo.context->restore(); @@ -607,8 +607,8 @@ bool RenderThemeWinCE::paintMediaSeekBackButton(RenderObject* o, const PaintInfo bool rc = paintButton(o, paintInfo, r); FloatRect imRect = r; imRect.inflate(-3); - FloatPoint pts[3] = { FloatPoint((imRect.x() + imRect.right()) / 2.0, imRect.y()), FloatPoint(imRect.x(), (imRect.y() + imRect.bottom()) / 2.0), FloatPoint((imRect.x() + imRect.right()) / 2.0, imRect.bottom()) }; - FloatPoint pts2[3] = { FloatPoint(imRect.right(), imRect.y()), FloatPoint((imRect.x() + imRect.right()) / 2.0, (imRect.y() + imRect.bottom()) / 2.0), FloatPoint(imRect.right(), imRect.bottom()) }; + FloatPoint pts[3] = { FloatPoint((imRect.x() + imRect.maxX()) / 2.0, imRect.y()), FloatPoint(imRect.x(), (imRect.y() + imRect.maxY()) / 2.0), FloatPoint((imRect.x() + imRect.maxX()) / 2.0, imRect.maxY()) }; + FloatPoint pts2[3] = { FloatPoint(imRect.maxX(), imRect.y()), FloatPoint((imRect.x() + imRect.maxX()) / 2.0, (imRect.y() + imRect.maxY()) / 2.0), FloatPoint(imRect.maxX(), imRect.maxY()) }; paintInfo.context->save(); paintInfo.context->setStrokeColor(Color::black); paintInfo.context->setFillColor(Color::black); @@ -623,8 +623,8 @@ bool RenderThemeWinCE::paintMediaSeekForwardButton(RenderObject* o, const PaintI bool rc = paintButton(o, paintInfo, r); FloatRect imRect = r; imRect.inflate(-3); - FloatPoint pts[3] = { FloatPoint(imRect.x(), imRect.y()), FloatPoint((imRect.x() + imRect.right()) / 2.0, (imRect.y() + imRect.bottom()) / 2.0), FloatPoint(imRect.x(), imRect.bottom()) }; - FloatPoint pts2[3] = { FloatPoint((imRect.x() + imRect.right()) / 2.0, imRect.y()), FloatPoint(imRect.right(), (imRect.y() + imRect.bottom()) / 2.0), FloatPoint((imRect.x() + imRect.right()) / 2.0, imRect.bottom()) }; + FloatPoint pts[3] = { FloatPoint(imRect.x(), imRect.y()), FloatPoint((imRect.x() + imRect.maxX()) / 2.0, (imRect.y() + imRect.maxY()) / 2.0), FloatPoint(imRect.x(), imRect.maxY()) }; + FloatPoint pts2[3] = { FloatPoint((imRect.x() + imRect.maxX()) / 2.0, imRect.y()), FloatPoint(imRect.maxX(), (imRect.y() + imRect.maxY()) / 2.0), FloatPoint((imRect.x() + imRect.maxX()) / 2.0, imRect.maxY()) }; paintInfo.context->save(); paintInfo.context->setStrokeColor(Color::black); paintInfo.context->setFillColor(Color::black); diff --git a/Source/WebCore/rendering/RenderTreeAsText.cpp b/Source/WebCore/rendering/RenderTreeAsText.cpp index 2e64999..a81163b 100644 --- a/Source/WebCore/rendering/RenderTreeAsText.cpp +++ b/Source/WebCore/rendering/RenderTreeAsText.cpp @@ -27,7 +27,6 @@ #include "RenderTreeAsText.h" #include "CSSMutableStyleDeclaration.h" -#include "CharacterNames.h" #include "Document.h" #include "Frame.h" #include "FrameView.h" @@ -48,6 +47,7 @@ #include "SelectionController.h" #include <wtf/UnusedParam.h> #include <wtf/Vector.h> +#include <wtf/unicode/CharacterNames.h> #if ENABLE(SVG) #include "RenderSVGContainer.h" @@ -621,10 +621,10 @@ static void writeLayers(TextStream& ts, const RenderLayer* rootLayer, RenderLaye // FIXME: Apply overflow to the root layer to not break every test. Complete hack. Sigh. IntRect paintDirtyRect(paintRect); if (rootLayer == l) { - paintDirtyRect.setWidth(max(paintDirtyRect.width(), rootLayer->renderBox()->rightLayoutOverflow())); - paintDirtyRect.setHeight(max(paintDirtyRect.height(), rootLayer->renderBox()->bottomLayoutOverflow())); - l->setWidth(max(l->width(), l->renderBox()->rightLayoutOverflow())); - l->setHeight(max(l->height(), l->renderBox()->bottomLayoutOverflow())); + paintDirtyRect.setWidth(max(paintDirtyRect.width(), rootLayer->renderBox()->maxXLayoutOverflow())); + paintDirtyRect.setHeight(max(paintDirtyRect.height(), rootLayer->renderBox()->maxYLayoutOverflow())); + l->setWidth(max(l->width(), l->renderBox()->maxXLayoutOverflow())); + l->setHeight(max(l->height(), l->renderBox()->maxYLayoutOverflow())); } // Calculate the clip rects we should use. @@ -769,13 +769,12 @@ String counterValueForElement(Element* element) element->document()->updateLayout(); TextStream stream; bool isFirstCounter = true; - // The counter renderers should be children of anonymous children - // (i.e., :before or :after pseudo-elements). + // The counter renderers should be children of :before or :after pseudo-elements. if (RenderObject* renderer = element->renderer()) { - for (RenderObject* child = renderer->firstChild(); child; child = child->nextSibling()) { - if (child->isAnonymous()) - writeCounterValuesFromChildren(stream, child, isFirstCounter); - } + if (RenderObject* pseudoElement = renderer->beforePseudoElementRenderer()) + writeCounterValuesFromChildren(stream, pseudoElement, isFirstCounter); + if (RenderObject* pseudoElement = renderer->afterPseudoElementRenderer()) + writeCounterValuesFromChildren(stream, pseudoElement, isFirstCounter); } return stream.release(); } diff --git a/Source/WebCore/rendering/RenderVideo.cpp b/Source/WebCore/rendering/RenderVideo.cpp index 0f3b551..1ae736b 100644 --- a/Source/WebCore/rendering/RenderVideo.cpp +++ b/Source/WebCore/rendering/RenderVideo.cpp @@ -56,7 +56,7 @@ RenderVideo::RenderVideo(HTMLVideoElement* video) RenderVideo::~RenderVideo() { - if (MediaPlayer* p = player()) { + if (MediaPlayer* p = mediaElement()->player()) { p->setVisible(false); p->setFrameView(0); } @@ -108,9 +108,9 @@ IntSize RenderVideo::calculateIntrinsicSize() // The intrinsic height of a video element's playback area is the intrinsic height // of the video resource, if that is available; otherwise it is the intrinsic // height of the poster frame, if that is available; otherwise it is 150 CSS pixels. - - if (player() && video->readyState() >= HTMLVideoElement::HAVE_METADATA) - return player()->naturalSize(); + MediaPlayer* player = mediaElement()->player(); + if (player && video->readyState() >= HTMLVideoElement::HAVE_METADATA) + return player->naturalSize(); if (video->shouldDisplayPosterImage() && !m_cachedImageSize.isEmpty() && !imageResource()->errorOccurred()) return m_cachedImageSize; @@ -186,7 +186,7 @@ bool RenderVideo::shouldDisplayVideo() const void RenderVideo::paintReplaced(PaintInfo& paintInfo, int tx, int ty) { - MediaPlayer* mediaPlayer = player(); + MediaPlayer* mediaPlayer = mediaElement()->player(); bool displayingPoster = videoElement()->shouldDisplayPosterImage(); if (!displayingPoster) { @@ -228,7 +228,7 @@ void RenderVideo::updatePlayer() { updateIntrinsicSize(); - MediaPlayer* mediaPlayer = player(); + MediaPlayer* mediaPlayer = mediaElement()->player(); if (!mediaPlayer) return; @@ -265,7 +265,7 @@ int RenderVideo::minimumReplacedHeight() const #if USE(ACCELERATED_COMPOSITING) bool RenderVideo::supportsAcceleratedRendering() const { - MediaPlayer* p = player(); + MediaPlayer* p = mediaElement()->player(); if (p) return p->supportsAcceleratedRendering(); @@ -274,7 +274,7 @@ bool RenderVideo::supportsAcceleratedRendering() const void RenderVideo::acceleratedRenderingStateChanged() { - MediaPlayer* p = player(); + MediaPlayer* p = mediaElement()->player(); if (p) p->acceleratedRenderingStateChanged(); } diff --git a/Source/WebCore/rendering/RenderView.cpp b/Source/WebCore/rendering/RenderView.cpp index cdd21fa..d25240b 100644 --- a/Source/WebCore/rendering/RenderView.cpp +++ b/Source/WebCore/rendering/RenderView.cpp @@ -112,7 +112,7 @@ void RenderView::layout() setPageLogicalHeight(0); if (printing()) - m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = width(); + m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = logicalWidth(); // Use calcWidth/Height to get the new width/height, since this will take the full page zoom factor into account. bool relayoutChildren = !printing() && (!m_frameView || width() != viewWidth() || height() != viewHeight()); @@ -156,13 +156,13 @@ void RenderView::mapLocalToContainer(RenderBoxModelObject* repaintContainer, boo } if (fixed && m_frameView) - transformState.move(m_frameView->scrollOffset()); + transformState.move(m_frameView->scrollOffsetForFixedPosition()); } void RenderView::mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState& transformState) const { if (fixed && m_frameView) - transformState.move(-m_frameView->scrollOffset()); + transformState.move(-m_frameView->scrollOffsetForFixedPosition()); if (useTransforms && shouldUseTransformFromContainer(0)) { TransformationMatrix t; @@ -311,13 +311,13 @@ void RenderView::computeRectForRepaint(RenderBoxModelObject* repaintContainer, I // We have to flip by hand since the view's logical height has not been determined. We // can use the viewport width and height. if (style()->isHorizontalWritingMode()) - rect.setY(viewHeight() - rect.bottom()); + rect.setY(viewHeight() - rect.maxY()); else - rect.setX(viewWidth() - rect.right()); + rect.setX(viewWidth() - rect.maxX()); } if (fixed && m_frameView) - rect.move(m_frameView->scrollX(), m_frameView->scrollY()); + rect.move(m_frameView->scrollXForFixedPosition(), m_frameView->scrollYForFixedPosition()); // Apply our transform if we have one (because of full page zooming). if (m_layer && m_layer->transform()) @@ -658,7 +658,7 @@ IntRect RenderView::viewRect() const int RenderView::docTop() const { - IntRect overflowRect(0, topLayoutOverflow(), 0, bottomLayoutOverflow() - topLayoutOverflow()); + IntRect overflowRect(0, minYLayoutOverflow(), 0, maxYLayoutOverflow() - minYLayoutOverflow()); flipForWritingMode(overflowRect); if (hasTransform()) overflowRect = layer()->currentTransform().mapRect(overflowRect); @@ -671,7 +671,7 @@ int RenderView::docBottom() const flipForWritingMode(overflowRect); if (hasTransform()) overflowRect = layer()->currentTransform().mapRect(overflowRect); - return overflowRect.bottom(); + return overflowRect.maxY(); } int RenderView::docLeft() const @@ -689,7 +689,7 @@ int RenderView::docRight() const flipForWritingMode(overflowRect); if (hasTransform()) overflowRect = layer()->currentTransform().mapRect(overflowRect); - return overflowRect.right(); + return overflowRect.maxX(); } int RenderView::viewHeight() const diff --git a/Source/WebCore/rendering/RenderWidget.cpp b/Source/WebCore/rendering/RenderWidget.cpp index d4b8ba6..13b572d 100644 --- a/Source/WebCore/rendering/RenderWidget.cpp +++ b/Source/WebCore/rendering/RenderWidget.cpp @@ -120,8 +120,6 @@ void RenderWidget::destroy() if (RenderView* v = view()) v->removeWidget(this); - if (m_hasCounterNodeMap) - RenderCounter::destroyCounterNodes(this); if (AXObjectCache::accessibilityEnabled()) { document()->axObjectCache()->childrenChanged(this->parent()); @@ -129,6 +127,9 @@ void RenderWidget::destroy() } remove(); + if (m_hasCounterNodeMap) + RenderCounter::destroyCounterNodes(this); + setWidget(0); // removes from override size map diff --git a/Source/WebCore/rendering/RenderingAllInOne.cpp b/Source/WebCore/rendering/RenderingAllInOne.cpp index faa3566..760f02d 100644 --- a/Source/WebCore/rendering/RenderingAllInOne.cpp +++ b/Source/WebCore/rendering/RenderingAllInOne.cpp @@ -45,6 +45,7 @@ #include "RenderBox.cpp" #include "RenderBoxModelObject.cpp" #include "RenderButton.cpp" +#include "RenderCombineText.cpp" #include "RenderCounter.cpp" #include "RenderDataGrid.cpp" #include "RenderDetails.cpp" diff --git a/Source/WebCore/rendering/RootInlineBox.cpp b/Source/WebCore/rendering/RootInlineBox.cpp index e9e2029..aa87683 100644 --- a/Source/WebCore/rendering/RootInlineBox.cpp +++ b/Source/WebCore/rendering/RootInlineBox.cpp @@ -544,14 +544,14 @@ IntRect RootInlineBox::paddedLayoutOverflowRect(int endPadding) const if (isHorizontal()) { if (isLeftToRightDirection()) - lineLayoutOverflow.shiftRightEdgeTo(max(lineLayoutOverflow.right(), logicalRight() + endPadding)); + lineLayoutOverflow.shiftMaxXEdgeTo(max(lineLayoutOverflow.maxX(), logicalRight() + endPadding)); else - lineLayoutOverflow.shiftLeftEdgeTo(min(lineLayoutOverflow.x(), logicalLeft() - endPadding)); + lineLayoutOverflow.shiftXEdgeTo(min(lineLayoutOverflow.x(), logicalLeft() - endPadding)); } else { if (isLeftToRightDirection()) - lineLayoutOverflow.shiftBottomEdgeTo(max(lineLayoutOverflow.bottom(), logicalRight() + endPadding)); + lineLayoutOverflow.shiftMaxYEdgeTo(max(lineLayoutOverflow.maxY(), logicalRight() + endPadding)); else - lineLayoutOverflow.shiftTopEdgeTo(min(lineLayoutOverflow.y(), logicalRight() - endPadding)); + lineLayoutOverflow.shiftYEdgeTo(min(lineLayoutOverflow.y(), logicalRight() - endPadding)); } return lineLayoutOverflow; diff --git a/Source/WebCore/rendering/ShadowElement.cpp b/Source/WebCore/rendering/ShadowElement.cpp index e1b247c..5b1a962 100644 --- a/Source/WebCore/rendering/ShadowElement.cpp +++ b/Source/WebCore/rendering/ShadowElement.cpp @@ -114,7 +114,7 @@ PassRefPtr<ShadowInputElement> ShadowInputElement::create(HTMLElement* shadowPar } ShadowInputElement::ShadowInputElement(HTMLElement* shadowParent) - : ShadowElement<HTMLInputElement>(inputTag, shadowParent) + : ShadowElement<HTMLInputElement>(inputTag, shadowParent, 0, false) { } diff --git a/Source/WebCore/rendering/ShadowElement.h b/Source/WebCore/rendering/ShadowElement.h index 8bcb34e..9a5d118 100644 --- a/Source/WebCore/rendering/ShadowElement.h +++ b/Source/WebCore/rendering/ShadowElement.h @@ -43,6 +43,12 @@ protected: BaseElement::setShadowHost(shadowParent); } + ShadowElement(const QualifiedName& name, HTMLElement* shadowParent, HTMLFormElement* form, bool createdByParser) + : BaseElement(name, shadowParent->document(), form, createdByParser) + { + BaseElement::setShadowHost(shadowParent); + } + public: virtual void detach(); }; diff --git a/Source/WebCore/rendering/TextControlInnerElements.cpp b/Source/WebCore/rendering/TextControlInnerElements.cpp index 7b1b36f..1162999 100644 --- a/Source/WebCore/rendering/TextControlInnerElements.cpp +++ b/Source/WebCore/rendering/TextControlInnerElements.cpp @@ -77,7 +77,6 @@ VisiblePosition RenderTextControlInnerBlock::positionForPoint(const IntPoint& po TextControlInnerElement::TextControlInnerElement(Document* document, HTMLElement* shadowParent) : HTMLDivElement(divTag, document) - , m_shadowParent(shadowParent) { setShadowHost(shadowParent); } @@ -220,7 +219,7 @@ void SearchFieldCancelButtonElement::detach() void SearchFieldCancelButtonElement::defaultEventHandler(Event* event) { // If the element is visible, on mouseup, clear the value, and set selection - HTMLInputElement* input = static_cast<HTMLInputElement*>(shadowAncestorNode()); + 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()) { @@ -233,13 +232,12 @@ void SearchFieldCancelButtonElement::defaultEventHandler(Event* event) event->setDefaultHandled(); } if (event->type() == eventNames().mouseupEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) { - if (m_capturing && renderer() && renderer()->visibleToHitTesting()) { + if (m_capturing) { if (Frame* frame = document()->frame()) { frame->eventHandler()->setCapturingMouseEventsNode(0); m_capturing = false; } if (hovered()) { - RefPtr<HTMLInputElement> protector(input); String oldValue = input->value(); input->setValue(""); if (!oldValue.isEmpty()) { @@ -272,6 +270,18 @@ PassRefPtr<SpinButtonElement> SpinButtonElement::create(HTMLElement* shadowParen 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()) { @@ -287,7 +297,7 @@ void SpinButtonElement::defaultEventHandler(Event* event) return; } - HTMLInputElement* input = static_cast<HTMLInputElement*>(shadowAncestorNode()); + RefPtr<HTMLInputElement> input(static_cast<HTMLInputElement*>(shadowAncestorNode())); if (input->disabled() || input->isReadOnlyFormControl()) { if (!event->defaultHandled()) HTMLDivElement::defaultEventHandler(event); @@ -298,12 +308,18 @@ void SpinButtonElement::defaultEventHandler(Event* event) IntPoint local = roundedIntPoint(box->absoluteToLocal(mouseEvent->absoluteLocation(), false, true)); if (mouseEvent->type() == eventNames().mousedownEvent && mouseEvent->button() == LeftButton) { if (box->borderBoxRect().contains(local)) { - RefPtr<Node> protector(input); + // 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(); - input->stepUpFromRenderer(m_upDownState == Up ? 1 : -1); + if (renderer()) { + input->stepUpFromRenderer(m_upDownState == Up ? 1 : -1); + if (renderer()) + startRepeatingTimer(); + } event->setDefaultHandled(); - startRepeatingTimer(); } } else if (mouseEvent->type() == eventNames().mouseupEvent && mouseEvent->button() == LeftButton) stopRepeatingTimer(); @@ -404,8 +420,12 @@ void InputFieldSpeechButtonElement::defaultEventHandler(Event* 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. - 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()) { @@ -413,10 +433,6 @@ void InputFieldSpeechButtonElement::defaultEventHandler(Event* event) m_capturing = true; } } - // 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> holdRef(input); RefPtr<InputFieldSpeechButtonElement> holdRefButton(this); input->focus(); input->select(); @@ -483,11 +499,10 @@ void InputFieldSpeechButtonElement::setRecognitionResult(int, const SpeechInputR { m_results = results; - HTMLInputElement* input = static_cast<HTMLInputElement*>(shadowAncestorNode()); // 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> holdRef(input); + 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)); diff --git a/Source/WebCore/rendering/TextControlInnerElements.h b/Source/WebCore/rendering/TextControlInnerElements.h index bb77dcd..4ba7857 100644 --- a/Source/WebCore/rendering/TextControlInnerElements.h +++ b/Source/WebCore/rendering/TextControlInnerElements.h @@ -48,8 +48,6 @@ protected: private: virtual bool isMouseFocusable() const { return false; } - - RefPtr<HTMLElement> m_shadowParent; }; class TextControlInnerTextElement : public TextControlInnerElement { @@ -101,6 +99,7 @@ public: 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(); } diff --git a/Source/WebCore/rendering/TransformState.cpp b/Source/WebCore/rendering/TransformState.cpp index ecc614e..9f177ea 100644 --- a/Source/WebCore/rendering/TransformState.cpp +++ b/Source/WebCore/rendering/TransformState.cpp @@ -60,9 +60,9 @@ void TransformState::applyTransform(const TransformationMatrix& transformFromCon // If we have an accumulated transform from last time, multiply in this transform if (m_accumulatedTransform) { if (m_direction == ApplyTransformDirection) - m_accumulatedTransform->multiply(transformFromContainer); + m_accumulatedTransform.set(new TransformationMatrix(transformFromContainer * *m_accumulatedTransform)); else - m_accumulatedTransform->multLeft(transformFromContainer); + m_accumulatedTransform->multiply(transformFromContainer); } else if (accumulate == AccumulateTransform) { // Make one if we started to accumulate m_accumulatedTransform.set(new TransformationMatrix(transformFromContainer)); @@ -140,7 +140,7 @@ void HitTestingTransformState::translate(int x, int y, TransformAccumulation acc void HitTestingTransformState::applyTransform(const TransformationMatrix& transformFromContainer, TransformAccumulation accumulate) { - m_accumulatedTransform.multLeft(transformFromContainer); + m_accumulatedTransform.multiply(transformFromContainer); if (accumulate == FlattenTransform) flattenWithTransform(m_accumulatedTransform); diff --git a/Source/WebCore/rendering/break_lines.cpp b/Source/WebCore/rendering/break_lines.cpp index 16bfcc2..b888fb8 100644 --- a/Source/WebCore/rendering/break_lines.cpp +++ b/Source/WebCore/rendering/break_lines.cpp @@ -26,9 +26,9 @@ #include "config.h" #include "break_lines.h" -#include "CharacterNames.h" #include "TextBreakIterator.h" #include <wtf/StdLibExtras.h> +#include <wtf/unicode/CharacterNames.h> #if PLATFORM(MAC) #include <CoreServices/CoreServices.h> diff --git a/Source/WebCore/rendering/mathml/RenderMathMLFraction.cpp b/Source/WebCore/rendering/mathml/RenderMathMLFraction.cpp index 9d80fbe..48d3f39 100644 --- a/Source/WebCore/rendering/mathml/RenderMathMLFraction.cpp +++ b/Source/WebCore/rendering/mathml/RenderMathMLFraction.cpp @@ -176,7 +176,7 @@ int RenderMathMLFraction::baselinePosition(FontBaseline, bool firstLine, LineDir refStyle = previousSibling()->style(); else if (nextSibling()) refStyle = nextSibling()->style(); - int shift = int(ceil((refStyle->font().xHeight() + 1) / 2)); + int shift = int(ceil((refStyle->fontMetrics().xHeight() + 1) / 2)); return numerator->offsetHeight() + shift; } return RenderBlock::baselinePosition(AlphabeticBaseline, firstLine, lineDirection, linePositionMode); diff --git a/Source/WebCore/rendering/mathml/RenderMathMLOperator.h b/Source/WebCore/rendering/mathml/RenderMathMLOperator.h index 6501494..3ef15c5 100644 --- a/Source/WebCore/rendering/mathml/RenderMathMLOperator.h +++ b/Source/WebCore/rendering/mathml/RenderMathMLOperator.h @@ -28,8 +28,8 @@ #if ENABLE(MATHML) -#include "CharacterNames.h" #include "RenderMathMLBlock.h" +#include <wtf/unicode/CharacterNames.h> namespace WebCore { diff --git a/Source/WebCore/rendering/style/RenderStyle.cpp b/Source/WebCore/rendering/style/RenderStyle.cpp index 2836fb9..b76a350 100644 --- a/Source/WebCore/rendering/style/RenderStyle.cpp +++ b/Source/WebCore/rendering/style/RenderStyle.cpp @@ -462,7 +462,8 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon inherited_flags._text_transform != other->inherited_flags._text_transform || inherited_flags._direction != other->inherited_flags._direction || inherited_flags._white_space != other->inherited_flags._white_space || - noninherited_flags._clear != other->noninherited_flags._clear) + noninherited_flags._clear != other->noninherited_flags._clear || + noninherited_flags._unicodeBidi != other->noninherited_flags._unicodeBidi) return StyleDifferenceLayout; // Check block flow direction. diff --git a/Source/WebCore/rendering/style/RenderStyle.h b/Source/WebCore/rendering/style/RenderStyle.h index 9d5239b..7b79db1 100644 --- a/Source/WebCore/rendering/style/RenderStyle.h +++ b/Source/WebCore/rendering/style/RenderStyle.h @@ -165,7 +165,6 @@ protected: (_text_align == other._text_align) && (_text_transform == other._text_transform) && (_text_decorations == other._text_decorations) && - (_text_transform == other._text_transform) && (_cursor_style == other._cursor_style) && (_direction == other._direction) && (_border_collapse == other._border_collapse) && @@ -463,6 +462,7 @@ public: ETableLayout tableLayout() const { return static_cast<ETableLayout>(noninherited_flags._table_layout); } const Font& font() const { return inherited->font; } + const FontMetrics& fontMetrics() const { return inherited->font.fontMetrics(); } const FontDescription& fontDescription() const { return inherited->font.fontDescription(); } int fontSize() const { return inherited->font.pixelSize(); } @@ -487,7 +487,7 @@ public: // Negative value means the line height is not set. Use the font's built-in spacing. if (lh.isNegative()) - return font().lineSpacing(); + return fontMetrics().lineSpacing(); if (lh.isPercent()) return lh.calcMinValue(fontSize()); @@ -727,6 +727,7 @@ public: bool hasMask() const { return rareNonInheritedData->m_mask.hasImage() || rareNonInheritedData->m_maskBoxImage.hasImage(); } TextCombine textCombine() const { return static_cast<TextCombine>(rareNonInheritedData->m_textCombine); } + bool hasTextCombine() const { return textCombine() != TextCombineNone; } // End CSS3 Getters // Apple-specific property getter methods diff --git a/Source/WebCore/rendering/style/RenderStyleConstants.h b/Source/WebCore/rendering/style/RenderStyleConstants.h index 7cd4903..44cd3f5 100644 --- a/Source/WebCore/rendering/style/RenderStyleConstants.h +++ b/Source/WebCore/rendering/style/RenderStyleConstants.h @@ -68,14 +68,9 @@ enum StyleDifferenceContextSensitiveProperty { enum PseudoId { // The order must be NOP ID, public IDs, and then internal IDs. NOPSEUDO, FIRST_LINE, FIRST_LETTER, BEFORE, AFTER, SELECTION, FIRST_LINE_INHERITED, SCROLLBAR, FILE_UPLOAD_BUTTON, INPUT_PLACEHOLDER, - SEARCH_CANCEL_BUTTON, SEARCH_DECORATION, SEARCH_RESULTS_DECORATION, SEARCH_RESULTS_BUTTON, MEDIA_CONTROLS_PANEL, - MEDIA_CONTROLS_PLAY_BUTTON, MEDIA_CONTROLS_MUTE_BUTTON, MEDIA_CONTROLS_TIMELINE, MEDIA_CONTROLS_TIMELINE_CONTAINER, - MEDIA_CONTROLS_VOLUME_SLIDER, MEDIA_CONTROLS_VOLUME_SLIDER_CONTAINER, MEDIA_CONTROLS_VOLUME_SLIDER_MUTE_BUTTON, - MEDIA_CONTROLS_CURRENT_TIME_DISPLAY, MEDIA_CONTROLS_TIME_REMAINING_DISPLAY, - MEDIA_CONTROLS_SEEK_BACK_BUTTON, MEDIA_CONTROLS_SEEK_FORWARD_BUTTON, MEDIA_CONTROLS_FULLSCREEN_BUTTON, MEDIA_CONTROLS_REWIND_BUTTON, - MEDIA_CONTROLS_RETURN_TO_REALTIME_BUTTON, MEDIA_CONTROLS_TOGGLE_CLOSED_CAPTIONS_BUTTON, - MEDIA_CONTROLS_STATUS_DISPLAY, SCROLLBAR_THUMB, SCROLLBAR_BUTTON, SCROLLBAR_TRACK, SCROLLBAR_TRACK_PIECE, SCROLLBAR_CORNER, RESIZER, - INPUT_LIST_BUTTON, INPUT_SPEECH_BUTTON, INNER_SPIN_BUTTON, OUTER_SPIN_BUTTON, VISITED_LINK, PROGRESS_BAR_VALUE, + SEARCH_CANCEL_BUTTON, SEARCH_DECORATION, SEARCH_RESULTS_DECORATION, SEARCH_RESULTS_BUTTON, + SCROLLBAR_THUMB, SCROLLBAR_BUTTON, SCROLLBAR_TRACK, SCROLLBAR_TRACK_PIECE, SCROLLBAR_CORNER, RESIZER, + INPUT_LIST_BUTTON, INPUT_SPEECH_BUTTON, INNER_SPIN_BUTTON, OUTER_SPIN_BUTTON, VISITED_LINK, METER_HORIZONTAL_BAR, METER_HORIZONTAL_OPTIMUM, METER_HORIZONTAL_SUBOPTIMAL, METER_HORIZONTAL_EVEN_LESS_GOOD, METER_VERTICAL_BAR, METER_VERTICAL_OPTIMUM, METER_VERTICAL_SUBOPTIMAL, METER_VERTICAL_EVEN_LESS_GOOD, AFTER_LAST_INTERNAL_PSEUDOID, diff --git a/Source/WebCore/rendering/style/StyleCachedImage.cpp b/Source/WebCore/rendering/style/StyleCachedImage.cpp index 1d7aba8..05cb0ea 100644 --- a/Source/WebCore/rendering/style/StyleCachedImage.cpp +++ b/Source/WebCore/rendering/style/StyleCachedImage.cpp @@ -84,7 +84,7 @@ void StyleCachedImage::removeClient(RenderObject* renderer) return m_image->removeClient(renderer); } -Image* StyleCachedImage::image(RenderObject*, const IntSize&) const +PassRefPtr<Image> StyleCachedImage::image(RenderObject*, const IntSize&) const { return m_image->image(); } diff --git a/Source/WebCore/rendering/style/StyleCachedImage.h b/Source/WebCore/rendering/style/StyleCachedImage.h index 3d6e1a2..2be6f4c 100644 --- a/Source/WebCore/rendering/style/StyleCachedImage.h +++ b/Source/WebCore/rendering/style/StyleCachedImage.h @@ -52,7 +52,7 @@ public: virtual void setImageContainerSize(const IntSize&); virtual void addClient(RenderObject*); virtual void removeClient(RenderObject*); - virtual Image* image(RenderObject*, const IntSize&) const; + virtual PassRefPtr<Image> image(RenderObject*, const IntSize&) const; private: StyleCachedImage(CachedImage* image) diff --git a/Source/WebCore/rendering/style/StyleGeneratedImage.cpp b/Source/WebCore/rendering/style/StyleGeneratedImage.cpp index 2322f5f..fa0aad7 100644 --- a/Source/WebCore/rendering/style/StyleGeneratedImage.cpp +++ b/Source/WebCore/rendering/style/StyleGeneratedImage.cpp @@ -72,7 +72,7 @@ void StyleGeneratedImage::removeClient(RenderObject* renderer) m_generator->removeClient(renderer); } -Image* StyleGeneratedImage::image(RenderObject* renderer, const IntSize& size) const +PassRefPtr<Image> StyleGeneratedImage::image(RenderObject* renderer, const IntSize& size) const { return m_generator->image(renderer, size); } diff --git a/Source/WebCore/rendering/style/StyleGeneratedImage.h b/Source/WebCore/rendering/style/StyleGeneratedImage.h index 7be1f6a..8e6076a 100644 --- a/Source/WebCore/rendering/style/StyleGeneratedImage.h +++ b/Source/WebCore/rendering/style/StyleGeneratedImage.h @@ -51,7 +51,7 @@ public: virtual void setImageContainerSize(const IntSize&); virtual void addClient(RenderObject*); virtual void removeClient(RenderObject*); - virtual Image* image(RenderObject*, const IntSize&) const; + virtual PassRefPtr<Image> image(RenderObject*, const IntSize&) const; private: StyleGeneratedImage(CSSImageGeneratorValue* val, bool fixedSize) diff --git a/Source/WebCore/rendering/style/StyleImage.h b/Source/WebCore/rendering/style/StyleImage.h index ead8d4a..2c844f6 100644 --- a/Source/WebCore/rendering/style/StyleImage.h +++ b/Source/WebCore/rendering/style/StyleImage.h @@ -25,6 +25,7 @@ #define StyleImage_h #include "CSSValue.h" +#include "Image.h" #include "IntSize.h" #include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> @@ -33,7 +34,6 @@ namespace WebCore { class CSSValue; -class Image; class RenderObject; typedef void* WrappedImagePtr; @@ -59,7 +59,7 @@ public: virtual void setImageContainerSize(const IntSize&) = 0; virtual void addClient(RenderObject*) = 0; virtual void removeClient(RenderObject*) = 0; - virtual Image* image(RenderObject*, const IntSize&) const = 0; + virtual PassRefPtr<Image> image(RenderObject*, const IntSize&) const = 0; virtual WrappedImagePtr data() const = 0; virtual bool isCachedImage() const { return false; } diff --git a/Source/WebCore/rendering/style/StylePendingImage.h b/Source/WebCore/rendering/style/StylePendingImage.h index b0c9b01..60c993c 100644 --- a/Source/WebCore/rendering/style/StylePendingImage.h +++ b/Source/WebCore/rendering/style/StylePendingImage.h @@ -26,6 +26,7 @@ #ifndef StylePendingImage_h #define StylePendingImage_h +#include "Image.h" #include "StyleImage.h" namespace WebCore { @@ -52,7 +53,7 @@ public: virtual void setImageContainerSize(const IntSize&) { } virtual void addClient(RenderObject*) { } virtual void removeClient(RenderObject*) { } - virtual Image* image(RenderObject*, const IntSize&) const + virtual PassRefPtr<Image> image(RenderObject*, const IntSize&) const { ASSERT_NOT_REACHED(); return 0; diff --git a/Source/WebCore/rendering/svg/RenderSVGImage.cpp b/Source/WebCore/rendering/svg/RenderSVGImage.cpp index 0f5a55e..81a5cea 100644 --- a/Source/WebCore/rendering/svg/RenderSVGImage.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGImage.cpp @@ -122,7 +122,7 @@ void RenderSVGImage::paint(PaintInfo& paintInfo, int, int) PaintInfo savedInfo(childPaintInfo); if (SVGRenderSupport::prepareToRenderSVGContent(this, childPaintInfo)) { - Image* image = m_imageResource->image(); + RefPtr<Image> image = m_imageResource->image(); FloatRect destRect = m_objectBoundingBox; FloatRect srcRect(0, 0, image->width(), image->height()); @@ -130,7 +130,7 @@ void RenderSVGImage::paint(PaintInfo& paintInfo, int, int) if (imageElement->preserveAspectRatio().align() != SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE) imageElement->preserveAspectRatio().transformRect(destRect, srcRect); - childPaintInfo.context->drawImage(image, ColorSpaceDeviceRGB, destRect, srcRect); + childPaintInfo.context->drawImage(image.get(), ColorSpaceDeviceRGB, destRect, srcRect); } SVGRenderSupport::finishRenderSVGContent(this, childPaintInfo, savedInfo.context); diff --git a/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp b/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp index 91ffb5c..a8aa0c8 100644 --- a/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp @@ -26,11 +26,14 @@ #if ENABLE(SVG) #include "RenderSVGInlineText.h" +#include "CSSStyleSelector.h" #include "FloatConversion.h" #include "FloatQuad.h" #include "RenderBlock.h" #include "RenderSVGRoot.h" #include "RenderSVGText.h" +#include "Settings.h" +#include "SVGImageBufferTools.h" #include "SVGInlineTextBox.h" #include "SVGRootInlineBox.h" #include "VisiblePosition.h" @@ -63,6 +66,7 @@ static PassRefPtr<StringImpl> applySVGWhitespaceRules(PassRefPtr<StringImpl> str RenderSVGInlineText::RenderSVGInlineText(Node* n, PassRefPtr<StringImpl> string) : RenderText(n, applySVGWhitespaceRules(string, false)) + , m_scalingFactor(1) { } @@ -74,6 +78,8 @@ void RenderSVGInlineText::styleDidChange(StyleDifference diff, const RenderStyle // The text metrics may be influenced by style changes. if (RenderSVGText* textRenderer = RenderSVGText::locateRenderSVGTextAncestor(this)) textRenderer->setNeedsPositioningValuesUpdate(); + + updateScaledFont(); } const RenderStyle* newStyle = style(); @@ -103,12 +109,12 @@ IntRect RenderSVGInlineText::localCaretRect(InlineBox* box, int caretOffset, int // Use the edge of the selection rect to determine the caret rect. if (static_cast<unsigned>(caretOffset) < textBox->start() + textBox->len()) { IntRect rect = textBox->selectionRect(0, 0, caretOffset, caretOffset + 1); - int x = box->isLeftToRightDirection() ? rect.x() : rect.right(); + int x = box->isLeftToRightDirection() ? rect.x() : rect.maxX(); return IntRect(x, rect.y(), caretWidth, rect.height()); } IntRect rect = textBox->selectionRect(0, 0, caretOffset - 1, caretOffset); - int x = box->isLeftToRightDirection() ? rect.right() : rect.x(); + int x = box->isLeftToRightDirection() ? rect.maxX() : rect.x(); return IntRect(x, rect.y(), caretWidth, rect.height()); } @@ -159,9 +165,7 @@ VisiblePosition RenderSVGInlineText::positionForPoint(const IntPoint& point) if (!firstTextBox() || !textLength()) return createVisiblePosition(0, DOWNSTREAM); - RenderStyle* style = this->style(); - ASSERT(style); - int baseline = style->font().ascent(); + float baseline = m_scaledFont.fontMetrics().floatAscent(); RenderBlock* containingBlock = this->containingBlock(); ASSERT(containingBlock); @@ -206,6 +210,39 @@ VisiblePosition RenderSVGInlineText::positionForPoint(const IntPoint& point) return createVisiblePosition(offset + closestDistanceBox->start(), offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM); } +void RenderSVGInlineText::updateScaledFont() +{ + computeNewScaledFontForStyle(this, style(), m_scalingFactor, m_scaledFont); +} + +void RenderSVGInlineText::computeNewScaledFontForStyle(RenderObject* renderer, const RenderStyle* style, float& scalingFactor, Font& scaledFont) +{ + ASSERT(style); + ASSERT(renderer); + + Document* document = renderer->document(); + ASSERT(document); + + CSSStyleSelector* styleSelector = document->styleSelector(); + ASSERT(styleSelector); + + // Alter font-size to the right on-screen value, to avoid scaling the glyphs themselves. + AffineTransform ctm; + SVGImageBufferTools::calculateTransformationToOutermostSVGCoordinateSystem(renderer, ctm); + scalingFactor = narrowPrecisionToFloat(sqrt((pow(ctm.xScale(), 2) + pow(ctm.yScale(), 2)) / 2)); + if (scalingFactor == 1 || !scalingFactor) { + scalingFactor = 1; + scaledFont = style->font(); + return; + } + + FontDescription fontDescription(style->fontDescription()); + fontDescription.setComputedSize(fontDescription.computedSize() * scalingFactor); + + scaledFont = Font(fontDescription, 0, 0); + scaledFont.update(styleSelector->fontSelector()); +} + } #endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/RenderSVGInlineText.h b/Source/WebCore/rendering/svg/RenderSVGInlineText.h index f5247f6..9eed8cd 100644 --- a/Source/WebCore/rendering/svg/RenderSVGInlineText.h +++ b/Source/WebCore/rendering/svg/RenderSVGInlineText.h @@ -40,6 +40,11 @@ public: const SVGTextLayoutAttributes& layoutAttributes() const { return m_attributes; } void storeLayoutAttributes(const SVGTextLayoutAttributes& attributes) { m_attributes = attributes; } + float scalingFactor() const { return m_scalingFactor; } + const Font& scaledFont() const { return m_scaledFont; } + void updateScaledFont(); + static void computeNewScaledFontForStyle(RenderObject*, const RenderStyle*, float& scalingFactor, Font& scaledFont); + private: virtual const char* renderName() const { return "RenderSVGInlineText"; } @@ -57,6 +62,8 @@ private: virtual IntRect linesBoundingBox() const; virtual InlineTextBox* createTextBox(); + float m_scalingFactor; + Font m_scaledFont; SVGTextLayoutAttributes m_attributes; }; diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp index 4ba4e0a..96514af 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp @@ -111,7 +111,7 @@ PassRefPtr<SVGFilterBuilder> RenderSVGResourceFilter::buildPrimitives(Filter* fi builder->clearEffects(); return 0; } - builder->appendEffectToEffectReferences(effect); + builder->appendEffectToEffectReferences(effect, effectElement->renderer()); effectElement->setStandardAttributes(primitiveBoundingBoxMode, effect.get()); builder->add(effectElement->result(), effect); } @@ -208,13 +208,13 @@ bool RenderSVGResourceFilter::applyResource(RenderObject* object, RenderStyle*, if (!lastEffect) return false; - RenderSVGResourceFilterPrimitive::determineFilterPrimitiveSubregion(lastEffect, filterData->filter.get()); + RenderSVGResourceFilterPrimitive::determineFilterPrimitiveSubregion(lastEffect); FloatRect subRegion = lastEffect->maxEffectRect(); // At least one FilterEffect has a too big image size, // recalculate the effect sizes with new scale factors. if (!fitsInMaximumImageSize(subRegion.size(), scale)) { filterData->filter->setFilterResolution(scale); - RenderSVGResourceFilterPrimitive::determineFilterPrimitiveSubregion(lastEffect, filterData->filter.get()); + RenderSVGResourceFilterPrimitive::determineFilterPrimitiveSubregion(lastEffect); } // If the drawingRegion is empty, we have something like <g filter=".."/>. @@ -290,16 +290,19 @@ void RenderSVGResourceFilter::postApplyResource(RenderObject* object, GraphicsCo // This is the real filtering of the object. It just needs to be called on the // initial filtering process. We just take the stored filter result on a // second drawing. - if (!filterData->builded) { + if (!filterData->builded) filterData->filter->setSourceImage(filterData->sourceGraphicBuffer.release()); + + // Always true if filterData is just built (filterData->builded is false). + if (!lastEffect->hasResult()) { lastEffect->apply(); #if !PLATFORM(CG) ImageBuffer* resultImage = lastEffect->asImageBuffer(); if (resultImage) resultImage->transformColorSpace(ColorSpaceLinearRGB, ColorSpaceDeviceRGB); #endif - filterData->builded = true; } + filterData->builded = true; ImageBuffer* resultImage = lastEffect->asImageBuffer(); if (resultImage) { @@ -324,5 +327,31 @@ FloatRect RenderSVGResourceFilter::resourceBoundingBox(RenderObject* object) return FloatRect(); } +void RenderSVGResourceFilter::primitiveAttributeChanged(RenderObject* object, const QualifiedName& attribute) +{ + HashMap<RenderObject*, FilterData*>::iterator it = m_filter.begin(); + HashMap<RenderObject*, FilterData*>::iterator end = m_filter.end(); + SVGFilterPrimitiveStandardAttributes* primitve = static_cast<SVGFilterPrimitiveStandardAttributes*>(object->node()); + + for (; it != end; ++it) { + FilterData* filterData = it->second; + if (!filterData->builded) + continue; + + SVGFilterBuilder* builder = filterData->builder.get(); + FilterEffect* effect = builder->effectByRenderer(object); + if (!effect) + continue; + // Since all effects shares the same attribute value, all + // or none of them will be changed. + if (!primitve->setFilterEffectAttribute(effect, attribute)) + return; + builder->clearResultsRecursive(effect); + + // Repaint the image on the screen. + markClientForInvalidation(it->first, RepaintInvalidation); + } +} + } #endif diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceFilter.h b/Source/WebCore/rendering/svg/RenderSVGResourceFilter.h index f9a15ce..c809f23 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceFilter.h +++ b/Source/WebCore/rendering/svg/RenderSVGResourceFilter.h @@ -64,6 +64,7 @@ public: virtual ~RenderSVGResourceFilter(); virtual const char* renderName() const { return "RenderSVGResourceFilter"; } + virtual bool isSVGResourceFilter() const { return true; } virtual void removeAllClientsFromCache(bool markForInvalidation = true); virtual void removeClientFromCache(RenderObject*, bool markForInvalidation = true); @@ -78,6 +79,8 @@ public: SVGUnitTypes::SVGUnitType filterUnits() const { return toUnitType(static_cast<SVGFilterElement*>(node())->filterUnits()); } SVGUnitTypes::SVGUnitType primitiveUnits() const { return toUnitType(static_cast<SVGFilterElement*>(node())->primitiveUnits()); } + void primitiveAttributeChanged(RenderObject*, const QualifiedName&); + virtual RenderSVGResourceType resourceType() const { return s_resourceType; } static RenderSVGResourceType s_resourceType; diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.cpp index fc7362e..64df700 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.cpp @@ -29,25 +29,29 @@ #if ENABLE(SVG) && ENABLE(FILTERS) #include "RenderSVGResourceFilterPrimitive.h" +#include "RenderSVGResource.h" #include "SVGFEImage.h" +#include "SVGFilter.h" namespace WebCore { -FloatRect RenderSVGResourceFilterPrimitive::determineFilterPrimitiveSubregion(FilterEffect* effect, SVGFilter* filter) +FloatRect RenderSVGResourceFilterPrimitive::determineFilterPrimitiveSubregion(FilterEffect* effect) { FloatRect uniteRect; FloatRect subregionBoundingBox = effect->effectBoundaries(); FloatRect subregion = subregionBoundingBox; + SVGFilter* filter = static_cast<SVGFilter*>(effect->filter()); + ASSERT(filter); if (effect->filterEffectType() != FilterEffectTypeTile) { // FETurbulence, FEImage and FEFlood don't have input effects, take the filter region as unite rect. if (unsigned numberOfInputEffects = effect->inputEffects().size()) { for (unsigned i = 0; i < numberOfInputEffects; ++i) - uniteRect.unite(determineFilterPrimitiveSubregion(effect->inputEffect(i), filter)); + uniteRect.unite(determineFilterPrimitiveSubregion(effect->inputEffect(i))); } else uniteRect = filter->filterRegionInUserSpace(); } else { - determineFilterPrimitiveSubregion(effect->inputEffect(0), filter); + determineFilterPrimitiveSubregion(effect->inputEffect(0)); uniteRect = filter->filterRegionInUserSpace(); } @@ -90,7 +94,7 @@ FloatRect RenderSVGResourceFilterPrimitive::determineFilterPrimitiveSubregion(Fi // FEImage needs the unclipped subregion in absolute coordinates to determine the correct // destination rect in combination with preserveAspectRatio. if (effect->filterEffectType() == FilterEffectTypeImage) - reinterpret_cast<FEImage*>(effect)->setAbsoluteSubregion(absoluteSubregion); + static_cast<FEImage*>(effect)->setAbsoluteSubregion(absoluteSubregion); // Clip every filter effect to the filter region. FloatRect absoluteScaledFilterRegion = filter->filterRegion(); diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.h b/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.h index f25f62e..8176d29 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.h +++ b/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.h @@ -30,25 +30,32 @@ #if ENABLE(SVG) && ENABLE(FILTERS) #include "RenderSVGHiddenContainer.h" -#include "SVGFilter.h" -#include "SVGFilterPrimitiveStandardAttributes.h" +#include "RenderSVGResourceFilter.h" namespace WebCore { +class FilterEffect; + class RenderSVGResourceFilterPrimitive : public RenderSVGHiddenContainer { public: - - explicit RenderSVGResourceFilterPrimitive(SVGFilterPrimitiveStandardAttributes* filterPrimitiveElement) + explicit RenderSVGResourceFilterPrimitive(SVGStyledElement* filterPrimitiveElement) : RenderSVGHiddenContainer(filterPrimitiveElement) { } - // They depend on the RenderObject argument of RenderSVGResourceFilter::applyResource. - static FloatRect determineFilterPrimitiveSubregion(FilterEffect*, SVGFilter*); - -private: virtual const char* renderName() const { return "RenderSVGResourceFilterPrimitive"; } virtual bool isSVGResourceFilterPrimitive() const { return true; } + + // They depend on the RenderObject argument of RenderSVGResourceFilter::applyResource. + static FloatRect determineFilterPrimitiveSubregion(FilterEffect*); + + inline void primitiveAttributeChanged(const QualifiedName& attribute) + { + RenderObject* filter = parent(); + if (!filter || !filter->isSVGResourceFilter()) + return; + static_cast<RenderSVGResourceFilter*>(filter)->primitiveAttributeChanged(this, attribute); + } }; } // namespace WebCore diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceMarker.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceMarker.cpp index 2a68d92..fcad27f 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceMarker.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGResourceMarker.cpp @@ -86,11 +86,10 @@ FloatRect RenderSVGResourceMarker::markerBoundaries(const AffineTransform& marke const AffineTransform& RenderSVGResourceMarker::localToParentTransform() const { - AffineTransform viewportTranslation(viewportTransform()); - m_localToParentTransform = viewportTranslation.translateRight(m_viewport.x(), m_viewport.y()); + m_localToParentTransform = AffineTransform::translation(m_viewport.x(), m_viewport.y()) * viewportTransform(); return m_localToParentTransform; // If this class were ever given a localTransform(), then the above would read: - // return viewportTransform() * localTransform() * viewportTranslation; + // return viewportTranslation * localTransform() * viewportTransform(); } FloatPoint RenderSVGResourceMarker::referencePoint() const diff --git a/Source/WebCore/rendering/svg/RenderSVGRoot.cpp b/Source/WebCore/rendering/svg/RenderSVGRoot.cpp index 3a8dce9..30f72b9 100644 --- a/Source/WebCore/rendering/svg/RenderSVGRoot.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGRoot.cpp @@ -261,18 +261,15 @@ IntSize RenderSVGRoot::borderOriginToContentBox() const AffineTransform RenderSVGRoot::localToRepaintContainerTransform(const IntPoint& parentOriginInContainer) const { - AffineTransform parentToContainer(localToParentTransform()); - return parentToContainer.translateRight(parentOriginInContainer.x(), parentOriginInContainer.y()); + return AffineTransform::translation(parentOriginInContainer.x(), parentOriginInContainer.y()) * localToParentTransform(); } const AffineTransform& RenderSVGRoot::localToParentTransform() const { IntSize parentToBorderBoxOffset = parentOriginToBorderBox(); - AffineTransform borderBoxOriginToParentOrigin(localToBorderBoxTransform()); - borderBoxOriginToParentOrigin.translateRight(parentToBorderBoxOffset.width(), parentToBorderBoxOffset.height()); + m_localToParentTransform = AffineTransform::translation(parentToBorderBoxOffset.width(), parentToBorderBoxOffset.height()) * localToBorderBoxTransform(); - m_localToParentTransform = borderBoxOriginToParentOrigin; return m_localToParentTransform; } diff --git a/Source/WebCore/rendering/svg/RenderSVGText.cpp b/Source/WebCore/rendering/svg/RenderSVGText.cpp index dad0b70..56d9306 100644 --- a/Source/WebCore/rendering/svg/RenderSVGText.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGText.cpp @@ -33,7 +33,7 @@ #include "GraphicsContext.h" #include "HitTestRequest.h" #include "PointerEventsHitRules.h" -#include "RenderLayer.h" +#include "RenderSVGInlineText.h" #include "RenderSVGResource.h" #include "RenderSVGRoot.h" #include "SVGLengthList.h" @@ -91,6 +91,18 @@ void RenderSVGText::mapLocalToContainer(RenderBoxModelObject* repaintContainer, SVGRenderSupport::mapLocalToContainer(this, repaintContainer, fixed, useTransforms, transformState); } +static inline void recursiveUpdateScaledFont(RenderObject* start) +{ + for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) { + if (child->isSVGInlineText()) { + toRenderSVGInlineText(child)->updateScaledFont(); + continue; + } + + recursiveUpdateScaledFont(child); + } +} + void RenderSVGText::layout() { ASSERT(needsLayout()); @@ -104,6 +116,13 @@ void RenderSVGText::layout() updateCachedBoundariesInParents = true; } + // If the root layout size changed (eg. window size changes) or the positioning values change, recompute the on-screen font size. + if (m_needsPositioningValuesUpdate || SVGRenderSupport::findTreeRootObject(this)->isLayoutSizeChanged()) { + recursiveUpdateScaledFont(this); + m_needsPositioningValuesUpdate = true; + updateCachedBoundariesInParents = true; + } + if (m_needsPositioningValuesUpdate) { // Perform SVG text layout phase one (see SVGTextLayoutAttributesBuilder for details). SVGTextLayoutAttributesBuilder layoutAttributesBuilder; diff --git a/Source/WebCore/rendering/svg/RenderSVGViewportContainer.cpp b/Source/WebCore/rendering/svg/RenderSVGViewportContainer.cpp index 7f4b6f7..0f2f273 100644 --- a/Source/WebCore/rendering/svg/RenderSVGViewportContainer.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGViewportContainer.cpp @@ -72,11 +72,10 @@ AffineTransform RenderSVGViewportContainer::viewportTransform() const const AffineTransform& RenderSVGViewportContainer::localToParentTransform() const { - AffineTransform viewportTranslation(viewportTransform()); - m_localToParentTransform = viewportTranslation.translateRight(m_viewport.x(), m_viewport.y()); + m_localToParentTransform = AffineTransform::translation(m_viewport.x(), m_viewport.y()) * viewportTransform(); return m_localToParentTransform; // If this class were ever given a localTransform(), then the above would read: - // return viewportTransform() * localTransform() * viewportTranslation; + // return viewportTranslation * localTransform() * viewportTransform() } bool RenderSVGViewportContainer::pointIsInsideViewportClip(const FloatPoint& pointInParent) diff --git a/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp b/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp index 2879f20..52976f2 100644 --- a/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp +++ b/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp @@ -30,6 +30,7 @@ #include "RenderSVGInlineText.h" #include "RenderSVGResource.h" #include "RenderSVGResourceSolidColor.h" +#include "SVGImageBufferTools.h" #include "SVGRootInlineBox.h" #include "TextRun.h" @@ -56,9 +57,12 @@ int SVGInlineTextBox::offsetForPosition(int, bool) const int SVGInlineTextBox::offsetForPositionInFragment(const SVGTextFragment& fragment, float position, bool includePartialGlyphs) const { - RenderText* textRenderer = this->textRenderer(); + RenderSVGInlineText* textRenderer = toRenderSVGInlineText(this->textRenderer()); ASSERT(textRenderer); + float scalingFactor = textRenderer->scalingFactor(); + ASSERT(scalingFactor); + RenderStyle* style = textRenderer->style(); ASSERT(style); @@ -69,7 +73,7 @@ int SVGInlineTextBox::offsetForPositionInFragment(const SVGTextFragment& fragmen if (!fragment.transform.isIdentity()) textRun.setHorizontalGlyphStretch(narrowPrecisionToFloat(fragment.transform.xScale())); - return fragment.positionListOffset - start() + style->font().offsetForPosition(textRun, position, includePartialGlyphs); + return fragment.positionListOffset - start() + textRenderer->scaledFont().offsetForPosition(textRun, position * scalingFactor, includePartialGlyphs); } int SVGInlineTextBox::positionForOffset(int) const @@ -82,10 +86,28 @@ int SVGInlineTextBox::positionForOffset(int) const FloatRect SVGInlineTextBox::selectionRectForTextFragment(const SVGTextFragment& fragment, int startPosition, int endPosition, RenderStyle* style) { ASSERT(startPosition < endPosition); + ASSERT(style); + + RenderSVGInlineText* textRenderer = toRenderSVGInlineText(this->textRenderer()); + ASSERT(textRenderer); + + float scalingFactor = textRenderer->scalingFactor(); + ASSERT(scalingFactor); - const Font& font = style->font(); - FloatPoint textOrigin(fragment.x, fragment.y - font.ascent()); - return font.selectionRectForText(constructTextRun(style, fragment), textOrigin, fragment.height, startPosition, endPosition); + const Font& scaledFont = textRenderer->scaledFont(); + const FontMetrics& scaledFontMetrics = scaledFont.fontMetrics(); + FloatPoint textOrigin(fragment.x, fragment.y); + if (scalingFactor != 1) + textOrigin.scale(scalingFactor, scalingFactor); + + textOrigin.move(0, -scaledFontMetrics.floatAscent()); + + FloatRect selectionRect = scaledFont.selectionRectForText(constructTextRun(style, fragment), textOrigin, fragment.height * scalingFactor, startPosition, endPosition); + if (scalingFactor == 1) + return selectionRect; + + selectionRect.scale(1 / scalingFactor); + return selectionRect; } IntRect SVGInlineTextBox::selectionRect(int, int, int startPosition, int endPosition) @@ -125,6 +147,13 @@ IntRect SVGInlineTextBox::selectionRect(int, int, int startPosition, int endPosi return enclosingIntRect(selectionRect); } +static inline bool textShouldBePainted(RenderSVGInlineText* textRenderer) +{ + // Font::pixelSize(), returns FontDescription::computedPixelSize(), which returns "int(x + 0.5)". + // If the absolute font size on screen is below x=0.5, don't render anything. + return textRenderer->scaledFont().pixelSize(); +} + void SVGInlineTextBox::paintSelectionBackground(PaintInfo& paintInfo) { ASSERT(paintInfo.shouldPaintWithinRoot(renderer())); @@ -148,6 +177,11 @@ void SVGInlineTextBox::paintSelectionBackground(PaintInfo& paintInfo) if (!backgroundColor.isValid() || !backgroundColor.alpha()) return; + RenderSVGInlineText* textRenderer = toRenderSVGInlineText(this->textRenderer()); + ASSERT(textRenderer); + if (!textShouldBePainted(textRenderer)) + return; + RenderStyle* style = parentRenderer->style(); ASSERT(style); @@ -222,6 +256,11 @@ void SVGInlineTextBox::paint(PaintInfo& paintInfo, int, int) if (!hasSelection && paintSelectedTextOnly) return; + RenderSVGInlineText* textRenderer = toRenderSVGInlineText(this->textRenderer()); + ASSERT(textRenderer); + if (!textShouldBePainted(textRenderer)) + return; + RenderStyle* style = parentRenderer->style(); ASSERT(style); @@ -286,8 +325,9 @@ void SVGInlineTextBox::paint(PaintInfo& paintInfo, int, int) ASSERT(!m_paintingResource); } -bool SVGInlineTextBox::acquirePaintingResource(GraphicsContext*& context, RenderObject* renderer, RenderStyle* style) +bool SVGInlineTextBox::acquirePaintingResource(GraphicsContext*& context, float scalingFactor, RenderObject* renderer, RenderStyle* style) { + ASSERT(scalingFactor); ASSERT(renderer); ASSERT(style); ASSERT(m_paintingResourceMode != ApplyToDefaultMode); @@ -315,6 +355,9 @@ bool SVGInlineTextBox::acquirePaintingResource(GraphicsContext*& context, Render } } + if (scalingFactor != 1 && m_paintingResourceMode & ApplyToStrokeMode) + context->setStrokeThickness(context->strokeThickness() * scalingFactor); + return true; } @@ -329,9 +372,9 @@ void SVGInlineTextBox::releasePaintingResource(GraphicsContext*& context, const m_paintingResource = 0; } -bool SVGInlineTextBox::prepareGraphicsContextForTextPainting(GraphicsContext*& context, TextRun& textRun, RenderStyle* style) +bool SVGInlineTextBox::prepareGraphicsContextForTextPainting(GraphicsContext*& context, float scalingFactor, TextRun& textRun, RenderStyle* style) { - bool acquiredResource = acquirePaintingResource(context, parent()->renderer(), style); + bool acquiredResource = acquirePaintingResource(context, scalingFactor, parent()->renderer(), style); #if ENABLE(SVG_FONTS) // SVG Fonts need access to the painting resource used to draw the current text chunk. @@ -364,14 +407,12 @@ TextRun SVGInlineTextBox::constructTextRun(RenderStyle* style, const SVGTextFrag , false /* allowTabs */ , 0 /* xPos, only relevant with allowTabs=true */ , 0 /* padding, only relevant for justified text, not relevant for SVG */ + , TextRun::AllowTrailingExpansion , direction() == RTL , m_dirOverride || style->visuallyOrdered() /* directionalOverride */); #if ENABLE(SVG_FONTS) - RenderObject* parentRenderer = parent()->renderer(); - ASSERT(parentRenderer); - - run.setReferencingRenderObject(parentRenderer); + run.setReferencingRenderObject(text); #endif // Disable any word/character rounding. @@ -409,16 +450,16 @@ bool SVGInlineTextBox::mapStartEndPositionsIntoFragmentCoordinates(const SVGText return true; } -static inline float positionOffsetForDecoration(ETextDecoration decoration, const Font& font, float thickness) +static inline float positionOffsetForDecoration(ETextDecoration decoration, const FontMetrics& fontMetrics, float thickness) { // FIXME: For SVG Fonts we need to use the attributes defined in the <font-face> if specified. // Compatible with Batik/Opera. if (decoration == UNDERLINE) - return font.ascent() + thickness * 1.5f; + return fontMetrics.floatAscent() + thickness * 1.5f; if (decoration == OVERLINE) return thickness; if (decoration == LINE_THROUGH) - return font.ascent() * 5.0f / 8.0f; + return fontMetrics.floatAscent() * 5 / 8.0f; ASSERT_NOT_REACHED(); return 0.0f; @@ -486,22 +527,34 @@ void SVGInlineTextBox::paintDecorationWithStyle(GraphicsContext* context, ETextD RenderStyle* decorationStyle = decorationRenderer->style(); ASSERT(decorationStyle); - const Font& font = decorationStyle->font(); + float scalingFactor = 1; + Font scaledFont; + RenderSVGInlineText::computeNewScaledFontForStyle(decorationRenderer, decorationStyle, scalingFactor, scaledFont); + ASSERT(scalingFactor); // The initial y value refers to overline position. - float thickness = thicknessForDecoration(decoration, font); + float thickness = thicknessForDecoration(decoration, scaledFont); if (fragment.width <= 0 && thickness <= 0) return; - float y = fragment.y - font.ascent() + positionOffsetForDecoration(decoration, font, thickness); - - Path path; - path.addRect(FloatRect(fragment.x, y, fragment.width, thickness)); + FloatPoint decorationOrigin(fragment.x, fragment.y); + float width = fragment.width; + const FontMetrics& scaledFontMetrics = scaledFont.fontMetrics(); context->save(); + if (scalingFactor != 1) { + width *= scalingFactor; + decorationOrigin.scale(scalingFactor, scalingFactor); + context->scale(FloatSize(1 / scalingFactor, 1 / scalingFactor)); + } - if (acquirePaintingResource(context, decorationRenderer, decorationStyle)) + decorationOrigin.move(0, -scaledFontMetrics.floatAscent() + positionOffsetForDecoration(decoration, scaledFontMetrics, thickness)); + + Path path; + path.addRect(FloatRect(decorationOrigin, FloatSize(width, thickness))); + + if (acquirePaintingResource(context, scalingFactor, decorationRenderer, decorationStyle)) releasePaintingResource(context, &path); context->restore(); @@ -509,21 +562,41 @@ void SVGInlineTextBox::paintDecorationWithStyle(GraphicsContext* context, ETextD void SVGInlineTextBox::paintTextWithShadows(GraphicsContext* context, RenderStyle* style, TextRun& textRun, const SVGTextFragment& fragment, int startPosition, int endPosition) { - const Font& font = style->font(); + RenderSVGInlineText* textRenderer = toRenderSVGInlineText(this->textRenderer()); + ASSERT(textRenderer); + + float scalingFactor = textRenderer->scalingFactor(); + ASSERT(scalingFactor); + + const Font& scaledFont = textRenderer->scaledFont(); const ShadowData* shadow = style->textShadow(); FloatPoint textOrigin(fragment.x, fragment.y); - FloatRect shadowRect(FloatPoint(textOrigin.x(), textOrigin.y() - font.ascent()), FloatSize(fragment.width, fragment.height)); + FloatSize textSize(fragment.width, fragment.height); + + if (scalingFactor != 1) { + textOrigin.scale(scalingFactor, scalingFactor); + textSize.scale(scalingFactor); + } + + FloatRect shadowRect(FloatPoint(textOrigin.x(), textOrigin.y() - scaledFont.fontMetrics().floatAscent()), textSize); do { - if (!prepareGraphicsContextForTextPainting(context, textRun, style)) + if (!prepareGraphicsContextForTextPainting(context, scalingFactor, textRun, style)) break; FloatSize extraOffset; if (shadow) extraOffset = applyShadowToGraphicsContext(context, shadow, shadowRect, false /* stroked */, true /* opaque */, true /* horizontal */); - font.drawText(context, textRun, textOrigin + extraOffset, startPosition, endPosition); + if (scalingFactor != 1) + context->scale(FloatSize(1 / scalingFactor, 1 / scalingFactor)); + + scaledFont.drawText(context, textRun, textOrigin + extraOffset, startPosition, endPosition); + + if (scalingFactor != 1) + context->scale(FloatSize(scalingFactor, scalingFactor)); + restoreGraphicsContextAfterTextPainting(context, textRun); if (!shadow) @@ -580,19 +653,18 @@ IntRect SVGInlineTextBox::calculateBoundaries() const { FloatRect textRect; - RenderText* textRenderer = this->textRenderer(); + RenderSVGInlineText* textRenderer = toRenderSVGInlineText(this->textRenderer()); ASSERT(textRenderer); - RenderStyle* style = textRenderer->style(); - ASSERT(style); + float scalingFactor = textRenderer->scalingFactor(); + ASSERT(scalingFactor); - int baseline = baselinePosition(AlphabeticBaseline); - int heightDifference = baseline - style->font().ascent(); + float baseline = textRenderer->scaledFont().fontMetrics().floatAscent() / scalingFactor; unsigned textFragmentsSize = m_textFragments.size(); for (unsigned i = 0; i < textFragmentsSize; ++i) { const SVGTextFragment& fragment = m_textFragments.at(i); - FloatRect fragmentRect(fragment.x, fragment.y - baseline, fragment.width, fragment.height + heightDifference); + FloatRect fragmentRect(fragment.x, fragment.y - baseline, fragment.width, fragment.height); if (!fragment.transform.isIdentity()) fragmentRect = fragment.transform.mapRect(fragmentRect); diff --git a/Source/WebCore/rendering/svg/SVGInlineTextBox.h b/Source/WebCore/rendering/svg/SVGInlineTextBox.h index 0458de0..f2ca303 100644 --- a/Source/WebCore/rendering/svg/SVGInlineTextBox.h +++ b/Source/WebCore/rendering/svg/SVGInlineTextBox.h @@ -66,10 +66,10 @@ public: private: TextRun constructTextRun(RenderStyle*, const SVGTextFragment&) const; - bool acquirePaintingResource(GraphicsContext*&, RenderObject*, RenderStyle*); + bool acquirePaintingResource(GraphicsContext*&, float scalingFactor, RenderObject*, RenderStyle*); void releasePaintingResource(GraphicsContext*&, const Path*); - bool prepareGraphicsContextForTextPainting(GraphicsContext*&, TextRun&, RenderStyle*); + bool prepareGraphicsContextForTextPainting(GraphicsContext*&, float scalingFactor, TextRun&, RenderStyle*); void restoreGraphicsContextAfterTextPainting(GraphicsContext*&, TextRun&); void paintDecoration(GraphicsContext*, ETextDecoration, const SVGTextFragment&); diff --git a/Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp b/Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp index 3b28d2b..c25ed79 100644 --- a/Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp +++ b/Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp @@ -310,7 +310,7 @@ void SVGTextLayoutEngine::finalizeTransformMatrices(Vector<SVGInlineTextBox*>& b SVGTextFragment& fragment = fragments.at(i); AffineTransform& transform = fragment.transform; if (!transform.isIdentity()) { - transform.translateRight(fragment.x, fragment.y); + transform = AffineTransform::translation(fragment.x, fragment.y) * transform; transform.translate(-fragment.x, -fragment.y); } diff --git a/Source/WebCore/rendering/svg/SVGTextLayoutEngineBaseline.cpp b/Source/WebCore/rendering/svg/SVGTextLayoutEngineBaseline.cpp index 3863322..4221f26 100644 --- a/Source/WebCore/rendering/svg/SVGTextLayoutEngineBaseline.cpp +++ b/Source/WebCore/rendering/svg/SVGTextLayoutEngineBaseline.cpp @@ -49,9 +49,9 @@ float SVGTextLayoutEngineBaseline::calculateBaselineShift(const SVGRenderStyle* case BS_BASELINE: return 0; case BS_SUB: - return -m_font.height() / 2; + return -m_font.fontMetrics().floatHeight() / 2; case BS_SUPER: - return m_font.height() / 2; + return m_font.fontMetrics().floatHeight() / 2; default: ASSERT_NOT_REACHED(); return 0; @@ -122,27 +122,29 @@ float SVGTextLayoutEngineBaseline::calculateAlignmentBaselineShift(bool isVertic ASSERT(baseline != AB_AUTO); } + const FontMetrics& fontMetrics = m_font.fontMetrics(); + // Note: http://wiki.apache.org/xmlgraphics-fop/LineLayout/AlignmentHandling switch (baseline) { case AB_BASELINE: return dominantBaselineToAlignmentBaseline(isVerticalText, textRendererParent); case AB_BEFORE_EDGE: case AB_TEXT_BEFORE_EDGE: - return m_font.ascent(); + return fontMetrics.floatAscent(); case AB_MIDDLE: - return m_font.xHeight() / 2; + return fontMetrics.xHeight() / 2; case AB_CENTRAL: - return (m_font.ascent() - m_font.descent()) / 2; + return (fontMetrics.floatAscent() - fontMetrics.floatDescent()) / 2; case AB_AFTER_EDGE: case AB_TEXT_AFTER_EDGE: case AB_IDEOGRAPHIC: - return m_font.descent(); + return fontMetrics.floatDescent(); case AB_ALPHABETIC: return 0; case AB_HANGING: - return m_font.ascent() * 8 / 10.f; + return fontMetrics.floatAscent() * 8 / 10.f; case AB_MATHEMATICAL: - return m_font.ascent() / 2; + return fontMetrics.floatAscent() / 2; default: ASSERT_NOT_REACHED(); return 0; @@ -192,12 +194,14 @@ float SVGTextLayoutEngineBaseline::calculateGlyphAdvanceAndOrientation(bool isVe // Spec: If if the 'glyph-orientation-vertical' results in an orientation angle that is not a multiple of // 180 degrees, then the current text position is incremented according to the horizontal metrics of the glyph. + const FontMetrics& fontMetrics = m_font.fontMetrics(); + // Vertical orientation handling. if (isVerticalText) { - float ascentMinusDescent = m_font.ascent() - m_font.descent(); + float ascentMinusDescent = fontMetrics.floatAscent() - fontMetrics.floatDescent(); if (!angle) { xOrientationShift = (ascentMinusDescent - metrics.width()) / 2; - yOrientationShift = m_font.ascent(); + yOrientationShift = fontMetrics.floatAscent(); } else if (angle == 180) xOrientationShift = (ascentMinusDescent + metrics.width()) / 2; else if (angle == 270) { @@ -217,7 +221,7 @@ float SVGTextLayoutEngineBaseline::calculateGlyphAdvanceAndOrientation(bool isVe yOrientationShift = -metrics.width(); else if (angle == 180) { xOrientationShift = metrics.width(); - yOrientationShift = -m_font.ascent(); + yOrientationShift = -fontMetrics.floatAscent(); } else if (angle == 270) xOrientationShift = metrics.width(); diff --git a/Source/WebCore/rendering/svg/SVGTextLayoutEngineSpacing.cpp b/Source/WebCore/rendering/svg/SVGTextLayoutEngineSpacing.cpp index 6c54b67..e9aa127 100644 --- a/Source/WebCore/rendering/svg/SVGTextLayoutEngineSpacing.cpp +++ b/Source/WebCore/rendering/svg/SVGTextLayoutEngineSpacing.cpp @@ -58,7 +58,7 @@ float SVGTextLayoutEngineSpacing::calculateSVGKerning(bool isVerticalText, const m_lastGlyph = currentGlyph; m_lastGlyph.isValid = true; - kerning *= m_font.size() / m_font.primaryFont()->unitsPerEm(); + kerning *= m_font.size() / m_font.fontMetrics().unitsPerEm(); return kerning; #else UNUSED_PARAM(isVerticalText); diff --git a/Source/WebCore/rendering/svg/SVGTextMetrics.cpp b/Source/WebCore/rendering/svg/SVGTextMetrics.cpp index ec8c2c6..ca20d3d 100644 --- a/Source/WebCore/rendering/svg/SVGTextMetrics.cpp +++ b/Source/WebCore/rendering/svg/SVGTextMetrics.cpp @@ -34,16 +34,21 @@ SVGTextMetrics::SVGTextMetrics() { } -SVGTextMetrics::SVGTextMetrics(const Font& font, const TextRun& run, unsigned position, unsigned textLength) - : m_width(0) - , m_height(0) - , m_length(0) +SVGTextMetrics::SVGTextMetrics(RenderSVGInlineText* textRenderer, const TextRun& run, unsigned position, unsigned textLength) { + ASSERT(textRenderer); + + float scalingFactor = textRenderer->scalingFactor(); + ASSERT(scalingFactor); + + const Font& scaledFont = textRenderer->scaledFont(); + int extraCharsAvailable = textLength - (position + run.length()); int length = 0; - m_width = font.floatWidth(run, extraCharsAvailable, length, m_glyph.name); - m_height = font.height(); + // 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_height = scaledFont.fontMetrics().floatHeight() / scalingFactor; m_glyph.unicodeString = String(run.characters(), length); m_glyph.isValid = true; @@ -71,8 +76,7 @@ static TextRun constructTextRun(RenderSVGInlineText* text, const UChar* characte TextRun run(characters + position, length); #if ENABLE(SVG_FONTS) - ASSERT(text->parent()); - run.setReferencingRenderObject(text->parent()); + run.setReferencingRenderObject(text); #endif // Disable any word/character rounding. @@ -86,18 +90,13 @@ static TextRun constructTextRun(RenderSVGInlineText* text, const UChar* characte SVGTextMetrics SVGTextMetrics::measureCharacterRange(RenderSVGInlineText* text, unsigned position, unsigned length) { ASSERT(text); - ASSERT(text->style()); - TextRun run(constructTextRun(text, text->characters(), position, length)); - return SVGTextMetrics(text->style()->font(), run, position, text->textLength()); + return SVGTextMetrics(text, run, position, text->textLength()); } void SVGTextMetrics::measureAllCharactersIndividually(RenderSVGInlineText* text, Vector<SVGTextMetrics>& allMetrics) { ASSERT(text); - ASSERT(text->style()); - - const Font& font = text->style()->font(); const UChar* characters = text->characters(); unsigned length = text->textLength(); @@ -105,7 +104,7 @@ void SVGTextMetrics::measureAllCharactersIndividually(RenderSVGInlineText* text, for (unsigned position = 0; position < length; ) { run.setText(characters + position, 1); - SVGTextMetrics metrics(font, run, position, text->textLength()); + SVGTextMetrics metrics(text, run, position, text->textLength()); allMetrics.append(metrics); position += metrics.length(); } diff --git a/Source/WebCore/rendering/svg/SVGTextMetrics.h b/Source/WebCore/rendering/svg/SVGTextMetrics.h index ba18589..7ef0f7d 100644 --- a/Source/WebCore/rendering/svg/SVGTextMetrics.h +++ b/Source/WebCore/rendering/svg/SVGTextMetrics.h @@ -25,7 +25,6 @@ namespace WebCore { -class Font; class RenderSVGInlineText; class TextRun; @@ -64,7 +63,7 @@ public: private: SVGTextMetrics(); - SVGTextMetrics(const Font&, const TextRun&, unsigned position, unsigned textLength); + SVGTextMetrics(RenderSVGInlineText*, const TextRun&, unsigned position, unsigned textLength); float m_width; float m_height; diff --git a/Source/WebCore/rendering/svg/SVGTextQuery.cpp b/Source/WebCore/rendering/svg/SVGTextQuery.cpp index 42d511b..1a4cdab 100644 --- a/Source/WebCore/rendering/svg/SVGTextQuery.cpp +++ b/Source/WebCore/rendering/svg/SVGTextQuery.cpp @@ -472,7 +472,10 @@ struct ExtentOfCharacterData : SVGTextQuery::Data { static inline void calculateGlyphBoundaries(SVGTextQuery::Data* queryData, const SVGTextFragment& fragment, int startPosition, FloatRect& extent) { - extent.setLocation(FloatPoint(fragment.x, fragment.y - queryData->textRenderer->style()->font().ascent())); + float scalingFactor = queryData->textRenderer->scalingFactor(); + ASSERT(scalingFactor); + + extent.setLocation(FloatPoint(fragment.x, fragment.y - queryData->textRenderer->scaledFont().fontMetrics().floatAscent() / scalingFactor)); if (startPosition) { SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.positionListOffset, startPosition); |