diff options
author | Ben Murdoch <benm@google.com> | 2011-06-02 12:07:03 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2011-06-10 10:47:21 +0100 |
commit | 2daae5fd11344eaa88a0d92b0f6d65f8d2255c00 (patch) | |
tree | e4964fbd1cb70599f7718ff03e50ea1dab33890b /Source/WebCore/rendering | |
parent | 87bdf0060a247bfbe668342b87e0874182e0ffa9 (diff) | |
download | external_webkit-2daae5fd11344eaa88a0d92b0f6d65f8d2255c00.zip external_webkit-2daae5fd11344eaa88a0d92b0f6d65f8d2255c00.tar.gz external_webkit-2daae5fd11344eaa88a0d92b0f6d65f8d2255c00.tar.bz2 |
Merge WebKit at r84325: Initial merge by git.
Change-Id: Ic1a909300ecc0a13ddc6b4e784371d2ac6e3d59b
Diffstat (limited to 'Source/WebCore/rendering')
126 files changed, 3815 insertions, 4412 deletions
diff --git a/Source/WebCore/rendering/EllipsisBox.cpp b/Source/WebCore/rendering/EllipsisBox.cpp index db66b43..1641ee5 100644 --- a/Source/WebCore/rendering/EllipsisBox.cpp +++ b/Source/WebCore/rendering/EllipsisBox.cpp @@ -29,7 +29,7 @@ namespace WebCore { -void EllipsisBox::paint(PaintInfo& paintInfo, int tx, int ty) +void EllipsisBox::paint(PaintInfo& paintInfo, int tx, int ty, int lineTop, int lineBottom) { GraphicsContext* context = paintInfo.context; RenderStyle* style = m_renderer->style(m_firstLine); @@ -66,7 +66,7 @@ void EllipsisBox::paint(PaintInfo& paintInfo, int tx, int ty) // Paint the markup box tx += m_x + m_logicalWidth - m_markupBox->x(); ty += m_y + style->fontMetrics().ascent() - (m_markupBox->y() + m_markupBox->renderer()->style(m_firstLine)->fontMetrics().ascent()); - m_markupBox->paint(paintInfo, tx, ty); + m_markupBox->paint(paintInfo, tx, ty, lineTop, lineBottom); } } @@ -99,7 +99,7 @@ void EllipsisBox::paintSelection(GraphicsContext* context, int tx, int ty, Rende context->restore(); } -bool EllipsisBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty) +bool EllipsisBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, int lineTop, int lineBottom) { tx += m_x; ty += m_y; @@ -109,7 +109,7 @@ bool EllipsisBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu RenderStyle* style = m_renderer->style(m_firstLine); int mtx = tx + m_logicalWidth - m_markupBox->x(); 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)) { + if (m_markupBox->nodeAtPoint(request, result, x, y, mtx, mty, lineTop, lineBottom)) { renderer()->updateHitTestResult(result, IntPoint(x - mtx, y - mty)); return true; } diff --git a/Source/WebCore/rendering/EllipsisBox.h b/Source/WebCore/rendering/EllipsisBox.h index ec1b00b..c178cba 100644 --- a/Source/WebCore/rendering/EllipsisBox.h +++ b/Source/WebCore/rendering/EllipsisBox.h @@ -39,8 +39,8 @@ public: { } - virtual void paint(PaintInfo&, int tx, int ty); - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty); + virtual void paint(PaintInfo&, int tx, int ty, int lineTop, int lineBottom); + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, int lineTop, int lineBottom); void setSelectionState(RenderObject::SelectionState s) { m_selectionState = s; } IntRect selectionRect(int tx, int ty); diff --git a/Source/WebCore/rendering/HitTestResult.cpp b/Source/WebCore/rendering/HitTestResult.cpp index e5638c9..77ccc4b 100644 --- a/Source/WebCore/rendering/HitTestResult.cpp +++ b/Source/WebCore/rendering/HitTestResult.cpp @@ -32,6 +32,7 @@ #include "HTMLNames.h" #include "HTMLParserIdioms.h" #include "RenderImage.h" +#include "RenderInline.h" #include "Scrollbar.h" #include "SelectionController.h" @@ -544,6 +545,20 @@ bool HitTestResult::addNodeToRectBasedTestResult(Node* node, int x, int y, const node = node->shadowAncestorNode(); mutableRectBasedTestResult().add(node); + if (node->renderer()->isInline()) { + for (RenderObject* curr = node->renderer()->parent(); curr; curr = curr->parent()) { + if (!curr->isRenderInline()) + break; + + // We need to make sure the nodes for culled inlines get included. + RenderInline* currInline = toRenderInline(curr); + if (currInline->alwaysCreateLineBoxes()) + break; + + if (currInline->visibleToHitTesting() && currInline->node()) + mutableRectBasedTestResult().add(currInline->node()->shadowAncestorNode()); + } + } return !rect.contains(rectForPoint(x, y)); } @@ -561,6 +576,20 @@ bool HitTestResult::addNodeToRectBasedTestResult(Node* node, int x, int y, const node = node->shadowAncestorNode(); mutableRectBasedTestResult().add(node); + if (node->renderer()->isInline()) { + for (RenderObject* curr = node->renderer()->parent(); curr; curr = curr->parent()) { + if (!curr->isRenderInline()) + break; + + // We need to make sure the nodes for culled inlines get included. + RenderInline* currInline = toRenderInline(curr); + if (currInline->alwaysCreateLineBoxes()) + break; + + if (currInline->visibleToHitTesting() && currInline->node()) + mutableRectBasedTestResult().add(currInline->node()->shadowAncestorNode()); + } + } return !rect.contains(rectForPoint(x, y)); } diff --git a/Source/WebCore/rendering/InlineBox.cpp b/Source/WebCore/rendering/InlineBox.cpp index 930071e..f3d3a2d 100644 --- a/Source/WebCore/rendering/InlineBox.cpp +++ b/Source/WebCore/rendering/InlineBox.cpp @@ -159,7 +159,7 @@ void InlineBox::adjustPosition(float dx, float dy) toRenderBox(m_renderer)->move(dx, dy); } -void InlineBox::paint(PaintInfo& paintInfo, int tx, int ty) +void InlineBox::paint(PaintInfo& paintInfo, int tx, int ty, int /* lineTop */, int /*lineBottom*/) { if (!paintInfo.shouldPaintWithinRoot(renderer()) || (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection)) return; @@ -187,7 +187,7 @@ void InlineBox::paint(PaintInfo& paintInfo, int tx, int ty) } } -bool InlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty) +bool InlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, int /* lineTop */, int /*lineBottom*/) { // Hit test all phases of replaced elements atomically, as though the replaced element established its // own stacking context. (See Appendix E.2, section 6.4 on inline block/table elements in the CSS2.1 @@ -283,6 +283,13 @@ float InlineBox::placeEllipsisBox(bool, float, float, float, bool&) return -1; } +void InlineBox::clearKnownToHaveNoOverflow() +{ + m_knownToHaveNoOverflow = false; + if (parent() && parent()->knownToHaveNoOverflow()) + parent()->clearKnownToHaveNoOverflow(); +} + FloatPoint InlineBox::locationIncludingFlipping() { if (!renderer()->style()->isFlippedBlocksWritingMode()) diff --git a/Source/WebCore/rendering/InlineBox.h b/Source/WebCore/rendering/InlineBox.h index 9335970..8989a77 100644 --- a/Source/WebCore/rendering/InlineBox.h +++ b/Source/WebCore/rendering/InlineBox.h @@ -54,6 +54,7 @@ public: , m_isHorizontal(true) , m_endsWithBreak(false) , m_hasSelectedChildrenOrCanHaveLeadingExpansion(false) + , m_knownToHaveNoOverflow(true) , m_hasEllipsisBoxOrHyphen(false) , m_dirOverride(false) , m_isText(false) @@ -87,7 +88,8 @@ public: #endif , m_isHorizontal(isHorizontal) , m_endsWithBreak(false) - , m_hasSelectedChildrenOrCanHaveLeadingExpansion(false) + , m_hasSelectedChildrenOrCanHaveLeadingExpansion(false) + , m_knownToHaveNoOverflow(true) , m_hasEllipsisBoxOrHyphen(false) , m_dirOverride(false) , m_isText(false) @@ -128,8 +130,8 @@ public: adjustPosition(delta, 0); } - virtual void paint(PaintInfo&, int tx, int ty); - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty); + virtual void paint(PaintInfo&, int tx, int ty, int lineTop, int lineBottom); + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, int lineTop, int lineBottom); InlineBox* next() const { return m_next; } @@ -261,6 +263,8 @@ public: // The logical height is our extent in the block flow direction, i.e., height for horizontal text and width for vertical text. int logicalHeight() const; + FloatRect logicalFrameRect() const { return isHorizontal() ? IntRect(m_x, m_y, m_logicalWidth, logicalHeight()) : IntRect(m_y, m_x, m_logicalWidth, logicalHeight()); } + virtual int baselinePosition(FontBaseline baselineType) const { return boxModelObject()->baselinePosition(baselineType, m_firstLine, isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine); } virtual int lineHeight() const { return boxModelObject()->lineHeight(m_firstLine, isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine); } @@ -310,6 +314,9 @@ public: void flipForWritingMode(IntRect&); IntPoint flipForWritingMode(const IntPoint&); + bool knownToHaveNoOverflow() const { return m_knownToHaveNoOverflow; } + void clearKnownToHaveNoOverflow(); + private: InlineBox* m_next; // The next element on the same line as us. InlineBox* m_prev; // The previous element on the same line as us. @@ -342,6 +349,7 @@ protected: bool m_endsWithBreak : 1; // Whether the line ends with a <br>. // shared between RootInlineBox and InlineTextBox bool m_hasSelectedChildrenOrCanHaveLeadingExpansion : 1; // Whether we have any children selected (this bit will also be set if the <br> that terminates our line is selected). + bool m_knownToHaveNoOverflow : 1; bool m_hasEllipsisBoxOrHyphen : 1; // for InlineTextBox diff --git a/Source/WebCore/rendering/InlineFlowBox.cpp b/Source/WebCore/rendering/InlineFlowBox.cpp index b58a30e..045edff 100644 --- a/Source/WebCore/rendering/InlineFlowBox.cpp +++ b/Source/WebCore/rendering/InlineFlowBox.cpp @@ -97,7 +97,8 @@ void InlineFlowBox::addToLine(InlineBox* child) child->setFirstLineStyleBit(m_firstLine); child->setIsHorizontal(isHorizontal()); if (child->isText()) { - m_hasTextChildren = true; + if (child->renderer()->parent() == renderer()) + m_hasTextChildren = true; m_hasTextDescendants = true; } else if (child->isInlineFlowBox()) { if (static_cast<InlineFlowBox*>(child)->hasTextDescendants()) @@ -111,12 +112,13 @@ void InlineFlowBox::addToLine(InlineBox* child) if (child->renderer()->isReplaced()) shouldClearDescendantsHaveSameLineHeightAndBaseline = true; else if (child->isText()) { - if (child->renderer()->isBR()) { - if (parentStyle->font().fontMetrics().ascent() != childStyle->font().fontMetrics().ascent() - || parentStyle->font().fontMetrics().descent() != childStyle->font().fontMetrics().descent() || parentStyle->lineHeight() != childStyle->lineHeight() + if (child->renderer()->isBR() || child->renderer()->parent() != renderer()) { + if (!parentStyle->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(childStyle->font().fontMetrics()) + || parentStyle->lineHeight() != childStyle->lineHeight() || (parentStyle->verticalAlign() != BASELINE && !isRootInlineBox()) || childStyle->verticalAlign() != BASELINE) shouldClearDescendantsHaveSameLineHeightAndBaseline = true; - } else if (childStyle->hasTextCombine() || childStyle->textEmphasisMark() != TextEmphasisMarkNone) + } + if (childStyle->hasTextCombine() || childStyle->textEmphasisMark() != TextEmphasisMarkNone) shouldClearDescendantsHaveSameLineHeightAndBaseline = true; } else { if (child->renderer()->isBR()) { @@ -127,8 +129,9 @@ void InlineFlowBox::addToLine(InlineBox* child) ASSERT(isInlineFlowBox()); InlineFlowBox* childFlowBox = static_cast<InlineFlowBox*>(child); // Check the child's bit, and then also check for differences in font, line-height, vertical-align - if (!childFlowBox->descendantsHaveSameLineHeightAndBaseline() || parentStyle->font().fontMetrics().ascent() != childStyle->font().fontMetrics().ascent() - || parentStyle->font().fontMetrics().descent() != childStyle->font().fontMetrics().descent() || parentStyle->lineHeight() != childStyle->lineHeight() + if (!childFlowBox->descendantsHaveSameLineHeightAndBaseline() + || !parentStyle->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(childStyle->font().fontMetrics()) + || parentStyle->lineHeight() != childStyle->lineHeight() || (parentStyle->verticalAlign() != BASELINE && !isRootInlineBox()) || childStyle->verticalAlign() != BASELINE || childStyle->hasBorder() || childStyle->hasPadding() || childStyle->hasTextCombine()) shouldClearDescendantsHaveSameLineHeightAndBaseline = true; @@ -139,6 +142,23 @@ void InlineFlowBox::addToLine(InlineBox* child) clearDescendantsHaveSameLineHeightAndBaseline(); } + if (!child->renderer()->isPositioned()) { + if (child->isText()) { + RenderStyle* childStyle = child->renderer()->style(m_firstLine); + if (childStyle->letterSpacing() < 0 || childStyle->textShadow() || childStyle->textEmphasisMark() != TextEmphasisMarkNone || childStyle->textStrokeWidth()) + child->clearKnownToHaveNoOverflow(); + } else if (child->renderer()->isReplaced()) { + RenderBox* box = toRenderBox(child->renderer()); + if (box->hasRenderOverflow() || box->hasSelfPaintingLayer()) + child->clearKnownToHaveNoOverflow(); + } else if (!child->renderer()->isBR() && (child->renderer()->style(m_firstLine)->boxShadow() || child->boxModelObject()->hasSelfPaintingLayer() + || (child->renderer()->isListMarker() && !toRenderListMarker(child->renderer())->isInside()))) + child->clearKnownToHaveNoOverflow(); + + if (knownToHaveNoOverflow() && child->isInlineFlowBox() && !static_cast<InlineFlowBox*>(child)->knownToHaveNoOverflow()) + clearKnownToHaveNoOverflow(); + } + checkConsistency(); } @@ -232,19 +252,21 @@ RenderLineBoxList* InlineFlowBox::rendererLineBoxes() const return toRenderInline(renderer())->lineBoxes(); } -bool InlineFlowBox::onEndChain(RenderObject* endObject) +static inline bool isLastChildForRenderer(RenderObject* ancestor, RenderObject* child) { - if (!endObject) + if (!child) return false; - if (endObject == renderer()) + if (child == ancestor) return true; - RenderObject* curr = endObject; + RenderObject* curr = child; RenderObject* parent = curr->parent(); - while (parent && !parent->isRenderBlock()) { - if (parent->lastChild() != curr || parent == renderer()) + while (parent && (!parent->isRenderBlock() || parent->isInline())) { + if (parent->lastChild() != curr) return false; + if (parent == ancestor) + return true; curr = parent; parent = curr->parent(); @@ -256,7 +278,7 @@ bool InlineFlowBox::onEndChain(RenderObject* endObject) static bool isAnsectorAndWithinBlock(RenderObject* ancestor, RenderObject* child) { RenderObject* object = child; - while (object && !object->isRenderBlock()) { + while (object && (!object->isRenderBlock() || object->isInline())) { if (object == ancestor) return true; object = object->parent(); @@ -264,7 +286,7 @@ static bool isAnsectorAndWithinBlock(RenderObject* ancestor, RenderObject* child return false; } -void InlineFlowBox::determineSpacingForFlowBoxes(bool lastLine, RenderObject* endObject, RenderObject* logicallyLastRunRenderer) +void InlineFlowBox::determineSpacingForFlowBoxes(bool lastLine, bool isLogicallyLastRunWrapped, RenderObject* logicallyLastRunRenderer) { // All boxes start off open. They will not apply any margins/border/padding on // any side. @@ -287,8 +309,13 @@ void InlineFlowBox::determineSpacingForFlowBoxes(bool lastLine, RenderObject* en if (!lineBoxList->lastLineBox()->isConstructed()) { RenderInline* inlineFlow = toRenderInline(renderer()); - bool isLastObjectOnLine = (endObject && endObject->isText()) ? !isAnsectorAndWithinBlock(renderer(), logicallyLastRunRenderer->parent()) : onEndChain(logicallyLastRunRenderer); + bool isLastObjectOnLine = !isAnsectorAndWithinBlock(renderer(), logicallyLastRunRenderer) || (isLastChildForRenderer(renderer(), logicallyLastRunRenderer) && !isLogicallyLastRunWrapped); + // We include the border under these conditions: + // (1) The next line was not created, or it is constructed. We check the previous line for rtl. + // (2) The logicallyLastRun is not a descendant of this renderer. + // (3) The logicallyLastRun is a descendant of this renderer, but it is the last child of this renderer and it does not wrap to the next line. + if (ltr) { if (!nextLineBox() && ((lastLine || isLastObjectOnLine) && !inlineFlow->continuation())) @@ -307,7 +334,7 @@ void InlineFlowBox::determineSpacingForFlowBoxes(bool lastLine, RenderObject* en for (InlineBox* currChild = firstChild(); currChild; currChild = currChild->nextOnLine()) { if (currChild->isInlineFlowBox()) { InlineFlowBox* currFlow = static_cast<InlineFlowBox*>(currChild); - currFlow->determineSpacingForFlowBoxes(lastLine, endObject, logicallyLastRunRenderer); + currFlow->determineSpacingForFlowBoxes(lastLine, isLogicallyLastRunWrapped, logicallyLastRunRenderer); } } } @@ -319,7 +346,10 @@ float InlineFlowBox::placeBoxesInInlineDirection(float logicalLeft, bool& needsW float startLogicalLeft = logicalLeft; logicalLeft += borderLogicalLeft() + paddingLogicalLeft(); - + + float minLogicalLeft = startLogicalLeft; + float maxLogicalRight = logicalLeft; + for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { if (curr->renderer()->isText()) { InlineTextBox* text = static_cast<InlineTextBox*>(curr); @@ -330,7 +360,11 @@ float InlineFlowBox::placeBoxesInInlineDirection(float logicalLeft, bool& needsW needsWordSpacing = !isSpaceOrNewline(rt->characters()[text->end()]); } text->setLogicalLeft(logicalLeft); + if (knownToHaveNoOverflow()) + minLogicalLeft = min(logicalLeft, minLogicalLeft); logicalLeft += text->logicalWidth(); + if (knownToHaveNoOverflow()) + maxLogicalRight = max(logicalLeft, maxLogicalRight); } else { if (curr->renderer()->isPositioned()) { if (curr->renderer()->parent()->style()->isLeftToRightDirection()) @@ -345,7 +379,11 @@ float InlineFlowBox::placeBoxesInInlineDirection(float logicalLeft, bool& needsW if (curr->renderer()->isRenderInline()) { InlineFlowBox* flow = static_cast<InlineFlowBox*>(curr); logicalLeft += flow->marginLogicalLeft(); + if (knownToHaveNoOverflow()) + minLogicalLeft = min(logicalLeft, minLogicalLeft); logicalLeft = flow->placeBoxesInInlineDirection(logicalLeft, needsWordSpacing, textBoxDataMap); + if (knownToHaveNoOverflow()) + maxLogicalRight = max(logicalLeft, maxLogicalRight); logicalLeft += flow->marginLogicalRight(); } else if (!curr->renderer()->isListMarker() || toRenderListMarker(curr->renderer())->isInside()) { // The box can have a different writing-mode than the overall line, so this is a bit complicated. @@ -355,13 +393,20 @@ float InlineFlowBox::placeBoxesInInlineDirection(float logicalLeft, bool& needsW logicalLeft += logicalLeftMargin; curr->setLogicalLeft(logicalLeft); - logicalLeft += curr->logicalWidth() + logicalRightMargin; + if (knownToHaveNoOverflow()) + minLogicalLeft = min(logicalLeft, minLogicalLeft); + logicalLeft += curr->logicalWidth(); + if (knownToHaveNoOverflow()) + maxLogicalRight = max(logicalLeft, maxLogicalRight); + logicalLeft += logicalRightMargin; } } } logicalLeft += borderLogicalRight() + paddingLogicalRight(); setLogicalWidth(logicalLeft - startLogicalLeft); + if (knownToHaveNoOverflow() && (minLogicalLeft < startLogicalLeft || maxLogicalRight > logicalLeft)) + clearKnownToHaveNoOverflow(); return logicalLeft; } @@ -631,7 +676,7 @@ void InlineFlowBox::placeBoxesInBlockDirection(int top, int maxHeight, int maxAs lineBottom = max(lineBottom, newLogicalTop + boxHeight); lineBottomIncludingMargins = max(lineBottom, max(lineBottomIncludingMargins, newLogicalTopIncludingMargins + boxHeightIncludingMargins)); } - + // Adjust boxes to use their real box y/height and not the logical height (as dictated by // line-height). if (inlineFlowBox) @@ -674,7 +719,7 @@ void InlineFlowBox::flipLinesInBlockDirection(int lineTop, int lineBottom) } } -void InlineFlowBox::addBoxShadowVisualOverflow(IntRect& logicalVisualOverflow) +inline void InlineFlowBox::addBoxShadowVisualOverflow(IntRect& logicalVisualOverflow) { if (!parent()) return; // Box-shadow doesn't apply to root line boxes. @@ -697,14 +742,15 @@ void InlineFlowBox::addBoxShadowVisualOverflow(IntRect& logicalVisualOverflow) logicalRightVisualOverflow - logicalLeftVisualOverflow, logicalBottomVisualOverflow - logicalTopVisualOverflow); } -void InlineFlowBox::addTextBoxVisualOverflow(const InlineTextBox* textBox, GlyphOverflowAndFallbackFontsMap& textBoxDataMap, IntRect& logicalVisualOverflow) +inline void InlineFlowBox::addTextBoxVisualOverflow(InlineTextBox* textBox, GlyphOverflowAndFallbackFontsMap& textBoxDataMap, IntRect& logicalVisualOverflow) { - RenderStyle* style = renderer()->style(m_firstLine); - int strokeOverflow = static_cast<int>(ceilf(style->textStrokeWidth() / 2.0f)); + if (textBox->knownToHaveNoOverflow()) + return; + RenderStyle* style = textBox->renderer()->style(m_firstLine); + GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.find(textBox); GlyphOverflow* glyphOverflow = it == textBoxDataMap.end() ? 0 : &it->second.second; - bool isFlippedLine = style->isFlippedLinesWritingMode(); int topGlyphEdge = glyphOverflow ? (isFlippedLine ? glyphOverflow->bottom : glyphOverflow->top) : 0; @@ -712,6 +758,7 @@ void InlineFlowBox::addTextBoxVisualOverflow(const InlineTextBox* textBox, Glyph int leftGlyphEdge = glyphOverflow ? glyphOverflow->left : 0; int rightGlyphEdge = glyphOverflow ? glyphOverflow->right : 0; + int strokeOverflow = static_cast<int>(ceilf(style->textStrokeWidth() / 2.0f)); int topGlyphOverflow = -strokeOverflow - topGlyphEdge; int bottomGlyphOverflow = strokeOverflow + bottomGlyphEdge; int leftGlyphOverflow = -strokeOverflow - leftGlyphEdge; @@ -728,8 +775,7 @@ void InlineFlowBox::addTextBoxVisualOverflow(const InlineTextBox* textBox, Glyph // If letter-spacing is negative, we should factor that into right layout overflow. (Even in RTL, letter-spacing is // applied to the right, so this is not an issue with left overflow. - int letterSpacing = min(0, (int)style->font().letterSpacing()); - rightGlyphOverflow -= letterSpacing; + rightGlyphOverflow -= min(0, (int)style->font().letterSpacing()); int textShadowLogicalTop; int textShadowLogicalBottom; @@ -752,9 +798,11 @@ void InlineFlowBox::addTextBoxVisualOverflow(const InlineTextBox* textBox, Glyph logicalVisualOverflow = IntRect(logicalLeftVisualOverflow, logicalTopVisualOverflow, logicalRightVisualOverflow - logicalLeftVisualOverflow, logicalBottomVisualOverflow - logicalTopVisualOverflow); + + textBox->setLogicalOverflowRect(logicalVisualOverflow); } -void InlineFlowBox::addReplacedChildOverflow(const InlineBox* inlineBox, IntRect& logicalLayoutOverflow, IntRect& logicalVisualOverflow) +inline void InlineFlowBox::addReplacedChildOverflow(const InlineBox* inlineBox, IntRect& logicalLayoutOverflow, IntRect& logicalVisualOverflow) { RenderBox* box = toRenderBox(inlineBox->renderer()); @@ -775,17 +823,16 @@ void InlineFlowBox::addReplacedChildOverflow(const InlineBox* inlineBox, IntRect logicalLayoutOverflow.unite(childLogicalLayoutOverflow); } -void InlineFlowBox::computeOverflow(int lineTop, int lineBottom, bool strictMode, GlyphOverflowAndFallbackFontsMap& textBoxDataMap) +void InlineFlowBox::computeOverflow(int lineTop, int lineBottom, GlyphOverflowAndFallbackFontsMap& textBoxDataMap) { - // Any spillage outside of the line top and bottom is not considered overflow. We just ignore this, since it only happens - // from the "your ascent/descent don't affect the line" quirk. - int topOverflow = max(logicalTop(), lineTop); - int bottomOverflow = min(logicalBottom(), lineBottom); - + // If we know we have no overflow, we can just bail. + if (knownToHaveNoOverflow()) + return; + // Visual overflow just includes overflow for stuff we need to repaint ourselves. Self-painting layers are ignored. // Layout overflow is used to determine scrolling extent, so it still includes child layers and also factors in // transforms, relative positioning, etc. - IntRect logicalLayoutOverflow(enclosingIntRect(FloatRect(logicalLeft(), topOverflow, logicalWidth(), bottomOverflow - topOverflow))); + IntRect logicalLayoutOverflow(enclosingIntRect(logicalFrameRectIncludingLineHeight(lineTop, lineBottom))); IntRect logicalVisualOverflow(logicalLayoutOverflow); // box-shadow on root line boxes is applying to the block and not to the lines. @@ -800,50 +847,40 @@ void InlineFlowBox::computeOverflow(int lineTop, int lineBottom, bool strictMode RenderText* rt = toRenderText(text->renderer()); if (rt->isBR()) continue; - addTextBoxVisualOverflow(text, textBoxDataMap, logicalVisualOverflow); + IntRect textBoxOverflow(enclosingIntRect(text->logicalFrameRect())); + addTextBoxVisualOverflow(text, textBoxDataMap, textBoxOverflow); + logicalVisualOverflow.unite(textBoxOverflow); } else if (curr->renderer()->isRenderInline()) { InlineFlowBox* flow = static_cast<InlineFlowBox*>(curr); - flow->computeOverflow(lineTop, lineBottom, strictMode, textBoxDataMap); + flow->computeOverflow(lineTop, lineBottom, textBoxDataMap); if (!flow->boxModelObject()->hasSelfPaintingLayer()) - logicalVisualOverflow.unite(flow->logicalVisualOverflowRect()); - IntRect childLayoutOverflow = flow->logicalLayoutOverflowRect(); + logicalVisualOverflow.unite(flow->logicalVisualOverflowRect(lineTop, lineBottom)); + IntRect childLayoutOverflow = flow->logicalLayoutOverflowRect(lineTop, lineBottom); childLayoutOverflow.move(flow->boxModelObject()->relativePositionLogicalOffset()); logicalLayoutOverflow.unite(childLayoutOverflow); } else addReplacedChildOverflow(curr, logicalLayoutOverflow, logicalVisualOverflow); } - setOverflowFromLogicalRects(logicalLayoutOverflow, logicalVisualOverflow); + setOverflowFromLogicalRects(logicalLayoutOverflow, logicalVisualOverflow, lineTop, lineBottom); } -// FIXME: You will notice there is no contains() check here. If the rect is smaller than the frame box it actually -// becomes the new overflow. The reason for this is that in quirks mode we don't let inline flow boxes paint -// outside of the root line box's lineTop and lineBottom values. We accomplish this visual clamping by actually -// insetting the overflow rect so that it's smaller than the frame rect. -// -// The reason we don't just mutate the frameRect in quirks mode is that we'd have to put the m_height member variable -// back into InlineBox. Basically the tradeoff is 4 bytes in all modes (for m_height) added to InlineFlowBox, or -// the allocation of a RenderOverflow struct for InlineFlowBoxes in quirks mode only. For now, we're opting to award -// the smaller memory consumption to strict mode pages. -// -// It might be possible to hash a custom height, or to require that lineTop and lineBottom be passed in to -// all functions that query overflow. -void InlineFlowBox::setLayoutOverflow(const IntRect& rect) +void InlineFlowBox::setLayoutOverflow(const IntRect& rect, int lineTop, int lineBottom) { - IntRect frameBox = enclosingIntRect(FloatRect(x(), y(), width(), height())); - if (frameBox == rect || rect.isEmpty()) + IntRect frameBox = enclosingIntRect(frameRectIncludingLineHeight(lineTop, lineBottom)); + if (frameBox.contains(rect) || rect.isEmpty()) return; - + if (!m_overflow) m_overflow.set(new RenderOverflow(frameBox, frameBox)); m_overflow->setLayoutOverflow(rect); } -void InlineFlowBox::setVisualOverflow(const IntRect& rect) +void InlineFlowBox::setVisualOverflow(const IntRect& rect, int lineTop, int lineBottom) { - IntRect frameBox = enclosingIntRect(FloatRect(x(), y(), width(), height())); - if (frameBox == rect || rect.isEmpty()) + IntRect frameBox = enclosingIntRect(frameRectIncludingLineHeight(lineTop, lineBottom)); + if (frameBox.contains(rect) || rect.isEmpty()) return; if (!m_overflow) @@ -852,18 +889,18 @@ void InlineFlowBox::setVisualOverflow(const IntRect& rect) m_overflow->setVisualOverflow(rect); } -void InlineFlowBox::setOverflowFromLogicalRects(const IntRect& logicalLayoutOverflow, const IntRect& logicalVisualOverflow) +void InlineFlowBox::setOverflowFromLogicalRects(const IntRect& logicalLayoutOverflow, const IntRect& logicalVisualOverflow, int lineTop, int lineBottom) { IntRect layoutOverflow(isHorizontal() ? logicalLayoutOverflow : logicalLayoutOverflow.transposedRect()); - setLayoutOverflow(layoutOverflow); + setLayoutOverflow(layoutOverflow, lineTop, lineBottom); IntRect visualOverflow(isHorizontal() ? logicalVisualOverflow : logicalVisualOverflow.transposedRect()); - setVisualOverflow(visualOverflow); + setVisualOverflow(visualOverflow, lineTop, lineBottom); } -bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty) +bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, int lineTop, int lineBottom) { - IntRect overflowRect(visualOverflowRect()); + IntRect overflowRect(visualOverflowRect(lineTop, lineBottom)); flipForWritingMode(overflowRect); overflowRect.move(tx, ty); if (!overflowRect.intersects(result.rectForPoint(x, y))) @@ -871,7 +908,7 @@ bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re // Check children first. for (InlineBox* curr = lastChild(); curr; curr = curr->prevOnLine()) { - if ((curr->renderer()->isText() || !curr->boxModelObject()->hasSelfPaintingLayer()) && curr->nodeAtPoint(request, result, x, y, tx, ty)) { + if ((curr->renderer()->isText() || !curr->boxModelObject()->hasSelfPaintingLayer()) && curr->nodeAtPoint(request, result, x, y, tx, ty, lineTop, lineBottom)) { renderer()->updateHitTestResult(result, IntPoint(x - tx, y - ty)); return true; } @@ -909,9 +946,9 @@ bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re return false; } -void InlineFlowBox::paint(PaintInfo& paintInfo, int tx, int ty) +void InlineFlowBox::paint(PaintInfo& paintInfo, int tx, int ty, int lineTop, int lineBottom) { - IntRect overflowRect(visualOverflowRect()); + IntRect overflowRect(visualOverflowRect(lineTop, lineBottom)); overflowRect.inflate(renderer()->maximalOutlineSize(paintInfo.phase)); flipForWritingMode(overflowRect); overflowRect.move(tx, ty); @@ -974,7 +1011,7 @@ void InlineFlowBox::paint(PaintInfo& paintInfo, int tx, int ty) if (paintPhase != PaintPhaseSelfOutline) { for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { if (curr->renderer()->isText() || !curr->boxModelObject()->hasSelfPaintingLayer()) - curr->paint(childInfo, tx, ty); + curr->paint(childInfo, tx, ty, lineTop, lineBottom); } } } @@ -992,7 +1029,7 @@ void InlineFlowBox::paintFillLayer(const PaintInfo& paintInfo, const Color& c, c StyleImage* img = fillLayer->image(); bool hasFillImage = img && img->canRender(renderer()->style()->effectiveZoom()); if ((!hasFillImage && !renderer()->style()->hasBorderRadius()) || (!prevLineBox() && !nextLineBox()) || !parent()) - boxModelObject()->paintFillLayerExtended(paintInfo, c, fillLayer, tx, ty, w, h, this, op); + boxModelObject()->paintFillLayerExtended(paintInfo, c, fillLayer, tx, ty, w, h, this, w, h, op); else { // We have a fill image that spans multiple lines. // We need to adjust tx and ty by the width of all previous lines. @@ -1021,7 +1058,7 @@ void InlineFlowBox::paintFillLayer(const PaintInfo& paintInfo, const Color& c, c int stripHeight = isHorizontal() ? height() : totalLogicalWidth; paintInfo.context->save(); paintInfo.context->clip(IntRect(tx, ty, width(), height())); - boxModelObject()->paintFillLayerExtended(paintInfo, c, fillLayer, stripX, stripY, stripWidth, stripHeight, this, op); + boxModelObject()->paintFillLayerExtended(paintInfo, c, fillLayer, stripX, stripY, stripWidth, stripHeight, this, w, h, op); paintInfo.context->restore(); } } diff --git a/Source/WebCore/rendering/InlineFlowBox.h b/Source/WebCore/rendering/InlineFlowBox.h index 9b6f8e4..9b34e9d 100644 --- a/Source/WebCore/rendering/InlineFlowBox.h +++ b/Source/WebCore/rendering/InlineFlowBox.h @@ -105,8 +105,8 @@ public: void paintFillLayers(const PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int w, int h, CompositeOperator = CompositeSourceOver); void paintFillLayer(const PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int w, int h, CompositeOperator = CompositeSourceOver); void paintBoxShadow(GraphicsContext*, RenderStyle*, ShadowStyle, int tx, int ty, int w, int h); - virtual void paint(PaintInfo&, int tx, int ty); - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty); + virtual void paint(PaintInfo&, int tx, int ty, int lineTop, int lineBottom); + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, int lineTop, int lineBottom); virtual RenderLineBoxList* rendererLineBoxes() const; @@ -159,9 +159,8 @@ public: } // Helper functions used during line construction and placement. - void determineSpacingForFlowBoxes(bool lastLine, RenderObject* endObject, RenderObject* logicallyLastRunRenderer); + void determineSpacingForFlowBoxes(bool lastLine, bool isLogicallyLastRunWrapped, RenderObject* logicallyLastRunRenderer); int getFlowSpacingLogicalWidth(); - bool onEndChain(RenderObject* endObject); float placeBoxesInInlineDirection(float logicalLeft, bool& needsWordSpacing, GlyphOverflowAndFallbackFontsMap&); void computeLogicalBoxHeights(RootInlineBox*, int& maxPositionTop, int& maxPositionBottom, int& maxAscent, int& maxDescent, bool& setMaxAscent, bool& setMaxDescent, @@ -176,7 +175,7 @@ public: int computeOverAnnotationAdjustment(int allowedPosition) const; int computeUnderAnnotationAdjustment(int allowedPosition) const; - void computeOverflow(int lineTop, int lineBottom, bool strictMode, GlyphOverflowAndFallbackFontsMap&); + void computeOverflow(int lineTop, int lineBottom, GlyphOverflowAndFallbackFontsMap&); void removeChild(InlineBox* child); @@ -194,44 +193,74 @@ public: // 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() : ceilf(m_y + height()); } - int minXLayoutOverflow() const { return m_overflow ? m_overflow->minXLayoutOverflow() : m_x; } - int maxXLayoutOverflow() const { return m_overflow ? m_overflow->maxXLayoutOverflow() : ceilf(m_x + width()); } - IntRect layoutOverflowRect() const { return m_overflow ? m_overflow->layoutOverflowRect() : enclosingIntRect(FloatRect(m_x, m_y, width(), height())); } - int logicalLeftLayoutOverflow() const { return renderer()->style()->isHorizontalWritingMode() ? minXLayoutOverflow() : minYLayoutOverflow(); } - int logicalRightLayoutOverflow() const { return renderer()->style()->isHorizontalWritingMode() ? maxXLayoutOverflow() : maxYLayoutOverflow(); } - int logicalTopLayoutOverflow() const { return renderer()->style()->isHorizontalWritingMode() ? minYVisualOverflow() : minXVisualOverflow(); } - int logicalBottomLayoutOverflow() const { return renderer()->style()->isHorizontalWritingMode() ? maxYLayoutOverflow() : maxXLayoutOverflow(); } - IntRect logicalLayoutOverflowRect() const + IntRect layoutOverflowRect(int lineTop, int lineBottom) const + { + return m_overflow ? m_overflow->layoutOverflowRect() : enclosingIntRect(frameRectIncludingLineHeight(lineTop, lineBottom)); + } + int logicalLeftLayoutOverflow() const { return m_overflow ? (isHorizontal() ? m_overflow->minXLayoutOverflow() : m_overflow->minYLayoutOverflow()) : logicalLeft(); } + int logicalRightLayoutOverflow() const { return m_overflow ? (isHorizontal() ? m_overflow->maxXLayoutOverflow() : m_overflow->maxYLayoutOverflow()) : ceilf(logicalRight()); } + int logicalTopLayoutOverflow(int lineTop) const { - IntRect result = layoutOverflowRect(); - if (!renderer()->style()->isHorizontalWritingMode()) + if (m_overflow) + return isHorizontal() ? m_overflow->minYLayoutOverflow() : m_overflow->minXLayoutOverflow(); + return lineTop; + } + int logicalBottomLayoutOverflow(int lineBottom) const + { + if (m_overflow) + return isHorizontal() ? m_overflow->maxYLayoutOverflow() : m_overflow->maxXLayoutOverflow(); + return lineBottom; + } + IntRect logicalLayoutOverflowRect(int lineTop, int lineBottom) const + { + IntRect result = layoutOverflowRect(lineTop, lineBottom); + if (!renderer()->isHorizontalWritingMode()) result = result.transposedRect(); return result; } - int minYVisualOverflow() const { return m_overflow ? m_overflow->minYVisualOverflow() : m_y; } - int maxYVisualOverflow() const { return m_overflow ? m_overflow->maxYVisualOverflow() : ceilf(m_y + height()); } - int minXVisualOverflow() const { return m_overflow ? m_overflow->minXVisualOverflow() : m_x; } - int maxXVisualOverflow() const { return m_overflow ? m_overflow->maxXVisualOverflow() : ceilf(m_x + width()); } - IntRect visualOverflowRect() const { return m_overflow ? m_overflow->visualOverflowRect() : enclosingIntRect(FloatRect(m_x, m_y, width(), height())); } - int logicalLeftVisualOverflow() const { return renderer()->style()->isHorizontalWritingMode() ? minXVisualOverflow() : minYVisualOverflow(); } - int logicalRightVisualOverflow() const { return renderer()->style()->isHorizontalWritingMode() ? maxXVisualOverflow() : maxYVisualOverflow(); } - int logicalTopVisualOverflow() const { return renderer()->style()->isHorizontalWritingMode() ? minYVisualOverflow() : minXVisualOverflow(); } - int logicalBottomVisualOverflow() const { return renderer()->style()->isHorizontalWritingMode() ? maxYVisualOverflow() : maxXVisualOverflow(); } - IntRect logicalVisualOverflowRect() const + IntRect visualOverflowRect(int lineTop, int lineBottom) const + { + return m_overflow ? m_overflow->visualOverflowRect() : enclosingIntRect(frameRectIncludingLineHeight(lineTop, lineBottom)); + } + int logicalLeftVisualOverflow() const { return m_overflow ? (isHorizontal() ? m_overflow->minXVisualOverflow() : m_overflow->minYVisualOverflow()) : logicalLeft(); } + int logicalRightVisualOverflow() const { return m_overflow ? (isHorizontal() ? m_overflow->maxXVisualOverflow() : m_overflow->maxYVisualOverflow()) : ceilf(logicalRight()); } + int logicalTopVisualOverflow(int lineTop) const + { + if (m_overflow) + return isHorizontal() ? m_overflow->minYVisualOverflow() : m_overflow->minXVisualOverflow(); + return lineTop; + } + int logicalBottomVisualOverflow(int lineBottom) const + { + if (m_overflow) + return isHorizontal() ? m_overflow->maxYVisualOverflow() : m_overflow->maxXVisualOverflow(); + return lineBottom; + } + IntRect logicalVisualOverflowRect(int lineTop, int lineBottom) const { - IntRect result = visualOverflowRect(); - if (!renderer()->style()->isHorizontalWritingMode()) + IntRect result = visualOverflowRect(lineTop, lineBottom); + if (!renderer()->isHorizontalWritingMode()) result = result.transposedRect(); return result; } - void setOverflowFromLogicalRects(const IntRect& logicalLayoutOverflow, const IntRect& logicalVisualOverflow); - void setLayoutOverflow(const IntRect&); - void setVisualOverflow(const IntRect&); + void setOverflowFromLogicalRects(const IntRect& logicalLayoutOverflow, const IntRect& logicalVisualOverflow, int lineTop, int lineBottom); + void setLayoutOverflow(const IntRect&, int lineTop, int lineBottom); + void setVisualOverflow(const IntRect&, int lineTop, int lineBottom); + FloatRect frameRectIncludingLineHeight(int lineTop, int lineBottom) const + { + if (isHorizontal()) + return FloatRect(m_x, lineTop, width(), lineBottom - lineTop); + return FloatRect(lineTop, m_y, lineBottom - lineTop, height()); + } + + FloatRect logicalFrameRectIncludingLineHeight(int lineTop, int lineBottom) const + { + return FloatRect(logicalLeft(), lineTop, logicalWidth(), lineBottom - lineTop); + } + bool descendantsHaveSameLineHeightAndBaseline() const { return m_descendantsHaveSameLineHeightAndBaseline; } void clearDescendantsHaveSameLineHeightAndBaseline() { @@ -242,7 +271,7 @@ public: private: void addBoxShadowVisualOverflow(IntRect& logicalVisualOverflow); - void addTextBoxVisualOverflow(const InlineTextBox*, GlyphOverflowAndFallbackFontsMap&, IntRect& logicalVisualOverflow); + void addTextBoxVisualOverflow(InlineTextBox*, GlyphOverflowAndFallbackFontsMap&, IntRect& logicalVisualOverflow); void addReplacedChildOverflow(const InlineBox*, IntRect& logicalLayoutOverflow, IntRect& logicalVisualOverflow); protected: diff --git a/Source/WebCore/rendering/InlineIterator.h b/Source/WebCore/rendering/InlineIterator.h index 75d9763..1f6b21c 100644 --- a/Source/WebCore/rendering/InlineIterator.h +++ b/Source/WebCore/rendering/InlineIterator.h @@ -34,15 +34,15 @@ namespace WebCore { class InlineIterator { public: InlineIterator() - : m_block(0) + : m_root(0) , m_obj(0) , m_pos(0) , m_nextBreakablePosition(-1) { } - InlineIterator(RenderBlock* b, RenderObject* o, unsigned p) - : m_block(b) + InlineIterator(RenderObject* root, RenderObject* o, unsigned p) + : m_root(root) , m_obj(o) , m_pos(p) , m_nextBreakablePosition(-1) @@ -63,13 +63,30 @@ public: m_nextBreakablePosition = nextBreak; } - void increment(InlineBidiResolver* resolver = 0); + RenderObject* root() const { return m_root; } + + void increment(InlineBidiResolver* = 0); bool atEnd() const; + inline bool atTextParagraphSeparator() + { + return m_obj && m_obj->preservesNewline() && m_obj->isText() && toRenderText(m_obj)->textLength() + && !toRenderText(m_obj)->isWordBreak() && toRenderText(m_obj)->characters()[m_pos] == '\n'; + } + + inline bool atParagraphSeparator() + { + return (m_obj && m_obj->isBR()) || atTextParagraphSeparator(); + } + UChar current() const; ALWAYS_INLINE WTF::Unicode::Direction direction() const; - RenderBlock* m_block; +private: + RenderObject* m_root; + + // FIXME: These should be private. +public: RenderObject* m_obj; unsigned m_pos; int m_nextBreakablePosition; @@ -117,7 +134,7 @@ static inline void notifyResolverWillExitObject(InlineBidiResolver* resolver, Re // FIXME: This function is misleadingly named. It has little to do with bidi. // This function will iterate over inlines within a block, optionally notifying // a bidi resolver as it enters/exits inlines (so it can push/pop embedding levels). -static inline RenderObject* bidiNext(RenderBlock* block, RenderObject* current, InlineBidiResolver* resolver = 0, bool skipInlines = true, bool* endOfInlinePtr = 0) +static inline RenderObject* bidiNext(RenderObject* root, RenderObject* current, InlineBidiResolver* resolver = 0, bool skipInlines = true, bool* endOfInlinePtr = 0) { RenderObject* next = 0; bool oldEndOfInline = endOfInlinePtr ? *endOfInlinePtr : false; @@ -137,7 +154,7 @@ static inline RenderObject* bidiNext(RenderBlock* block, RenderObject* current, break; } - while (current && current != block) { + while (current && current != root) { notifyResolverWillExitObject(resolver, current); next = current->nextSibling(); @@ -147,7 +164,7 @@ static inline RenderObject* bidiNext(RenderBlock* block, RenderObject* current, } current = current->parent(); - if (!skipInlines && current && current != block && current->isRenderInline()) { + if (!skipInlines && current && current != root && current->isRenderInline()) { next = current; endOfInline = true; break; @@ -171,16 +188,16 @@ static inline RenderObject* bidiNext(RenderBlock* block, RenderObject* current, return next; } -static inline RenderObject* bidiFirst(RenderBlock* block, InlineBidiResolver* resolver, bool skipInlines = true) +static inline RenderObject* bidiFirst(RenderObject* root, InlineBidiResolver* resolver, bool skipInlines = true) { - if (!block->firstChild()) + if (!root->firstChild()) return 0; - RenderObject* o = block->firstChild(); + RenderObject* o = root->firstChild(); if (o->isRenderInline()) { notifyResolverEnteredObject(resolver, o); if (skipInlines && o->firstChild()) - o = bidiNext(block, o, resolver, skipInlines); + o = bidiNext(root, o, resolver, skipInlines); else { // Never skip empty inlines. if (resolver) @@ -190,7 +207,7 @@ static inline RenderObject* bidiFirst(RenderBlock* block, InlineBidiResolver* re } if (o && !o->isText() && !o->isReplaced() && !o->isFloating() && !o->isPositioned()) - o = bidiNext(block, o, resolver, skipInlines); + o = bidiNext(root, o, resolver, skipInlines); if (resolver) resolver->commitExplicitEmbedding(); @@ -207,7 +224,7 @@ inline void InlineIterator::increment(InlineBidiResolver* resolver) return; } // bidiNext can return 0, so use moveTo instead of moveToStartOf - moveTo(bidiNext(m_block, m_obj, resolver), 0); + moveTo(bidiNext(m_root, m_obj, resolver), 0); } inline bool InlineIterator::atEnd() const @@ -247,13 +264,13 @@ inline void InlineBidiResolver::increment() template <> inline void InlineBidiResolver::appendRun() { - if (!emptyRun && !m_eor.atEnd()) { + if (!m_emptyRun && !m_eor.atEnd()) { int start = m_sor.m_pos; RenderObject* obj = m_sor.m_obj; while (obj && obj != m_eor.m_obj && obj != endOfLine.m_obj) { - RenderBlock::appendRunsForObject(start, obj->length(), obj, *this); + RenderBlock::appendRunsForObject(m_runs, start, obj->length(), obj, *this); start = 0; - obj = bidiNext(m_sor.m_block, obj); + obj = bidiNext(m_sor.root(), obj); } if (obj) { unsigned pos = obj == m_eor.m_obj ? m_eor.m_pos : UINT_MAX; @@ -263,9 +280,9 @@ inline void InlineBidiResolver::appendRun() } // It's OK to add runs for zero-length RenderObjects, just don't make the run larger than it should be int end = obj->length() ? pos + 1 : 0; - RenderBlock::appendRunsForObject(start, end, obj, *this); + RenderBlock::appendRunsForObject(m_runs, start, end, obj, *this); } - + m_eor.increment(); m_sor = m_eor; } diff --git a/Source/WebCore/rendering/InlineTextBox.cpp b/Source/WebCore/rendering/InlineTextBox.cpp index b614f0f..5815b8b 100644 --- a/Source/WebCore/rendering/InlineTextBox.cpp +++ b/Source/WebCore/rendering/InlineTextBox.cpp @@ -48,20 +48,49 @@ using namespace std; namespace WebCore { +typedef WTF::HashMap<const InlineTextBox*, IntRect> InlineTextBoxOverflowMap; +static InlineTextBoxOverflowMap* gTextBoxesWithOverflow; + +void InlineTextBox::destroy(RenderArena* arena) +{ + if (!m_knownToHaveNoOverflow && gTextBoxesWithOverflow) + gTextBoxesWithOverflow->remove(this); + InlineBox::destroy(arena); +} + +IntRect InlineTextBox::logicalOverflowRect() const +{ + if (m_knownToHaveNoOverflow || !gTextBoxesWithOverflow) + return enclosingIntRect(logicalFrameRect()); + return gTextBoxesWithOverflow->get(this); +} + +void InlineTextBox::setLogicalOverflowRect(const IntRect& rect) +{ + ASSERT(!m_knownToHaveNoOverflow); + if (!gTextBoxesWithOverflow) + gTextBoxesWithOverflow = new InlineTextBoxOverflowMap; + gTextBoxesWithOverflow->add(this, rect); +} + int InlineTextBox::baselinePosition(FontBaseline baselineType) const { if (!isText() || !parent()) return 0; - return parent()->baselinePosition(baselineType); + if (parent()->renderer() == renderer()->parent()) + return parent()->baselinePosition(baselineType); + return toRenderBoxModelObject(renderer()->parent())->baselinePosition(baselineType, m_firstLine, isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine); } int InlineTextBox::lineHeight() const { - if (!isText() || !parent()) + if (!isText() || !renderer()->parent()) return 0; if (m_renderer->isBR()) return toRenderBR(m_renderer)->lineHeight(m_firstLine); - return parent()->lineHeight(); + if (parent()->renderer() == renderer()->parent()) + return parent()->lineHeight(); + return toRenderBoxModelObject(renderer()->parent())->lineHeight(m_firstLine, isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine); } int InlineTextBox::selectionTop() @@ -314,7 +343,7 @@ bool InlineTextBox::isLineBreak() const return renderer()->isBR() || (renderer()->style()->preserveNewline() && len() == 1 && (*textRenderer()->text())[start()] == '\n'); } -bool InlineTextBox::nodeAtPoint(const HitTestRequest&, HitTestResult& result, int x, int y, int tx, int ty) +bool InlineTextBox::nodeAtPoint(const HitTestRequest&, HitTestResult& result, int x, int y, int tx, int ty, int /* lineTop */, int /*lineBottom*/) { if (isLineBreak()) return false; @@ -435,7 +464,7 @@ static inline AffineTransform rotation(const FloatRect& boxRect, RotationDirecti : AffineTransform(0, -1, 1, 0, boxRect.x() - boxRect.maxY(), boxRect.x() + boxRect.maxY()); } -void InlineTextBox::paint(PaintInfo& paintInfo, int tx, int ty) +void InlineTextBox::paint(PaintInfo& paintInfo, int tx, int ty, int /*lineTop*/, int /*lineBottom*/) { if (isLineBreak() || !paintInfo.shouldPaintWithinRoot(renderer()) || renderer()->style()->visibility() != VISIBLE || m_truncation == cFullTruncation || paintInfo.phase == PaintPhaseOutline || !m_len) @@ -443,12 +472,10 @@ void InlineTextBox::paint(PaintInfo& paintInfo, int tx, int ty) ASSERT(paintInfo.phase != PaintPhaseSelfOutline && paintInfo.phase != PaintPhaseChildOutlines); - // FIXME: Technically we're potentially incorporating other visual overflow that had nothing to do with us. - // Would it be simpler to just check our own shadow and stroke overflow by hand here? - int logicalLeftOverflow = parent()->logicalLeft() - parent()->logicalLeftVisualOverflow(); - int logicalRightOverflow = parent()->logicalRightVisualOverflow() - (parent()->logicalLeft() + parent()->logicalWidth()); - int logicalStart = logicalLeft() - logicalLeftOverflow + (isHorizontal() ? tx : ty); - int logicalExtent = logicalWidth() + logicalLeftOverflow + logicalRightOverflow; + int logicalLeftSide = logicalLeftVisualOverflow(); + int logicalRightSide = logicalRightVisualOverflow(); + int logicalStart = logicalLeftSide + (isHorizontal() ? tx : ty); + int logicalExtent = logicalRightSide - logicalLeftSide; int paintEnd = isHorizontal() ? paintInfo.rect.maxX() : paintInfo.rect.maxY(); int paintStart = isHorizontal() ? paintInfo.rect.x() : paintInfo.rect.y(); diff --git a/Source/WebCore/rendering/InlineTextBox.h b/Source/WebCore/rendering/InlineTextBox.h index 98a1b78..1878c9f 100644 --- a/Source/WebCore/rendering/InlineTextBox.h +++ b/Source/WebCore/rendering/InlineTextBox.h @@ -51,6 +51,8 @@ public: { } + virtual void destroy(RenderArena*); + InlineTextBox* prevTextBox() const { return m_prevTextBox; } InlineTextBox* nextTextBox() const { return m_nextTextBox; } void setNextTextBox(InlineTextBox* n) { m_nextTextBox = n; } @@ -80,6 +82,13 @@ public: bool getEmphasisMarkPosition(RenderStyle*, TextEmphasisPosition&) const; + IntRect logicalOverflowRect() const; + void setLogicalOverflowRect(const IntRect&); + int logicalTopVisualOverflow() const { return logicalOverflowRect().y(); } + int logicalBottomVisualOverflow() const { return logicalOverflowRect().maxY(); } + int logicalLeftVisualOverflow() const { return logicalOverflowRect().x(); } + int logicalRightVisualOverflow() const { return logicalOverflowRect().maxX(); } + private: int selectionTop(); int selectionBottom(); @@ -93,8 +102,8 @@ public: void selectionStartEnd(int& sPos, int& ePos); protected: - virtual void paint(PaintInfo&, int tx, int ty); - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty); + virtual void paint(PaintInfo&, int tx, int ty, int lineTop, int lineBottom); + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, int lineTop, int lineBottom); public: RenderText* textRenderer() const; diff --git a/Source/WebCore/rendering/MediaControlElements.cpp b/Source/WebCore/rendering/MediaControlElements.cpp deleted file mode 100644 index 07df4d9..0000000 --- a/Source/WebCore/rendering/MediaControlElements.cpp +++ /dev/null @@ -1,1130 +0,0 @@ -/* - * Copyright (C) 2008, 2009, 2010 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" - -#if ENABLE(VIDEO) - -#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 "RenderFlexibleBox.h" -#include "RenderMedia.h" -#include "RenderSlider.h" -#include "RenderTheme.h" -#include "RenderView.h" -#include "Settings.h" - -namespace WebCore { - -using namespace HTMLNames; - -HTMLMediaElement* toParentMediaElement(RenderObject* o) -{ - Node* node = o->node(); - Node* mediaNode = node ? node->shadowAncestorNode() : 0; - if (!mediaNode || (!mediaNode->hasTagName(HTMLNames::videoTag) && !mediaNode->hasTagName(HTMLNames::audioTag))) - return 0; - - return static_cast<HTMLMediaElement*>(mediaNode); -} - -// FIXME: These constants may need to be tweaked to better match the seeking in the QuickTime plug-in. -static const float cSeekRepeatDelay = 0.1f; -static const float cStepTime = 0.07f; -static const float cSeekTime = 0.2f; - -inline MediaControlShadowRootElement::MediaControlShadowRootElement(HTMLMediaElement* mediaElement) - : HTMLDivElement(divTag, mediaElement->document()) -{ - setShadowHost(mediaElement); -} - -PassRefPtr<MediaControlShadowRootElement> MediaControlShadowRootElement::create(HTMLMediaElement* mediaElement) -{ - RefPtr<MediaControlShadowRootElement> element = adoptRef(new MediaControlShadowRootElement(mediaElement)); - - RefPtr<RenderStyle> rootStyle = RenderStyle::create(); - rootStyle->inheritFrom(mediaElement->renderer()->style()); - rootStyle->setDisplay(BLOCK); - rootStyle->setPosition(RelativePosition); - - RenderMediaControlShadowRoot* renderer = new (mediaElement->renderer()->renderArena()) RenderMediaControlShadowRoot(element.get()); - renderer->setStyle(rootStyle.release()); - - element->setRenderer(renderer); - element->setAttached(); - element->setInDocument(); - - return element.release(); -} - -void MediaControlShadowRootElement::detach() -{ - HTMLDivElement::detach(); - // FIXME: Remove once shadow DOM uses Element::setShadowRoot(). - setShadowHost(0); -} - -// ---------------------------- - -MediaControlElement::MediaControlElement(HTMLMediaElement* mediaElement) - : HTMLDivElement(divTag, mediaElement->document()) - , m_mediaElement(mediaElement) -{ - setInDocument(); -} - -void MediaControlElement::attachToParent(Element* parent) -{ - // FIXME: This code seems very wrong. Why are we magically adding |this| to the DOM here? - // We shouldn't be calling parser API methods outside of the parser! - parent->parserAddChild(this); -} - -void MediaControlElement::update() -{ - if (renderer()) - renderer()->updateFromElement(); - updateStyle(); -} - -PassRefPtr<RenderStyle> MediaControlElement::styleForElement() -{ - ASSERT(m_mediaElement->renderer()); - RefPtr<RenderStyle> style = document()->styleSelector()->styleForElement(this, m_mediaElement->renderer()->style(), true); - if (!style) - return 0; - - // text-decoration can't be overrided from CSS. So we do it here. - // See https://bugs.webkit.org/show_bug.cgi?id=27015 - style->setTextDecoration(TDNONE); - style->setTextDecorationsInEffect(TDNONE); - - return style; -} - -bool MediaControlElement::rendererIsNeeded(RenderStyle* style) -{ - ASSERT(document()->page()); - - return HTMLDivElement::rendererIsNeeded(style) && parentNode() && parentNode()->renderer() - && (!style->hasAppearance() || document()->page()->theme()->shouldRenderMediaControlPart(style->appearance(), m_mediaElement)); -} - -void MediaControlElement::attach() -{ - RefPtr<RenderStyle> style = styleForElement(); - if (!style) - return; - bool needsRenderer = rendererIsNeeded(style.get()); - if (!needsRenderer) - return; - RenderObject* renderer = createRenderer(m_mediaElement->renderer()->renderArena(), style.get()); - if (!renderer) - return; - renderer->setStyle(style.get()); - setRenderer(renderer); - if (parentNode() && parentNode()->renderer()) { - // Find next sibling with a renderer to determine where to insert. - Node* sibling = nextSibling(); - while (sibling && !sibling->renderer()) - sibling = sibling->nextSibling(); - parentNode()->renderer()->addChild(renderer, sibling ? sibling->renderer() : 0); - } - ContainerNode::attach(); -} - -void MediaControlElement::updateStyle() -{ - if (!m_mediaElement || !m_mediaElement->renderer()) - return; - - RefPtr<RenderStyle> style = styleForElement(); - if (!style) - return; - - bool needsRenderer = rendererIsNeeded(style.get()) && parentNode() && parentNode()->renderer(); - if (renderer() && !needsRenderer) - detach(); - else if (!renderer() && needsRenderer) - attach(); - else if (renderer()) { - renderer()->setStyle(style.get()); - - // Make sure that if there is any innerText renderer, it is updated as well. - if (firstChild() && firstChild()->renderer()) - firstChild()->renderer()->setStyle(style.get()); - } -} - -// ---------------------------- - -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) -{ -} - -PassRefPtr<MediaControlTimelineContainerElement> MediaControlTimelineContainerElement::create(HTMLMediaElement* mediaElement) -{ - return adoptRef(new MediaControlTimelineContainerElement(mediaElement)); -} - -bool MediaControlTimelineContainerElement::rendererIsNeeded(RenderStyle* style) -{ - if (!MediaControlElement::rendererIsNeeded(style)) - return false; - - // 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; -} - -// ---------------------------- - -class RenderMediaVolumeSliderContainer : public RenderBlock { -public: - RenderMediaVolumeSliderContainer(Node*); - -private: - virtual void layout(); -}; - -RenderMediaVolumeSliderContainer::RenderMediaVolumeSliderContainer(Node* node) - : RenderBlock(node) -{ -} - -void RenderMediaVolumeSliderContainer::layout() -{ - RenderBlock::layout(); - if (style()->display() == NONE || !previousSibling() || !previousSibling()->isBox()) - return; - - RenderBox* buttonBox = toRenderBox(previousSibling()); - - if (view()) - view()->disableLayoutState(); - - IntPoint offset = theme()->volumeSliderOffsetFromMuteButton(buttonBox, IntSize(width(), height())); - setX(offset.x() + buttonBox->offsetLeft()); - setY(offset.y() + buttonBox->offsetTop()); - - if (view()) - view()->enableLayoutState(); -} - -inline MediaControlVolumeSliderContainerElement::MediaControlVolumeSliderContainerElement(HTMLMediaElement* mediaElement) - : MediaControlElement(mediaElement) - , m_isVisible(false) -{ -} - -PassRefPtr<MediaControlVolumeSliderContainerElement> MediaControlVolumeSliderContainerElement::create(HTMLMediaElement* mediaElement) -{ - return adoptRef(new MediaControlVolumeSliderContainerElement(mediaElement)); -} - -RenderObject* MediaControlVolumeSliderContainerElement::createRenderer(RenderArena* arena, RenderStyle*) -{ - return new (arena) RenderMediaVolumeSliderContainer(this); -} - -PassRefPtr<RenderStyle> MediaControlVolumeSliderContainerElement::styleForElement() -{ - RefPtr<RenderStyle> style = MediaControlElement::styleForElement(); - style->setPosition(AbsolutePosition); - style->setDisplay(m_isVisible ? BLOCK : NONE); - return style; -} - -void MediaControlVolumeSliderContainerElement::setVisible(bool visible) -{ - if (visible == m_isVisible) - return; - m_isVisible = visible; -} - -bool MediaControlVolumeSliderContainerElement::hitTest(const IntPoint& absPoint) -{ - if (renderer() && renderer()->style()->hasAppearance()) - return renderer()->theme()->hitTestMediaControlPart(renderer(), 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) - , m_stateBeingDisplayed(Nothing) -{ -} - -PassRefPtr<MediaControlStatusDisplayElement> MediaControlStatusDisplayElement::create(HTMLMediaElement* mediaElement) -{ - return adoptRef(new MediaControlStatusDisplayElement(mediaElement)); -} - -void MediaControlStatusDisplayElement::update() -{ - MediaControlElement::update(); - - // Get the new state that we'll have to display. - StateBeingDisplayed newStateToDisplay = Nothing; - - if (mediaElement()->readyState() != HTMLMediaElement::HAVE_ENOUGH_DATA && !mediaElement()->currentSrc().isEmpty()) - newStateToDisplay = Loading; - else if (mediaElement()->movieLoadType() == MediaPlayer::LiveStream) - newStateToDisplay = LiveBroadcast; - - // Propagate only if needed. - if (newStateToDisplay == m_stateBeingDisplayed) - return; - m_stateBeingDisplayed = newStateToDisplay; - - ExceptionCode e; - switch (m_stateBeingDisplayed) { - case Nothing: - setInnerText("", e); - break; - case Loading: - setInnerText(mediaElementLoadingStateText(), e); - break; - case LiveBroadcast: - setInnerText(mediaElementLiveBroadcastStateText(), e); - break; - } -} - -bool MediaControlStatusDisplayElement::rendererIsNeeded(RenderStyle* 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, MediaControlElementType displayType) - : HTMLInputElement(inputTag, mediaElement->document(), 0, false) - , m_mediaElement(mediaElement) - , m_displayType(displayType) -{ -} - -void MediaControlInputElement::attachToParent(Element* parent) -{ - // FIXME: This code seems very wrong. Why are we magically adding |this| to the DOM here? - // We shouldn't be calling parser API methods outside of the parser! - parent->parserAddChild(this); -} - -void MediaControlInputElement::update() -{ - updateDisplayType(); - if (renderer()) - renderer()->updateFromElement(); - updateStyle(); -} - -PassRefPtr<RenderStyle> MediaControlInputElement::styleForElement() -{ - return document()->styleSelector()->styleForElement(this, 0, true); -} - -bool MediaControlInputElement::rendererIsNeeded(RenderStyle* style) -{ - ASSERT(document()->page()); - - return HTMLInputElement::rendererIsNeeded(style) && parentNode() && parentNode()->renderer() - && (!style->hasAppearance() || document()->page()->theme()->shouldRenderMediaControlPart(style->appearance(), mediaElement())); -} - -void MediaControlInputElement::attach() -{ - RefPtr<RenderStyle> style = styleForElement(); - if (!style) - return; - - bool needsRenderer = rendererIsNeeded(style.get()); - if (!needsRenderer) - return; - RenderObject* renderer = createRenderer(mediaElement()->renderer()->renderArena(), style.get()); - if (!renderer) - return; - renderer->setStyle(style.get()); - setRenderer(renderer); - if (parentNode() && parentNode()->renderer()) { - // Find next sibling with a renderer to determine where to insert. - Node* sibling = nextSibling(); - while (sibling && !sibling->renderer()) - sibling = sibling->nextSibling(); - parentNode()->renderer()->addChild(renderer, sibling ? sibling->renderer() : 0); - } - ContainerNode::attach(); - // FIXME: Currently, MeidaControlInput circumvents the normal attachment - // and style recalc cycle and thus we need to add extra logic to be aware of - // the shadow DOM. Remove this once all media controls are transitioned to use the regular - // style calculation. - if (Node* shadowNode = shadowRoot()) - shadowNode->attach(); -} - -void MediaControlInputElement::updateStyle() -{ - if (!mediaElement() || !mediaElement()->renderer()) - return; - - RefPtr<RenderStyle> style = styleForElement(); - if (!style) - return; - - bool needsRenderer = rendererIsNeeded(style.get()) && parentNode() && parentNode()->renderer(); - if (renderer() && !needsRenderer) - detach(); - else if (!renderer() && needsRenderer) - attach(); - else if (renderer()) - renderer()->setStyle(style.get()); - - // FIXME: Currently, MeidaControlInput circumvents the normal attachment - // and style recalc cycle and thus we need to add extra logic to be aware of - // the shadow DOM. Remove this once all media controls are transitioned to use - // the new shadow DOM. - if (Node* shadowNode = shadowRoot()) - shadowNode->recalcStyle(Node::Force); -} - -bool MediaControlInputElement::hitTest(const IntPoint& absPoint) -{ - if (renderer() && renderer()->style()->hasAppearance()) - return renderer()->theme()->hitTestMediaControlPart(renderer(), absPoint); - - return false; -} - -void MediaControlInputElement::setDisplayType(MediaControlElementType displayType) -{ - if (displayType == m_displayType) - return; - - m_displayType = displayType; - if (RenderObject* object = renderer()) - object->repaint(); -} - -// ---------------------------- - -inline MediaControlMuteButtonElement::MediaControlMuteButtonElement(HTMLMediaElement* mediaElement, MediaControlElementType displayType) - : MediaControlInputElement(mediaElement, displayType) -{ -} - -void MediaControlMuteButtonElement::defaultEventHandler(Event* event) -{ - if (event->type() == eventNames().clickEvent) { - mediaElement()->setMuted(!mediaElement()->muted()); - event->setDefaultHandled(); - } - HTMLInputElement::defaultEventHandler(event); -} - -void MediaControlMuteButtonElement::updateDisplayType() -{ - setDisplayType(mediaElement()->muted() ? MediaUnMuteButton : MediaMuteButton); -} - -// ---------------------------- - -inline MediaControlPanelMuteButtonElement::MediaControlPanelMuteButtonElement(HTMLMediaElement* mediaElement) - : MediaControlMuteButtonElement(mediaElement, MediaMuteButton) -{ -} - -PassRefPtr<MediaControlPanelMuteButtonElement> MediaControlPanelMuteButtonElement::create(HTMLMediaElement* mediaElement) -{ - RefPtr<MediaControlPanelMuteButtonElement> button = adoptRef(new MediaControlPanelMuteButtonElement(mediaElement)); - button->setType("button"); - return button.release(); -} - -const AtomicString& MediaControlPanelMuteButtonElement::shadowPseudoId() const -{ - DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-mute-button")); - return id; -} - -// ---------------------------- - -inline MediaControlVolumeSliderMuteButtonElement::MediaControlVolumeSliderMuteButtonElement(HTMLMediaElement* mediaElement) - : MediaControlMuteButtonElement(mediaElement, MediaVolumeSliderMuteButton) -{ -} - -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, MediaPlayButton) -{ -} - -PassRefPtr<MediaControlPlayButtonElement> MediaControlPlayButtonElement::create(HTMLMediaElement* mediaElement) -{ - RefPtr<MediaControlPlayButtonElement> button = adoptRef(new MediaControlPlayButtonElement(mediaElement)); - button->setType("button"); - return button.release(); -} - -void MediaControlPlayButtonElement::defaultEventHandler(Event* event) -{ - if (event->type() == eventNames().clickEvent) { - mediaElement()->togglePlayState(); - event->setDefaultHandled(); - } - HTMLInputElement::defaultEventHandler(event); -} - -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, MediaControlElementType displayType) - : MediaControlInputElement(mediaElement, displayType) - , m_seeking(false) - , m_capturing(false) - , m_seekTimer(this, &MediaControlSeekButtonElement::seekTimerFired) -{ -} - -void MediaControlSeekButtonElement::defaultEventHandler(Event* event) -{ - if (event->type() == eventNames().mousedownEvent) { - if (Frame* frame = document()->frame()) { - m_capturing = true; - frame->eventHandler()->setCapturingMouseEventsNode(this); - } - mediaElement()->pause(event->fromUserGesture()); - m_seekTimer.startRepeating(cSeekRepeatDelay); - event->setDefaultHandled(); - } else if (event->type() == eventNames().mouseupEvent) { - if (m_capturing) - if (Frame* frame = document()->frame()) { - m_capturing = false; - frame->eventHandler()->setCapturingMouseEventsNode(0); - } - ExceptionCode ec; - if (m_seeking || m_seekTimer.isActive()) { - if (!m_seeking) { - float stepTime = isForwardButton() ? cStepTime : -cStepTime; - mediaElement()->setCurrentTime(mediaElement()->currentTime() + stepTime, ec); - } - m_seekTimer.stop(); - m_seeking = false; - event->setDefaultHandled(); - } - } - HTMLInputElement::defaultEventHandler(event); -} - -void MediaControlSeekButtonElement::seekTimerFired(Timer<MediaControlSeekButtonElement>*) -{ - ExceptionCode ec; - m_seeking = true; - float seekTime = isForwardButton() ? cSeekTime : -cSeekTime; - mediaElement()->setCurrentTime(mediaElement()->currentTime() + seekTime, ec); -} - -void MediaControlSeekButtonElement::detach() -{ - if (m_capturing) { - if (Frame* frame = document()->frame()) - frame->eventHandler()->setCapturingMouseEventsNode(0); - } - MediaControlInputElement::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, MediaRewindButton) -{ -} - -PassRefPtr<MediaControlRewindButtonElement> MediaControlRewindButtonElement::create(HTMLMediaElement* mediaElement) -{ - RefPtr<MediaControlRewindButtonElement> button = adoptRef(new MediaControlRewindButtonElement(mediaElement)); - button->setType("button"); - return button.release(); -} - -void MediaControlRewindButtonElement::defaultEventHandler(Event* event) -{ - if (event->type() == eventNames().clickEvent) { - mediaElement()->rewind(30); - event->setDefaultHandled(); - } - 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, MediaReturnToRealtimeButton) -{ -} - -PassRefPtr<MediaControlReturnToRealtimeButtonElement> MediaControlReturnToRealtimeButtonElement::create(HTMLMediaElement* mediaElement) -{ - RefPtr<MediaControlReturnToRealtimeButtonElement> button = adoptRef(new MediaControlReturnToRealtimeButtonElement(mediaElement)); - button->setType("button"); - return button.release(); -} - -void MediaControlReturnToRealtimeButtonElement::defaultEventHandler(Event* event) -{ - if (event->type() == eventNames().clickEvent) { - mediaElement()->returnToRealtime(); - event->setDefaultHandled(); - } - 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, MediaShowClosedCaptionsButton) -{ -} - -PassRefPtr<MediaControlToggleClosedCaptionsButtonElement> MediaControlToggleClosedCaptionsButtonElement::create(HTMLMediaElement* mediaElement) -{ - RefPtr<MediaControlToggleClosedCaptionsButtonElement> button = adoptRef(new MediaControlToggleClosedCaptionsButtonElement(mediaElement)); - button->setType("button"); - return button.release(); -} - -void MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler(Event* event) -{ - if (event->type() == eventNames().clickEvent) { - mediaElement()->setClosedCaptionsVisible(!mediaElement()->closedCaptionsVisible()); - setChecked(mediaElement()->closedCaptionsVisible()); - event->setDefaultHandled(); - } - HTMLInputElement::defaultEventHandler(event); -} - -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, MediaSlider) -{ -} - -PassRefPtr<MediaControlTimelineElement> MediaControlTimelineElement::create(HTMLMediaElement* mediaElement) -{ - RefPtr<MediaControlTimelineElement> timeline = adoptRef(new MediaControlTimelineElement(mediaElement)); - timeline->setType("range"); - timeline->setAttribute(precisionAttr, "float"); - return timeline.release(); -} - -void MediaControlTimelineElement::defaultEventHandler(Event* event) -{ - // Left button is 0. Rejects mouse events not from left button. - if (event->isMouseEvent() && static_cast<MouseEvent*>(event)->button()) - return; - - if (!attached()) - return; - - if (event->type() == eventNames().mousedownEvent) - mediaElement()->beginScrubbing(); - - MediaControlInputElement::defaultEventHandler(event); - - if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent) - return; - - float time = narrowPrecisionToFloat(value().toDouble()); - if (time != mediaElement()->currentTime()) { - ExceptionCode ec; - mediaElement()->setCurrentTime(time, ec); - } - - RenderSlider* slider = toRenderSlider(renderer()); - if (slider && slider->inDragMode()) { - toRenderMedia(mediaElement()->renderer())->controls()->updateTimeDisplay(); -#if PLATFORM(ANDROID) - toRenderMedia(mediaElement()->renderer())->controls()->updateLastTouch(); -#endif - } - - if (event->type() == eventNames().mouseupEvent) - mediaElement()->endScrubbing(); -} - -void MediaControlTimelineElement::update(bool updateDuration) -{ - if (updateDuration) { - float duration = mediaElement()->duration(); - setAttribute(maxAttr, String::number(isfinite(duration) ? duration : 0)); - } - setValue(String::number(mediaElement()->currentTime())); - 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, MediaVolumeSlider) -{ -} - -PassRefPtr<MediaControlVolumeSliderElement> MediaControlVolumeSliderElement::create(HTMLMediaElement* mediaElement) -{ - RefPtr<MediaControlVolumeSliderElement> slider = adoptRef(new MediaControlVolumeSliderElement(mediaElement)); - slider->setType("range"); - slider->setAttribute(precisionAttr, "float"); - slider->setAttribute(maxAttr, "1"); - slider->setAttribute(valueAttr, String::number(mediaElement->volume())); - return slider.release(); -} - -void MediaControlVolumeSliderElement::defaultEventHandler(Event* event) -{ - // Left button is 0. Rejects mouse events not from left button. - if (event->isMouseEvent() && static_cast<MouseEvent*>(event)->button()) - return; - - if (!attached()) - return; - - MediaControlInputElement::defaultEventHandler(event); - - if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent) - return; - - float volume = narrowPrecisionToFloat(value().toDouble()); - if (volume != mediaElement()->volume()) { - ExceptionCode ec = 0; - mediaElement()->setVolume(volume, ec); - ASSERT(!ec); - } -} - -void MediaControlVolumeSliderElement::update() -{ - float volume = mediaElement()->volume(); - if (value().toFloat() != volume) - setValue(String::number(volume)); - MediaControlInputElement::update(); -} - -const AtomicString& MediaControlVolumeSliderElement::shadowPseudoId() const -{ - DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-volume-slider")); - return id; -} - -// ---------------------------- - -inline MediaControlFullscreenVolumeSliderElement::MediaControlFullscreenVolumeSliderElement(HTMLMediaElement* mediaElement) -: MediaControlVolumeSliderElement(mediaElement) -{ -} - -PassRefPtr<MediaControlFullscreenVolumeSliderElement> MediaControlFullscreenVolumeSliderElement::create(HTMLMediaElement* mediaElement) -{ - RefPtr<MediaControlFullscreenVolumeSliderElement> slider = adoptRef(new MediaControlFullscreenVolumeSliderElement(mediaElement)); - slider->setType("range"); - slider->setAttribute(precisionAttr, "float"); - slider->setAttribute(maxAttr, "1"); - slider->setAttribute(valueAttr, String::number(mediaElement->volume())); - return slider.release(); -} - -const AtomicString& MediaControlFullscreenVolumeSliderElement::shadowPseudoId() const -{ - DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-volume-slider")); - return id; -} - -// ---------------------------- - -inline MediaControlFullscreenButtonElement::MediaControlFullscreenButtonElement(HTMLMediaElement* mediaElement) - : MediaControlInputElement(mediaElement, MediaFullscreenButton) -{ -} - -PassRefPtr<MediaControlFullscreenButtonElement> MediaControlFullscreenButtonElement::create(HTMLMediaElement* mediaElement) -{ - RefPtr<MediaControlFullscreenButtonElement> button = adoptRef(new MediaControlFullscreenButtonElement(mediaElement)); - button->setType("button"); - return button.release(); -} - -void MediaControlFullscreenButtonElement::defaultEventHandler(Event* event) -{ - if (event->type() == eventNames().clickEvent) { -#if ENABLE(FULLSCREEN_API) - // Only use the new full screen API if the fullScreenEnabled setting has - // been explicitly enabled. Otherwise, use the old fullscreen API. This - // allows apps which embed a WebView to retain the existing full screen - // video implementation without requiring them to implement their own full - // screen behavior. - if (document()->settings() && document()->settings()->fullScreenEnabled()) { - if (document()->webkitIsFullScreen() && document()->webkitCurrentFullScreenElement() == mediaElement()) - document()->webkitCancelFullScreen(); - else - mediaElement()->webkitRequestFullScreen(0); - } else -#endif - mediaElement()->enterFullscreen(); - event->setDefaultHandled(); - } - HTMLInputElement::defaultEventHandler(event); -} - -const AtomicString& MediaControlFullscreenButtonElement::shadowPseudoId() const -{ - DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-button")); - return id; -} - -// ---------------------------- - -inline MediaControlFullscreenVolumeMinButtonElement::MediaControlFullscreenVolumeMinButtonElement(HTMLMediaElement* mediaElement) -: MediaControlInputElement(mediaElement, MediaUnMuteButton) -{ -} - -PassRefPtr<MediaControlFullscreenVolumeMinButtonElement> MediaControlFullscreenVolumeMinButtonElement::create(HTMLMediaElement* mediaElement) -{ - RefPtr<MediaControlFullscreenVolumeMinButtonElement> button = adoptRef(new MediaControlFullscreenVolumeMinButtonElement(mediaElement)); - button->setType("button"); - return button.release(); -} - -void MediaControlFullscreenVolumeMinButtonElement::defaultEventHandler(Event* event) -{ - if (event->type() == eventNames().clickEvent) { - ExceptionCode code = 0; - mediaElement()->setVolume(0, code); - event->setDefaultHandled(); - } - HTMLInputElement::defaultEventHandler(event); -} - -const AtomicString& MediaControlFullscreenVolumeMinButtonElement::shadowPseudoId() const -{ - DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-volume-min-button")); - return id; -} - -// ---------------------------- - -inline MediaControlFullscreenVolumeMaxButtonElement::MediaControlFullscreenVolumeMaxButtonElement(HTMLMediaElement* mediaElement) -: MediaControlInputElement(mediaElement, MediaMuteButton) -{ -} - -PassRefPtr<MediaControlFullscreenVolumeMaxButtonElement> MediaControlFullscreenVolumeMaxButtonElement::create(HTMLMediaElement* mediaElement) -{ - RefPtr<MediaControlFullscreenVolumeMaxButtonElement> button = adoptRef(new MediaControlFullscreenVolumeMaxButtonElement(mediaElement)); - button->setType("button"); - return button.release(); -} - -void MediaControlFullscreenVolumeMaxButtonElement::defaultEventHandler(Event* event) -{ - if (event->type() == eventNames().clickEvent) { - ExceptionCode code = 0; - mediaElement()->setVolume(1, code); - event->setDefaultHandled(); - } - HTMLInputElement::defaultEventHandler(event); -} - -const AtomicString& MediaControlFullscreenVolumeMaxButtonElement::shadowPseudoId() const -{ - DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-volume-max-button")); - return id; -} - -// ---------------------------- - -class RenderMediaControlTimeDisplay : public RenderFlexibleBox { -public: - RenderMediaControlTimeDisplay(Node*); - -private: - virtual void layout(); -}; - -RenderMediaControlTimeDisplay::RenderMediaControlTimeDisplay(Node* node) - : RenderFlexibleBox(node) -{ -} - -// We want the timeline slider to be at least 100 pixels wide. -// FIXME: Eliminate hard-coded widths altogether. -static const int minWidthToDisplayTimeDisplays = 45 + 100 + 45; - -void RenderMediaControlTimeDisplay::layout() -{ - RenderFlexibleBox::layout(); - RenderBox* timelineContainerBox = parentBox(); - if (timelineContainerBox && timelineContainerBox->width() < minWidthToDisplayTimeDisplays) - setWidth(0); -} - -inline MediaControlTimeDisplayElement::MediaControlTimeDisplayElement(HTMLMediaElement* mediaElement) - : MediaControlElement(mediaElement) - , m_currentValue(0) -{ -} - -void MediaControlTimeDisplayElement::setCurrentValue(float time) -{ - m_currentValue = time; -} - -RenderObject* MediaControlTimeDisplayElement::createRenderer(RenderArena* arena, RenderStyle*) -{ - return new (arena) RenderMediaControlTimeDisplay(this); -} - -// ---------------------------- - -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 deleted file mode 100644 index 77116e3..0000000 --- a/Source/WebCore/rendering/MediaControlElements.h +++ /dev/null @@ -1,492 +0,0 @@ -/* - * Copyright (C) 2008, 2009, 2010 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef MediaControlElements_h -#define MediaControlElements_h - -#if ENABLE(VIDEO) - -#include "HTMLDivElement.h" -#include "HTMLInputElement.h" -#include "HTMLMediaElement.h" -#include "RenderBlock.h" - -// These are the shadow elements used in RenderMedia - -namespace WebCore { - -class Event; -class Frame; - -// Must match WebKitSystemInterface.h -enum MediaControlElementType { - MediaFullscreenButton = 0, - MediaMuteButton, - MediaPlayButton, - MediaSeekBackButton, - MediaSeekForwardButton, - MediaSlider, - MediaSliderThumb, - MediaRewindButton, - MediaReturnToRealtimeButton, - MediaShowClosedCaptionsButton, - MediaHideClosedCaptionsButton, - MediaUnMuteButton, - MediaPauseButton, - MediaTimelineContainer, - MediaCurrentTimeDisplay, - MediaTimeRemainingDisplay, - MediaStatusDisplay, - MediaControlsPanel, - MediaVolumeSliderContainer, - MediaVolumeSlider, - MediaVolumeSliderThumb, - MediaVolumeSliderMuteButton, -}; - -HTMLMediaElement* toParentMediaElement(RenderObject*); - -class MediaControlShadowRootElement : public HTMLDivElement { -public: - static PassRefPtr<MediaControlShadowRootElement> create(HTMLMediaElement*); - - virtual void detach(); - -private: - MediaControlShadowRootElement(HTMLMediaElement*); -}; - -// ---------------------------- - -class MediaControlElement : public HTMLDivElement { -public: - virtual void attach(); - void attachToParent(Element*); - void update(); - void updateStyle(); - - virtual MediaControlElementType displayType() const = 0; - - HTMLMediaElement* mediaElement() const { return m_mediaElement; } - -protected: - MediaControlElement(HTMLMediaElement*); - - virtual bool rendererIsNeeded(RenderStyle*); - - virtual PassRefPtr<RenderStyle> styleForElement(); - -private: - virtual bool isMediaControlElement() const { return true; } - - HTMLMediaElement* m_mediaElement; -}; - -// ---------------------------- - -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; -}; - -// ---------------------------- - -class MediaControlVolumeSliderContainerElement : public MediaControlElement { -public: - static PassRefPtr<MediaControlVolumeSliderContainerElement> create(HTMLMediaElement*); - - virtual PassRefPtr<RenderStyle> styleForElement(); - void setVisible(bool); - bool isVisible() { return m_isVisible; } - bool hitTest(const IntPoint& absPoint); - -private: - MediaControlVolumeSliderContainerElement(HTMLMediaElement*); - - virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); - virtual MediaControlElementType displayType() const; - virtual const AtomicString& shadowPseudoId() const; - - bool m_isVisible; -}; - -// ---------------------------- - -class MediaControlStatusDisplayElement : public MediaControlElement { -public: - static PassRefPtr<MediaControlStatusDisplayElement> create(HTMLMediaElement*); - - void update(); - -private: - MediaControlStatusDisplayElement(HTMLMediaElement*); - - virtual MediaControlElementType displayType() const; - virtual bool rendererIsNeeded(RenderStyle*); - virtual const AtomicString& shadowPseudoId() const; - - enum StateBeingDisplayed { Nothing, Loading, LiveBroadcast }; - StateBeingDisplayed m_stateBeingDisplayed; -}; - -// ---------------------------- - -class MediaControlInputElement : public HTMLInputElement { -public: - void attachToParent(Element*); - void update(); - void updateStyle(); - - bool hitTest(const IntPoint& absPoint); - - MediaControlElementType displayType() const { return m_displayType; } - - HTMLMediaElement* mediaElement() const { return m_mediaElement; } - -protected: - MediaControlInputElement(HTMLMediaElement*, MediaControlElementType); - - void setDisplayType(MediaControlElementType); - -private: - virtual void attach(); - virtual bool rendererIsNeeded(RenderStyle*); - - virtual PassRefPtr<RenderStyle> styleForElement(); - - virtual bool isMediaControlElement() const { return true; } - - virtual void updateDisplayType() { } - - HTMLMediaElement* m_mediaElement; - MediaControlElementType m_displayType; -}; - -// ---------------------------- - -class MediaControlMuteButtonElement : public MediaControlInputElement { -public: - virtual void defaultEventHandler(Event*); - -protected: - MediaControlMuteButtonElement(HTMLMediaElement*, MediaControlElementType); - -private: - virtual void updateDisplayType(); -}; - -// ---------------------------- - -class MediaControlPanelMuteButtonElement : public MediaControlMuteButtonElement { -public: - static PassRefPtr<MediaControlPanelMuteButtonElement> create(HTMLMediaElement*); - -private: - MediaControlPanelMuteButtonElement(HTMLMediaElement*); - - 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 { -public: - static PassRefPtr<MediaControlPlayButtonElement> create(HTMLMediaElement*); - - virtual void defaultEventHandler(Event*); - -private: - MediaControlPlayButtonElement(HTMLMediaElement*); - - virtual void updateDisplayType(); - virtual const AtomicString& shadowPseudoId() const; -}; - -// ---------------------------- - -class MediaControlSeekButtonElement : public MediaControlInputElement { -public: - virtual void defaultEventHandler(Event*); - -protected: - MediaControlSeekButtonElement(HTMLMediaElement*, MediaControlElementType); - -private: - virtual bool isForwardButton() const = 0; - - virtual void detach(); - void seekTimerFired(Timer<MediaControlSeekButtonElement>*); - - bool m_seeking; - 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 { -public: - static PassRefPtr<MediaControlRewindButtonElement> create(HTMLMediaElement*); - - virtual void defaultEventHandler(Event*); - -private: - MediaControlRewindButtonElement(HTMLMediaElement*); - - virtual const AtomicString& shadowPseudoId() const; -}; - -// ---------------------------- - -class MediaControlReturnToRealtimeButtonElement : public MediaControlInputElement { -public: - static PassRefPtr<MediaControlReturnToRealtimeButtonElement> create(HTMLMediaElement*); - - virtual void defaultEventHandler(Event*); - -private: - MediaControlReturnToRealtimeButtonElement(HTMLMediaElement*); - - virtual const AtomicString& shadowPseudoId() const; -}; - -// ---------------------------- - -class MediaControlToggleClosedCaptionsButtonElement : public MediaControlInputElement { -public: - static PassRefPtr<MediaControlToggleClosedCaptionsButtonElement> create(HTMLMediaElement*); - - virtual void defaultEventHandler(Event*); - -private: - MediaControlToggleClosedCaptionsButtonElement(HTMLMediaElement*); - - virtual void updateDisplayType(); - virtual const AtomicString& shadowPseudoId() const; -}; - -// ---------------------------- - -class MediaControlTimelineElement : public MediaControlInputElement { -public: - static PassRefPtr<MediaControlTimelineElement> create(HTMLMediaElement*); - - virtual void defaultEventHandler(Event*); - void update(bool updateDuration = true); - -private: - MediaControlTimelineElement(HTMLMediaElement*); - - virtual const AtomicString& shadowPseudoId() const; -}; - -// ---------------------------- - -class MediaControlVolumeSliderElement : public MediaControlInputElement { -public: - static PassRefPtr<MediaControlVolumeSliderElement> create(HTMLMediaElement*); - - virtual void defaultEventHandler(Event*); - void update(); - -protected: - MediaControlVolumeSliderElement(HTMLMediaElement*); - -private: - virtual const AtomicString& shadowPseudoId() const; -}; - -// ---------------------------- - -class MediaControlFullscreenButtonElement : public MediaControlInputElement { -public: - static PassRefPtr<MediaControlFullscreenButtonElement> create(HTMLMediaElement*); - - virtual void defaultEventHandler(Event*); - -private: - MediaControlFullscreenButtonElement(HTMLMediaElement*); - - virtual const AtomicString& shadowPseudoId() const; -}; - -// ---------------------------- - -class MediaControlFullscreenVolumeSliderElement : public MediaControlVolumeSliderElement { -public: - static PassRefPtr<MediaControlFullscreenVolumeSliderElement> create(HTMLMediaElement*); - -private: - MediaControlFullscreenVolumeSliderElement(HTMLMediaElement*); - - virtual const AtomicString& shadowPseudoId() const; -}; - -// ---------------------------- - -class MediaControlFullscreenVolumeMinButtonElement : public MediaControlInputElement { -public: - static PassRefPtr<MediaControlFullscreenVolumeMinButtonElement> create(HTMLMediaElement*); - - virtual void defaultEventHandler(Event*); - -private: - MediaControlFullscreenVolumeMinButtonElement(HTMLMediaElement*); - - virtual const AtomicString& shadowPseudoId() const; -}; - -// ---------------------------- - -class MediaControlFullscreenVolumeMaxButtonElement : public MediaControlInputElement { -public: - static PassRefPtr<MediaControlFullscreenVolumeMaxButtonElement> create(HTMLMediaElement*); - - virtual void defaultEventHandler(Event*); - -private: - MediaControlFullscreenVolumeMaxButtonElement(HTMLMediaElement*); - - virtual const AtomicString& shadowPseudoId() const; -}; - -// ---------------------------- - -class MediaControlTimeDisplayElement : public MediaControlElement { -public: - void setCurrentValue(float); - float currentValue() const { return m_currentValue; } - -protected: - MediaControlTimeDisplayElement(HTMLMediaElement*); - -private: - virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); - - float m_currentValue; -}; - -// ---------------------------- - -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) { } - void setParent(RenderObject* p) { RenderObject::setParent(p); } -}; - -// ---------------------------- - -} //namespace WebCore - -#endif // ENABLE(VIDEO) - -#endif // MediaControlElements_h diff --git a/Source/WebCore/rendering/RenderBlock.cpp b/Source/WebCore/rendering/RenderBlock.cpp index 919e23b..de3af60 100644 --- a/Source/WebCore/rendering/RenderBlock.cpp +++ b/Source/WebCore/rendering/RenderBlock.cpp @@ -52,7 +52,6 @@ #include "Settings.h" #include "TextRun.h" #include "TransformState.h" -#include "visible_units.h" #include <wtf/StdLibExtras.h> #ifdef ANDROID_LAYOUT @@ -1550,8 +1549,9 @@ bool RenderBlock::handleRunInChild(RenderBox* child) runInChild = nextSibling; } - // Now insert the new child under |currBlock|. - currBlock->children()->insertChildNode(currBlock, inlineRunIn, currBlock->firstChild()); + // Now insert the new child under |currBlock|. Use addChild instead of insertChildNode since it handles correct placement of the children, esp where we cannot insert + // anything before the first child. e.g. details tag. See https://bugs.webkit.org/show_bug.cgi?id=58228. + currBlock->addChild(inlineRunIn, currBlock->firstChild()); // If the run-in had an element, we need to set the new renderer. if (runInNode) @@ -2106,7 +2106,7 @@ void RenderBlock::simplifiedNormalFlowLayout() GlyphOverflowAndFallbackFontsMap textBoxDataMap; for (ListHashSet<RootInlineBox*>::const_iterator it = lineBoxes.begin(); it != lineBoxes.end(); ++it) { RootInlineBox* box = *it; - box->computeOverflow(box->lineTop(), box->lineBottom(), document()->inNoQuirksMode(), textBoxDataMap); + box->computeOverflow(box->lineTop(), box->lineBottom(), textBoxDataMap); } } else { for (RenderBox* box = firstChildBox(); box; box = box->nextSiblingBox()) { @@ -2123,11 +2123,8 @@ bool RenderBlock::simplifiedLayout() LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasColumns() || hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode()); - if (needsPositionedMovementLayout()) { - tryLayoutDoingPositionedMovementOnly(); - if (needsLayout()) - return false; - } + if (needsPositionedMovementLayout() && !tryLayoutDoingPositionedMovementOnly()) + return false; // Lay out positioned descendants or objects that just need to recompute overflow. if (needsSimplifiedNormalFlowLayout()) @@ -2190,8 +2187,8 @@ void RenderBlock::layoutPositionedObjects(bool relayoutChildren) // We don't have to do a full layout. We just have to update our position. Try that first. If we have shrink-to-fit width // and we hit the available width constraint, the layoutIfNeeded() will catch it and do a full layout. - if (r->needsPositionedMovementLayoutOnly()) - r->tryLayoutDoingPositionedMovementOnly(); + if (r->needsPositionedMovementLayoutOnly() && r->tryLayoutDoingPositionedMovementOnly()) + r->setNeedsLayout(false); r->layoutIfNeeded(); } @@ -2376,7 +2373,7 @@ void RenderBlock::paintContents(PaintInfo& paintInfo, int tx, int ty) // Avoid painting descendants of the root element when stylesheets haven't loaded. This eliminates FOUC. // It's ok not to draw, because later on, when all the stylesheets do load, updateStyleSelector on the Document // will do a full repaint(). - if (document()->mayCauseFlashOfUnstyledContent() && !isRenderView()) + if (document()->didLayoutWithPendingStylesheets() && !isRenderView()) return; if (childrenInline()) @@ -2606,7 +2603,7 @@ void RenderBlock::paintEllipsisBoxes(PaintInfo& paintInfo, int tx, int ty) yPos = ty + curr->y(); h = curr->logicalHeight(); if (curr->ellipsisBox() && yPos < paintInfo.rect.maxY() && yPos + h > paintInfo.rect.y()) - curr->paintEllipsisBox(paintInfo, tx, ty); + curr->paintEllipsisBox(paintInfo, tx, ty, curr->lineTop(), curr->lineBottom()); } } } @@ -3336,59 +3333,6 @@ bool RenderBlock::positionNewFloats() return true; } -bool RenderBlock::positionNewFloatOnLine(FloatingObject* newFloat, FloatingObject* lastFloatFromPreviousLine, bool firstLine, int& lineLeftOffset, int& lineRightOffset) -{ - bool didPosition = positionNewFloats(); - if (!didPosition) - return didPosition; - - int blockOffset = logicalHeight(); - if (blockOffset >= logicalTopForFloat(newFloat) && blockOffset < logicalBottomForFloat(newFloat)) { - if (newFloat->type() == FloatingObject::FloatLeft) - lineLeftOffset = logicalRightForFloat(newFloat); - else - lineRightOffset = logicalLeftForFloat(newFloat); - } - - if (!newFloat->m_paginationStrut) - return didPosition; - - FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); - ASSERT(floatingObjectSet.last() == newFloat); - - int floatLogicalTop = logicalTopForFloat(newFloat); - int paginationStrut = newFloat->m_paginationStrut; - - if (floatLogicalTop - paginationStrut != logicalHeight()) - return didPosition; - - FloatingObjectSetIterator it = floatingObjectSet.end(); - --it; // Last float is newFloat, skip that one. - FloatingObjectSetIterator begin = floatingObjectSet.begin(); - while (it != begin) { - --it; - FloatingObject* f = *it; - if (f == lastFloatFromPreviousLine) - break; - if (logicalTopForFloat(f) == logicalHeight()) { - ASSERT(!f->m_paginationStrut); - f->m_paginationStrut = paginationStrut; - RenderBox* o = f->m_renderer; - setLogicalTopForChild(o, logicalTopForChild(o) + marginBeforeForChild(o) + paginationStrut); - if (o->isRenderBlock()) - toRenderBlock(o)->setChildNeedsLayout(true, false); - o->layoutIfNeeded(); - setLogicalTopForFloat(f, logicalTopForFloat(f) + f->m_paginationStrut); - } - } - - setLogicalHeight(blockOffset + paginationStrut); - lineLeftOffset = logicalLeftOffsetForLine(logicalHeight(), firstLine); - lineRightOffset = logicalRightOffsetForLine(logicalHeight(), firstLine); - - return didPosition; -} - void RenderBlock::newLine(EClear clear) { positionNewFloats(); @@ -3721,6 +3665,7 @@ int RenderBlock::addOverhangingFloats(RenderBlock* child, int logicalLeftOffset, if (child->hasOverflowClip() || !child->containsFloats() || child->isRoot() || child->hasColumns() || child->isWritingModeRoot()) return 0; + int childLogicalTop = child->logicalTop(); int lowestFloatLogicalBottom = 0; // Floats that will remain the child's responsibility to paint should factor into its @@ -3728,7 +3673,8 @@ int RenderBlock::addOverhangingFloats(RenderBlock* child, int logicalLeftOffset, FloatingObjectSetIterator childEnd = child->m_floatingObjects->set().end(); for (FloatingObjectSetIterator childIt = child->m_floatingObjects->set().begin(); childIt != childEnd; ++childIt) { FloatingObject* r = *childIt; - int logicalBottom = child->logicalTop() + logicalBottomForFloat(r); + int logicalBottomForFloat = min(this->logicalBottomForFloat(r), numeric_limits<int>::max() - childLogicalTop); + int logicalBottom = childLogicalTop + logicalBottomForFloat; lowestFloatLogicalBottom = max(lowestFloatLogicalBottom, logicalBottom); if (logicalBottom > logicalHeight()) { @@ -4277,34 +4223,15 @@ void RenderBlock::calcColumnWidth() int colWidth = max(1, static_cast<int>(style()->columnWidth())); int colCount = max(1, static_cast<int>(style()->columnCount())); - if (style()->hasAutoColumnWidth()) { - if ((colCount - 1) * colGap < availWidth) { - desiredColumnCount = colCount; - desiredColumnWidth = (availWidth - (desiredColumnCount - 1) * colGap) / desiredColumnCount; - } else if (colGap < availWidth) { - desiredColumnCount = availWidth / colGap; - if (desiredColumnCount < 1) - desiredColumnCount = 1; - desiredColumnWidth = (availWidth - (desiredColumnCount - 1) * colGap) / desiredColumnCount; - } - } else if (style()->hasAutoColumnCount()) { - if (colWidth < availWidth) { - desiredColumnCount = (availWidth + colGap) / (colWidth + colGap); - if (desiredColumnCount < 1) - desiredColumnCount = 1; - desiredColumnWidth = (availWidth - (desiredColumnCount - 1) * colGap) / desiredColumnCount; - } + if (style()->hasAutoColumnWidth() && !style()->hasAutoColumnCount()) { + desiredColumnCount = colCount; + desiredColumnWidth = max<int>(0, (availWidth - ((desiredColumnCount - 1) * colGap)) / desiredColumnCount); + } else if (!style()->hasAutoColumnWidth() && style()->hasAutoColumnCount()) { + desiredColumnCount = max<int>(1, (float)(availWidth + colGap) / (colWidth + colGap)); + desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap; } else { - // Both are set. - if (colCount * colWidth + (colCount - 1) * colGap <= availWidth) { - desiredColumnCount = colCount; - desiredColumnWidth = colWidth; - } else if (colWidth < availWidth) { - desiredColumnCount = (availWidth + colGap) / (colWidth + colGap); - if (desiredColumnCount < 1) - desiredColumnCount = 1; - desiredColumnWidth = (availWidth - (desiredColumnCount - 1) * colGap) / desiredColumnCount; - } + desiredColumnCount = max(min<int>(colCount, (float)(availWidth + colGap) / (colWidth + colGap)), 1); + desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap; } setDesiredColumnCountAndWidth(desiredColumnCount, desiredColumnWidth); } @@ -5395,7 +5322,7 @@ void RenderBlock::updateFirstLetter() view()->disableLayoutState(); while (RenderObject* child = firstLetter->firstChild()) { if (child->isText()) - toRenderText(child)->dirtyLineBoxes(true); + toRenderText(child)->removeAndDestroyTextBoxes(); firstLetter->removeChild(child); newFirstLetter->addChild(child, 0); } @@ -6081,8 +6008,9 @@ void RenderBlock::adjustLinePositionForPagination(RootInlineBox* lineBox, int& d // line and all following lines. LayoutState* layoutState = view()->layoutState(); int pageLogicalHeight = layoutState->m_pageLogicalHeight; - int logicalOffset = lineBox->logicalTopVisualOverflow(); - int lineHeight = lineBox->logicalBottomVisualOverflow() - logicalOffset; + IntRect logicalVisualOverflow = lineBox->logicalVisualOverflowRect(lineBox->lineTop(), lineBox->lineBottom()); + int logicalOffset = logicalVisualOverflow.y(); + int lineHeight = logicalVisualOverflow.maxY() - logicalOffset; if (layoutState->m_columnInfo) layoutState->m_columnInfo->updateMinimumColumnHeight(lineHeight); logicalOffset += delta; diff --git a/Source/WebCore/rendering/RenderBlock.h b/Source/WebCore/rendering/RenderBlock.h index 74751e1..75d93e9 100644 --- a/Source/WebCore/rendering/RenderBlock.h +++ b/Source/WebCore/rendering/RenderBlock.h @@ -32,16 +32,19 @@ namespace WebCore { +class BidiContext; class ColumnInfo; class InlineIterator; class LayoutStateMaintainer; class LazyLineBreakIterator; +class LineWidth; class RenderInline; struct BidiRun; struct PaintInfo; template <class Iterator, class Run> class BidiResolver; +template <class Run> class BidiRunList; template <class Iterator> struct MidpointState; typedef BidiResolver<InlineIterator, BidiRun> InlineBidiResolver; typedef MidpointState<InlineIterator> LineMidpointState; @@ -151,7 +154,7 @@ public: RenderBlock* createAnonymousColumnSpanBlock() const; RenderBlock* createAnonymousBlockWithSameTypeAs(RenderBlock* otherAnonymousBlock) const; - static void appendRunsForObject(int start, int end, RenderObject*, InlineBidiResolver&); + static void appendRunsForObject(BidiRunList<BidiRun>&, int start, int end, RenderObject*, InlineBidiResolver&); static bool requiresLineBox(const InlineIterator&, bool isLineEmpty = true, bool previousLineBrokeCleanly = true); ColumnInfo* columnInfo() const; @@ -349,6 +352,7 @@ private: void layoutBlockChildren(bool relayoutChildren, int& maxFloatLogicalBottom); void layoutInlineChildren(bool relayoutChildren, int& repaintLogicalTop, int& repaintLogicalBottom); + BidiRun* handleTrailingSpaces(BidiRunList<BidiRun>&, BidiContext*); virtual void borderFitAdjust(int& x, int& w) const; // Shrink the box in which the border paints if border-fit is set. @@ -492,22 +496,23 @@ private: RootInlineBox*& endLine, int& endYPos, int& repaintBottom, int& repaintTop); void skipTrailingWhitespace(InlineIterator&, bool isLineEmpty, bool previousLineBrokeCleanly); - void skipLeadingWhitespace(InlineBidiResolver&, bool firstLine, bool isLineEmpty, bool previousLineBrokeCleanly, FloatingObject* lastFloatFromPreviousLine, int& lineLeftOffset, int& lineRightOffset); - void fitBelowFloats(float widthToFit, bool firstLine, float& availableWidth); + void skipLeadingWhitespace(InlineBidiResolver&, bool isLineEmpty, bool previousLineBrokeCleanly, FloatingObject* lastFloatFromPreviousLine, LineWidth&); typedef std::pair<RenderText*, LazyLineBreakIterator> LineBreakIteratorInfo; InlineIterator findNextLineBreak(InlineBidiResolver&, bool firstLine, bool& isLineEmpty, LineBreakIteratorInfo&, bool& previousLineBrokeCleanly, bool& hyphenated, EClear*, FloatingObject* lastFloatFromPreviousLine, Vector<RenderBox*>& positionedObjects); - RootInlineBox* constructLine(unsigned runCount, BidiRun* firstRun, BidiRun* lastRun, bool firstLine, bool lastLine, RenderObject* endObject, RenderObject* logicallyLastRunRenderer); + RootInlineBox* constructLine(BidiRunList<BidiRun>&, bool firstLine, bool lastLine); InlineFlowBox* createLineBoxes(RenderObject*, bool firstLine, InlineBox* childBox); void computeInlineDirectionPositionsForLine(RootInlineBox*, bool firstLine, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd, GlyphOverflowAndFallbackFontsMap&, VerticalPositionCache&); void computeBlockDirectionPositionsForLine(RootInlineBox*, BidiRun*, GlyphOverflowAndFallbackFontsMap&, VerticalPositionCache&); void deleteEllipsisLineBoxes(); void checkLinesForTextOverflow(); - int beforeSideVisualOverflowForLine(RootInlineBox*) const; - int afterSideVisualOverflowForLine(RootInlineBox*) const; - int beforeSideLayoutOverflowForLine(RootInlineBox*) const; - int afterSideLayoutOverflowForLine(RootInlineBox*) const; + + // Positions new floats and also adjust all floats encountered on the line if any of them + // have to move to the next page/column. + bool positionNewFloatOnLine(FloatingObject* newFloat, FloatingObject* lastFloatFromPreviousLine, LineWidth&); + void appendFloatingObjectToLastLine(FloatingObject*); + // End of functions defined in RenderBlockLineLayout.cpp. void paintFloats(PaintInfo&, int tx, int ty, bool preservePhase = false); @@ -526,10 +531,6 @@ private: // Called from lineWidth, to position the floats added in the last line. // Returns true if and only if it has positioned any floats. bool positionNewFloats(); - - // Positions new floats and also adjust all floats encountered on the line if any of them - // have to move to the next page/column. - bool positionNewFloatOnLine(FloatingObject* newFloat, FloatingObject* lastFloatFromPreviousLine, bool firstLine, int& lineLeftOffset, int& lineRightOffset); void clearFloats(); int getClearDelta(RenderBox* child, int yPos); @@ -785,6 +786,7 @@ private: // RenderRubyBase objects need to be able to split and merge, moving their children around // (calling moveChildTo, moveAllChildrenTo, and makeChildrenNonInline). friend class RenderRubyBase; + friend class LineWidth; // Needs to know FloatingObject }; inline RenderBlock* toRenderBlock(RenderObject* object) diff --git a/Source/WebCore/rendering/RenderBlockLineLayout.cpp b/Source/WebCore/rendering/RenderBlockLineLayout.cpp index 3a0f016..06cbf90 100644 --- a/Source/WebCore/rendering/RenderBlockLineLayout.cpp +++ b/Source/WebCore/rendering/RenderBlockLineLayout.cpp @@ -32,6 +32,7 @@ #include "RenderInline.h" #include "RenderLayer.h" #include "RenderListMarker.h" +#include "RenderRubyRun.h" #include "RenderView.h" #include "Settings.h" #include "TextBreakIterator.h" @@ -67,23 +68,27 @@ namespace WebCore { // We don't let our line box tree for a single line get any deeper than this. const unsigned cMaxLineDepth = 200; -static int getBorderPaddingMargin(RenderBoxModelObject* child, bool endOfInline) +static inline int borderPaddingMarginStart(RenderInline* child) { - if (endOfInline) - return child->marginEnd() + child->paddingEnd() + child->borderEnd(); return child->marginStart() + child->paddingStart() + child->borderStart(); } +static inline int borderPaddingMarginEnd(RenderInline* child) +{ + return child->marginEnd() + child->paddingEnd() + child->borderEnd(); +} + static int inlineLogicalWidth(RenderObject* child, bool start = true, bool end = true) { unsigned lineDepth = 1; int extraWidth = 0; RenderObject* parent = child->parent(); - while (parent->isInline() && !parent->isInlineBlockOrInlineTable() && lineDepth++ < cMaxLineDepth) { + while (parent->isRenderInline() && lineDepth++ < cMaxLineDepth) { + RenderInline* parentAsRenderInline = toRenderInline(parent); if (start && !child->previousSibling()) - extraWidth += getBorderPaddingMargin(toRenderBoxModelObject(parent), false); + extraWidth += borderPaddingMarginStart(parentAsRenderInline); if (end && !child->nextSibling()) - extraWidth += getBorderPaddingMargin(toRenderBoxModelObject(parent), true); + extraWidth += borderPaddingMarginEnd(parentAsRenderInline); child = parent; parent = child->parent(); } @@ -120,10 +125,15 @@ static void addMidpoint(LineMidpointState& lineMidpointState, const InlineIterat midpoints[lineMidpointState.numMidpoints++] = midpoint; } -void RenderBlock::appendRunsForObject(int start, int end, RenderObject* obj, InlineBidiResolver& resolver) +static inline BidiRun* createRun(int start, int end, RenderObject* obj, InlineBidiResolver& resolver) +{ + return new (obj->renderArena()) BidiRun(start, end, obj, resolver.context(), resolver.dir()); +} + +void RenderBlock::appendRunsForObject(BidiRunList<BidiRun>& runs, int start, int end, RenderObject* obj, InlineBidiResolver& resolver) { if (start > end || obj->isFloating() || - (obj->isPositioned() && !obj->style()->hasAutoLeftAndRight() && !obj->style()->hasAutoTopAndBottom() && !obj->container()->isRenderInline())) + (obj->isPositioned() && !obj->style()->isOriginalDisplayInlineType() && !obj->container()->isRenderInline())) return; LineMidpointState& lineMidpointState = resolver.midpointState(); @@ -140,10 +150,10 @@ void RenderBlock::appendRunsForObject(int start, int end, RenderObject* obj, Inl start = nextMidpoint.m_pos; lineMidpointState.currentMidpoint++; if (start < end) - return appendRunsForObject(start, end, obj, resolver); + return appendRunsForObject(runs, start, end, obj, resolver); } else { if (!haveNextMidpoint || (obj != nextMidpoint.m_obj)) { - resolver.addRun(new (obj->renderArena()) BidiRun(start, end, obj, resolver.context(), resolver.dir())); + runs.addRun(createRun(start, end, obj, resolver)); return; } @@ -154,12 +164,11 @@ void RenderBlock::appendRunsForObject(int start, int end, RenderObject* obj, Inl lineMidpointState.currentMidpoint++; if (nextMidpoint.m_pos != UINT_MAX) { // UINT_MAX means stop at the object and don't include any of it. if (static_cast<int>(nextMidpoint.m_pos + 1) > start) - resolver.addRun(new (obj->renderArena()) - BidiRun(start, nextMidpoint.m_pos + 1, obj, resolver.context(), resolver.dir())); - return appendRunsForObject(nextMidpoint.m_pos + 1, end, obj, resolver); + runs.addRun(createRun(start, nextMidpoint.m_pos + 1, obj, resolver)); + return appendRunsForObject(runs, nextMidpoint.m_pos + 1, end, obj, resolver); } } else - resolver.addRun(new (obj->renderArena()) BidiRun(start, end, obj, resolver.context(), resolver.dir())); + runs.addRun(createRun(start, end, obj, resolver)); } } @@ -214,8 +223,10 @@ InlineFlowBox* RenderBlock::createLineBoxes(RenderObject* obj, bool firstLine, I do { ASSERT(obj->isRenderInline() || obj == this); + RenderInline* inlineFlow = (obj != this) ? toRenderInline(obj) : 0; + // Get the last box we made for this render object. - parentBox = obj->isRenderInline() ? toRenderInline(obj)->lastLineBox() : toRenderBlock(obj)->lastLineBox(); + parentBox = inlineFlow ? inlineFlow->lastLineBox() : toRenderBlock(obj)->lastLineBox(); // 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 @@ -223,7 +234,9 @@ InlineFlowBox* RenderBlock::createLineBoxes(RenderObject* obj, bool firstLine, I // 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 || parentIsConstructedOrHaveNext(parentBox)) { + bool allowedToConstructNewBox = !hasDefaultLineBoxContain || !inlineFlow || inlineFlow->alwaysCreateLineBoxes(); + bool canUseExistingParentBox = parentBox && !parentIsConstructedOrHaveNext(parentBox); + if (allowedToConstructNewBox && !canUseExistingParentBox) { // 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); @@ -236,19 +249,21 @@ InlineFlowBox* RenderBlock::createLineBoxes(RenderObject* obj, bool firstLine, I constructedNewBox = true; } - if (!result) - result = parentBox; + if (constructedNewBox || canUseExistingParentBox) { + if (!result) + result = parentBox; - // If we have hit the block itself, then |box| represents the root - // inline box for the line, and it doesn't have to be appended to any parent - // inline. - if (childBox) - parentBox->addToLine(childBox); + // If we have hit the block itself, then |box| represents the root + // inline box for the line, and it doesn't have to be appended to any parent + // inline. + if (childBox) + parentBox->addToLine(childBox); - if (!constructedNewBox || obj == this) - break; + if (!constructedNewBox || obj == this) + break; - childBox = parentBox; + childBox = parentBox; + } // If we've exceeded our line depth, then jump straight to the root and skip all the remaining // intermediate inline flows. @@ -259,17 +274,38 @@ InlineFlowBox* RenderBlock::createLineBoxes(RenderObject* obj, bool firstLine, I return result; } -RootInlineBox* RenderBlock::constructLine(unsigned runCount, BidiRun* firstRun, BidiRun* lastRun, bool firstLine, bool lastLine, RenderObject* endObject, RenderObject* logicallyLastRunRenderer) +static bool reachedEndOfTextRenderer(const BidiRunList<BidiRun>& bidiRuns) +{ + BidiRun* run = bidiRuns.logicallyLastRun(); + if (!run) + return true; + unsigned int pos = run->stop(); + RenderObject* r = run->m_object; + if (!r->isText() || r->isBR()) + return false; + RenderText* renderText = toRenderText(r); + if (pos >= renderText->textLength()) + return true; + + while (isASCIISpace(renderText->characters()[pos])) { + pos++; + if (pos >= renderText->textLength()) + return true; + } + return false; +} + +RootInlineBox* RenderBlock::constructLine(BidiRunList<BidiRun>& bidiRuns, bool firstLine, bool lastLine) { - ASSERT(firstRun); + ASSERT(bidiRuns.firstRun()); bool rootHasSelectedChildren = false; InlineFlowBox* parentBox = 0; - for (BidiRun* r = firstRun; r; r = r->next()) { + for (BidiRun* r = bidiRuns.firstRun(); r; r = r->next()) { // Create a box for our object. - bool isOnlyRun = (runCount == 1); - if (runCount == 2 && !r->m_object->isListMarker()) - isOnlyRun = (!style()->isLeftToRightDirection() ? lastRun : firstRun)->m_object->isListMarker(); + bool isOnlyRun = (bidiRuns.runCount() == 1); + if (bidiRuns.runCount() == 2 && !r->m_object->isListMarker()) + isOnlyRun = (!style()->isLeftToRightDirection() ? bidiRuns.lastRun() : bidiRuns.firstRun())->m_object->isListMarker(); InlineBox* box = createInlineBoxForRenderer(r->m_object, false, isOnlyRun); r->m_box = box; @@ -318,7 +354,8 @@ RootInlineBox* RenderBlock::constructLine(unsigned runCount, BidiRun* firstRun, // paint borders/margins/padding. This knowledge will ultimately be used when // we determine the horizontal positions and widths of all the inline boxes on // the line. - lastLineBox()->determineSpacingForFlowBoxes(lastLine, endObject, logicallyLastRunRenderer); + bool isLogicallyLastRunWrapped = bidiRuns.logicallyLastRun()->m_object && bidiRuns.logicallyLastRun()->m_object->isText() ? !reachedEndOfTextRenderer(bidiRuns) : true; + lastLineBox()->determineSpacingForFlowBoxes(lastLine, isLogicallyLastRunWrapped, bidiRuns.logicallyLastRun()->m_object); // Now mark the line boxes as being constructed. lastLineBox()->setConstructed(); @@ -400,6 +437,7 @@ void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox, unsigned expansionOpportunityCount = 0; bool isAfterExpansion = true; Vector<unsigned, 16> expansionOpportunities; + RenderObject* previousObject = 0; for (BidiRun* r = firstRun; r; r = r->next()) { if (!r->m_box || r->m_object->isPositioned() || r->m_box->isLineBreak()) @@ -456,18 +494,33 @@ void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox, ASSERT(r->m_box->isText()); GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.add(static_cast<InlineTextBox*>(r->m_box), make_pair(Vector<const SimpleFontData*>(), GlyphOverflow())).first; it->second.second = glyphOverflow; + r->m_box->clearKnownToHaveNoOverflow(); } } else { isAfterExpansion = false; if (!r->m_object->isRenderInline()) { RenderBox* renderBox = toRenderBox(r->m_object); - renderBox->computeLogicalWidth(); + if (renderBox->isRubyRun()) { + int startOverhang; + int endOverhang; + RenderObject* nextObject = 0; + for (BidiRun* runWithNextObject = r->next(); runWithNextObject; runWithNextObject = runWithNextObject->next()) { + if (!runWithNextObject->m_object->isPositioned() && !runWithNextObject->m_box->isLineBreak()) { + nextObject = runWithNextObject->m_object; + break; + } + } + toRenderRubyRun(renderBox)->getOverhang(firstLine, renderBox->style()->isLeftToRightDirection() ? previousObject : nextObject, renderBox->style()->isLeftToRightDirection() ? nextObject : previousObject, startOverhang, endOverhang); + setMarginStartForChild(renderBox, -startOverhang); + setMarginEndForChild(renderBox, -endOverhang); + } r->m_box->setLogicalWidth(logicalWidthForChild(renderBox)); totalLogicalWidth += marginStartForChild(renderBox) + marginEndForChild(renderBox); } } totalLogicalWidth += r->m_box->logicalWidth(); + previousObject = r->m_object; } if (isAfterExpansion && !expansionOpportunities.isEmpty()) { @@ -616,27 +669,70 @@ static void setStaticPositions(RenderBlock* block, RenderBox* child) child->layer()->setStaticBlockPosition(blockHeight); } -static bool reachedEndOfTextRenderer(InlineBidiResolver& resolver) +inline BidiRun* RenderBlock::handleTrailingSpaces(BidiRunList<BidiRun>& bidiRuns, BidiContext* currentContext) { - BidiRun* run = resolver.logicallyLastRun(); - if (!run) - return true; - unsigned int pos = run->stop(); - RenderObject* r = run->m_object; - if (!r->isText() || r->isBR()) - return false; - RenderText* renderText = toRenderText(r); - if (pos >= renderText->textLength()) - return true; + if (!bidiRuns.runCount() + || !bidiRuns.logicallyLastRun()->m_object->style()->breakOnlyAfterWhiteSpace() + || !bidiRuns.logicallyLastRun()->m_object->style()->autoWrap()) + return 0; - while (isASCIISpace(renderText->characters()[pos])) { - pos++; - if (pos >= renderText->textLength()) - return true; + BidiRun* trailingSpaceRun = bidiRuns.logicallyLastRun(); + RenderObject* lastObject = trailingSpaceRun->m_object; + if (!lastObject->isText()) + return 0; + + RenderText* lastText = toRenderText(lastObject); + const UChar* characters = lastText->characters(); + int firstSpace = trailingSpaceRun->stop(); + while (firstSpace > trailingSpaceRun->start()) { + UChar current = characters[firstSpace - 1]; + if (!isCollapsibleSpace(current, lastText)) + break; + firstSpace--; } - return false; + if (firstSpace == trailingSpaceRun->stop()) + return 0; + + TextDirection direction = style()->direction(); + bool shouldReorder = trailingSpaceRun != (direction == LTR ? bidiRuns.lastRun() : bidiRuns.firstRun()); + if (firstSpace != trailingSpaceRun->start()) { + BidiContext* baseContext = currentContext; + while (BidiContext* parent = baseContext->parent()) + baseContext = parent; + + BidiRun* newTrailingRun = new (renderArena()) BidiRun(firstSpace, trailingSpaceRun->m_stop, trailingSpaceRun->m_object, baseContext, OtherNeutral); + trailingSpaceRun->m_stop = firstSpace; + if (direction == LTR) + bidiRuns.addRun(newTrailingRun); + else + bidiRuns.prependRun(newTrailingRun); + trailingSpaceRun = newTrailingRun; + return trailingSpaceRun; + } + if (!shouldReorder) + return trailingSpaceRun; + + if (direction == LTR) { + bidiRuns.moveRunToEnd(trailingSpaceRun); + trailingSpaceRun->m_level = 0; + } else { + bidiRuns.moveRunToBeginning(trailingSpaceRun); + trailingSpaceRun->m_level = 1; + } + return trailingSpaceRun; } - + +void RenderBlock::appendFloatingObjectToLastLine(FloatingObject* floatingObject) +{ + // Ensure that the float touches the line. + if (RootInlineBox* previousLine = lastRootBox()->prevRootBox()) { + if (logicalBottomForFloat(floatingObject) < previousLine->blockLogicalHeight()) + setLogicalHeightForFloat(floatingObject, previousLine->blockLogicalHeight() - logicalTopForFloat(floatingObject)); + } + + lastRootBox()->appendFloat(floatingObject->renderer()); +} + void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogicalTop, int& repaintLogicalBottom) { bool useRepaintBounds = false; @@ -741,6 +837,8 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogica } #endif // PLATFORM(ANDROID) } else if (o->isText() || (o->isRenderInline() && !endOfInline)) { + if (!o->isText()) + toRenderInline(o)->updateAlwaysCreateLineBoxes(); if (fullLayout || o->selfNeedsLayout()) dirtyLineBoxesForRenderer(o, fullLayout); o->setNeedsLayout(false); @@ -853,8 +951,8 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogica RenderArena* arena = renderArena(); RootInlineBox* box = startLine; while (box) { - repaintLogicalTop = min(repaintLogicalTop, beforeSideVisualOverflowForLine(box)); - repaintLogicalBottom = max(repaintLogicalBottom, afterSideVisualOverflowForLine(box)); + repaintLogicalTop = min(repaintLogicalTop, box->logicalTopVisualOverflow()); + repaintLogicalBottom = max(repaintLogicalBottom, box->logicalBottomVisualOverflow()); RootInlineBox* next = box->nextRootBox(); box->deleteLine(arena); box = next; @@ -906,7 +1004,10 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogica FloatingObject* lastFloatFromPreviousLine = (m_floatingObjects && !m_floatingObjects->set().isEmpty()) ? m_floatingObjects->set().last() : 0; end = findNextLineBreak(resolver, firstLine, isLineEmpty, lineBreakIteratorInfo, previousLineBrokeCleanly, hyphenated, &clear, lastFloatFromPreviousLine, positionedObjects); if (resolver.position().atEnd()) { - resolver.deleteRuns(); + // FIXME: We shouldn't be creating any runs in findNextLineBreak to begin with! + // Once BidiRunList is separated from BidiResolver this will not be needed. + resolver.runs().deleteRuns(); + resolver.markCurrentRunEmpty(); // FIXME: This can probably be replaced by an ASSERT (or just removed). checkForFloatsFromLastLine = true; break; } @@ -917,56 +1018,12 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogica lastRootBox()->setLineBreakInfo(end.m_obj, end.m_pos, resolver.status()); } else { VisualDirectionOverride override = (style()->visuallyOrdered() ? (style()->direction() == LTR ? VisualLeftToRightOverride : VisualRightToLeftOverride) : NoVisualOverride); + // FIXME: This ownership is reversed. We should own the BidiRunList and pass it to createBidiRunsForLine. + BidiRunList<BidiRun>& bidiRuns = resolver.runs(); resolver.createBidiRunsForLine(end, override, previousLineBrokeCleanly); ASSERT(resolver.position() == end); - BidiRun* trailingSpaceRun = 0; - if (!previousLineBrokeCleanly && resolver.runCount() && resolver.logicallyLastRun()->m_object->style()->breakOnlyAfterWhiteSpace() - && resolver.logicallyLastRun()->m_object->style()->autoWrap()) { - trailingSpaceRun = resolver.logicallyLastRun(); - RenderObject* lastObject = trailingSpaceRun->m_object; - if (lastObject->isText()) { - RenderText* lastText = toRenderText(lastObject); - const UChar* characters = lastText->characters(); - int firstSpace = trailingSpaceRun->stop(); - while (firstSpace > trailingSpaceRun->start()) { - UChar current = characters[firstSpace - 1]; - if (!isCollapsibleSpace(current, lastText)) - break; - firstSpace--; - } - if (firstSpace == trailingSpaceRun->stop()) - trailingSpaceRun = 0; - else { - TextDirection direction = style()->direction(); - bool shouldReorder = trailingSpaceRun != (direction == LTR ? resolver.lastRun() : resolver.firstRun()); - if (firstSpace != trailingSpaceRun->start()) { - BidiContext* baseContext = resolver.context(); - while (BidiContext* parent = baseContext->parent()) - baseContext = parent; - - BidiRun* newTrailingRun = new (renderArena()) BidiRun(firstSpace, trailingSpaceRun->m_stop, trailingSpaceRun->m_object, baseContext, OtherNeutral); - trailingSpaceRun->m_stop = firstSpace; - if (direction == LTR) - resolver.addRun(newTrailingRun); - else - resolver.prependRun(newTrailingRun); - trailingSpaceRun = newTrailingRun; - shouldReorder = false; - } - if (shouldReorder) { - if (direction == LTR) { - resolver.moveRunToEnd(trailingSpaceRun); - trailingSpaceRun->m_level = 0; - } else { - resolver.moveRunToBeginning(trailingSpaceRun); - trailingSpaceRun->m_level = 1; - } - } - } - } else - trailingSpaceRun = 0; - } + BidiRun* trailingSpaceRun = !previousLineBrokeCleanly ? handleTrailingSpaces(bidiRuns, resolver.context()) : 0; // Now that the runs have been ordered, we create the line boxes. // At the same time we figure out where border/padding/margin should be applied for @@ -974,11 +1031,10 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogica RootInlineBox* lineBox = 0; int oldLogicalHeight = logicalHeight(); - if (resolver.runCount()) { + if (bidiRuns.runCount()) { if (hyphenated) - resolver.logicallyLastRun()->m_hasHyphen = true; - bool lastLine = end.m_obj && end.m_obj->isText() ? reachedEndOfTextRenderer(resolver) : !end.m_obj; - lineBox = constructLine(resolver.runCount(), resolver.firstRun(), resolver.lastRun(), firstLine, lastLine, end.m_obj && !end.m_pos ? end.m_obj : 0, resolver.logicallyLastRun()->m_object); + bidiRuns.logicallyLastRun()->m_hasHyphen = true; + lineBox = constructLine(bidiRuns, firstLine, !end.m_obj); if (lineBox) { lineBox->setEndsWithBreak(previousLineBrokeCleanly); @@ -992,10 +1048,10 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogica // Now we position all of our text runs horizontally. if (!isSVGRootInlineBox) - computeInlineDirectionPositionsForLine(lineBox, firstLine, resolver.firstRun(), trailingSpaceRun, end.atEnd(), textBoxDataMap, verticalPositionCache); + computeInlineDirectionPositionsForLine(lineBox, firstLine, bidiRuns.firstRun(), trailingSpaceRun, end.atEnd(), textBoxDataMap, verticalPositionCache); // Now position our text runs vertically. - computeBlockDirectionPositionsForLine(lineBox, resolver.firstRun(), textBoxDataMap, verticalPositionCache); + computeBlockDirectionPositionsForLine(lineBox, bidiRuns.firstRun(), textBoxDataMap, verticalPositionCache); #if ENABLE(SVG) // SVG text layout code computes vertical & horizontal positions on its own. @@ -1010,7 +1066,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogica #endif // Compute our overflow now. - lineBox->computeOverflow(lineBox->lineTop(), lineBox->lineBottom(), document()->inNoQuirksMode(), textBoxDataMap); + lineBox->computeOverflow(lineBox->lineTop(), lineBox->lineBottom(), textBoxDataMap); #if PLATFORM(MAC) // Highlight acts as an overflow inflation. @@ -1020,13 +1076,14 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogica } } - resolver.deleteRuns(); + bidiRuns.deleteRuns(); + resolver.markCurrentRunEmpty(); // FIXME: This can probably be replaced by an ASSERT (or just removed). if (lineBox) { lineBox->setLineBreakInfo(end.m_obj, end.m_pos, resolver.status()); if (useRepaintBounds) { - repaintLogicalTop = min(repaintLogicalTop, beforeSideVisualOverflowForLine(lineBox)); - repaintLogicalBottom = max(repaintLogicalBottom, afterSideVisualOverflowForLine(lineBox)); + repaintLogicalTop = min(repaintLogicalTop, lineBox->logicalTopVisualOverflow()); + repaintLogicalBottom = max(repaintLogicalBottom, lineBox->logicalBottomVisualOverflow()); } if (paginated) { @@ -1036,7 +1093,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogica int oldLineWidth = availableLogicalWidthForLine(oldLogicalHeight, firstLine); lineBox->adjustBlockDirectionPosition(adjustment); if (useRepaintBounds) // This can only be a positive adjustment, so no need to update repaintTop. - repaintLogicalBottom = max(repaintLogicalBottom, afterSideVisualOverflowForLine(lineBox)); + repaintLogicalBottom = max(repaintLogicalBottom, lineBox->logicalBottomVisualOverflow()); if (availableLogicalWidthForLine(oldLogicalHeight + adjustment, firstLine) != oldLineWidth) { // We have to delete this line, remove all floats that got added, and let line layout re-run. @@ -1072,7 +1129,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogica } for (; it != end; ++it) { FloatingObject* f = *it; - lastRootBox()->floats().append(f->m_renderer); + appendFloatingObjectToLastLine(f); ASSERT(f->m_renderer == floats[floatIndex].object); // If a float's geometry has changed, give up on syncing with clean lines. if (floats[floatIndex].rect != f->frameRect()) @@ -1097,8 +1154,8 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogica adjustLinePositionForPagination(line, delta); } if (delta) { - repaintLogicalTop = min(repaintLogicalTop, beforeSideVisualOverflowForLine(line) + min(delta, 0)); - repaintLogicalBottom = max(repaintLogicalBottom, afterSideVisualOverflowForLine(line) + max(delta, 0)); + repaintLogicalTop = min(repaintLogicalTop, line->logicalTopVisualOverflow() + min(delta, 0)); + repaintLogicalBottom = max(repaintLogicalBottom, line->logicalBottomVisualOverflow() + max(delta, 0)); line->adjustBlockDirectionPosition(delta); } if (Vector<RenderBox*>* cleanLineFloats = line->floatsPtr()) { @@ -1116,8 +1173,8 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogica RootInlineBox* line = endLine; RenderArena* arena = renderArena(); while (line) { - repaintLogicalTop = min(repaintLogicalTop, beforeSideVisualOverflowForLine(line)); - repaintLogicalBottom = max(repaintLogicalBottom, afterSideVisualOverflowForLine(line)); + repaintLogicalTop = min(repaintLogicalTop, line->logicalTopVisualOverflow()); + repaintLogicalBottom = max(repaintLogicalBottom, line->logicalBottomVisualOverflow()); RootInlineBox* next = line->nextRootBox(); line->deleteLine(arena); line = next; @@ -1129,17 +1186,18 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogica // This has to be done before adding in the bottom border/padding, or the float will // include the padding incorrectly. -dwh if (checkForFloatsFromLastLine) { - int bottomVisualOverflow = afterSideVisualOverflowForLine(lastRootBox()); - int bottomLayoutOverflow = afterSideLayoutOverflowForLine(lastRootBox()); + int bottomVisualOverflow = lastRootBox()->logicalBottomVisualOverflow(); + int bottomLayoutOverflow = lastRootBox()->logicalBottomLayoutOverflow(); TrailingFloatsRootInlineBox* trailingFloatsLineBox = new (renderArena()) TrailingFloatsRootInlineBox(this); m_lineBoxes.appendLineBox(trailingFloatsLineBox); trailingFloatsLineBox->setConstructed(); GlyphOverflowAndFallbackFontsMap textBoxDataMap; VerticalPositionCache verticalPositionCache; trailingFloatsLineBox->alignBoxesInBlockDirection(logicalHeight(), textBoxDataMap, verticalPositionCache); - IntRect logicalLayoutOverflow(0, logicalHeight(), 1, bottomLayoutOverflow); - IntRect logicalVisualOverflow(0, logicalHeight(), 1, bottomVisualOverflow); - trailingFloatsLineBox->setOverflowFromLogicalRects(logicalLayoutOverflow, logicalVisualOverflow); + int blockLogicalHeight = logicalHeight(); + IntRect logicalLayoutOverflow(0, blockLogicalHeight, 1, bottomLayoutOverflow - blockLogicalHeight); + IntRect logicalVisualOverflow(0, blockLogicalHeight, 1, bottomVisualOverflow - blockLogicalHeight); + trailingFloatsLineBox->setOverflowFromLogicalRects(logicalLayoutOverflow, logicalVisualOverflow, trailingFloatsLineBox->lineTop(), trailingFloatsLineBox->lineBottom()); trailingFloatsLineBox->setBlockLogicalHeight(logicalHeight()); } @@ -1153,7 +1211,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogica it = lastFloatIterator; } for (; it != end; ++it) - lastRootBox()->floats().append((*it)->m_renderer); + appendFloatingObjectToLastLine(*it); lastFloat = !floatingObjectSet.isEmpty() ? floatingObjectSet.last() : 0; } size_t floatCount = floats.size(); @@ -1211,6 +1269,7 @@ void RenderBlock::checkFloatsInCleanLine(RootInlineBox* line, Vector<FloatWithRe int floatTop = isHorizontalWritingMode() ? floats[floatIndex].rect.y() : floats[floatIndex].rect.x(); int floatHeight = isHorizontalWritingMode() ? max(floats[floatIndex].rect.height(), newSize.height()) : max(floats[floatIndex].rect.width(), newSize.width()); + floatHeight = min(floatHeight, numeric_limits<int>::max() - floatTop); line->markDirty(); markLinesDirtyInBlockRange(line->blockLogicalHeight(), floatTop + floatHeight, line); floats[floatIndex].rect.setSize(newSize); @@ -1247,8 +1306,8 @@ RootInlineBox* RenderBlock::determineStartPosition(bool& firstLine, bool& fullLa if (!useRepaintBounds) useRepaintBounds = true; - repaintLogicalTop = min(repaintLogicalTop, beforeSideVisualOverflowForLine(curr) + min(paginationDelta, 0)); - repaintLogicalBottom = max(repaintLogicalBottom, afterSideVisualOverflowForLine(curr) + max(paginationDelta, 0)); + repaintLogicalTop = min(repaintLogicalTop, curr->logicalTopVisualOverflow() + min(paginationDelta, 0)); + repaintLogicalBottom = max(repaintLogicalBottom, curr->logicalBottomVisualOverflow() + max(paginationDelta, 0)); curr->adjustBlockDirectionPosition(paginationDelta); } } @@ -1448,8 +1507,8 @@ bool RenderBlock::matchedEndLine(const InlineBidiResolver& resolver, const Inlin RootInlineBox* boxToDelete = endLine; RenderArena* arena = renderArena(); while (boxToDelete && boxToDelete != result) { - repaintLogicalTop = min(repaintLogicalTop, beforeSideVisualOverflowForLine(boxToDelete)); - repaintLogicalBottom = max(repaintLogicalBottom, afterSideVisualOverflowForLine(boxToDelete)); + repaintLogicalTop = min(repaintLogicalTop, boxToDelete->logicalTopVisualOverflow()); + repaintLogicalBottom = max(repaintLogicalBottom, boxToDelete->logicalBottomVisualOverflow()); RootInlineBox* next = boxToDelete->nextRootBox(); boxToDelete->deleteLine(arena); boxToDelete = next; @@ -1484,16 +1543,6 @@ static inline bool shouldCollapseWhiteSpace(const RenderStyle* style, bool isLin return style->collapseWhiteSpace() || (style->whiteSpace() == PRE_WRAP && (!isLineEmpty || !previousLineBrokeCleanly)); } -static inline bool shouldPreserveNewline(RenderObject* object) -{ -#if ENABLE(SVG) - if (object->isSVGInlineText()) - return false; -#endif - - return object->style()->preserveNewline(); -} - static bool inlineFlowRequiresLineBox(RenderInline* flow) { // FIXME: Right now, we only allow line boxes for inlines that are truly empty. @@ -1514,7 +1563,7 @@ bool RenderBlock::requiresLineBox(const InlineIterator& it, bool isLineEmpty, bo return true; UChar current = it.current(); - return current != ' ' && current != '\t' && current != softHyphen && (current != '\n' || shouldPreserveNewline(it.m_obj)) + return current != ' ' && current != '\t' && current != softHyphen && (current != '\n' || it.m_obj->preservesNewline()) && !skipNonBreakingSpace(it, isLineEmpty, previousLineBrokeCleanly); } @@ -1547,13 +1596,13 @@ void RenderBlock::skipTrailingWhitespace(InlineIterator& iterator, bool isLineEm } } -void RenderBlock::skipLeadingWhitespace(InlineBidiResolver& resolver, bool firstLine, bool isLineEmpty, bool previousLineBrokeCleanly, - FloatingObject* lastFloatFromPreviousLine, int& lineLeftOffset, int& lineRightOffset) +void RenderBlock::skipLeadingWhitespace(InlineBidiResolver& resolver, bool isLineEmpty, bool previousLineBrokeCleanly, + FloatingObject* lastFloatFromPreviousLine, LineWidth& width) { while (!resolver.position().atEnd() && !requiresLineBox(resolver.position(), isLineEmpty, previousLineBrokeCleanly)) { RenderObject* object = resolver.position().m_obj; if (object->isFloating()) - positionNewFloatOnLine(insertFloatingObject(toRenderBox(object)), lastFloatFromPreviousLine, firstLine, lineLeftOffset, lineRightOffset); + positionNewFloatOnLine(insertFloatingObject(toRenderBox(object)), lastFloatFromPreviousLine, width); else if (object->isPositioned()) setStaticPositions(this, toRenderBox(object)); resolver.increment(); @@ -1578,30 +1627,6 @@ static bool shouldSkipWhitespaceAfterStartObject(RenderBlock* block, RenderObjec return false; } -void RenderBlock::fitBelowFloats(float widthToFit, bool firstLine, float& availableWidth) -{ - ASSERT(widthToFit > availableWidth); - - int floatLogicalBottom; - int lastFloatLogicalBottom = logicalHeight(); - float newLineWidth = availableWidth; - while (true) { - floatLogicalBottom = nextFloatLogicalBottomBelow(lastFloatLogicalBottom); - if (!floatLogicalBottom) - break; - - newLineWidth = availableLogicalWidthForLine(floatLogicalBottom, firstLine); - lastFloatLogicalBottom = floatLogicalBottom; - if (newLineWidth >= widthToFit) - break; - } - - if (newLineWidth > availableWidth) { - setLogicalHeight(lastFloatLogicalBottom); - availableWidth = newLineWidth; - } -} - static inline float textWidth(RenderText* text, unsigned from, unsigned len, const Font& font, float xPos, bool isFixedPitch, bool collapseWhiteSpace) { if (isFixedPitch || (!from && len == text->textLength()) || text->style()->hasTextCombine()) @@ -1654,23 +1679,131 @@ static void tryHyphenating(RenderText* text, const Font& font, const AtomicStrin hyphenated = true; } +class LineWidth { +public: + LineWidth(RenderBlock* block, bool isFirstLine) + : m_block(block) + , m_uncommittedWidth(0) + , m_committedWidth(0) + , m_overhangWidth(0) + , m_left(0) + , m_right(0) + , m_availableWidth(0) + , m_isFirstLine(isFirstLine) + { + ASSERT(block); + updateAvailableWidth(); + } + bool fitsOnLine() const { return currentWidth() <= m_availableWidth; } + bool fitsOnLine(float extra) const { return currentWidth() + extra <= m_availableWidth; } + float currentWidth() const { return m_committedWidth + m_uncommittedWidth; } + + // FIXME: We should eventually replace these three functions by ones that work on a higher abstraction. + float uncommittedWidth() const { return m_uncommittedWidth; } + float committedWidth() const { return m_committedWidth; } + float availableWidth() const { return m_availableWidth; } + + void updateAvailableWidth(); + void shrinkAvailableWidthForNewFloatIfNeeded(RenderBlock::FloatingObject*); + void addUncommittedWidth(float delta) { m_uncommittedWidth += delta; } + void commit() + { + m_committedWidth += m_uncommittedWidth; + m_uncommittedWidth = 0; + } + void applyOverhang(RenderRubyRun*, RenderObject* startRenderer, RenderObject* endRenderer); + void fitBelowFloats(); + +private: + void computeAvailableWidthFromLeftAndRight() + { + m_availableWidth = max(0, m_right - m_left) + m_overhangWidth; + } + +private: + RenderBlock* m_block; + float m_uncommittedWidth; + float m_committedWidth; + float m_overhangWidth; // The amount by which |m_availableWidth| has been inflated to account for possible contraction due to ruby overhang. + int m_left; + int m_right; + float m_availableWidth; + bool m_isFirstLine; +}; + +inline void LineWidth::updateAvailableWidth() +{ + int height = m_block->logicalHeight(); + m_left = m_block->logicalLeftOffsetForLine(height, m_isFirstLine); + m_right = m_block->logicalRightOffsetForLine(height, m_isFirstLine); + + computeAvailableWidthFromLeftAndRight(); +} + +inline void LineWidth::shrinkAvailableWidthForNewFloatIfNeeded(RenderBlock::FloatingObject* newFloat) +{ + int height = m_block->logicalHeight(); + if (height < m_block->logicalTopForFloat(newFloat) || height >= m_block->logicalBottomForFloat(newFloat)) + return; + + if (newFloat->type() == RenderBlock::FloatingObject::FloatLeft) + m_left = m_block->logicalRightForFloat(newFloat); + else + m_right = m_block->logicalLeftForFloat(newFloat); + + computeAvailableWidthFromLeftAndRight(); +} + +void LineWidth::applyOverhang(RenderRubyRun* rubyRun, RenderObject* startRenderer, RenderObject* endRenderer) +{ + int startOverhang; + int endOverhang; + rubyRun->getOverhang(m_isFirstLine, startRenderer, endRenderer, startOverhang, endOverhang); + + startOverhang = min<int>(startOverhang, m_committedWidth); + m_availableWidth += startOverhang; + + endOverhang = max(min<int>(endOverhang, m_availableWidth - currentWidth()), 0); + m_availableWidth += endOverhang; + m_overhangWidth += startOverhang + endOverhang; +} + +void LineWidth::fitBelowFloats() +{ + ASSERT(!m_committedWidth); + ASSERT(!fitsOnLine()); + + int floatLogicalBottom; + int lastFloatLogicalBottom = m_block->logicalHeight(); + float newLineWidth = m_availableWidth; + while (true) { + floatLogicalBottom = m_block->nextFloatLogicalBottomBelow(lastFloatLogicalBottom); + if (!floatLogicalBottom) + break; + + newLineWidth = m_block->availableLogicalWidthForLine(floatLogicalBottom, m_isFirstLine); + lastFloatLogicalBottom = floatLogicalBottom; + if (newLineWidth >= m_uncommittedWidth) + break; + } + + if (newLineWidth > m_availableWidth) { + m_block->setLogicalHeight(lastFloatLogicalBottom); + m_availableWidth = newLineWidth + m_overhangWidth; + } +} + InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool firstLine, bool& isLineEmpty, LineBreakIteratorInfo& lineBreakIteratorInfo, bool& previousLineBrokeCleanly, bool& hyphenated, EClear* clear, FloatingObject* lastFloatFromPreviousLine, Vector<RenderBox*>& positionedBoxes) { - ASSERT(resolver.position().m_block == this); + ASSERT(resolver.position().root() == this); bool appliedStartWidth = resolver.position().m_pos > 0; LineMidpointState& lineMidpointState = resolver.midpointState(); - - int blockOffset = logicalHeight(); - int lineLeftOffset = logicalLeftOffsetForLine(blockOffset, firstLine); - int lineRightOffset = logicalRightOffsetForLine(blockOffset, firstLine); - - skipLeadingWhitespace(resolver, firstLine, isLineEmpty, previousLineBrokeCleanly, lastFloatFromPreviousLine, lineLeftOffset, lineRightOffset); - float width = max(0, lineRightOffset - lineLeftOffset); - float w = 0; - float tmpW = 0; + LineWidth width(this, firstLine); + + skipLeadingWhitespace(resolver, isLineEmpty, previousLineBrokeCleanly, lastFloatFromPreviousLine, width); if (resolver.position().atEnd()) return resolver.position(); @@ -1714,6 +1847,8 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool EWhiteSpace currWS = style()->whiteSpace(); EWhiteSpace lastWS = currWS; while (o) { + RenderObject* next = bidiNext(this, o); + currWS = o->isReplaced() ? o->parent()->style()->whiteSpace() : o->style()->whiteSpace(); lastWS = last->isReplaced() ? last->parent()->style()->whiteSpace() : last->style()->whiteSpace(); @@ -1729,7 +1864,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool bool collapseWhiteSpace = RenderStyle::collapseWhiteSpace(currWS); if (o->isBR()) { - if (w + tmpW <= width) { + if (width.fitsOnLine()) { lBreak.moveToStartOf(o); lBreak.increment(); @@ -1757,9 +1892,8 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool // check if it fits in the current line. // If it does, position it now, otherwise, position // it after moving to next line (in newLine() func) - if (floatsFitOnLine && logicalWidthForFloat(f) + w + tmpW <= width) { - positionNewFloatOnLine(f, lastFloatFromPreviousLine, firstLine, lineLeftOffset, lineRightOffset); - width = max(0, lineRightOffset - lineLeftOffset); + if (floatsFitOnLine && width.fitsOnLine(logicalWidthForFloat(f))) { + positionNewFloatOnLine(f, lastFloatFromPreviousLine, width); if (lBreak.m_obj == o) { ASSERT(!lBreak.m_pos); lBreak.increment(); @@ -1820,15 +1954,13 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool } } - tmpW += flowBox->marginStart() + flowBox->borderStart() + flowBox->paddingStart() + - flowBox->marginEnd() + flowBox->borderEnd() + flowBox->paddingEnd(); + width.addUncommittedWidth(borderPaddingMarginStart(flowBox) + borderPaddingMarginEnd(flowBox)); } else if (o->isReplaced()) { RenderBox* replacedBox = toRenderBox(o); // Break on replaced elements if either has normal white-space. if ((autoWrap || RenderStyle::autoWrap(lastWS)) && (!o->isImage() || allowImagesToBreak)) { - w += tmpW; - tmpW = 0; + width.commit(); lBreak.moveToStartOf(o); } @@ -1854,9 +1986,11 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool ignoringSpaces = true; } if (toRenderListMarker(o)->isInside()) - tmpW += replacedLogicalWidth; + width.addUncommittedWidth(replacedLogicalWidth); } else - tmpW += replacedLogicalWidth; + width.addUncommittedWidth(replacedLogicalWidth); + if (o->isRubyRun()) + width.applyOverhang(toRenderRubyRun(o), last, next); } else if (o->isText()) { if (!pos) appliedStartWidth = false; @@ -1887,19 +2021,18 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool // space, then subtract its width. float wordTrailingSpaceWidth = f.typesettingFeatures() & Kerning ? f.width(TextRun(&space, 1)) + wordSpacing : 0; - float wrapW = tmpW + inlineLogicalWidth(o, !appliedStartWidth, true); + float wrapW = width.uncommittedWidth() + inlineLogicalWidth(o, !appliedStartWidth, true); float charWidth = 0; bool breakNBSP = autoWrap && o->style()->nbspMode() == SPACE; // Auto-wrapping text should wrap in the middle of a word only if it could not wrap before the word, // which is only possible if the word is the first thing on the line, that is, if |w| is zero. - bool breakWords = o->style()->breakWords() && ((autoWrap && !w) || currWS == PRE); + bool breakWords = o->style()->breakWords() && ((autoWrap && !width.committedWidth()) || currWS == PRE); bool midWordBreak = false; bool breakAll = o->style()->wordBreak() == BreakAllWordBreak && autoWrap; float hyphenWidth = 0; if (t->isWordBreak()) { - w += tmpW; - tmpW = 0; + width.commit(); lBreak.moveToStartOf(o); ASSERT(!len); } @@ -1916,29 +2049,17 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool if (c == softHyphen && autoWrap && !hyphenWidth && style->hyphens() != HyphensNone) { const AtomicString& hyphenString = style->hyphenString(); hyphenWidth = f.width(TextRun(hyphenString.characters(), hyphenString.length())); - tmpW += hyphenWidth; + width.addUncommittedWidth(hyphenWidth); } -#if ENABLE(SVG) - if (isSVGText) { - RenderSVGInlineText* svgInlineText = static_cast<RenderSVGInlineText*>(t); - if (pos > 0) { - if (svgInlineText->characterStartsNewTextChunk(pos)) { - addMidpoint(lineMidpointState, InlineIterator(0, o, pos - 1)); - addMidpoint(lineMidpointState, InlineIterator(0, o, pos)); - } - } - } -#endif - bool applyWordSpacing = false; currentCharacterIsWS = currentCharacterIsSpace || (breakNBSP && c == noBreakSpace); if ((breakAll || breakWords) && !midWordBreak) { wrapW += charWidth; - charWidth = textWidth(t, pos, 1, f, w + wrapW, isFixedPitch, collapseWhiteSpace); - midWordBreak = w + wrapW + charWidth > width; + charWidth = textWidth(t, pos, 1, f, width.committedWidth() + wrapW, isFixedPitch, collapseWhiteSpace); + midWordBreak = width.committedWidth() + wrapW + charWidth > width.availableWidth(); } if (lineBreakIteratorInfo.first != t) { @@ -1969,44 +2090,44 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool float additionalTmpW; if (wordTrailingSpaceWidth && currentCharacterIsSpace) - additionalTmpW = textWidth(t, lastSpace, pos + 1 - lastSpace, f, w + tmpW, isFixedPitch, collapseWhiteSpace) - wordTrailingSpaceWidth + lastSpaceWordSpacing; + additionalTmpW = textWidth(t, lastSpace, pos + 1 - lastSpace, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace) - wordTrailingSpaceWidth + lastSpaceWordSpacing; else - additionalTmpW = textWidth(t, lastSpace, pos - lastSpace, f, w + tmpW, isFixedPitch, collapseWhiteSpace) + lastSpaceWordSpacing; - tmpW += additionalTmpW; + additionalTmpW = textWidth(t, lastSpace, pos - lastSpace, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace) + lastSpaceWordSpacing; + width.addUncommittedWidth(additionalTmpW); if (!appliedStartWidth) { - tmpW += inlineLogicalWidth(o, true, false); + width.addUncommittedWidth(inlineLogicalWidth(o, true, false)); appliedStartWidth = true; } applyWordSpacing = wordSpacing && currentCharacterIsSpace && !previousCharacterIsSpace; - if (!w && autoWrap && tmpW > width) - fitBelowFloats(tmpW, firstLine, width); + if (!width.committedWidth() && autoWrap && !width.fitsOnLine()) + width.fitBelowFloats(); if (autoWrap || breakWords) { // If we break only after white-space, consider the current character // as candidate width for this line. bool lineWasTooWide = false; - if (w + tmpW <= width && currentCharacterIsWS && o->style()->breakOnlyAfterWhiteSpace() && !midWordBreak) { - int charWidth = textWidth(t, pos, 1, f, w + tmpW, isFixedPitch, collapseWhiteSpace) + (applyWordSpacing ? wordSpacing : 0); + if (width.fitsOnLine() && currentCharacterIsWS && o->style()->breakOnlyAfterWhiteSpace() && !midWordBreak) { + int charWidth = textWidth(t, pos, 1, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace) + (applyWordSpacing ? wordSpacing : 0); // Check if line is too big even without the extra space // at the end of the line. If it is not, do nothing. // If the line needs the extra whitespace to be too long, // then move the line break to the space and skip all // additional whitespace. - if (w + tmpW + charWidth > width) { + if (!width.fitsOnLine(charWidth)) { lineWasTooWide = true; lBreak.moveTo(o, pos, nextBreakable); skipTrailingWhitespace(lBreak, isLineEmpty, previousLineBrokeCleanly); } } - if (lineWasTooWide || w + tmpW > width) { - if (canHyphenate && w + tmpW > width) { - tryHyphenating(t, f, style->locale(), style->hyphenationLimitBefore(), style->hyphenationLimitAfter(), lastSpace, pos, w + tmpW - additionalTmpW, width, isFixedPitch, collapseWhiteSpace, lastSpaceWordSpacing, lBreak, nextBreakable, hyphenated); + if (lineWasTooWide || !width.fitsOnLine()) { + if (canHyphenate && !width.fitsOnLine()) { + tryHyphenating(t, f, style->locale(), style->hyphenationLimitBefore(), style->hyphenationLimitAfter(), lastSpace, pos, width.currentWidth() - additionalTmpW, width.availableWidth(), isFixedPitch, collapseWhiteSpace, lastSpaceWordSpacing, lBreak, nextBreakable, hyphenated); if (hyphenated) goto end; } - if (lBreak.m_obj && shouldPreserveNewline(lBreak.m_obj) && lBreak.m_obj->isText() && toRenderText(lBreak.m_obj)->textLength() && !toRenderText(lBreak.m_obj)->isWordBreak() && toRenderText(lBreak.m_obj)->characters()[lBreak.m_pos] == '\n') { + if (lBreak.atTextParagraphSeparator()) { if (!stoppedIgnoringSpaces && pos > 0) { // We need to stop right before the newline and then start up again. addMidpoint(lineMidpointState, InlineIterator(0, o, pos - 1)); // Stop @@ -2020,10 +2141,10 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool goto end; // Didn't fit. Jump to the end. } else { if (!betweenWords || (midWordBreak && !autoWrap)) - tmpW -= additionalTmpW; + width.addUncommittedWidth(-additionalTmpW); if (hyphenWidth) { // Subtract the width of the soft hyphen out since we fit on a line. - tmpW -= hyphenWidth; + width.addUncommittedWidth(-hyphenWidth); hyphenWidth = 0; } } @@ -2042,9 +2163,8 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool } if (autoWrap && betweenWords) { - w += tmpW; + width.commit(); wrapW = 0; - tmpW = 0; lBreak.moveTo(o, pos, nextBreakable); // Auto-wrapping text should not wrap in the middle of a word once it has had an // opportunity to break after a word. @@ -2085,6 +2205,16 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool addMidpoint(lineMidpointState, InlineIterator(0, o, pos)); } +#if ENABLE(SVG) + if (isSVGText && pos > 0) { + // Force creation of new InlineBoxes for each absolute positioned character (those that start new text chunks). + if (static_cast<RenderSVGInlineText*>(t)->characterStartsNewTextChunk(pos)) { + addMidpoint(lineMidpointState, InlineIterator(0, o, pos - 1)); + addMidpoint(lineMidpointState, InlineIterator(0, o, pos)); + } + } +#endif + if (currentCharacterIsSpace && !previousCharacterIsSpace) { ignoreStart.m_obj = o; ignoreStart.m_pos = pos; @@ -2108,26 +2238,24 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool } // IMPORTANT: pos is > length here! - float additionalTmpW = ignoringSpaces ? 0 : textWidth(t, lastSpace, pos - lastSpace, f, w + tmpW, isFixedPitch, collapseWhiteSpace) + lastSpaceWordSpacing; - tmpW += additionalTmpW; - tmpW += inlineLogicalWidth(o, !appliedStartWidth, true); + float additionalTmpW = ignoringSpaces ? 0 : textWidth(t, lastSpace, pos - lastSpace, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace) + lastSpaceWordSpacing; + width.addUncommittedWidth(additionalTmpW + inlineLogicalWidth(o, !appliedStartWidth, true)); - if (w + tmpW > width) { + if (!width.fitsOnLine()) { if (canHyphenate) - tryHyphenating(t, f, style->locale(), style->hyphenationLimitBefore(), style->hyphenationLimitAfter(), lastSpace, pos, w + tmpW - additionalTmpW, width, isFixedPitch, collapseWhiteSpace, lastSpaceWordSpacing, lBreak, nextBreakable, hyphenated); - + tryHyphenating(t, f, style->locale(), style->hyphenationLimitBefore(), style->hyphenationLimitAfter(), lastSpace, pos, width.currentWidth() - additionalTmpW, width.availableWidth(), isFixedPitch, collapseWhiteSpace, lastSpaceWordSpacing, lBreak, nextBreakable, hyphenated); + if (!hyphenated && lBreak.m_obj && lBreak.m_pos && lBreak.m_obj->isText() && toRenderText(lBreak.m_obj)->textLength() && toRenderText(lBreak.m_obj)->characters()[lBreak.m_pos - 1] == softHyphen && style->hyphens() != HyphensNone) hyphenated = true; - + if (hyphenated) goto end; } } else ASSERT_NOT_REACHED(); - RenderObject* next = bidiNext(this, o); bool checkForBreak = autoWrap; - if (w && w + tmpW > width && lBreak.m_obj && currWS == NOWRAP) + if (width.committedWidth() && !width.fitsOnLine() && lBreak.m_obj && currWS == NOWRAP) checkForBreak = true; else if (next && o->isText() && next->isText() && !next->isBR()) { if (autoWrap || (next->style()->autoWrap())) { @@ -2138,52 +2266,49 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool RenderText* nextText = toRenderText(next); if (nextText->textLength()) { UChar c = nextText->characters()[0]; - if (c == ' ' || c == '\t' || (c == '\n' && !shouldPreserveNewline(next))) + if (c == ' ' || c == '\t' || (c == '\n' && !next->preservesNewline())) // If the next item on the line is text, and if we did not end with // a space, then the next text run continues our word (and so it needs to // keep adding to |tmpW|. Just update and continue. checkForBreak = true; } else if (nextText->isWordBreak()) checkForBreak = true; - bool willFitOnLine = w + tmpW <= width; - if (!willFitOnLine && !w) { - fitBelowFloats(tmpW, firstLine, width); - willFitOnLine = tmpW <= width; - } - bool canPlaceOnLine = willFitOnLine || !autoWrapWasEverTrueOnLine; + + if (!width.fitsOnLine() && !width.committedWidth()) + width.fitBelowFloats(); + + bool canPlaceOnLine = width.fitsOnLine() || !autoWrapWasEverTrueOnLine; if (canPlaceOnLine && checkForBreak) { - w += tmpW; - tmpW = 0; + width.commit(); lBreak.moveToStartOf(next); } } } } - if (checkForBreak && (w + tmpW > width)) { + if (checkForBreak && !width.fitsOnLine()) { // if we have floats, try to get below them. if (currentCharacterIsSpace && !ignoringSpaces && o->style()->collapseWhiteSpace()) { trailingSpaceObject = 0; trailingPositionedBoxes.clear(); } - if (w) + if (width.committedWidth()) goto end; - fitBelowFloats(tmpW, firstLine, width); + width.fitBelowFloats(); // |width| may have been adjusted because we got shoved down past a float (thus // giving us more room), so we need to retest, and only jump to // the end label if we still don't fit on the line. -dwh - if (w + tmpW > width) + if (!width.fitsOnLine()) goto end; } if (!o->isFloatingOrPositioned()) { last = o; if (last->isReplaced() && autoWrap && (!last->isImage() || allowImagesToBreak) && (!last->isListMarker() || toRenderListMarker(last)->isInside())) { - w += tmpW; - tmpW = 0; + width.commit(); lBreak.moveToStartOf(next); } } @@ -2199,9 +2324,8 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool pos = 0; atStart = false; } - - if (w + tmpW <= width || lastWS == NOWRAP) + if (width.fitsOnLine() || lastWS == NOWRAP) lBreak.clear(); end: @@ -2294,42 +2418,10 @@ void RenderBlock::addOverflowFromInlineChildren() for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) { addLayoutOverflow(curr->paddedLayoutOverflowRect(endPadding)); if (!hasOverflowClip()) - addVisualOverflow(curr->visualOverflowRect()); + addVisualOverflow(curr->visualOverflowRect(curr->lineTop(), curr->lineBottom())); } } -int RenderBlock::beforeSideVisualOverflowForLine(RootInlineBox* line) const -{ - // Overflow is in the block's coordinate space, which means it isn't purely physical. - if (isHorizontalWritingMode()) - 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. - if (isHorizontalWritingMode()) - 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. - if (isHorizontalWritingMode()) - 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. - if (isHorizontalWritingMode()) - return line->maxYLayoutOverflow(); - return line->maxXLayoutOverflow(); -} - void RenderBlock::deleteEllipsisLineBoxes() { for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) @@ -2369,4 +2461,49 @@ void RenderBlock::checkLinesForTextOverflow() } } +bool RenderBlock::positionNewFloatOnLine(FloatingObject* newFloat, FloatingObject* lastFloatFromPreviousLine, LineWidth& width) +{ + if (!positionNewFloats()) + return false; + + width.shrinkAvailableWidthForNewFloatIfNeeded(newFloat); + + if (!newFloat->m_paginationStrut) + return true; + + FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); + ASSERT(floatingObjectSet.last() == newFloat); + + int floatLogicalTop = logicalTopForFloat(newFloat); + int paginationStrut = newFloat->m_paginationStrut; + + if (floatLogicalTop - paginationStrut != logicalHeight()) + return true; + + FloatingObjectSetIterator it = floatingObjectSet.end(); + --it; // Last float is newFloat, skip that one. + FloatingObjectSetIterator begin = floatingObjectSet.begin(); + while (it != begin) { + --it; + FloatingObject* f = *it; + if (f == lastFloatFromPreviousLine) + break; + if (logicalTopForFloat(f) == logicalHeight()) { + ASSERT(!f->m_paginationStrut); + f->m_paginationStrut = paginationStrut; + RenderBox* o = f->m_renderer; + setLogicalTopForChild(o, logicalTopForChild(o) + marginBeforeForChild(o) + paginationStrut); + if (o->isRenderBlock()) + toRenderBlock(o)->setChildNeedsLayout(true, false); + o->layoutIfNeeded(); + setLogicalTopForFloat(f, logicalTopForFloat(f) + f->m_paginationStrut); + } + } + + setLogicalHeight(logicalHeight() + paginationStrut); + width.updateAvailableWidth(); + + return true; +} + } diff --git a/Source/WebCore/rendering/RenderBox.cpp b/Source/WebCore/rendering/RenderBox.cpp index 7b32f07..11c0306 100644 --- a/Source/WebCore/rendering/RenderBox.cpp +++ b/Source/WebCore/rendering/RenderBox.cpp @@ -966,7 +966,7 @@ void RenderBox::paintFillLayers(const PaintInfo& paintInfo, const Color& c, cons void RenderBox::paintFillLayer(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, int tx, int ty, int width, int height, CompositeOperator op, RenderObject* backgroundObject) { - paintFillLayerExtended(paintInfo, c, fillLayer, tx, ty, width, height, 0, op, backgroundObject); + paintFillLayerExtended(paintInfo, c, fillLayer, tx, ty, width, height, 0, 0, 0, op, backgroundObject); } #if USE(ACCELERATED_COMPOSITING) diff --git a/Source/WebCore/rendering/RenderBox.h b/Source/WebCore/rendering/RenderBox.h index ccedc66..f8aee06 100644 --- a/Source/WebCore/rendering/RenderBox.h +++ b/Source/WebCore/rendering/RenderBox.h @@ -350,15 +350,15 @@ public: // Called when a positioned object moves but doesn't necessarily change size. A simplified layout is attempted // that just updates the object's position. If the size does change, the object remains dirty. - void tryLayoutDoingPositionedMovementOnly() + bool tryLayoutDoingPositionedMovementOnly() { int oldWidth = width(); computeLogicalWidth(); // If we shrink to fit our width may have changed, so we still need full layout. if (oldWidth != width()) - return; + return false; computeLogicalHeight(); - setNeedsLayout(false); + return true; } IntRect maskClipRect(); @@ -398,9 +398,13 @@ public: IntRect logicalLayoutOverflowRectForPropagation(RenderStyle*) const; IntRect layoutOverflowRectForPropagation(RenderStyle*) const; +<<<<<<< HEAD #ifdef ANDROID_LAYOUT int getVisibleWidth() const { return m_visibleWidth; } #endif +======= + RenderOverflow* hasRenderOverflow() const { return m_overflow.get(); } +>>>>>>> WebKit.org at r84325 protected: virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle); diff --git a/Source/WebCore/rendering/RenderBoxModelObject.cpp b/Source/WebCore/rendering/RenderBoxModelObject.cpp index 3e2974d..52196e3 100644 --- a/Source/WebCore/rendering/RenderBoxModelObject.cpp +++ b/Source/WebCore/rendering/RenderBoxModelObject.cpp @@ -559,7 +559,20 @@ int RenderBoxModelObject::paddingEnd(bool) const return padding.calcMinValue(w); } -void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, const Color& c, const FillLayer* bgLayer, int tx, int ty, int w, int h, InlineFlowBox* box, CompositeOperator op, RenderObject* backgroundObject) +RoundedIntRect RenderBoxModelObject::getBackgroundRoundedRect(const IntRect& borderRect, InlineFlowBox* box, int inlineBoxWidth, int inlineBoxHeight, + bool includeLogicalLeftEdge, bool includeLogicalRightEdge) +{ + RoundedIntRect border = style()->getRoundedBorderFor(borderRect, includeLogicalLeftEdge, includeLogicalRightEdge); + if (box && (box->nextLineBox() || box->prevLineBox())) { + RoundedIntRect segmentBorder = style()->getRoundedBorderFor(IntRect(0, 0, inlineBoxWidth, inlineBoxHeight), includeLogicalLeftEdge, includeLogicalRightEdge); + border.setRadii(segmentBorder.radii()); + } + + return border; +} + +void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, const Color& color, const FillLayer* bgLayer, int tx, int ty, int w, int h, + InlineFlowBox* box, int inlineBoxWidth, int inlineBoxHeight, CompositeOperator op, RenderObject* backgroundObject) { GraphicsContext* context = paintInfo.context; if (context->paintingDisabled()) @@ -567,13 +580,53 @@ void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co bool includeLeftEdge = box ? box->includeLogicalLeftEdge() : true; bool includeRightEdge = box ? box->includeLogicalRightEdge() : true; - int bLeft = includeLeftEdge ? borderLeft() : 0; - int bRight = includeRightEdge ? borderRight() : 0; - int pLeft = includeLeftEdge ? paddingLeft() : 0; - int pRight = includeRightEdge ? paddingRight() : 0; + + bool hasRoundedBorder = style()->hasBorderRadius() && (includeLeftEdge || includeRightEdge); + bool clippedWithLocalScrolling = hasOverflowClip() && bgLayer->attachment() == LocalBackgroundAttachment; + bool isBorderFill = bgLayer->clip() == BorderFillBox; + bool isRoot = this->isRoot(); + + Color bgColor = color; + StyleImage* bgImage = bgLayer->image(); + bool shouldPaintBackgroundImage = bgImage && bgImage->canRender(style()->effectiveZoom()); + + // When this style flag is set, change existing background colors and images to a solid white background. + // If there's no bg color or image, leave it untouched to avoid affecting transparency. + // We don't try to avoid loading the background images, because this style flag is only set + // when printing, and at that point we've already loaded the background images anyway. (To avoid + // loading the background images we'd have to do this check when applying styles rather than + // while rendering.) + if (style()->forceBackgroundsToWhite()) { + // Note that we can't reuse this variable below because the bgColor might be changed + bool shouldPaintBackgroundColor = !bgLayer->next() && bgColor.isValid() && bgColor.alpha() > 0; + if (shouldPaintBackgroundImage || shouldPaintBackgroundColor) { + bgColor = Color::white; + shouldPaintBackgroundImage = false; + } + } + + bool colorVisible = bgColor.isValid() && bgColor.alpha() > 0; + + // Fast path for drawing simple color backgrounds. + if (!isRoot && !clippedWithLocalScrolling && !shouldPaintBackgroundImage && isBorderFill) { + if (!colorVisible) + return; + + IntRect borderRect(tx, ty, w, h); + if (borderRect.isEmpty()) + return; + + if (hasRoundedBorder) { + RoundedIntRect border = getBackgroundRoundedRect(borderRect, box, inlineBoxWidth, inlineBoxHeight, includeLeftEdge, includeRightEdge); + context->fillRoundedRect(border, bgColor, style()->colorSpace()); + } else + context->fillRect(borderRect, bgColor, style()->colorSpace()); + + return; + } bool clippedToBorderRadius = false; - if (style()->hasBorderRadius() && (includeLeftEdge || includeRightEdge)) { + if (hasRoundedBorder) { IntRect borderRect(tx, ty, w, h); if (borderRect.isEmpty()) @@ -581,13 +634,16 @@ void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co context->save(); - RoundedIntRect border = style()->getRoundedBorderFor(borderRect); - border.excludeLogicalEdges(box && box->isHorizontal(), !includeLeftEdge, !includeRightEdge); + RoundedIntRect border = getBackgroundRoundedRect(borderRect, box, inlineBoxWidth, inlineBoxHeight, includeLeftEdge, includeRightEdge); context->addRoundedRectClip(border); clippedToBorderRadius = true; } + + int bLeft = includeLeftEdge ? borderLeft() : 0; + int bRight = includeRightEdge ? borderRight() : 0; + int pLeft = includeLeftEdge ? paddingLeft() : 0; + int pRight = includeRightEdge ? paddingRight() : 0; - bool clippedWithLocalScrolling = hasOverflowClip() && bgLayer->attachment() == LocalBackgroundAttachment; if (clippedWithLocalScrolling) { // Clip to the overflow area. context->save(); @@ -628,9 +684,10 @@ void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co // Now add the text to the clip. We do this by painting using a special paint phase that signals to // InlineTextBoxes that they should just add their contents to the clip. PaintInfo info(maskImageContext, maskRect, PaintPhaseTextClip, true, 0, 0); - if (box) - box->paint(info, tx - box->x(), ty - box->y()); - else { + if (box) { + RootInlineBox* root = box->root(); + box->paint(info, tx - box->x(), ty - box->y(), root->lineTop(), root->lineBottom()); + } else { int x = isBox() ? toRenderBox(this)->x() : 0; int y = isBox() ? toRenderBox(this)->y() : 0; paint(info, tx - x, ty - y); @@ -641,27 +698,6 @@ void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co context->clipToImageBuffer(maskImage.get(), maskRect); } - StyleImage* bg = bgLayer->image(); - bool shouldPaintBackgroundImage = bg && bg->canRender(style()->effectiveZoom()); - Color bgColor = c; - - // When this style flag is set, change existing background colors and images to a solid white background. - // If there's no bg color or image, leave it untouched to avoid affecting transparency. - // We don't try to avoid loading the background images, because this style flag is only set - // when printing, and at that point we've already loaded the background images anyway. (To avoid - // loading the background images we'd have to do this check when applying styles rather than - // while rendering.) - if (style()->forceBackgroundsToWhite()) { - // Note that we can't reuse this variable below because the bgColor might be changed - bool shouldPaintBackgroundColor = !bgLayer->next() && bgColor.isValid() && bgColor.alpha() > 0; - if (shouldPaintBackgroundImage || shouldPaintBackgroundColor) { - bgColor = Color::white; - shouldPaintBackgroundImage = false; - } - } - - bool isRoot = this->isRoot(); - // Only fill with a base color (e.g., white) if we're the root document, since iframes/frames with // no background in the child document should show the parent's background. bool isOpaqueRoot = false; @@ -726,18 +762,16 @@ void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co phase += destRect.location() - destOrigin; CompositeOperator compositeOp = op == CompositeSourceOver ? bgLayer->composite() : op; RenderObject* clientForBackgroundImage = backgroundObject ? backgroundObject : this; - RefPtr<Image> image = bg->image(clientForBackgroundImage, tileSize); + RefPtr<Image> image = bgImage->image(clientForBackgroundImage, tileSize); bool useLowQualityScaling = shouldPaintAtLowQuality(context, image.get(), bgLayer, tileSize); context->drawTiledImage(image.get(), style()->colorSpace(), destRect, phase, tileSize, compositeOp, useLowQualityScaling); } } - if (bgLayer->clip() != BorderFillBox) - // Undo the background clip + if (!isBorderFill) // Undo the background clip context->restore(); - if (clippedToBorderRadius) - // Undo the border radius clip + if (clippedToBorderRadius) // Undo the border radius clip context->restore(); if (clippedWithLocalScrolling) // Undo the clip for local background attachments. @@ -1001,170 +1035,560 @@ bool RenderBoxModelObject::paintNinePieceImage(GraphicsContext* graphicsContext, } #if HAVE(PATH_BASED_BORDER_RADIUS_DRAWING) -static bool borderWillArcInnerEdge(const IntSize& firstRadius, const IntSize& secondRadius, int firstBorderWidth, int secondBorderWidth, int middleBorderWidth) +static bool borderWillArcInnerEdge(const IntSize& firstRadius, const IntSize& secondRadius) { - // FIXME: This test is insufficient. We need to take border style into account. - return (!firstRadius.width() || firstRadius.width() >= firstBorderWidth) - && (!firstRadius.height() || firstRadius.height() >= middleBorderWidth) - && (!secondRadius.width() || secondRadius.width() >= secondBorderWidth) - && (!secondRadius.height() || secondRadius.height() >= middleBorderWidth); + return !firstRadius.isZero() || !secondRadius.isZero(); } -void RenderBoxModelObject::paintBorder(GraphicsContext* graphicsContext, int tx, int ty, int w, int h, - const RenderStyle* style, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) +enum BorderEdgeFlag { + TopBorderEdge = 1 << BSTop, + RightBorderEdge = 1 << BSRight, + BottomBorderEdge = 1 << BSBottom, + LeftBorderEdge = 1 << BSLeft, + AllBorderEdges = TopBorderEdge | BottomBorderEdge | LeftBorderEdge | RightBorderEdge +}; + +static inline BorderEdgeFlag edgeFlagForSide(BoxSide side) { - if (paintNinePieceImage(graphicsContext, tx, ty, w, h, style, style->borderImage())) - return; + return static_cast<BorderEdgeFlag>(1 << side); +} - if (graphicsContext->paintingDisabled()) - return; +static inline bool includesEdge(BorderEdgeFlags flags, BoxSide side) +{ + return flags & edgeFlagForSide(side); +} - const Color& topColor = style->visitedDependentColor(CSSPropertyBorderTopColor); - const Color& bottomColor = style->visitedDependentColor(CSSPropertyBorderBottomColor); - const Color& leftColor = style->visitedDependentColor(CSSPropertyBorderLeftColor); - const Color& rightColor = style->visitedDependentColor(CSSPropertyBorderRightColor); +class BorderEdge { +public: + BorderEdge(int edgeWidth, const Color& edgeColor, EBorderStyle edgeStyle, bool edgeIsTransparent, bool edgeIsPresent) + : width(edgeWidth) + , color(edgeColor) + , style(edgeStyle) + , isTransparent(edgeIsTransparent) + , isPresent(edgeIsPresent) + { + if (style == DOUBLE && edgeWidth < 3) + style = SOLID; + } + + bool hasVisibleColorAndStyle() const { return style > BHIDDEN && !isTransparent; } + bool shouldRender() const { return isPresent && hasVisibleColorAndStyle(); } + bool presentButInvisible() const { return usedWidth() && !hasVisibleColorAndStyle(); } - bool topTransparent = style->borderTopIsTransparent(); - bool bottomTransparent = style->borderBottomIsTransparent(); - bool rightTransparent = style->borderRightIsTransparent(); - bool leftTransparent = style->borderLeftIsTransparent(); + int usedWidth() const { return isPresent ? width : 0; } + + void getDoubleBorderStripeWidths(int& outerWidth, int& innerWidth) const + { + int fullWidth = usedWidth(); + outerWidth = fullWidth / 3; + innerWidth = fullWidth * 2 / 3; + + // We need certain integer rounding results + if (fullWidth % 3 == 2) + outerWidth += 1; + + if (fullWidth % 3 == 1) + innerWidth += 1; + } + + int width; + Color color; + EBorderStyle style; + bool isTransparent; + bool isPresent; +}; - EBorderStyle topStyle = style->borderTopStyle(); - EBorderStyle bottomStyle = style->borderBottomStyle(); - EBorderStyle leftStyle = style->borderLeftStyle(); - EBorderStyle rightStyle = style->borderRightStyle(); +inline bool edgesShareColor(const BorderEdge& firstEdge, const BorderEdge& secondEdge) +{ + return firstEdge.color == secondEdge.color; +} - bool horizontal = style->isHorizontalWritingMode(); +inline bool styleRequiresClipPolygon(EBorderStyle style) +{ + return style == DOTTED || style == DASHED; // These are drawn with a stroke, so we have to clip to get corner miters. +} - bool renderTop = topStyle > BHIDDEN && !topTransparent && (horizontal || includeLogicalLeftEdge); - bool renderLeft = leftStyle > BHIDDEN && !leftTransparent && (!horizontal || includeLogicalLeftEdge); - bool renderRight = rightStyle > BHIDDEN && !rightTransparent && (!horizontal || includeLogicalRightEdge); - bool renderBottom = bottomStyle > BHIDDEN && !bottomTransparent && (horizontal || includeLogicalRightEdge); +static bool borderStyleFillsBorderArea(EBorderStyle style) +{ + return !(style == DOTTED || style == DASHED || style == DOUBLE); +} - Path roundedPath; - RoundedIntRect border(tx, ty, w, h); +static bool borderStyleHasInnerDetail(EBorderStyle style) +{ + return style == GROOVE || style == RIDGE || style == DOUBLE; +} - if (style->hasBorderRadius()) { - border.includeLogicalEdges(style->getRoundedBorderFor(border.rect()).radii(), - horizontal, includeLogicalLeftEdge, includeLogicalRightEdge); +static bool borderStyleIsDottedOrDashed(EBorderStyle style) +{ + return style == DOTTED || style == DASHED; +} - int leftWidth = (!horizontal || includeLogicalLeftEdge) ? style->borderLeftWidth() : 0; - int rightWidth = (!horizontal || includeLogicalRightEdge) ? style->borderRightWidth() : 0; - int topWidth = (horizontal || includeLogicalLeftEdge) ? style->borderTopWidth() : 0; - int bottomWidth = (horizontal || includeLogicalRightEdge) ? style->borderBottomWidth() : 0; +// OUTSET darkens the bottom and right (and maybe lightens the top and left) +// INSET darkens the top and left (and maybe lightens the bottom and right) +static inline bool borderStyleHasUnmatchedColorsAtCorner(EBorderStyle style, BoxSide side, BoxSide adjacentSide) +{ + // These styles match at the top/left and bottom/right. + if (style == INSET || style == GROOVE || style == RIDGE || style == OUTSET) { + const BorderEdgeFlags topRightFlags = edgeFlagForSide(BSTop) | edgeFlagForSide(BSRight); + const BorderEdgeFlags bottomLeftFlags = edgeFlagForSide(BSBottom) | edgeFlagForSide(BSLeft); - RoundedIntRect inner(borderInnerRect(border.rect(), topWidth, bottomWidth, leftWidth, rightWidth)); - inner.includeLogicalEdges(style->getRoundedInnerBorderWithBorderWidths(inner.rect(), topWidth, bottomWidth, leftWidth, rightWidth).radii(), - horizontal, includeLogicalLeftEdge, includeLogicalRightEdge); + BorderEdgeFlags flags = edgeFlagForSide(side) | edgeFlagForSide(adjacentSide); + return flags == topRightFlags || flags == bottomLeftFlags; + } + return false; +} - if (border.isRounded()) { - // Clip to the inner and outer radii rects. - graphicsContext->save(); - graphicsContext->addRoundedRectClip(border); - graphicsContext->clipOutRoundedRect(inner); - roundedPath.addRoundedRect(border.rect(), border.radii().topLeft(), border.radii().topRight(), border.radii().bottomLeft(), border.radii().bottomRight()); - } +static inline bool colorsMatchAtCorner(BoxSide side, BoxSide adjacentSide, const BorderEdge edges[]) +{ + if (edges[side].shouldRender() != edges[adjacentSide].shouldRender()) + return false; + + if (!edgesShareColor(edges[side], edges[adjacentSide])) + return false; + + return !borderStyleHasUnmatchedColorsAtCorner(edges[side].style, side, adjacentSide); +} + +// This assumes that we draw in order: top, bottom, left, right. +static inline bool willBeOverdrawn(BoxSide side, BoxSide adjacentSide, const BorderEdge edges[]) +{ + switch (side) { + case BSTop: + case BSBottom: + if (edges[adjacentSide].presentButInvisible()) + return false; + + if (!edgesShareColor(edges[side], edges[adjacentSide]) && edges[adjacentSide].color.hasAlpha()) + return false; + + if (!borderStyleFillsBorderArea(edges[adjacentSide].style)) + return false; + + return true; + + case BSLeft: + case BSRight: + // These draw last, so are never overdrawn. + return false; } + return false; +} - bool renderRadii = border.isRounded(); - bool upperLeftBorderStylesMatch = renderLeft && (topStyle == leftStyle) && (topColor == leftColor); - bool upperRightBorderStylesMatch = renderRight && (topStyle == rightStyle) && (topColor == rightColor) && (topStyle != OUTSET) && (topStyle != RIDGE) && (topStyle != INSET) && (topStyle != GROOVE); - bool lowerLeftBorderStylesMatch = renderLeft && (bottomStyle == leftStyle) && (bottomColor == leftColor) && (bottomStyle != OUTSET) && (bottomStyle != RIDGE) && (bottomStyle != INSET) && (bottomStyle != GROOVE); - bool lowerRightBorderStylesMatch = renderRight && (bottomStyle == rightStyle) && (bottomColor == rightColor); +static inline bool borderStylesRequireMitre(BoxSide side, BoxSide adjacentSide, EBorderStyle style, EBorderStyle adjacentStyle) +{ + if (style == DOUBLE || adjacentStyle == DOUBLE || adjacentStyle == GROOVE || adjacentStyle == RIDGE) + return true; - if (renderTop) { - int x = tx; - int x2 = tx + w; + if (borderStyleIsDottedOrDashed(style) != borderStyleIsDottedOrDashed(adjacentStyle)) + return true; + + if (style != adjacentStyle) + return true; - if (renderRadii && borderWillArcInnerEdge(border.radii().topLeft(), border.radii().topRight(), style->borderLeftWidth(), style->borderRightWidth(), style->borderTopWidth())) { + return borderStyleHasUnmatchedColorsAtCorner(style, side, adjacentSide); +} + +static bool joinRequiresMitre(BoxSide side, BoxSide adjacentSide, const BorderEdge edges[], bool allowOverdraw) +{ + if ((edges[side].isTransparent && edges[adjacentSide].isTransparent) || !edges[adjacentSide].isPresent) + return false; + + if (allowOverdraw && willBeOverdrawn(side, adjacentSide, edges)) + return false; + + if (!edgesShareColor(edges[side], edges[adjacentSide])) + return true; + + if (borderStylesRequireMitre(side, adjacentSide, edges[side].style, edges[adjacentSide].style)) + return true; + + return false; +} + +void RenderBoxModelObject::paintOneBorderSide(GraphicsContext* graphicsContext, const RenderStyle* style, const RoundedIntRect& outerBorder, const RoundedIntRect& innerBorder, + const IntRect& sideRect, BoxSide side, BoxSide adjacentSide1, BoxSide adjacentSide2, const BorderEdge edges[], const Path* path, + bool includeLogicalLeftEdge, bool includeLogicalRightEdge, bool antialias, const Color* overrideColor) +{ + const BorderEdge& edgeToRender = edges[side]; + const BorderEdge& adjacentEdge1 = edges[adjacentSide1]; + const BorderEdge& adjacentEdge2 = edges[adjacentSide2]; + + bool mitreAdjacentSide1 = joinRequiresMitre(side, adjacentSide1, edges, !antialias); + bool mitreAdjacentSide2 = joinRequiresMitre(side, adjacentSide2, edges, !antialias); + + bool adjacentSide1StylesMatch = colorsMatchAtCorner(side, adjacentSide1, edges); + bool adjacentSide2StylesMatch = colorsMatchAtCorner(side, adjacentSide2, edges); + + const Color& colorToPaint = overrideColor ? *overrideColor : edgeToRender.color; + + if (path) { + graphicsContext->save(); + clipBorderSidePolygon(graphicsContext, outerBorder, innerBorder, side, adjacentSide1StylesMatch, adjacentSide2StylesMatch); + float thickness = max(max(edgeToRender.width, adjacentEdge1.width), adjacentEdge2.width); + drawBoxSideFromPath(graphicsContext, outerBorder.rect(), *path, edges, edgeToRender.width, thickness, side, style, colorToPaint, edgeToRender.style, includeLogicalLeftEdge, includeLogicalRightEdge); + graphicsContext->restore(); + } else { + bool didClip = false; + + if (styleRequiresClipPolygon(edgeToRender.style) && (mitreAdjacentSide1 || mitreAdjacentSide2)) { graphicsContext->save(); - clipBorderSidePolygon(graphicsContext, border, BSTop, upperLeftBorderStylesMatch, upperRightBorderStylesMatch, style, includeLogicalLeftEdge, includeLogicalRightEdge); - float thickness = max(max(style->borderTopWidth(), style->borderLeftWidth()), style->borderRightWidth()); - drawBoxSideFromPath(graphicsContext, border.rect(), roundedPath, style->borderTopWidth(), thickness, BSTop, style, topColor, topStyle); + clipBorderSidePolygon(graphicsContext, outerBorder, innerBorder, side, !mitreAdjacentSide1, !mitreAdjacentSide2); + didClip = true; + // Since we clipped, no need to draw with a mitre. + mitreAdjacentSide1 = false; + mitreAdjacentSide2 = false; + } + + drawLineForBoxSide(graphicsContext, sideRect.x(), sideRect.y(), sideRect.maxX(), sideRect.maxY(), side, colorToPaint, edgeToRender.style, + mitreAdjacentSide1 ? adjacentEdge1.width : 0, mitreAdjacentSide2 ? adjacentEdge2.width : 0, antialias); + + if (didClip) graphicsContext->restore(); - } else { - bool ignoreLeft = (topColor == leftColor && topTransparent == leftTransparent && topStyle >= OUTSET - && (leftStyle == DOTTED || leftStyle == DASHED || leftStyle == SOLID || leftStyle == OUTSET)); - bool ignoreRight = (topColor == rightColor && topTransparent == rightTransparent && topStyle >= OUTSET - && (rightStyle == DOTTED || rightStyle == DASHED || rightStyle == SOLID || rightStyle == INSET)); + } +} - drawLineForBoxSide(graphicsContext, x, ty, x2, ty + style->borderTopWidth(), BSTop, topColor, topStyle, - ignoreLeft ? 0 : style->borderLeftWidth(), ignoreRight ? 0 : style->borderRightWidth()); - } +void RenderBoxModelObject::paintBorderSides(GraphicsContext* graphicsContext, const RenderStyle* style, const RoundedIntRect& outerBorder, const RoundedIntRect& innerBorder, + const BorderEdge edges[], BorderEdgeFlags edgeSet, bool includeLogicalLeftEdge, bool includeLogicalRightEdge, bool antialias, const Color* overrideColor) +{ + bool renderRadii = outerBorder.isRounded(); + + Path roundedPath; + if (renderRadii) + roundedPath.addRoundedRect(outerBorder); + + if (edges[BSTop].shouldRender() && includesEdge(edgeSet, BSTop)) { + IntRect sideRect = outerBorder.rect(); + sideRect.setHeight(edges[BSTop].width); + + bool usePath = renderRadii && (borderStyleHasInnerDetail(edges[BSTop].style) || borderWillArcInnerEdge(innerBorder.radii().topLeft(), innerBorder.radii().topRight())); + paintOneBorderSide(graphicsContext, style, outerBorder, innerBorder, sideRect, BSTop, BSLeft, BSRight, edges, usePath ? &roundedPath : 0, includeLogicalLeftEdge, includeLogicalRightEdge, antialias, overrideColor); } - if (renderBottom) { - int x = tx; - int x2 = tx + w; + if (edges[BSBottom].shouldRender() && includesEdge(edgeSet, BSBottom)) { + IntRect sideRect = outerBorder.rect(); + sideRect.shiftYEdgeTo(sideRect.maxY() - edges[BSBottom].width); - if (renderRadii && borderWillArcInnerEdge(border.radii().bottomLeft(), border.radii().bottomRight(), style->borderLeftWidth(), style->borderRightWidth(), style->borderBottomWidth())) { - graphicsContext->save(); - clipBorderSidePolygon(graphicsContext, border, BSBottom, lowerLeftBorderStylesMatch, lowerRightBorderStylesMatch, style, includeLogicalLeftEdge, includeLogicalRightEdge); - float thickness = max(max(style->borderBottomWidth(), style->borderLeftWidth()), style->borderRightWidth()); - drawBoxSideFromPath(graphicsContext, border.rect(), roundedPath, style->borderBottomWidth(), thickness, BSBottom, style, bottomColor, bottomStyle); - graphicsContext->restore(); - } else { - bool ignoreLeft = (bottomColor == leftColor && bottomTransparent == leftTransparent && bottomStyle >= OUTSET - && (leftStyle == DOTTED || leftStyle == DASHED || leftStyle == SOLID || leftStyle == OUTSET)); + bool usePath = renderRadii && (borderStyleHasInnerDetail(edges[BSBottom].style) || borderWillArcInnerEdge(innerBorder.radii().bottomLeft(), innerBorder.radii().bottomRight())); + paintOneBorderSide(graphicsContext, style, outerBorder, innerBorder, sideRect, BSBottom, BSLeft, BSRight, edges, usePath ? &roundedPath : 0, includeLogicalLeftEdge, includeLogicalRightEdge, antialias, overrideColor); + } - bool ignoreRight = (bottomColor == rightColor && bottomTransparent == rightTransparent && bottomStyle >= OUTSET - && (rightStyle == DOTTED || rightStyle == DASHED || rightStyle == SOLID || rightStyle == INSET)); + if (edges[BSLeft].shouldRender() && includesEdge(edgeSet, BSLeft)) { + IntRect sideRect = outerBorder.rect(); + sideRect.setWidth(edges[BSLeft].width); + + bool usePath = renderRadii && (borderStyleHasInnerDetail(edges[BSLeft].style) || borderWillArcInnerEdge(innerBorder.radii().bottomLeft(), innerBorder.radii().topLeft())); + paintOneBorderSide(graphicsContext, style, outerBorder, innerBorder, sideRect, BSLeft, BSTop, BSBottom, edges, usePath ? &roundedPath : 0, includeLogicalLeftEdge, includeLogicalRightEdge, antialias, overrideColor); + } + + if (edges[BSRight].shouldRender() && includesEdge(edgeSet, BSRight)) { + IntRect sideRect = outerBorder.rect(); + sideRect.shiftXEdgeTo(sideRect.maxX() - edges[BSRight].width); + + bool usePath = renderRadii && (borderStyleHasInnerDetail(edges[BSRight].style) || borderWillArcInnerEdge(innerBorder.radii().bottomRight(), innerBorder.radii().topRight())); + paintOneBorderSide(graphicsContext, style, outerBorder, innerBorder, sideRect, BSRight, BSTop, BSBottom, edges, usePath ? &roundedPath : 0, includeLogicalLeftEdge, includeLogicalRightEdge, antialias, overrideColor); + } +} - drawLineForBoxSide(graphicsContext, x, ty + h - style->borderBottomWidth(), x2, ty + h, BSBottom, bottomColor, - bottomStyle, ignoreLeft ? 0 : style->borderLeftWidth(), - ignoreRight ? 0 : style->borderRightWidth()); +void RenderBoxModelObject::paintTranslucentBorderSides(GraphicsContext* graphicsContext, const RenderStyle* style, const RoundedIntRect& outerBorder, const RoundedIntRect& innerBorder, + const BorderEdge edges[], bool includeLogicalLeftEdge, bool includeLogicalRightEdge, bool antialias) +{ + BorderEdgeFlags edgesToDraw = AllBorderEdges; + while (edgesToDraw) { + // Find undrawn edges sharing a color. + Color commonColor; + + BorderEdgeFlags commonColorEdgeSet = 0; + for (int i = BSTop; i <= BSLeft; ++i) { + BoxSide currSide = static_cast<BoxSide>(i); + if (!includesEdge(edgesToDraw, currSide)) + continue; + + bool includeEdge; + if (!commonColorEdgeSet) { + commonColor = edges[currSide].color; + includeEdge = true; + } else + includeEdge = edges[currSide].color == commonColor; + + if (includeEdge) + commonColorEdgeSet |= edgeFlagForSide(currSide); } + + bool useTransparencyLayer = commonColor.hasAlpha(); + if (useTransparencyLayer) { + graphicsContext->beginTransparencyLayer(static_cast<float>(commonColor.alpha()) / 255); + commonColor = Color(commonColor.red(), commonColor.green(), commonColor.blue()); + } + + paintBorderSides(graphicsContext, style, outerBorder, innerBorder, edges, commonColorEdgeSet, includeLogicalLeftEdge, includeLogicalRightEdge, antialias, &commonColor); + + if (useTransparencyLayer) + graphicsContext->endTransparencyLayer(); + + edgesToDraw &= ~commonColorEdgeSet; } +} - if (renderLeft) { - int y = ty; - int y2 = ty + h; +void RenderBoxModelObject::paintBorder(GraphicsContext* graphicsContext, int tx, int ty, int w, int h, + const RenderStyle* style, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) +{ + if (paintNinePieceImage(graphicsContext, tx, ty, w, h, style, style->borderImage())) + return; - if (renderRadii && borderWillArcInnerEdge(border.radii().bottomLeft(), border.radii().topLeft(), style->borderBottomWidth(), style->borderTopWidth(), style->borderLeftWidth())) { - graphicsContext->save(); - clipBorderSidePolygon(graphicsContext, border, BSLeft, upperLeftBorderStylesMatch, lowerLeftBorderStylesMatch, style, includeLogicalLeftEdge, includeLogicalRightEdge); - float thickness = max(max(style->borderLeftWidth(), style->borderTopWidth()), style->borderBottomWidth()); - drawBoxSideFromPath(graphicsContext, border.rect(), roundedPath, style->borderLeftWidth(), thickness, BSLeft, style, leftColor, leftStyle); - graphicsContext->restore(); - } else { - bool ignoreTop = (topColor == leftColor && topTransparent == leftTransparent && leftStyle >= OUTSET - && (topStyle == DOTTED || topStyle == DASHED || topStyle == SOLID || topStyle == OUTSET)); + if (graphicsContext->paintingDisabled()) + return; - bool ignoreBottom = (bottomColor == leftColor && bottomTransparent == leftTransparent && leftStyle >= OUTSET - && (bottomStyle == DOTTED || bottomStyle == DASHED || bottomStyle == SOLID || bottomStyle == INSET)); + bool horizontal = style->isHorizontalWritingMode(); - drawLineForBoxSide(graphicsContext, tx, y, tx + style->borderLeftWidth(), y2, BSLeft, leftColor, - leftStyle, ignoreTop ? 0 : style->borderTopWidth(), ignoreBottom ? 0 : style->borderBottomWidth()); + BorderEdge edges[4] = { + // BSTop + BorderEdge(style->borderTopWidth(), + style->visitedDependentColor(CSSPropertyBorderTopColor), + style->borderTopStyle(), + style->borderTopIsTransparent(), + horizontal || includeLogicalLeftEdge), + // BSRight + BorderEdge(style->borderRightWidth(), + style->visitedDependentColor(CSSPropertyBorderRightColor), + style->borderRightStyle(), + style->borderRightIsTransparent(), + !horizontal || includeLogicalRightEdge), + // BSBottom + BorderEdge(style->borderBottomWidth(), + style->visitedDependentColor(CSSPropertyBorderBottomColor), + style->borderBottomStyle(), + style->borderBottomIsTransparent(), + horizontal || includeLogicalRightEdge), + // BSLeft + BorderEdge(style->borderLeftWidth(), + style->visitedDependentColor(CSSPropertyBorderLeftColor), + style->borderLeftStyle(), + style->borderLeftIsTransparent(), + !horizontal || includeLogicalLeftEdge) + }; + + IntRect borderRect(tx, ty, w, h); + RoundedIntRect outerBorder = style->getRoundedBorderFor(borderRect, includeLogicalLeftEdge, includeLogicalRightEdge); + RoundedIntRect innerBorder = style->getRoundedInnerBorderFor(borderRect, includeLogicalLeftEdge, includeLogicalRightEdge); + + const AffineTransform& currentCTM = graphicsContext->getCTM(); + // FIXME: this isn't quite correct. We may want to antialias when scaled by a non-integral value, or when the translation is non-integral. + bool antialias = !currentCTM.isIdentityOrTranslationOrFlipped(); + + bool haveAlphaColor = false; + bool haveAllSolidEdges = true; + bool allEdgesVisible = true; + bool allEdgesShareColor = true; + int firstVisibleEdge = -1; + + for (int i = BSTop; i <= BSLeft; ++i) { + const BorderEdge& currEdge = edges[i]; + if (currEdge.presentButInvisible()) { + allEdgesVisible = false; + continue; } + + if (!currEdge.width) + continue; + + if (firstVisibleEdge == -1) + firstVisibleEdge = i; + else if (currEdge.color != edges[firstVisibleEdge].color) + allEdgesShareColor = false; + + if (currEdge.color.hasAlpha()) + haveAlphaColor = true; + + if (currEdge.style != SOLID) + haveAllSolidEdges = false; } + + // isRenderable() check avoids issue described in https://bugs.webkit.org/show_bug.cgi?id=38787 + if (haveAllSolidEdges && allEdgesVisible && allEdgesShareColor && innerBorder.isRenderable()) { + // Fast path for drawing all solid edges. + if (outerBorder.isRounded() || haveAlphaColor) { + Path path; + + // FIXME: Path should take a RoundedIntRect directly. + if (outerBorder.isRounded()) + path.addRoundedRect(outerBorder); + else + path.addRect(outerBorder.rect()); - if (renderRight) { - if (renderRadii && borderWillArcInnerEdge(border.radii().bottomRight(), border.radii().topRight(), style->borderBottomWidth(), style->borderTopWidth(), style->borderRightWidth())) { - graphicsContext->save(); - clipBorderSidePolygon(graphicsContext, border, BSRight, upperRightBorderStylesMatch, lowerRightBorderStylesMatch, style, includeLogicalLeftEdge, includeLogicalRightEdge); - float thickness = max(max(style->borderRightWidth(), style->borderTopWidth()), style->borderBottomWidth()); - drawBoxSideFromPath(graphicsContext, border.rect(), roundedPath, style->borderRightWidth(), thickness, BSRight, style, rightColor, rightStyle); - graphicsContext->restore(); - } else { - bool ignoreTop = ((topColor == rightColor) && (topTransparent == rightTransparent) - && (rightStyle >= DOTTED || rightStyle == INSET) - && (topStyle == DOTTED || topStyle == DASHED || topStyle == SOLID || topStyle == OUTSET)); + if (innerBorder.isRounded()) + path.addRoundedRect(innerBorder); + else + path.addRect(innerBorder.rect()); + + graphicsContext->setFillRule(RULE_EVENODD); + graphicsContext->setFillColor(edges[firstVisibleEdge].color, style->colorSpace()); + graphicsContext->fillPath(path); + } else + paintBorderSides(graphicsContext, style, outerBorder, innerBorder, edges, AllBorderEdges, includeLogicalLeftEdge, includeLogicalRightEdge, antialias); + + return; + } - bool ignoreBottom = ((bottomColor == rightColor) && (bottomTransparent == rightTransparent) - && (rightStyle >= DOTTED || rightStyle == INSET) - && (bottomStyle == DOTTED || bottomStyle == DASHED || bottomStyle == SOLID || bottomStyle == INSET)); + if (outerBorder.isRounded()) { + // Clip to the inner and outer radii rects. + graphicsContext->save(); + graphicsContext->addRoundedRectClip(outerBorder); + graphicsContext->clipOutRoundedRect(innerBorder); + } + + if (haveAlphaColor) + paintTranslucentBorderSides(graphicsContext, style, outerBorder, innerBorder, edges, includeLogicalLeftEdge, includeLogicalRightEdge, antialias); + else + paintBorderSides(graphicsContext, style, outerBorder, innerBorder, edges, AllBorderEdges, includeLogicalLeftEdge, includeLogicalRightEdge, antialias); + + if (outerBorder.isRounded()) + graphicsContext->restore(); +} + +void RenderBoxModelObject::drawBoxSideFromPath(GraphicsContext* graphicsContext, const IntRect& borderRect, const Path& borderPath, const BorderEdge edges[], + float thickness, float drawThickness, BoxSide side, const RenderStyle* style, + Color color, EBorderStyle borderStyle, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) +{ + if (thickness <= 0) + return; - int y = ty; - int y2 = ty + h; + if (borderStyle == DOUBLE && thickness < 3) + borderStyle = SOLID; - drawLineForBoxSide(graphicsContext, tx + w - style->borderRightWidth(), y, tx + w, y2, BSRight, rightColor, - rightStyle, ignoreTop ? 0 : style->borderTopWidth(), - ignoreBottom ? 0 : style->borderBottomWidth()); + switch (borderStyle) { + case BNONE: + case BHIDDEN: + return; + case DOTTED: + case DASHED: { + graphicsContext->setStrokeColor(color, style->colorSpace()); + + // The stroke is doubled here because the provided path is the + // outside edge of the border so half the stroke is clipped off. + // The extra multiplier is so that the clipping mask can antialias + // the edges to prevent jaggies. + graphicsContext->setStrokeThickness(drawThickness * 2 * 1.1f); + graphicsContext->setStrokeStyle(borderStyle == DASHED ? DashedStroke : DottedStroke); + + // If the number of dashes that fit in the path is odd and non-integral then we + // will have an awkwardly-sized dash at the end of the path. To try to avoid that + // here, we simply make the whitespace dashes ever so slightly bigger. + // FIXME: This could be even better if we tried to manipulate the dash offset + // and possibly the gapLength to get the corners dash-symmetrical. + float dashLength = thickness * ((borderStyle == DASHED) ? 3.0f : 1.0f); + float gapLength = dashLength; + float numberOfDashes = borderPath.length() / dashLength; + // Don't try to show dashes if we have less than 2 dashes + 2 gaps. + // FIXME: should do this test per side. + if (numberOfDashes >= 4) { + bool evenNumberOfFullDashes = !((int)numberOfDashes % 2); + bool integralNumberOfDashes = !(numberOfDashes - (int)numberOfDashes); + if (!evenNumberOfFullDashes && !integralNumberOfDashes) { + float numberOfGaps = numberOfDashes / 2; + gapLength += (dashLength / numberOfGaps); + } + + DashArray lineDash; + lineDash.append(dashLength); + lineDash.append(gapLength); + graphicsContext->setLineDash(lineDash, dashLength); } + + // FIXME: stroking the border path causes issues with tight corners: + // https://bugs.webkit.org/show_bug.cgi?id=58711 + // Also, to get the best appearance we should stroke a path between the two borders. + graphicsContext->strokePath(borderPath); + return; } + case DOUBLE: { + // Get the inner border rects for both the outer border line and the inner border line + int outerBorderTopWidth; + int innerBorderTopWidth; + edges[BSTop].getDoubleBorderStripeWidths(outerBorderTopWidth, innerBorderTopWidth); + + int outerBorderRightWidth; + int innerBorderRightWidth; + edges[BSRight].getDoubleBorderStripeWidths(outerBorderRightWidth, innerBorderRightWidth); + + int outerBorderBottomWidth; + int innerBorderBottomWidth; + edges[BSBottom].getDoubleBorderStripeWidths(outerBorderBottomWidth, innerBorderBottomWidth); + + int outerBorderLeftWidth; + int innerBorderLeftWidth; + edges[BSLeft].getDoubleBorderStripeWidths(outerBorderLeftWidth, innerBorderLeftWidth); + + // Draw inner border line + graphicsContext->save(); + + RoundedIntRect innerClip = style->getRoundedInnerBorderFor(borderRect, + innerBorderTopWidth, innerBorderBottomWidth, innerBorderLeftWidth, innerBorderRightWidth, + includeLogicalLeftEdge, includeLogicalRightEdge); + + graphicsContext->addRoundedRectClip(innerClip); + drawBoxSideFromPath(graphicsContext, borderRect, borderPath, edges, thickness, drawThickness, side, style, color, SOLID, includeLogicalLeftEdge, includeLogicalRightEdge); + graphicsContext->restore(); - if (renderRadii) + // Draw outer border line + graphicsContext->save(); + + RoundedIntRect outerClip = style->getRoundedInnerBorderFor(borderRect, + outerBorderTopWidth, outerBorderBottomWidth, outerBorderLeftWidth, outerBorderRightWidth, + includeLogicalLeftEdge, includeLogicalRightEdge); + + graphicsContext->clipOutRoundedRect(outerClip); + drawBoxSideFromPath(graphicsContext, borderRect, borderPath, edges, thickness, drawThickness, side, style, color, SOLID, includeLogicalLeftEdge, includeLogicalRightEdge); + graphicsContext->restore(); + return; + } + case RIDGE: + case GROOVE: + { + EBorderStyle s1; + EBorderStyle s2; + if (borderStyle == GROOVE) { + s1 = INSET; + s2 = OUTSET; + } else { + s1 = OUTSET; + s2 = INSET; + } + + // Paint full border + drawBoxSideFromPath(graphicsContext, borderRect, borderPath, edges, thickness, drawThickness, side, style, color, s1, includeLogicalLeftEdge, includeLogicalRightEdge); + + // Paint inner only + graphicsContext->save(); + + int topWidth = edges[BSTop].usedWidth() / 2; + int bottomWidth = edges[BSBottom].usedWidth() / 2; + int leftWidth = edges[BSLeft].usedWidth() / 2; + int rightWidth = edges[BSRight].usedWidth() / 2; + + RoundedIntRect clipRect = style->getRoundedInnerBorderFor(borderRect, + topWidth, bottomWidth, leftWidth, rightWidth, + includeLogicalLeftEdge, includeLogicalRightEdge); + + graphicsContext->addRoundedRectClip(clipRect); + drawBoxSideFromPath(graphicsContext, borderRect, borderPath, edges, thickness, drawThickness, side, style, color, s2, includeLogicalLeftEdge, includeLogicalRightEdge); graphicsContext->restore(); + return; + } + case INSET: + if (side == BSTop || side == BSLeft) + color = color.dark(); + break; + case OUTSET: + if (side == BSBottom || side == BSRight) + color = color.dark(); + break; + default: + break; + } + + graphicsContext->setStrokeStyle(NoStroke); + graphicsContext->setFillColor(color, style->colorSpace()); + graphicsContext->drawRect(borderRect); } #else void RenderBoxModelObject::paintBorder(GraphicsContext* graphicsContext, int tx, int ty, int w, int h, @@ -1507,50 +1931,92 @@ void RenderBoxModelObject::paintBorder(GraphicsContext* graphicsContext, int tx, } #endif -void RenderBoxModelObject::clipBorderSidePolygon(GraphicsContext* graphicsContext, const RoundedIntRect& border, - const BoxSide side, bool firstEdgeMatches, bool secondEdgeMatches, const RenderStyle* style, - bool includeLogicalLeftEdge, bool includeLogicalRightEdge) +static void findInnerVertex(const FloatPoint& outerCorner, const FloatPoint& innerCorner, const FloatPoint& centerPoint, FloatPoint& result) { - FloatPoint quad[4]; - int tx = border.rect().x(); - int ty = border.rect().y(); - int w = border.rect().width(); - int h = border.rect().height(); + // If the line between outer and inner corner is towards the horizontal, intersect with a vertical line through the center, + // otherwise with a horizontal line through the center. The points that form this line are arbitrary (we use 0, 100). + // Note that if findIntersection fails, it will leave result untouched. + if (fabs(outerCorner.x() - innerCorner.x()) > fabs(outerCorner.y() - innerCorner.y())) + findIntersection(outerCorner, innerCorner, FloatPoint(centerPoint.x(), 0), FloatPoint(centerPoint.x(), 100), result); + else + findIntersection(outerCorner, innerCorner, FloatPoint(0, centerPoint.y()), FloatPoint(100, centerPoint.y()), result); +} - bool horizontal = style->isHorizontalWritingMode(); - int leftWidth = (!horizontal || includeLogicalLeftEdge) ? style->borderLeftWidth() : 0; - int rightWidth = (!horizontal || includeLogicalRightEdge) ? style->borderRightWidth() : 0; - int topWidth = (horizontal || includeLogicalLeftEdge) ? style->borderTopWidth() : 0; - int bottomWidth = (horizontal || includeLogicalRightEdge) ? style->borderBottomWidth() : 0; +void RenderBoxModelObject::clipBorderSidePolygon(GraphicsContext* graphicsContext, const RoundedIntRect& outerBorder, const RoundedIntRect& innerBorder, + BoxSide side, bool firstEdgeMatches, bool secondEdgeMatches) +{ + FloatPoint quad[4]; - // For each side, create an array of FloatPoints where each point is based on whichever value in each corner - // is larger -- the radius width/height or the border width/height -- as appropriate. + const IntRect& outerRect = outerBorder.rect(); + const IntRect& innerRect = innerBorder.rect(); + + FloatPoint centerPoint(innerRect.location().x() + static_cast<float>(innerRect.width()) / 2, innerRect.location().y() + static_cast<float>(innerRect.height()) / 2); + + // For each side, create a quad that encompasses all parts of that side that may draw, + // including areas inside the innerBorder. + // + // 0----------------3 + // 0 \ / 0 + // |\ 1----------- 2 /| + // | 1 1 | + // | | | | + // | | | | + // | 2 2 | + // |/ 1------------2 \| + // 3 / \ 3 + // 0----------------3 + // switch (side) { case BSTop: - quad[0] = FloatPoint(tx, ty); - quad[1] = FloatPoint(tx + max(border.radii().topLeft().width(), leftWidth), ty + max(border.radii().topLeft().height(), topWidth)); - quad[2] = FloatPoint(tx + w - max(border.radii().topRight().width(), rightWidth), ty + max(border.radii().topRight().height(), topWidth)); - quad[3] = FloatPoint(tx + w, ty); + quad[0] = outerRect.minXMinYCorner(); + quad[1] = innerRect.minXMinYCorner(); + quad[2] = innerRect.maxXMinYCorner(); + quad[3] = outerRect.maxXMinYCorner(); + + if (!innerBorder.radii().topLeft().isZero()) + findInnerVertex(outerRect.minXMinYCorner(), innerRect.minXMinYCorner(), centerPoint, quad[1]); + + if (!innerBorder.radii().topRight().isZero()) + findInnerVertex(outerRect.maxXMinYCorner(), innerRect.maxXMinYCorner(), centerPoint, quad[2]); break; + case BSLeft: - quad[0] = FloatPoint(tx, ty); - quad[1] = FloatPoint(tx + max(border.radii().topLeft().width(), leftWidth), ty + max(border.radii().topLeft().height(), topWidth)); - quad[2] = FloatPoint(tx + max(border.radii().bottomLeft().width(), leftWidth), ty + h - max(border.radii().bottomLeft().height(), bottomWidth)); - quad[3] = FloatPoint(tx, ty + h); + quad[0] = outerRect.minXMinYCorner(); + quad[1] = innerRect.minXMinYCorner(); + quad[2] = innerRect.minXMaxYCorner(); + quad[3] = outerRect.minXMaxYCorner(); + + if (!innerBorder.radii().topLeft().isZero()) + findInnerVertex(outerRect.minXMinYCorner(), innerRect.minXMinYCorner(), centerPoint, quad[1]); + + if (!innerBorder.radii().bottomLeft().isZero()) + findInnerVertex(outerRect.minXMaxYCorner(), innerRect.minXMaxYCorner(), centerPoint, quad[2]); break; + case BSBottom: - quad[0] = FloatPoint(tx, ty + h); - quad[1] = FloatPoint(tx + max(border.radii().bottomLeft().width(), leftWidth), ty + h - max(border.radii().bottomLeft().height(), bottomWidth)); - quad[2] = FloatPoint(tx + w - max(border.radii().bottomRight().width(), rightWidth), ty + h - max(border.radii().bottomRight().height(), bottomWidth)); - quad[3] = FloatPoint(tx + w, ty + h); + quad[0] = outerRect.minXMaxYCorner(); + quad[1] = innerRect.minXMaxYCorner(); + quad[2] = innerRect.maxXMaxYCorner(); + quad[3] = outerRect.maxXMaxYCorner(); + + if (!innerBorder.radii().bottomLeft().isZero()) + findInnerVertex(outerRect.minXMaxYCorner(), innerRect.minXMaxYCorner(), centerPoint, quad[1]); + + if (!innerBorder.radii().bottomRight().isZero()) + findInnerVertex(outerRect.maxXMaxYCorner(), innerRect.maxXMaxYCorner(), centerPoint, quad[2]); break; + case BSRight: - quad[0] = FloatPoint(tx + w, ty); - quad[1] = FloatPoint(tx + w - max(border.radii().topRight().width(), rightWidth), ty + max(border.radii().topRight().height(), topWidth)); - quad[2] = FloatPoint(tx + w - max(border.radii().bottomRight().width(), rightWidth), ty + h - max(border.radii().bottomRight().height(), bottomWidth)); - quad[3] = FloatPoint(tx + w, ty + h); - break; - default: + quad[0] = outerRect.maxXMinYCorner(); + quad[1] = innerRect.maxXMinYCorner(); + quad[2] = innerRect.maxXMaxYCorner(); + quad[3] = outerRect.maxXMaxYCorner(); + + if (!innerBorder.radii().topRight().isZero()) + findInnerVertex(outerRect.maxXMinYCorner(), innerRect.maxXMinYCorner(), centerPoint, quad[1]); + + if (!innerBorder.radii().bottomRight().isZero()) + findInnerVertex(outerRect.maxXMaxYCorner(), innerRect.maxXMaxYCorner(), centerPoint, quad[2]); break; } @@ -1561,6 +2027,7 @@ void RenderBoxModelObject::clipBorderSidePolygon(GraphicsContext* graphicsContex return; } + // Square off the end which shouldn't be affected by antialiasing, and clip. FloatPoint firstQuad[4]; firstQuad[0] = quad[0]; firstQuad[1] = quad[1]; @@ -1575,6 +2042,7 @@ void RenderBoxModelObject::clipBorderSidePolygon(GraphicsContext* graphicsContex : FloatPoint(quad[1].x(), quad[0].y()); secondQuad[2] = quad[2]; secondQuad[3] = quad[3]; + // Antialiasing affects the second side. graphicsContext->clipConvexPolygon(4, secondQuad, !secondEdgeMatches); } @@ -1599,21 +2067,13 @@ void RenderBoxModelObject::paintBoxShadow(GraphicsContext* context, int tx, int if (context->paintingDisabled() || !s->boxShadow()) return; - RoundedIntRect border(tx, ty, w, h); + IntRect borderRect(tx, ty, w, h); + RoundedIntRect border = (shadowStyle == Inset) ? s->getRoundedInnerBorderFor(borderRect, includeLogicalLeftEdge, includeLogicalRightEdge) + : s->getRoundedBorderFor(borderRect, includeLogicalLeftEdge, includeLogicalRightEdge); + bool hasBorderRadius = s->hasBorderRadius(); bool isHorizontal = s->isHorizontalWritingMode(); - - 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) @@ -1661,9 +2121,7 @@ void RenderBoxModelObject::paintBoxShadow(GraphicsContext* context, int tx, int if (!rectToClipOut.isEmpty()) context->clipOutRoundedRect(rectToClipOut); - if (shadowSpread < 0) - fillRect.expandRadii(shadowSpread); - + fillRect.expandRadii(shadowSpread); context->fillRoundedRect(fillRect, Color::black, s->colorSpace()); } else { IntRect rectToClipOut = border.rect(); @@ -1717,13 +2175,15 @@ void RenderBoxModelObject::paintBoxShadow(GraphicsContext* context, int tx, int Color fillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), 255); IntRect outerRect = areaCastingShadowInHole(border.rect(), shadowBlur, shadowSpread, shadowOffset); + RoundedIntRect roundedHole(holeRect, border.radii()); + context->save(); - Path path; if (hasBorderRadius) { Path path; - path.addRoundedRect(border.rect(), border.radii().topLeft(), border.radii().topRight(), border.radii().bottomLeft(), border.radii().bottomRight()); + path.addRoundedRect(border); context->clip(path); + roundedHole.shrinkRadii(shadowSpread); } else context->clip(border.rect()); @@ -1731,15 +2191,11 @@ void RenderBoxModelObject::paintBoxShadow(GraphicsContext* context, int tx, int context->translate(extraOffset.width(), extraOffset.height()); shadowOffset -= extraOffset; - 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()); - RoundedIntRect roundedHole(holeRect, border.radii()); context->fillRectWithRoundedHole(outerRect, roundedHole, fillColor, s->colorSpace()); context->restore(); diff --git a/Source/WebCore/rendering/RenderBoxModelObject.h b/Source/WebCore/rendering/RenderBoxModelObject.h index 2e0bdda..d2f5972 100644 --- a/Source/WebCore/rendering/RenderBoxModelObject.h +++ b/Source/WebCore/rendering/RenderBoxModelObject.h @@ -32,6 +32,7 @@ namespace WebCore { // Modes for some of the line-related functions. enum LinePositionMode { PositionOnContainingLine, PositionOfInteriorLineBoxes }; enum LineDirectionMode { HorizontalLine, VerticalLine }; +typedef unsigned BorderEdgeFlags; // This class is the base for all objects that adhere to the CSS box model as described // at http://www.w3.org/TR/CSS21/box.html @@ -114,7 +115,7 @@ public: void paintBorder(GraphicsContext*, int tx, int ty, int w, int h, const RenderStyle*, bool includeLogicalLeftEdge = true, bool includeLogicalRightEdge = true); bool paintNinePieceImage(GraphicsContext*, int tx, int ty, int w, int h, const RenderStyle*, const NinePieceImage&, CompositeOperator = CompositeSourceOver); void paintBoxShadow(GraphicsContext*, int tx, int ty, int w, int h, const RenderStyle*, ShadowStyle, bool includeLogicalLeftEdge = true, bool includeLogicalRightEdge = true); - void paintFillLayerExtended(const PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int width, int height, InlineFlowBox* = 0, CompositeOperator = CompositeSourceOver, RenderObject* backgroundObject = 0); + void paintFillLayerExtended(const PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int width, int height, InlineFlowBox* = 0, int inlineBoxWidth = 0, int inlineBoxHeight = 0, CompositeOperator = CompositeSourceOver, RenderObject* backgroundObject = 0); // Overridden by subclasses to determine line height and baseline position. virtual int lineHeight(bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const = 0; @@ -133,15 +134,27 @@ protected: RenderBoxModelObject* continuation() const; void setContinuation(RenderBoxModelObject*); - + private: virtual bool isBoxModelObject() const { return true; } IntSize calculateFillTileSize(const FillLayer*, IntSize scaledSize) const; - void clipBorderSidePolygon(GraphicsContext*, const RoundedIntRect& border, - const BoxSide, bool firstEdgeMatches, bool secondEdgeMatches, const RenderStyle*, - bool includeLogicalLeftEdge, bool includeLogicalRightEdge); + RoundedIntRect getBackgroundRoundedRect(const IntRect&, InlineFlowBox*, int inlineBoxWidth, int inlineBoxHeight, + bool includeLogicalLeftEdge, bool includeLogicalRightEdge); + + void clipBorderSidePolygon(GraphicsContext*, const RoundedIntRect& outerBorder, const RoundedIntRect& innerBorder, + BoxSide, bool firstEdgeMatches, bool secondEdgeMatches); + void paintOneBorderSide(GraphicsContext*, const RenderStyle*, const RoundedIntRect& outerBorder, const RoundedIntRect& innerBorder, + const IntRect& sideRect, BoxSide, BoxSide adjacentSide1, BoxSide adjacentSide2, const class BorderEdge[], + const Path*, bool includeLogicalLeftEdge, bool includeLogicalRightEdge, bool antialias, const Color* overrideColor = 0); + void paintTranslucentBorderSides(GraphicsContext*, const RenderStyle*, const RoundedIntRect& outerBorder, const RoundedIntRect& innerBorder, + const class BorderEdge[], bool includeLogicalLeftEdge, bool includeLogicalRightEdge, bool antialias = false); + void paintBorderSides(GraphicsContext*, const RenderStyle*, const RoundedIntRect& outerBorder, const RoundedIntRect& innerBorder, + const class BorderEdge[], BorderEdgeFlags, bool includeLogicalLeftEdge, bool includeLogicalRightEdge, bool antialias = false, const Color* overrideColor = 0); + void drawBoxSideFromPath(GraphicsContext*, const IntRect&, const Path&, const class BorderEdge[], + float thickness, float drawThickness, BoxSide, const RenderStyle*, + Color, EBorderStyle, bool includeLogicalLeftEdge, bool includeLogicalRightEdge); friend class RenderView; diff --git a/Source/WebCore/rendering/RenderDetails.cpp b/Source/WebCore/rendering/RenderDetails.cpp index be2b435..6b5a1b2 100644 --- a/Source/WebCore/rendering/RenderDetails.cpp +++ b/Source/WebCore/rendering/RenderDetails.cpp @@ -24,10 +24,6 @@ #include "CSSStyleSelector.h" #include "HTMLDetailsElement.h" #include "HTMLNames.h" -#include "LocalizedStrings.h" -#include "RenderDetailsMarker.h" -#include "RenderTextFragment.h" -#include "RenderView.h" namespace WebCore { @@ -37,23 +33,10 @@ RenderDetails::RenderDetails(Node* node) : RenderBlock(node) , m_summaryBlock(0) , m_contentBlock(0) - , m_defaultSummaryBlock(0) - , m_defaultSummaryText(0) - , m_marker(0) , m_mainSummary(0) { } -void RenderDetails::destroy() -{ - if (m_marker) { - m_marker->destroy(); - m_marker = 0; - } - - RenderBlock::destroy(); -} - RenderBlock* RenderDetails::summaryBlock() { if (!m_summaryBlock) { @@ -106,26 +89,9 @@ void RenderDetails::removeChild(RenderObject* oldChild) ASSERT_NOT_REACHED(); } -void RenderDetails::setMarkerStyle() -{ - if (m_marker) { - RefPtr<RenderStyle> markerStyle = RenderStyle::create(); - markerStyle->inheritFrom(style()); - m_marker->setStyle(markerStyle.release()); - } -} - void RenderDetails::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { RenderBlock::styleDidChange(diff, oldStyle); - - if (m_defaultSummaryBlock) { - m_defaultSummaryBlock->setStyle(createSummaryStyle()); - m_defaultSummaryText->setStyle(m_defaultSummaryBlock->style()); - } - - setMarkerStyle(); - // Ensure that if we ended up being inline that we set our replaced flag // so that we're treated like an inline-block. setReplaced(isInline()); @@ -144,11 +110,6 @@ RenderObject* RenderDetails::getRenderPosition(RenderObject* object) return element ? element->renderer() : 0; } -void RenderDetails::markerDestroyed() -{ - m_marker = 0; -} - void RenderDetails::summaryDestroyed(RenderObject* summary) { if (summary == m_mainSummary) @@ -157,14 +118,6 @@ void RenderDetails::summaryDestroyed(RenderObject* summary) void RenderDetails::moveSummaryToContents() { - if (m_defaultSummaryBlock) { - ASSERT(!m_mainSummary); - m_defaultSummaryBlock->destroy(); - m_defaultSummaryBlock = 0; - m_defaultSummaryText = 0; - return; - } - if (!m_mainSummary) return; @@ -173,12 +126,6 @@ void RenderDetails::moveSummaryToContents() m_mainSummary = 0; } -PassRefPtr<RenderStyle> RenderDetails::createSummaryStyle() -{ - RefPtr<HTMLElement> summary(HTMLElement::create(summaryTag, document())); - return document()->styleSelector()->styleForElement(summary.get(), style(), true); -} - void RenderDetails::replaceMainSummary(RenderObject* newSummary) { ASSERT(newSummary); @@ -191,68 +138,20 @@ void RenderDetails::replaceMainSummary(RenderObject* newSummary) m_mainSummary = newSummary; } -void RenderDetails::createDefaultSummary() -{ - if (m_defaultSummaryBlock) - return; - - moveSummaryToContents(); - - m_defaultSummaryBlock = summaryBlock()->createAnonymousBlock(); - m_defaultSummaryBlock->setStyle(createSummaryStyle()); - - m_defaultSummaryText = new (renderArena()) RenderTextFragment(document(), defaultDetailsSummaryText().impl()); - m_defaultSummaryText->setStyle(m_defaultSummaryBlock->style()); - m_defaultSummaryBlock->addChild(m_defaultSummaryText); - - summaryBlock()->addChild(m_defaultSummaryBlock); -} - void RenderDetails::checkMainSummary() { if (!node() || !node()->hasTagName(detailsTag)) return; Node* mainSummaryNode = static_cast<HTMLDetailsElement*>(node())->mainSummary(); - - if (!mainSummaryNode || !mainSummaryNode->renderer() || mainSummaryNode->renderer()->isFloatingOrPositioned()) - createDefaultSummary(); - else + if (mainSummaryNode && mainSummaryNode->renderer()) replaceMainSummary(mainSummaryNode->renderer()); - } void RenderDetails::layout() { - ASSERT(needsLayout()); - checkMainSummary(); - ASSERT(m_summaryBlock); - - if (!m_marker) { - m_marker = new (renderArena()) RenderDetailsMarker(this); - setMarkerStyle(); - } - updateMarkerLocation(); - RenderBlock::layout(); - - m_interactiveArea = m_summaryBlock->frameRect(); - - // FIXME: the following code will not be needed once absoluteToLocal get patched to handle flipped blocks writing modes. - switch (style()->writingMode()) { - case TopToBottomWritingMode: - case LeftToRightWritingMode: - break; - case RightToLeftWritingMode: { - m_interactiveArea.setX(width() - m_interactiveArea.x() - m_interactiveArea.width()); - break; - } - case BottomToTopWritingMode: { - m_interactiveArea.setY(height() - m_interactiveArea.y() - m_interactiveArea.height()); - break; - } - } } bool RenderDetails::isOpen() const @@ -260,77 +159,4 @@ bool RenderDetails::isOpen() const return node() && node()->isElementNode() ? !static_cast<Element*>(node())->getAttribute(openAttr).isNull() : false; } -RenderObject* RenderDetails::getParentOfFirstLineBox(RenderBlock* curr) -{ - RenderObject* firstChild = curr->firstChild(); - if (!firstChild) - return 0; - - for (RenderObject* currChild = firstChild; currChild; currChild = currChild->nextSibling()) { - if (currChild == m_marker) - continue; - - if (currChild->isInline() && (!currChild->isRenderInline() || curr->generatesLineBoxesForInlineChild(currChild))) - return curr; - - if (currChild->isFloating() || currChild->isPositioned()) - continue; - - if (currChild->isTable() || !currChild->isRenderBlock() || (currChild->isBox() && toRenderBox(currChild)->isWritingModeRoot())) - break; - - if (currChild->isDetails()) - break; - - RenderObject* lineBox = getParentOfFirstLineBox(toRenderBlock(currChild)); - if (lineBox) - return lineBox; - } - - return 0; -} - -RenderObject* RenderDetails::firstNonMarkerChild(RenderObject* parent) -{ - RenderObject* result = parent->firstChild(); - while (result && result->isDetailsMarker()) - result = result->nextSibling(); - return result; -} - -void RenderDetails::updateMarkerLocation() -{ - // Sanity check the location of our marker. - if (m_marker) { - RenderObject* markerPar = m_marker->parent(); - RenderObject* lineBoxParent = getParentOfFirstLineBox(m_summaryBlock); - if (!lineBoxParent) { - // If the marker is currently contained inside an anonymous box, - // then we are the only item in that anonymous box (since no line box - // parent was found). It's ok to just leave the marker where it is - // in this case. - if (markerPar && markerPar->isAnonymousBlock()) - lineBoxParent = markerPar; - else - lineBoxParent = m_summaryBlock; - } - - if (markerPar != lineBoxParent || m_marker->preferredLogicalWidthsDirty()) { - // Removing and adding the marker can trigger repainting in - // containers other than ourselves, so we need to disable LayoutState. - view()->disableLayoutState(); - m_marker->remove(); - if (!lineBoxParent) - lineBoxParent = m_summaryBlock; - lineBoxParent->addChild(m_marker, firstNonMarkerChild(lineBoxParent)); - - if (m_marker->preferredLogicalWidthsDirty()) - m_marker->computePreferredLogicalWidths(); - - view()->enableLayoutState(); - } - } -} - } // namespace WebCore - diff --git a/Source/WebCore/rendering/RenderDetails.h b/Source/WebCore/rendering/RenderDetails.h index 0b56c13..974c174 100644 --- a/Source/WebCore/rendering/RenderDetails.h +++ b/Source/WebCore/rendering/RenderDetails.h @@ -27,21 +27,17 @@ namespace WebCore { -class RenderDetailsMarker; - class RenderDetails : public RenderBlock { public: explicit RenderDetails(Node*); - virtual const char* renderName() const { return "RenderDetails"; } - virtual bool isDetails() const { return true; } - bool isOpen() const; - IntRect interactiveArea() const { return m_interactiveArea; } - void markerDestroyed(); void summaryDestroyed(RenderObject*); private: + virtual const char* renderName() const { return "RenderDetails"; } + virtual bool isDetails() const { return true; } + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); virtual void addChild(RenderObject* newChild, RenderObject *beforeChild = 0); @@ -52,33 +48,18 @@ private: virtual bool requiresForcedStyleRecalcPropagation() const { return true; } virtual void layout(); - virtual void destroy(); - void createDefaultSummary(); void replaceMainSummary(RenderObject*); void moveSummaryToContents(); void checkMainSummary(); RenderObject* getRenderPosition(RenderObject*); - PassRefPtr<RenderStyle> createSummaryStyle(); - void setMarkerStyle(); RenderBlock* summaryBlock(); RenderBlock* contentBlock(); - RenderObject* getParentOfFirstLineBox(RenderBlock* curr); - RenderObject* firstNonMarkerChild(RenderObject* parent); - void updateMarkerLocation(); - RenderBlock* m_summaryBlock; RenderBlock* m_contentBlock; - RenderObject* m_defaultSummaryBlock; - RenderObject* m_defaultSummaryText; - - IntRect m_interactiveArea; - - RenderDetailsMarker* m_marker; - RenderObject* m_mainSummary; }; diff --git a/Source/WebCore/rendering/RenderDetailsMarker.cpp b/Source/WebCore/rendering/RenderDetailsMarker.cpp index e040eb3..0347e7f 100644 --- a/Source/WebCore/rendering/RenderDetailsMarker.cpp +++ b/Source/WebCore/rendering/RenderDetailsMarker.cpp @@ -25,79 +25,21 @@ #include "HTMLNames.h" #include "PaintInfo.h" #include "RenderDetails.h" -#include "RenderSummary.h" namespace WebCore { using namespace HTMLNames; -RenderDetailsMarker::RenderDetailsMarker(RenderDetails* item) - : RenderBox(item->document()) - , m_details(item) +RenderDetailsMarker::RenderDetailsMarker(Node* node) + : RenderBlock(node) { - setInline(true); - setReplaced(true); -} - -void RenderDetailsMarker::destroy() -{ - if (m_details) - m_details->markerDestroyed(); - - RenderBox::destroy(); -} - -int RenderDetailsMarker::lineHeight(bool firstLine, LineDirectionMode direction, LinePositionMode) const -{ - return m_details->lineHeight(firstLine, direction, PositionOfInteriorLineBoxes); -} - -int RenderDetailsMarker::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode direction, LinePositionMode) const -{ - return m_details->baselinePosition(baselineType, firstLine, direction, PositionOfInteriorLineBoxes); -} - -void RenderDetailsMarker::computePreferredLogicalWidths() -{ - ASSERT(preferredLogicalWidthsDirty()); - - m_minPreferredLogicalWidth = 2 * style()->fontMetrics().ascent() / 3; - m_maxPreferredLogicalWidth = m_minPreferredLogicalWidth; - - setPreferredLogicalWidthsDirty(false); -} - -void RenderDetailsMarker::layout() -{ - ASSERT(needsLayout()); - - setLogicalWidth(minPreferredLogicalWidth()); - setLogicalHeight(style()->fontMetrics().height()); - - setMarginStart(0); - setMarginEnd(style()->fontMetrics().ascent() - minPreferredLogicalWidth() + 1); - - setNeedsLayout(false); -} - -IntRect RenderDetailsMarker::getRelativeMarkerRect() const -{ - IntRect relativeRect; - - int bulletWidth = minPreferredLogicalWidth(); - relativeRect = IntRect((logicalWidth() - bulletWidth) / 2, (logicalHeight() - bulletWidth) / 2, bulletWidth, bulletWidth); - - if (!style()->isHorizontalWritingMode()) { - relativeRect = relativeRect.transposedRect(); - relativeRect.setX(width() - relativeRect.x() - relativeRect.width()); - } - - return relativeRect; } bool RenderDetailsMarker::isOpen() const { - return m_details && m_details->isOpen(); + if (RenderDetails* owner = details()) + return owner->isOpen(); + return false; } static Path createPath(const FloatPoint* path) @@ -170,17 +112,18 @@ Path RenderDetailsMarker::getCanonicalPath() const Path RenderDetailsMarker::getPath(const IntPoint& origin) const { - IntRect rect = getRelativeMarkerRect(); Path result = getCanonicalPath(); - result.transform(AffineTransform().scale(rect.width())); - result.translate(FloatSize(origin.x() + rect.x(), origin.y() + rect.y())); + result.transform(AffineTransform().scale(logicalHeight())); + result.translate(FloatSize(origin.x(), origin.y())); return result; } void RenderDetailsMarker::paint(PaintInfo& paintInfo, int tx, int ty) { - if (paintInfo.phase != PaintPhaseForeground || style()->visibility() != VISIBLE) + if (paintInfo.phase != PaintPhaseForeground || style()->visibility() != VISIBLE) { + RenderBlock::paint(paintInfo, tx, ty); return; + } IntPoint boxOrigin(tx + x(), ty + y()); IntRect overflowRect(visualOverflowRect()); @@ -199,4 +142,14 @@ void RenderDetailsMarker::paint(PaintInfo& paintInfo, int tx, int ty) paintInfo.context->fillPath(getPath(boxOrigin)); } +RenderDetails* RenderDetailsMarker::details() const +{ + for (RenderObject* renderer = parent(); renderer; renderer = renderer->parent()) { + if (renderer->isDetails()) + return toRenderDetails(renderer); + } + + return 0; +} + } diff --git a/Source/WebCore/rendering/RenderDetailsMarker.h b/Source/WebCore/rendering/RenderDetailsMarker.h index de8f60b..f53a0c3 100644 --- a/Source/WebCore/rendering/RenderDetailsMarker.h +++ b/Source/WebCore/rendering/RenderDetailsMarker.h @@ -21,38 +21,29 @@ #ifndef RenderDetailsMarker_h #define RenderDetailsMarker_h -#include "RenderBox.h" +#include "RenderBlock.h" namespace WebCore { class RenderDetails; -class RenderDetailsMarker : public RenderBox { +class RenderDetailsMarker : public RenderBlock { public: - RenderDetailsMarker(RenderDetails*); + RenderDetailsMarker(Node*); enum Orientation { Up, Down, Left, Right }; Orientation orientation() const; - virtual void computePreferredLogicalWidths(); - virtual void destroy(); - private: virtual const char* renderName() const { return "RenderDetailsMarker"; } virtual bool isDetailsMarker() const { return true; } virtual void paint(PaintInfo&, int tx, int ty); - virtual void layout(); - virtual int lineHeight(bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const; - virtual int baselinePosition(FontBaseline, bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const; - - IntRect getRelativeMarkerRect() const; bool isOpen() const; Path getCanonicalPath() const; Path getPath(const IntPoint& origin) const; - - RenderDetails* m_details; + RenderDetails* details() const; }; inline RenderDetailsMarker* toRenderDetailsMarker(RenderObject* object) diff --git a/Source/WebCore/rendering/RenderFileUploadControl.cpp b/Source/WebCore/rendering/RenderFileUploadControl.cpp index b50b2ad..8056662 100644 --- a/Source/WebCore/rendering/RenderFileUploadControl.cpp +++ b/Source/WebCore/rendering/RenderFileUploadControl.cpp @@ -109,6 +109,12 @@ bool RenderFileUploadControl::allowsDirectoryUpload() HTMLInputElement* input = static_cast<HTMLInputElement*>(node()); return input->fastHasAttribute(webkitdirectoryAttr); } + +void RenderFileUploadControl::receiveDropForDirectoryUpload(const Vector<String>& paths) +{ + if (Chrome* chromePointer = chrome()) + chromePointer->enumerateChosenDirectory(paths[0], m_fileChooser.get()); +} #endif String RenderFileUploadControl::acceptTypes() @@ -304,6 +310,13 @@ VisiblePosition RenderFileUploadControl::positionForPoint(const IntPoint&) void RenderFileUploadControl::receiveDroppedFiles(const Vector<String>& paths) { +#if ENABLE(DIRECTORY_UPLOAD) + if (allowsDirectoryUpload()) { + receiveDropForDirectoryUpload(paths); + return; + } +#endif + if (allowsMultipleFiles()) m_fileChooser->chooseFiles(paths); else diff --git a/Source/WebCore/rendering/RenderFileUploadControl.h b/Source/WebCore/rendering/RenderFileUploadControl.h index 22974fe..e9fb7f0 100644 --- a/Source/WebCore/rendering/RenderFileUploadControl.h +++ b/Source/WebCore/rendering/RenderFileUploadControl.h @@ -64,6 +64,7 @@ private: bool allowsMultipleFiles(); #if ENABLE(DIRECTORY_UPLOAD) bool allowsDirectoryUpload(); + void receiveDropForDirectoryUpload(const Vector<String>&); #endif String acceptTypes(); void chooseIconForFiles(FileChooser*, const Vector<String>&); diff --git a/Source/WebCore/rendering/RenderFlexibleBox.cpp b/Source/WebCore/rendering/RenderFlexibleBox.cpp index 4d97da0..dc5c171 100644 --- a/Source/WebCore/rendering/RenderFlexibleBox.cpp +++ b/Source/WebCore/rendering/RenderFlexibleBox.cpp @@ -978,7 +978,7 @@ void RenderFlexibleBox::applyLineClamp(FlexBoxIterator& iterator, bool relayoutC // Get ellipsis width, and if the last child is an anchor, it will go after the ellipsis, so add in a space and the anchor width too int totalWidth; InlineBox* anchorBox = lastLine->lastChild(); - if (anchorBox && anchorBox->renderer()->node() && anchorBox->renderer()->node()->isLink()) + if (anchorBox && anchorBox->renderer()->style()->isLink()) totalWidth = anchorBox->logicalWidth() + font.width(TextRun(ellipsisAndSpace, 2)); else { anchorBox = 0; diff --git a/Source/WebCore/rendering/RenderFullScreen.cpp b/Source/WebCore/rendering/RenderFullScreen.cpp index a685064..476727d 100644 --- a/Source/WebCore/rendering/RenderFullScreen.cpp +++ b/Source/WebCore/rendering/RenderFullScreen.cpp @@ -46,7 +46,7 @@ PassRefPtr<RenderStyle> RenderFullScreen::createFullScreenStyle() RefPtr<RenderStyle> fullscreenStyle = RenderStyle::createDefaultStyle(); // Create a stacking context: - fullscreenStyle->setZIndex(0); + fullscreenStyle->setZIndex(INT_MAX); fullscreenStyle->setFontDescription(FontDescription()); fullscreenStyle->font().update(0); @@ -54,7 +54,7 @@ PassRefPtr<RenderStyle> RenderFullScreen::createFullScreenStyle() fullscreenStyle->setDisplay(BOX); fullscreenStyle->setBoxPack(BCENTER); fullscreenStyle->setBoxAlign(BCENTER); - fullscreenStyle->setBoxOrient(HORIZONTAL); + fullscreenStyle->setBoxOrient(VERTICAL); fullscreenStyle->setPosition(FixedPosition); fullscreenStyle->setWidth(Length(100.0, Percent)); diff --git a/Source/WebCore/rendering/RenderIFrame.cpp b/Source/WebCore/rendering/RenderIFrame.cpp index 01b8a17..1468acd 100644 --- a/Source/WebCore/rendering/RenderIFrame.cpp +++ b/Source/WebCore/rendering/RenderIFrame.cpp @@ -124,6 +124,7 @@ void RenderIFrame::layout() setNeedsLayout(false); } +<<<<<<< HEAD #if USE(ACCELERATED_COMPOSITING) bool RenderIFrame::requiresLayer() const { @@ -156,4 +157,6 @@ bool RenderIFrame::requiresAcceleratedCompositing() const } #endif +======= +>>>>>>> WebKit.org at r84325 } diff --git a/Source/WebCore/rendering/RenderIFrame.h b/Source/WebCore/rendering/RenderIFrame.h index 0bb3182..b6b30c9 100644 --- a/Source/WebCore/rendering/RenderIFrame.h +++ b/Source/WebCore/rendering/RenderIFrame.h @@ -34,19 +34,12 @@ class RenderIFrame : public RenderFrameBase { public: explicit RenderIFrame(Element*); -#if USE(ACCELERATED_COMPOSITING) - bool requiresAcceleratedCompositing() const; -#endif - private: virtual void computeLogicalHeight(); virtual void computeLogicalWidth(); virtual void layout(); -#if USE(ACCELERATED_COMPOSITING) - virtual bool requiresLayer() const; -#endif virtual bool isRenderIFrame() const { return true; } virtual const char* renderName() const { return "RenderPartObject"; } // Lying for now to avoid breaking tests diff --git a/Source/WebCore/rendering/RenderImage.cpp b/Source/WebCore/rendering/RenderImage.cpp index 9500aeb..1ea4e09 100644 --- a/Source/WebCore/rendering/RenderImage.cpp +++ b/Source/WebCore/rendering/RenderImage.cpp @@ -362,7 +362,12 @@ void RenderImage::paintAreaElementFocusRing(PaintInfo& paintInfo) // 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(), + unsigned short outlineWidth = areaElementStyle->outlineWidth(); + if (!outlineWidth) + return; + + paintInfo.context->drawFocusRing(path, outlineWidth, + areaElementStyle->outlineOffset(), areaElementStyle->visitedDependentColor(CSSPropertyOutlineColor)); } diff --git a/Source/WebCore/rendering/RenderIndicator.cpp b/Source/WebCore/rendering/RenderIndicator.cpp deleted file mode 100644 index 8f34a40..0000000 --- a/Source/WebCore/rendering/RenderIndicator.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). - * - * 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" - -#if ENABLE(PROGRESS_TAG) || ENABLE(METER_TAG) - -#include "RenderIndicator.h" - -#include "RenderTheme.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) -{ -} - -RenderIndicator::~RenderIndicator() -{ -} - -void RenderIndicator::layout() -{ - ASSERT(needsLayout()); - - LayoutRepainter repainter(*this, checkForRepaintDuringLayout()); - computeLogicalWidth(); - computeLogicalHeight(); - layoutParts(); - repainter.repaintAfterLayout(); - setNeedsLayout(false); -} - -void RenderIndicator::updateFromElement() -{ - setNeedsLayout(true); - repaint(); -} - -} // namespace WebCore - -#endif diff --git a/Source/WebCore/rendering/RenderIndicator.h b/Source/WebCore/rendering/RenderIndicator.h deleted file mode 100644 index 7c2a346..0000000 --- a/Source/WebCore/rendering/RenderIndicator.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). - * - * 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 RenderIndicator_h -#define RenderIndicator_h - -#if ENABLE(PROGRESS_TAG) || ENABLE(METER_TAG) -#include "RenderBlock.h" - -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*); - virtual ~RenderIndicator(); - -protected: - virtual void layout(); - virtual void updateFromElement(); - virtual bool requiresForcedStyleRecalcPropagation() const { return true; } - virtual bool canHaveChildren() const { return false; } - - virtual void layoutParts() = 0; -}; - -} // namespace WebCore - -#endif - -#endif // RenderIndicator_h - diff --git a/Source/WebCore/rendering/RenderInline.cpp b/Source/WebCore/rendering/RenderInline.cpp index 3a27307..ae18514 100644 --- a/Source/WebCore/rendering/RenderInline.cpp +++ b/Source/WebCore/rendering/RenderInline.cpp @@ -27,6 +27,7 @@ #include "FloatQuad.h" #include "GraphicsContext.h" #include "HitTestResult.h" +#include "InlineTextBox.h" #include "Page.h" #include "RenderArena.h" #include "RenderBlock.h" @@ -47,6 +48,7 @@ namespace WebCore { RenderInline::RenderInline(Node* node) : RenderBoxModelObject(node) , m_lineHeight(-1) + , m_alwaysCreateLineBoxes(false) { setChildrenInline(true); } @@ -144,6 +146,15 @@ void RenderInline::styleDidChange(StyleDifference diff, const RenderStyle* oldSt m_lineHeight = -1; + if (!m_alwaysCreateLineBoxes) { + bool alwaysCreateLineBoxes = hasSelfPaintingLayer() || hasBoxDecorations() || style()->hasPadding() || style()->hasMargin() || style()->hasOutline(); + if (oldStyle && alwaysCreateLineBoxes) { + dirtyLineBoxes(false); + setNeedsLayout(true); + } + m_alwaysCreateLineBoxes = alwaysCreateLineBoxes; + } + // Update pseudos for :before and :after now. if (!isAnonymous() && document()->usesBeforeAfterRules()) { children()->updateBeforeAfterContent(this, BEFORE); @@ -151,6 +162,38 @@ void RenderInline::styleDidChange(StyleDifference diff, const RenderStyle* oldSt } } +void RenderInline::updateAlwaysCreateLineBoxes() +{ + // Once we have been tainted once, just assume it will happen again. This way effects like hover highlighting that change the + // background color will only cause a layout on the first rollover. + if (m_alwaysCreateLineBoxes) + return; + + RenderStyle* parentStyle = parent()->style(); + RenderInline* parentRenderInline = parent()->isRenderInline() ? toRenderInline(parent()) : 0; + bool checkFonts = document()->inNoQuirksMode(); + bool alwaysCreateLineBoxes = (parentRenderInline && parentRenderInline->alwaysCreateLineBoxes()) + || (parentRenderInline && parentStyle->verticalAlign() != BASELINE) + || style()->verticalAlign() != BASELINE + || style()->textEmphasisMark() != TextEmphasisMarkNone + || (checkFonts && (!parentStyle->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(style()->font().fontMetrics()) + || parentStyle->lineHeight() != style()->lineHeight())); + + if (!alwaysCreateLineBoxes && checkFonts && document()->usesFirstLineRules()) { + // Have to check the first line style as well. + parentStyle = parent()->style(true); + RenderStyle* childStyle = style(true); + alwaysCreateLineBoxes = !parentStyle->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(childStyle->font().fontMetrics()) + || childStyle->verticalAlign() != BASELINE + || parentStyle->lineHeight() != childStyle->lineHeight(); + } + + if (alwaysCreateLineBoxes) { + dirtyLineBoxes(false); + m_alwaysCreateLineBoxes = true; + } +} + void RenderInline::addChild(RenderObject* newChild, RenderObject* beforeChild) { if (continuation()) @@ -424,9 +467,11 @@ void RenderInline::paint(PaintInfo& paintInfo, int tx, int ty) void RenderInline::absoluteRects(Vector<IntRect>& rects, int tx, int ty) { - if (InlineFlowBox* curr = firstLineBox()) { + if (!alwaysCreateLineBoxes()) + culledInlineAbsoluteRects(this, rects, IntSize(tx, ty)); + else if (InlineFlowBox* curr = firstLineBox()) { for (; curr; curr = curr->nextLineBox()) - rects.append(IntRect(tx + curr->x(), ty + curr->y(), curr->logicalWidth(), curr->logicalHeight())); + rects.append(enclosingIntRect(FloatRect(tx + curr->x(), ty + curr->y(), curr->width(), curr->height()))); } else rects.append(IntRect(tx, ty, 0, 0)); @@ -441,11 +486,76 @@ void RenderInline::absoluteRects(Vector<IntRect>& rects, int tx, int ty) } } +void RenderInline::culledInlineAbsoluteRects(const RenderInline* container, Vector<IntRect>& rects, const IntSize& offset) +{ + bool isHorizontal = style()->isHorizontalWritingMode(); + for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { + if (curr->isFloatingOrPositioned()) + continue; + + // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block + // direction (aligned to the root box's baseline). + if (curr->isBox()) { + RenderBox* currBox = toRenderBox(curr); + if (currBox->inlineBoxWrapper()) { + RootInlineBox* rootBox = currBox->inlineBoxWrapper()->root(); + int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent()); + int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height(); + FloatRect result; + if (isHorizontal) + result = FloatRect(offset.width() + currBox->inlineBoxWrapper()->x() - currBox->marginLeft(), offset.height() + logicalTop, currBox->width() + currBox->marginLeft() + currBox->marginRight(), logicalHeight); + else + result = FloatRect(offset.width() + logicalTop, offset.height() + currBox->inlineBoxWrapper()->y() - currBox->marginTop(), logicalHeight, currBox->height() + currBox->marginTop() + currBox->marginBottom()); + rects.append(enclosingIntRect(result)); + } + } else if (curr->isRenderInline()) { + // If the child doesn't need line boxes either, then we can recur. + RenderInline* currInline = toRenderInline(curr); + if (!currInline->alwaysCreateLineBoxes()) + currInline->culledInlineAbsoluteRects(container, rects, offset); + else { + for (InlineFlowBox* childLine = currInline->firstLineBox(); childLine; childLine = childLine->nextLineBox()) { + RootInlineBox* rootBox = childLine->root(); + int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent()); + int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height(); + FloatRect result; + if (isHorizontal) + result = FloatRect(offset.width() + childLine->x() - childLine->marginLogicalLeft(), + offset.height() + logicalTop, + childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight(), + logicalHeight); + else + result = FloatRect(offset.width() + logicalTop, + offset.height() + childLine->y() - childLine->marginLogicalLeft(), + logicalHeight, + childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight()); + rects.append(enclosingIntRect(result)); + } + } + } else if (curr->isText()) { + RenderText* currText = toRenderText(curr); + for (InlineTextBox* childText = currText->firstTextBox(); childText; childText = childText->nextTextBox()) { + RootInlineBox* rootBox = childText->root(); + int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent()); + int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height(); + FloatRect result; + if (isHorizontal) + result = FloatRect(offset.width() + childText->x(), offset.height() + logicalTop, childText->logicalWidth(), logicalHeight); + else + result = FloatRect(offset.width() + logicalTop, offset.height() + childText->y(), logicalHeight, childText->logicalWidth()); + rects.append(enclosingIntRect(result)); + } + } + } +} + void RenderInline::absoluteQuads(Vector<FloatQuad>& quads) { - if (InlineFlowBox* curr = firstLineBox()) { + if (!alwaysCreateLineBoxes()) + culledInlineAbsoluteQuads(this, quads); + else if (InlineFlowBox* curr = firstLineBox()) { for (; curr; curr = curr->nextLineBox()) { - FloatRect localRect(curr->x(), curr->y(), curr->logicalWidth(), curr->logicalHeight()); + FloatRect localRect(curr->x(), curr->y(), curr->width(), curr->height()); quads.append(localToAbsoluteQuad(localRect)); } } else @@ -455,19 +565,82 @@ void RenderInline::absoluteQuads(Vector<FloatQuad>& quads) continuation()->absoluteQuads(quads); } +void RenderInline::culledInlineAbsoluteQuads(const RenderInline* container, Vector<FloatQuad>& quads) +{ + bool isHorizontal = style()->isHorizontalWritingMode(); + for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { + if (curr->isFloatingOrPositioned()) + continue; + + // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block + // direction (aligned to the root box's baseline). + if (curr->isBox()) { + RenderBox* currBox = toRenderBox(curr); + if (currBox->inlineBoxWrapper()) { + RootInlineBox* rootBox = currBox->inlineBoxWrapper()->root(); + int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent()); + int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height(); + FloatRect result; + if (isHorizontal) + result = FloatRect(currBox->inlineBoxWrapper()->x() - currBox->marginLeft(), logicalTop, currBox->width() + currBox->marginLeft() + currBox->marginRight(), logicalHeight); + else + result = FloatRect(logicalTop, currBox->inlineBoxWrapper()->y() - currBox->marginTop(), logicalHeight, currBox->height() + currBox->marginTop() + currBox->marginBottom()); + quads.append(localToAbsoluteQuad(result)); + } + } else if (curr->isRenderInline()) { + // If the child doesn't need line boxes either, then we can recur. + RenderInline* currInline = toRenderInline(curr); + if (!currInline->alwaysCreateLineBoxes()) + currInline->culledInlineAbsoluteQuads(container, quads); + else { + for (InlineFlowBox* childLine = currInline->firstLineBox(); childLine; childLine = childLine->nextLineBox()) { + RootInlineBox* rootBox = childLine->root(); + int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent()); + int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height(); + FloatRect result; + if (isHorizontal) + result = FloatRect(childLine->x() - childLine->marginLogicalLeft(), + logicalTop, + childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight(), + logicalHeight); + else + result = FloatRect(logicalTop, + childLine->y() - childLine->marginLogicalLeft(), + logicalHeight, + childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight()); + quads.append(localToAbsoluteQuad(result)); + } + } + } else if (curr->isText()) { + RenderText* currText = toRenderText(curr); + for (InlineTextBox* childText = currText->firstTextBox(); childText; childText = childText->nextTextBox()) { + RootInlineBox* rootBox = childText->root(); + int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent()); + int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height(); + FloatRect result; + if (isHorizontal) + result = FloatRect(childText->x(), logicalTop, childText->logicalWidth(), logicalHeight); + else + result = FloatRect(logicalTop, childText->y(), logicalHeight, childText->logicalWidth()); + quads.append(localToAbsoluteQuad(result)); + } + } + } +} + int RenderInline::offsetLeft() const { int x = RenderBoxModelObject::offsetLeft(); - if (firstLineBox()) - x += firstLineBox()->x(); + if (InlineBox* firstBox = firstLineBoxIncludingCulling()) + x += firstBox->x(); return x; } int RenderInline::offsetTop() const { int y = RenderBoxModelObject::offsetTop(); - if (firstLineBox()) - y += firstLineBox()->y(); + if (InlineBox* firstBox = firstLineBoxIncludingCulling()) + y += firstBox->y(); return y; } @@ -565,6 +738,11 @@ VisiblePosition RenderInline::positionForPoint(const IntPoint& point) IntRect RenderInline::linesBoundingBox() const { + if (!alwaysCreateLineBoxes()) { + ASSERT(!firstLineBox()); + return enclosingIntRect(culledInlineBoundingBox(this)); + } + IntRect result; // See <rdar://problem/5289721>, for an unknown reason the linked list here is sometimes inconsistent, first is non-zero and last is zero. We have been @@ -594,26 +772,183 @@ IntRect RenderInline::linesBoundingBox() const return result; } +FloatRect RenderInline::culledInlineBoundingBox(const RenderInline* container) const +{ + FloatRect result; + bool isHorizontal = style()->isHorizontalWritingMode(); + for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { + if (curr->isFloatingOrPositioned()) + continue; + + // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block + // direction (aligned to the root box's baseline). + if (curr->isBox()) { + RenderBox* currBox = toRenderBox(curr); + if (currBox->inlineBoxWrapper()) { + RootInlineBox* rootBox = currBox->inlineBoxWrapper()->root(); + int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent()); + int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height(); + if (isHorizontal) + result.uniteIfNonZero(FloatRect(currBox->inlineBoxWrapper()->x() - currBox->marginLeft(), logicalTop, currBox->width() + currBox->marginLeft() + currBox->marginRight(), logicalHeight)); + else + result.uniteIfNonZero(FloatRect(logicalTop, currBox->inlineBoxWrapper()->y() - currBox->marginTop(), logicalHeight, currBox->height() + currBox->marginTop() + currBox->marginBottom())); + } + } else if (curr->isRenderInline()) { + // If the child doesn't need line boxes either, then we can recur. + RenderInline* currInline = toRenderInline(curr); + if (!currInline->alwaysCreateLineBoxes()) + result.uniteIfNonZero(currInline->culledInlineBoundingBox(container)); + else { + for (InlineFlowBox* childLine = currInline->firstLineBox(); childLine; childLine = childLine->nextLineBox()) { + RootInlineBox* rootBox = childLine->root(); + int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent()); + int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height(); + if (isHorizontal) + result.uniteIfNonZero(FloatRect(childLine->x() - childLine->marginLogicalLeft(), + logicalTop, + childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight(), + logicalHeight)); + else + result.uniteIfNonZero(FloatRect(logicalTop, + childLine->y() - childLine->marginLogicalLeft(), + logicalHeight, + childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight())); + + } + } + } else if (curr->isText()) { + RenderText* currText = toRenderText(curr); + for (InlineTextBox* childText = currText->firstTextBox(); childText; childText = childText->nextTextBox()) { + RootInlineBox* rootBox = childText->root(); + int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent()); + int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height(); + if (isHorizontal) + result.uniteIfNonZero(FloatRect(childText->x(), logicalTop, childText->logicalWidth(), logicalHeight)); + else + result.uniteIfNonZero(FloatRect(logicalTop, childText->y(), logicalHeight, childText->logicalWidth())); + } + } + } + return enclosingIntRect(result); +} + +InlineBox* RenderInline::culledInlineFirstLineBox() const +{ + for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { + if (curr->isFloatingOrPositioned()) + continue; + + // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block + // direction (aligned to the root box's baseline). + if (curr->isBox()) { + RenderBox* currBox = toRenderBox(curr); + if (currBox->inlineBoxWrapper()) + return currBox->inlineBoxWrapper(); + } else if (curr->isRenderInline()) { + RenderInline* currInline = toRenderInline(curr); + InlineBox* result = currInline->firstLineBoxIncludingCulling(); + if (result) + return result; + } else if (curr->isText()) { + RenderText* currText = toRenderText(curr); + if (currText->firstTextBox()) + return currText->firstTextBox(); + } + } + return 0; +} + +InlineBox* RenderInline::culledInlineLastLineBox() const +{ + for (RenderObject* curr = lastChild(); curr; curr = curr->previousSibling()) { + if (curr->isFloatingOrPositioned()) + continue; + + // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block + // direction (aligned to the root box's baseline). + if (curr->isBox()) { + RenderBox* currBox = toRenderBox(curr); + if (currBox->inlineBoxWrapper()) + return currBox->inlineBoxWrapper(); + } else if (curr->isRenderInline()) { + RenderInline* currInline = toRenderInline(curr); + InlineBox* result = currInline->lastLineBoxIncludingCulling(); + if (result) + return result; + } else if (curr->isText()) { + RenderText* currText = toRenderText(curr); + if (currText->lastTextBox()) + return currText->lastTextBox(); + } + } + return 0; +} + +IntRect RenderInline::culledInlineVisualOverflowBoundingBox() const +{ + IntRect result(culledInlineBoundingBox(this)); + bool isHorizontal = style()->isHorizontalWritingMode(); + for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { + if (curr->isFloatingOrPositioned()) + continue; + + // For overflow we just have to propagate by hand and recompute it all. + if (curr->isBox()) { + RenderBox* currBox = toRenderBox(curr); + if (!currBox->hasSelfPaintingLayer() && currBox->inlineBoxWrapper()) { + IntRect logicalRect = currBox->logicalVisualOverflowRectForPropagation(style()); + if (isHorizontal) { + logicalRect.move(currBox->x(), currBox->y()); + result.uniteIfNonZero(logicalRect); + } else { + logicalRect.move(currBox->y(), currBox->x()); + result.uniteIfNonZero(logicalRect.transposedRect()); + } + } + } else if (curr->isRenderInline()) { + // If the child doesn't need line boxes either, then we can recur. + RenderInline* currInline = toRenderInline(curr); + if (!currInline->alwaysCreateLineBoxes()) + result.uniteIfNonZero(currInline->culledInlineVisualOverflowBoundingBox()); + else if (!currInline->hasSelfPaintingLayer()) + result.uniteIfNonZero(currInline->linesVisualOverflowBoundingBox()); + } else if (curr->isText()) { + // FIXME; Overflow from text boxes is lost. We will need to cache this information in + // InlineTextBoxes. + RenderText* currText = toRenderText(curr); + result.uniteIfNonZero(currText->linesVisualOverflowBoundingBox()); + } + } + return result; +} + IntRect RenderInline::linesVisualOverflowBoundingBox() const { + if (!alwaysCreateLineBoxes()) + return culledInlineVisualOverflowBoundingBox(); + if (!firstLineBox() || !lastLineBox()) return IntRect(); // Return the width of the minimal left side and the maximal right side. - float logicalLeftSide = numeric_limits<int>::max(); - float logicalRightSide = numeric_limits<int>::min(); + int logicalLeftSide = numeric_limits<int>::max(); + int logicalRightSide = numeric_limits<int>::min(); for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) { - logicalLeftSide = min(logicalLeftSide, static_cast<float>(curr->logicalLeftVisualOverflow())); - logicalRightSide = max(logicalRightSide, static_cast<float>(curr->logicalRightVisualOverflow())); + logicalLeftSide = min(logicalLeftSide, curr->logicalLeftVisualOverflow()); + logicalRightSide = max(logicalRightSide, curr->logicalRightVisualOverflow()); } - bool isHorizontal = style()->isHorizontalWritingMode(); - - float x = isHorizontal ? logicalLeftSide : firstLineBox()->minXVisualOverflow(); - float y = isHorizontal ? firstLineBox()->minYVisualOverflow() : logicalLeftSide; - float width = isHorizontal ? logicalRightSide - logicalLeftSide : lastLineBox()->maxXVisualOverflow() - firstLineBox()->minXVisualOverflow(); - float height = isHorizontal ? lastLineBox()->maxYVisualOverflow() - firstLineBox()->minYVisualOverflow() : logicalRightSide - logicalLeftSide; - return enclosingIntRect(FloatRect(x, y, width, height)); + RootInlineBox* firstRootBox = firstLineBox()->root(); + RootInlineBox* lastRootBox = lastLineBox()->root(); + + int logicalTop = firstLineBox()->logicalTopVisualOverflow(firstRootBox->lineTop()); + int logicalWidth = logicalRightSide - logicalLeftSide; + int logicalHeight = lastLineBox()->logicalBottomVisualOverflow(lastRootBox->lineBottom()) - logicalTop; + + IntRect rect(logicalLeftSide, logicalTop, logicalWidth, logicalHeight); + if (!style()->isHorizontalWritingMode()) + rect = rect.transposedRect(); + return rect; } IntRect RenderInline::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) @@ -621,7 +956,7 @@ IntRect RenderInline::clippedOverflowRectForRepaint(RenderBoxModelObject* repain // Only run-ins are allowed in here during layout. ASSERT(!view() || !view()->layoutStateEnabled() || isRunIn()); - if (!firstLineBox() && !continuation()) + if (!firstLineBoxIncludingCulling() && !continuation()) return IntRect(); // Find our leftmost position. @@ -889,9 +1224,33 @@ void RenderInline::updateHitTestResult(HitTestResult& result, const IntPoint& po void RenderInline::dirtyLineBoxes(bool fullLayout) { - if (fullLayout) + if (fullLayout) { m_lineBoxes.deleteLineBoxes(renderArena()); - else + return; + } + + if (!alwaysCreateLineBoxes()) { + // We have to grovel into our children in order to dirty the appropriate lines. + for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { + if (curr->isFloatingOrPositioned()) + continue; + if (curr->isBox() && !curr->needsLayout()) { + RenderBox* currBox = toRenderBox(curr); + if (currBox->inlineBoxWrapper()) + currBox->inlineBoxWrapper()->root()->markDirty(); + } else if (!curr->selfNeedsLayout()) { + if (curr->isRenderInline()) { + RenderInline* currInline = toRenderInline(curr); + for (InlineFlowBox* childLine = currInline->firstLineBox(); childLine; childLine = childLine->nextLineBox()) + childLine->root()->markDirty(); + } else if (curr->isText()) { + RenderText* currText = toRenderText(curr); + for (InlineTextBox* childText = currText->firstTextBox(); childText; childText = childText->nextTextBox()) + childText->root()->markDirty(); + } + } + } + } else m_lineBoxes.dirtyLineBoxes(); } @@ -902,6 +1261,7 @@ InlineFlowBox* RenderInline::createInlineFlowBox() InlineFlowBox* RenderInline::createAndAppendInlineFlowBox() { + setAlwaysCreateLineBoxes(); InlineFlowBox* flowBox = createInlineFlowBox(); m_lineBoxes.appendLineBox(flowBox); return flowBox; @@ -978,13 +1338,11 @@ void RenderInline::imageChanged(WrappedImagePtr, const IntRect*) void RenderInline::addFocusRingRects(Vector<IntRect>& rects, int tx, int ty) { - for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) { - RootInlineBox* root = curr->root(); - int top = max(root->lineTop(), curr->logicalTop()); - int bottom = min(root->lineBottom(), curr->logicalBottom()); - IntRect rect(tx + curr->x(), ty + top, curr->logicalWidth(), bottom - top); - if (!rect.isEmpty()) - rects.append(rect); + if (!alwaysCreateLineBoxes()) + culledInlineAbsoluteRects(this, rects, IntSize(tx, ty)); + else { + for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) + rects.append(enclosingIntRect(FloatRect(tx + curr->x(), ty + curr->y(), curr->width(), curr->height()))); } for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { @@ -995,7 +1353,7 @@ void RenderInline::addFocusRingRects(Vector<IntRect>& rects, int tx, int ty) pos = curr->localToAbsolute(); else if (curr->isBox()) pos.move(toRenderBox(curr)->x(), toRenderBox(curr)->y()); - curr->addFocusRingRects(rects, pos.x(), pos.y()); + curr->addFocusRingRects(rects, pos.x(), pos.y()); } } diff --git a/Source/WebCore/rendering/RenderInline.h b/Source/WebCore/rendering/RenderInline.h index 08ac002..dc3eaea 100644 --- a/Source/WebCore/rendering/RenderInline.h +++ b/Source/WebCore/rendering/RenderInline.h @@ -23,6 +23,7 @@ #ifndef RenderInline_h #define RenderInline_h +#include "InlineFlowBox.h" #include "RenderBoxModelObject.h" #include "RenderLineBoxList.h" @@ -64,6 +65,8 @@ public: InlineFlowBox* firstLineBox() const { return m_lineBoxes.firstLineBox(); } InlineFlowBox* lastLineBox() const { return m_lineBoxes.lastLineBox(); } + InlineBox* firstLineBoxIncludingCulling() const { return alwaysCreateLineBoxes() ? firstLineBox() : culledInlineFirstLineBox(); } + InlineBox* lastLineBoxIncludingCulling() const { return alwaysCreateLineBoxes() ? lastLineBox() : culledInlineLastLineBox(); } virtual RenderBoxModelObject* virtualContinuation() const { return continuation(); } RenderInline* inlineElementContinuation() const; @@ -78,6 +81,10 @@ public: using RenderBoxModelObject::continuation; using RenderBoxModelObject::setContinuation; + bool alwaysCreateLineBoxes() const { return m_alwaysCreateLineBoxes; } + void setAlwaysCreateLineBoxes() { m_alwaysCreateLineBoxes = true; } + void updateAlwaysCreateLineBoxes(); + protected: virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); @@ -91,6 +98,13 @@ private: virtual bool isRenderInline() const { return true; } + FloatRect culledInlineBoundingBox(const RenderInline* container) const; + IntRect culledInlineVisualOverflowBoundingBox() const; + InlineBox* culledInlineFirstLineBox() const; + InlineBox* culledInlineLastLineBox() const; + void culledInlineAbsoluteRects(const RenderInline* container, Vector<IntRect>&, const IntSize&); + void culledInlineAbsoluteQuads(const RenderInline* container, Vector<FloatQuad>&); + void addChildToContinuation(RenderObject* newChild, RenderObject* beforeChild); virtual void addChildIgnoringContinuation(RenderObject* newChild, RenderObject* beforeChild = 0); @@ -154,7 +168,8 @@ private: RenderObjectChildList m_children; RenderLineBoxList m_lineBoxes; // All of the line boxes created for this inline flow. For example, <i>Hello<br>world.</i> will have two <i> line boxes. - mutable int m_lineHeight; + mutable int m_lineHeight : 31; + bool m_alwaysCreateLineBoxes : 1; }; inline RenderInline* toRenderInline(RenderObject* object) diff --git a/Source/WebCore/rendering/RenderInputSpeech.cpp b/Source/WebCore/rendering/RenderInputSpeech.cpp index 8a1e73f..e5dba78 100644 --- a/Source/WebCore/rendering/RenderInputSpeech.cpp +++ b/Source/WebCore/rendering/RenderInputSpeech.cpp @@ -57,6 +57,10 @@ void RenderInputSpeech::adjustInputFieldSpeechButtonStyle(CSSStyleSelector*, Ren bool RenderInputSpeech::paintInputFieldSpeechButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect) { + Element* element = object->node()->isElementNode() ? toElement(object->node()) : 0; + if (!element || !element->isInputFieldSpeechButtonElement()) + return false; + // Get the renderer of <input> element. Node* input = object->node()->shadowAncestorNode(); if (!input->renderer()->isBox()) @@ -84,7 +88,7 @@ bool RenderInputSpeech::paintInputFieldSpeechButton(RenderObject* object, const DEFINE_STATIC_LOCAL(RefPtr<Image>, imageStateRecording, (Image::loadPlatformResource("inputSpeechRecording"))); DEFINE_STATIC_LOCAL(RefPtr<Image>, imageStateWaiting, (Image::loadPlatformResource("inputSpeechWaiting"))); - InputFieldSpeechButtonElement* speechButton = reinterpret_cast<InputFieldSpeechButtonElement*>(object->node()); + InputFieldSpeechButtonElement* speechButton = toInputFieldSpeechButtonElement(element); Image* image = imageStateNormal.get(); if (speechButton->state() == InputFieldSpeechButtonElement::Recording) image = imageStateRecording.get(); diff --git a/Source/WebCore/rendering/RenderLayer.cpp b/Source/WebCore/rendering/RenderLayer.cpp index 3c6bc31..da82996 100644 --- a/Source/WebCore/rendering/RenderLayer.cpp +++ b/Source/WebCore/rendering/RenderLayer.cpp @@ -1420,7 +1420,7 @@ void RenderLayer::scrollTo(int x, int y) renderer()->repaintUsingContainer(repaintContainer, rectForRepaint); // Schedule the scroll DOM event. - renderer()->node()->document()->eventQueue()->enqueueScrollEvent(renderer()->node(), EventQueue::ScrollEventElementTarget); + renderer()->node()->document()->eventQueue()->enqueueOrDispatchScrollEvent(renderer()->node(), EventQueue::ScrollEventElementTarget); } void RenderLayer::scrollRectToVisible(const IntRect& rect, bool scrollToAnchor, const ScrollAlignment& alignX, const ScrollAlignment& alignY) @@ -1716,17 +1716,17 @@ static IntRect cornerRect(const RenderLayer* layer, const IntRect& bounds) horizontalThickness, verticalThickness); } -static IntRect scrollCornerRect(const RenderLayer* layer, const IntRect& bounds) +IntRect RenderLayer::scrollCornerRect() const { // We have a scrollbar corner when a scrollbar is visible and not filling the entire length of the box. // This happens when: // (a) A resizer is present and at least one scrollbar is present // (b) Both scrollbars are present. - bool hasHorizontalBar = layer->horizontalScrollbar(); - bool hasVerticalBar = layer->verticalScrollbar(); - bool hasResizer = layer->renderer()->style()->resize() != RESIZE_NONE; + bool hasHorizontalBar = horizontalScrollbar(); + bool hasVerticalBar = verticalScrollbar(); + bool hasResizer = renderer()->style()->resize() != RESIZE_NONE; if ((hasHorizontalBar && hasVerticalBar) || (hasResizer && (hasHorizontalBar || hasVerticalBar))) - return cornerRect(layer, bounds); + return cornerRect(this, renderBox()->borderBoxRect()); return IntRect(); } @@ -1738,10 +1738,21 @@ static IntRect resizerCornerRect(const RenderLayer* layer, const IntRect& bounds return cornerRect(layer, bounds); } -bool RenderLayer::scrollbarCornerPresent() const +IntRect RenderLayer::scrollCornerAndResizerRect() const +{ + RenderBox* box = renderBox(); + if (!box) + return IntRect(); + IntRect scrollCornerAndResizer = scrollCornerRect(); + if (scrollCornerAndResizer.isEmpty()) + scrollCornerAndResizer = resizerCornerRect(this, box->borderBoxRect()); + return scrollCornerAndResizer; +} + +bool RenderLayer::isScrollCornerVisible() const { ASSERT(renderer()->isBox()); - return !scrollCornerRect(this, renderBox()->borderBoxRect()).isEmpty(); + return !scrollCornerRect().isEmpty(); } IntRect RenderLayer::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntRect& scrollbarRect) const @@ -1834,6 +1845,19 @@ IntSize RenderLayer::scrollbarOffset(const Scrollbar* scrollbar) const void RenderLayer::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect) { +#if USE(ACCELERATED_COMPOSITING) + if (scrollbar == m_vBar.get()) { + if (GraphicsLayer* layer = layerForVerticalScrollbar()) { + layer->setNeedsDisplayInRect(rect); + return; + } + } else { + if (GraphicsLayer* layer = layerForHorizontalScrollbar()) { + layer->setNeedsDisplayInRect(rect); + return; + } + } +#endif IntRect scrollRect = rect; RenderBox* box = renderBox(); ASSERT(box); @@ -1844,6 +1868,20 @@ void RenderLayer::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& r renderer()->repaintRectangle(scrollRect); } +void RenderLayer::invalidateScrollCornerRect(const IntRect& rect) +{ +#if USE(ACCELERATED_COMPOSITING) + if (GraphicsLayer* layer = layerForScrollCorner()) { + layer->setNeedsDisplayInRect(rect); + return; + } +#endif + if (m_scrollCorner) + m_scrollCorner->repaintRectangle(rect); + if (m_resizer) + m_resizer->repaintRectangle(rect); +} + PassRefPtr<Scrollbar> RenderLayer::createScrollbar(ScrollbarOrientation orientation) { RefPtr<Scrollbar> widget; @@ -1972,8 +2010,8 @@ void RenderLayer::positionOverflowControls(int tx, int ty) if (!box) return; - IntRect borderBox = box->borderBoxRect(); - IntRect scrollCorner(scrollCornerRect(this, borderBox)); + const IntRect& borderBox = box->borderBoxRect(); + const IntRect& scrollCorner = scrollCornerRect(); IntRect absBounds(borderBox.x() + tx, borderBox.y() + ty, borderBox.width(), borderBox.height()); if (m_vBar) m_vBar->setFrameRect(IntRect(absBounds.maxX() - box->borderRight() - m_vBar->width(), @@ -1986,7 +2024,31 @@ void RenderLayer::positionOverflowControls(int tx, int ty) absBounds.maxY() - box->borderBottom() - m_hBar->height(), absBounds.width() - (box->borderLeft() + box->borderRight()) - scrollCorner.width(), m_hBar->height())); - + +#if USE(ACCELERATED_COMPOSITING) + if (GraphicsLayer* layer = layerForHorizontalScrollbar()) { + if (m_hBar) { + layer->setPosition(IntPoint(m_hBar->frameRect().x() - tx, m_hBar->frameRect().y() - ty)); + layer->setSize(m_hBar->frameRect().size()); + } + layer->setDrawsContent(m_hBar); + } + if (GraphicsLayer* layer = layerForVerticalScrollbar()) { + if (m_vBar) { + layer->setPosition(IntPoint(m_vBar->frameRect().x() - tx, m_vBar->frameRect().y() - ty)); + layer->setSize(m_vBar->frameRect().size()); + } + layer->setDrawsContent(m_vBar); + } + + if (GraphicsLayer* layer = layerForScrollCorner()) { + const IntRect& scrollCornerAndResizer = scrollCornerAndResizerRect(); + layer->setPosition(scrollCornerAndResizer.location()); + layer->setSize(scrollCornerAndResizer.size()); + layer->setDrawsContent(!scrollCornerAndResizer.isEmpty()); + } +#endif + if (m_scrollCorner) m_scrollCorner->setFrameRect(scrollCorner); if (m_resizer) @@ -2239,9 +2301,10 @@ void RenderLayer::paintOverflowControls(GraphicsContext* context, int tx, int ty // and we'll paint the scrollbars then. In the meantime, cache tx and ty so that the // second pass doesn't need to re-enter the RenderTree to get it right. if (hasOverlayScrollbars() && !paintingOverlayControls) { - RenderLayer* rootLayer = renderer()->view()->layer(); - rootLayer->setContainsDirtyOverlayScrollbars(true); + RenderView* renderView = renderer()->view(); + renderView->layer()->setContainsDirtyOverlayScrollbars(true); m_cachedOverlayScrollbarOffset = IntPoint(tx, ty); + renderView->frameView()->setContainsScrollableAreaWithOverlayScrollbars(true); return; } @@ -2258,11 +2321,24 @@ void RenderLayer::paintOverflowControls(GraphicsContext* context, int tx, int ty positionOverflowControls(offsetX, offsetY); // Now that we're sure the scrollbars are in the right place, paint them. - if (m_hBar) + if (m_hBar +#if USE(ACCELERATED_COMPOSITING) + && !layerForHorizontalScrollbar() +#endif + ) m_hBar->paint(context, damageRect); - if (m_vBar) + if (m_vBar +#if USE(ACCELERATED_COMPOSITING) + && !layerForVerticalScrollbar() +#endif + ) m_vBar->paint(context, damageRect); +#if USE(ACCELERATED_COMPOSITING) + if (layerForScrollCorner()) + return; +#endif + // We fill our scroll corner with white if we have a scrollbar that doesn't run all the way up to the // edge of the box. paintScrollCorner(context, offsetX, offsetY, damageRect); @@ -2276,7 +2352,7 @@ void RenderLayer::paintScrollCorner(GraphicsContext* context, int tx, int ty, co RenderBox* box = renderBox(); ASSERT(box); - IntRect cornerRect = scrollCornerRect(this, box->borderBoxRect()); + IntRect cornerRect = scrollCornerRect(); IntRect absRect = IntRect(cornerRect.x() + tx, cornerRect.y() + ty, cornerRect.width(), cornerRect.height()); if (!absRect.intersects(damageRect)) return; @@ -2327,7 +2403,7 @@ void RenderLayer::paintResizer(GraphicsContext* context, int tx, int ty, const I // Draw a frame around the resizer (1px grey line) if there are any scrollbars present. // Clipping will exclude the right and bottom edges of this frame. - if (m_hBar || m_vBar) { + if (!hasOverlayScrollbars() && (m_vBar || m_hBar)) { context->save(); context->clip(absRect); IntRect largerCorner = absRect; @@ -2479,7 +2555,7 @@ void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p, // Avoid painting layers when stylesheets haven't loaded. This eliminates FOUC. // It's ok not to draw, because later on, when all the stylesheets do load, updateStyleSelector on the Document // will do a full repaint(). - if (renderer()->document()->mayCauseFlashOfUnstyledContent() && !renderer()->isRenderView() && !renderer()->isRoot()) + if (renderer()->document()->didLayoutWithPendingStylesheets() && !renderer()->isRenderView() && !renderer()->isRoot()) return; // If this layer is totally invisible then there is nothing to paint. @@ -2921,6 +2997,7 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont #if USE(ACCELERATED_COMPOSITING) useTemporaryClipRects = compositor()->inCompositingMode(); #endif + useTemporaryClipRects |= renderer()->view()->frameView()->containsScrollableAreaWithOverlayScrollbars(); IntRect hitTestArea = result.rectForPoint(hitTestPoint); @@ -2928,7 +3005,7 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont if (transform() && !appliedTransform) { // Make sure the parent's clip rects have been calculated. if (parent()) { - IntRect clipRect = backgroundClipRect(rootLayer, useTemporaryClipRects); + IntRect clipRect = backgroundClipRect(rootLayer, useTemporaryClipRects, IncludeOverlayScrollbarSize); // Go ahead and test the enclosing clip now. if (!clipRect.intersects(hitTestArea)) return 0; @@ -2996,7 +3073,7 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont IntRect bgRect; IntRect fgRect; IntRect outlineRect; - calculateRects(rootLayer, hitTestRect, layerBounds, bgRect, fgRect, outlineRect, useTemporaryClipRects); + calculateRects(rootLayer, hitTestRect, layerBounds, bgRect, fgRect, outlineRect, useTemporaryClipRects, IncludeOverlayScrollbarSize); // The following are used for keeping track of the z-depth of the hit point of 3d-transformed // descendants. @@ -3265,7 +3342,7 @@ RenderLayer* RenderLayer::hitTestChildLayerColumns(RenderLayer* childLayer, Rend return 0; } -void RenderLayer::updateClipRects(const RenderLayer* rootLayer) +void RenderLayer::updateClipRects(const RenderLayer* rootLayer, OverlayScrollbarSizeRelevancy relevancy) { if (m_clipRects) { ASSERT(rootLayer == m_clipRectsRoot); @@ -3276,10 +3353,10 @@ void RenderLayer::updateClipRects(const RenderLayer* rootLayer) // examine the parent. We want to cache clip rects with us as the root. RenderLayer* parentLayer = rootLayer != this ? parent() : 0; if (parentLayer) - parentLayer->updateClipRects(rootLayer); + parentLayer->updateClipRects(rootLayer, relevancy); ClipRects clipRects; - calculateClipRects(rootLayer, clipRects, true); + calculateClipRects(rootLayer, clipRects, true, relevancy); if (parentLayer && parentLayer->clipRects() && clipRects == *parentLayer->clipRects()) m_clipRects = parentLayer->clipRects(); @@ -3291,7 +3368,7 @@ void RenderLayer::updateClipRects(const RenderLayer* rootLayer) #endif } -void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, ClipRects& clipRects, bool useCached) const +void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, ClipRects& clipRects, bool useCached, OverlayScrollbarSizeRelevancy relevancy) const { if (!parent()) { // The root layer's clip rect is always infinite. @@ -3339,6 +3416,7 @@ void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, ClipRects& cl } if (renderer()->hasOverflowClip()) { +<<<<<<< HEAD IntRect newOverflowClip = toRenderBox(renderer())->overflowClipRect(x, y); #if ENABLE(ANDROID_OVERFLOW_SCROLL) clipRects.setHitTestClip(intersection(clipRects.fixed() ? clipRects.fixedClipRect() @@ -3350,6 +3428,9 @@ void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, ClipRects& cl m_scrollWidth, m_scrollHeight); } #endif +======= + IntRect newOverflowClip = toRenderBox(renderer())->overflowClipRect(x, y, relevancy); +>>>>>>> WebKit.org at r84325 clipRects.setOverflowClipRect(intersection(newOverflowClip, clipRects.overflowClipRect())); if (renderer()->isPositioned() || renderer()->isRelPositioned()) clipRects.setPosClipRect(intersection(newOverflowClip, clipRects.posClipRect())); @@ -3363,24 +3444,24 @@ void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, ClipRects& cl } } -void RenderLayer::parentClipRects(const RenderLayer* rootLayer, ClipRects& clipRects, bool temporaryClipRects) const +void RenderLayer::parentClipRects(const RenderLayer* rootLayer, ClipRects& clipRects, bool temporaryClipRects, OverlayScrollbarSizeRelevancy relevancy) const { ASSERT(parent()); if (temporaryClipRects) { - parent()->calculateClipRects(rootLayer, clipRects); + parent()->calculateClipRects(rootLayer, clipRects, false, relevancy); return; } - parent()->updateClipRects(rootLayer); + parent()->updateClipRects(rootLayer, relevancy); clipRects = *parent()->clipRects(); } -IntRect RenderLayer::backgroundClipRect(const RenderLayer* rootLayer, bool temporaryClipRects) const +IntRect RenderLayer::backgroundClipRect(const RenderLayer* rootLayer, bool temporaryClipRects, OverlayScrollbarSizeRelevancy relevancy) const { IntRect backgroundRect; if (parent()) { ClipRects parentRects; - parentClipRects(rootLayer, parentRects, temporaryClipRects); + parentClipRects(rootLayer, parentRects, temporaryClipRects, relevancy); backgroundRect = renderer()->style()->position() == FixedPosition ? parentRects.fixedClipRect() : (renderer()->isPositioned() ? parentRects.posClipRect() : parentRects.overflowClipRect()); @@ -3393,10 +3474,11 @@ IntRect RenderLayer::backgroundClipRect(const RenderLayer* rootLayer, bool tempo } void RenderLayer::calculateRects(const RenderLayer* rootLayer, const IntRect& paintDirtyRect, IntRect& layerBounds, - IntRect& backgroundRect, IntRect& foregroundRect, IntRect& outlineRect, bool temporaryClipRects) const + IntRect& backgroundRect, IntRect& foregroundRect, IntRect& outlineRect, bool temporaryClipRects, + OverlayScrollbarSizeRelevancy relevancy) const { if (rootLayer != this && parent()) { - backgroundRect = backgroundClipRect(rootLayer, temporaryClipRects); + backgroundRect = backgroundClipRect(rootLayer, temporaryClipRects, relevancy); backgroundRect.intersect(paintDirtyRect); } else backgroundRect = paintDirtyRect; @@ -3422,7 +3504,7 @@ void RenderLayer::calculateRects(const RenderLayer* rootLayer, const IntRect& pa } else #endif if (renderer()->hasOverflowClip()) - foregroundRect.intersect(toRenderBox(renderer())->overflowClipRect(x, y)); + foregroundRect.intersect(toRenderBox(renderer())->overflowClipRect(x, y, relevancy)); if (renderer()->hasClip()) { // Clip applies to *us* as well, so go ahead and update the damageRect. IntRect newPosClip = toRenderBox(renderer())->clipRect(x, y); @@ -3629,6 +3711,21 @@ bool RenderLayer::hasCompositedMask() const { return m_backing && m_backing->hasMaskLayer(); } + +GraphicsLayer* RenderLayer::layerForHorizontalScrollbar() const +{ + return m_backing ? m_backing->layerForHorizontalScrollbar() : 0; +} + +GraphicsLayer* RenderLayer::layerForVerticalScrollbar() const +{ + return m_backing ? m_backing->layerForVerticalScrollbar() : 0; +} + +GraphicsLayer* RenderLayer::layerForScrollCorner() const +{ + return m_backing ? m_backing->layerForScrollCorner() : 0; +} #endif bool RenderLayer::paintsWithTransform(PaintBehavior paintBehavior) const @@ -3957,7 +4054,7 @@ bool RenderLayer::isSelfPaintingLayer() const || renderer()->isRenderIFrame(); } -void RenderLayer::styleChanged(StyleDifference diff, const RenderStyle*) +void RenderLayer::styleChanged(StyleDifference diff, const RenderStyle* oldStyle) { bool isNormalFlowOnly = shouldBeNormalFlowOnly(); if (isNormalFlowOnly != m_isNormalFlowOnly) { @@ -4002,7 +4099,11 @@ void RenderLayer::styleChanged(StyleDifference diff, const RenderStyle*) compositor()->setCompositingLayersNeedRebuild(); else if (m_backing) m_backing->updateGraphicsLayerGeometry(); - + else if (oldStyle && oldStyle->overflowX() != renderer()->style()->overflowX()) { + if (stackingContext()->hasCompositingDescendant()) + compositor()->setCompositingLayersNeedRebuild(); + } + if (m_backing && diff >= StyleDifferenceRepaint) m_backing->setContentsNeedDisplay(); #else diff --git a/Source/WebCore/rendering/RenderLayer.h b/Source/WebCore/rendering/RenderLayer.h index 17ba99e..4cf96ce 100644 --- a/Source/WebCore/rendering/RenderLayer.h +++ b/Source/WebCore/rendering/RenderLayer.h @@ -207,7 +207,7 @@ public: void repaintIncludingNonCompositingDescendants(RenderBoxModelObject* repaintContainer); #endif - void styleChanged(StyleDifference, const RenderStyle*); + void styleChanged(StyleDifference, const RenderStyle* oldStyle); RenderMarquee* marquee() const { return m_marquee; } @@ -279,18 +279,22 @@ public: PassRefPtr<Scrollbar> createScrollbar(ScrollbarOrientation); void destroyScrollbar(ScrollbarOrientation); - Scrollbar* horizontalScrollbar() const { return m_hBar.get(); } - Scrollbar* verticalScrollbar() const { return m_vBar.get(); } + // ScrollableArea overrides + virtual Scrollbar* horizontalScrollbar() const { return m_hBar.get(); } + virtual Scrollbar* verticalScrollbar() const { return m_vBar.get(); } - int verticalScrollbarWidth(OverlayScrollbarSizeRelevancy relevancy = IgnoreOverlayScrollbarSize) const; - int horizontalScrollbarHeight(OverlayScrollbarSizeRelevancy relevancy = IgnoreOverlayScrollbarSize) const; + int verticalScrollbarWidth(OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize) const; + int horizontalScrollbarHeight(OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize) const; bool hasOverflowControls() const; +<<<<<<< HEAD #if ENABLE(ANDROID_OVERFLOW_SCROLL) bool hasOverflowScroll() const { return m_hasOverflowScroll; } bool hasOverflowParent() const; #endif void positionOverflowControls(int tx, int ty); +======= +>>>>>>> WebKit.org at r84325 bool isPointInResizeControl(const IntPoint& absolutePoint) const; bool hitTestOverflowControls(HitTestResult&, const IntPoint& localPoint); IntSize offsetFromResizeCorner(const IntPoint& absolutePoint) const; @@ -414,13 +418,14 @@ public: // |rootLayer}. It also computes our background and foreground clip rects // for painting/event handling. void calculateRects(const RenderLayer* rootLayer, const IntRect& paintDirtyRect, IntRect& layerBounds, - IntRect& backgroundRect, IntRect& foregroundRect, IntRect& outlineRect, bool temporaryClipRects = false) const; + IntRect& backgroundRect, IntRect& foregroundRect, IntRect& outlineRect, bool temporaryClipRects = false, + OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize) const; // Compute and cache clip rects computed with the given layer as the root - void updateClipRects(const RenderLayer* rootLayer); + void updateClipRects(const RenderLayer* rootLayer, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize); // Compute and return the clip rects. If useCached is true, will used previously computed clip rects on ancestors // (rather than computing them all from scratch up the parent chain). - void calculateClipRects(const RenderLayer* rootLayer, ClipRects&, bool useCached = false) const; + void calculateClipRects(const RenderLayer* rootLayer, ClipRects&, bool useCached = false, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize) const; ClipRects* clipRects() const { return m_clipRects; } IntRect childrenClipRect() const; // Returns the foreground clip rect of the layer in the document's coordinate space. @@ -479,6 +484,9 @@ public: RenderLayerBacking* backing() const { return m_backing.get(); } RenderLayerBacking* ensureBacking(); void clearBacking(); + virtual GraphicsLayer* layerForHorizontalScrollbar() const; + virtual GraphicsLayer* layerForVerticalScrollbar() const; + virtual GraphicsLayer* layerForScrollCorner() const; #else bool isComposited() const { return false; } bool hasCompositedMask() const { return false; } @@ -568,8 +576,10 @@ private: virtual void setScrollOffset(const IntPoint&); virtual int scrollPosition(Scrollbar*) const; virtual void invalidateScrollbarRect(Scrollbar*, const IntRect&); + virtual void invalidateScrollCornerRect(const IntRect&); virtual bool isActive() const; - virtual bool scrollbarCornerPresent() const; + virtual bool isScrollCornerVisible() const; + virtual IntRect scrollCornerRect() const; virtual IntRect convertFromScrollbarToContainingView(const Scrollbar*, const IntRect&) const; virtual IntRect convertFromContainingViewToScrollbar(const Scrollbar*, const IntRect&) const; virtual IntPoint convertFromScrollbarToContainingView(const Scrollbar*, const IntPoint&) const; @@ -580,6 +590,9 @@ private: virtual IntPoint currentMousePosition() const; virtual bool shouldSuspendScrollAnimations() const; + // Rectangle encompassing the scroll corner and resizer rect. + IntRect scrollCornerAndResizerRect() const; + virtual void disconnectFromPage() { m_page = 0; } // NOTE: This should only be called by the overriden setScrollOffset from ScrollableArea. @@ -610,14 +623,15 @@ private: bool paintingInsideReflection() const { return m_paintingInsideReflection; } void setPaintingInsideReflection(bool b) { m_paintingInsideReflection = b; } - void parentClipRects(const RenderLayer* rootLayer, ClipRects&, bool temporaryClipRects = false) const; - IntRect backgroundClipRect(const RenderLayer* rootLayer, bool temporaryClipRects) const; + void parentClipRects(const RenderLayer* rootLayer, ClipRects&, bool temporaryClipRects = false, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize) const; + IntRect backgroundClipRect(const RenderLayer* rootLayer, bool temporaryClipRects, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize) const; RenderLayer* enclosingTransformedAncestor() const; // Convert a point in absolute coords into layer coords, taking transforms into account IntPoint absoluteToContents(const IntPoint&) const; + void positionOverflowControls(int tx, int ty); void updateScrollCornerStyle(); void updateResizerStyle(); @@ -730,7 +744,7 @@ protected: bool m_has3DTransformedDescendant : 1; // Set on a stacking context layer that has 3D descendants anywhere // in a preserves3D hierarchy. Hint to do 3D-aware hit testing. #if USE(ACCELERATED_COMPOSITING) - bool m_hasCompositingDescendant : 1; + bool m_hasCompositingDescendant : 1; // In the z-order tree. bool m_mustOverlapCompositedLayers : 1; #endif diff --git a/Source/WebCore/rendering/RenderLayerBacking.cpp b/Source/WebCore/rendering/RenderLayerBacking.cpp index 26a10dd..63b1d20 100644 --- a/Source/WebCore/rendering/RenderLayerBacking.cpp +++ b/Source/WebCore/rendering/RenderLayerBacking.cpp @@ -94,6 +94,7 @@ RenderLayerBacking::RenderLayerBacking(RenderLayer* layer) RenderLayerBacking::~RenderLayerBacking() { updateClippingLayers(false, false); + updateOverflowControlsLayers(false, false, false); updateForegroundLayer(false); updateMaskLayer(false); destroyGraphicsLayer(); @@ -225,9 +226,11 @@ void RenderLayerBacking::updateCompositedBounds() void RenderLayerBacking::updateAfterWidgetResize() { - if (renderer()->isRenderIFrame()) { - if (RenderLayerCompositor* innerCompositor = RenderLayerCompositor::iframeContentsCompositor(toRenderIFrame(renderer()))) - innerCompositor->frameViewDidChangeSize(contentsBox().location()); + if (renderer()->isRenderPart()) { + if (RenderLayerCompositor* innerCompositor = RenderLayerCompositor::frameContentsCompositor(toRenderPart(renderer()))) { + innerCompositor->frameViewDidChangeSize(); + innerCompositor->frameViewDidChangeLocation(contentsBox().location()); + } } } @@ -264,6 +267,12 @@ bool RenderLayerBacking::updateGraphicsLayerConfiguration() if (updateClippingLayers(compositor->clippedByAncestor(m_owningLayer), compositor->clipsCompositingDescendants(m_owningLayer))) layerConfigChanged = true; + if (updateOverflowControlsLayers(requiresHorizontalScrollbarLayer(), requiresVerticalScrollbarLayer(), requiresScrollCornerLayer())) + layerConfigChanged = true; + + if (layerConfigChanged) + updateInternalHierarchy(); + if (updateMaskLayer(renderer->hasMask())) m_graphicsLayer->setMaskLayer(m_maskLayer.get()); @@ -298,8 +307,8 @@ bool RenderLayerBacking::updateGraphicsLayerConfiguration() } #endif - if (renderer->isRenderIFrame()) - layerConfigChanged = RenderLayerCompositor::parentIFrameContentLayers(toRenderIFrame(renderer)); + if (renderer->isRenderPart()) + layerConfigChanged = RenderLayerCompositor::parentFrameContentLayers(toRenderPart(renderer)); return layerConfigChanged; } @@ -365,6 +374,7 @@ void RenderLayerBacking::updateGraphicsLayerGeometry() // layer. Note that we call it with temporaryClipRects = true because normally when computing clip rects // for a compositing layer, rootLayer is the layer itself. IntRect parentClipRect = m_owningLayer->backgroundClipRect(compAncestor, true); + ASSERT(parentClipRect != PaintInfo::infiniteRect()); m_ancestorClippingLayer->setPosition(FloatPoint() + (parentClipRect.location() - graphicsLayerParentLocation)); m_ancestorClippingLayer->setSize(parentClipRect.size()); @@ -491,6 +501,22 @@ void RenderLayerBacking::updateInternalHierarchy() if (m_clippingLayer) { m_clippingLayer->removeFromParent(); m_graphicsLayer->addChild(m_clippingLayer.get()); + + // The clip for child layers does not include space for overflow controls, so they exist as + // siblings of the clipping layer if we have one. Normal children of this layer are set as + // children of the clipping layer. + if (m_layerForHorizontalScrollbar) { + m_layerForHorizontalScrollbar->removeFromParent(); + m_graphicsLayer->addChild(m_layerForHorizontalScrollbar.get()); + } + if (m_layerForVerticalScrollbar) { + m_layerForVerticalScrollbar->removeFromParent(); + m_graphicsLayer->addChild(m_layerForVerticalScrollbar.get()); + } + if (m_layerForScrollCorner) { + m_layerForScrollCorner->removeFromParent(); + m_graphicsLayer->addChild(m_layerForScrollCorner.get()); + } } } @@ -534,8 +560,77 @@ bool RenderLayerBacking::updateClippingLayers(bool needsAncestorClip, bool needs layersChanged = true; } - if (layersChanged) - updateInternalHierarchy(); + return layersChanged; +} + +bool RenderLayerBacking::requiresHorizontalScrollbarLayer() const +{ +#if !PLATFORM(CHROMIUM) + if (!m_owningLayer->hasOverlayScrollbars()) + return false; +#endif + return m_owningLayer->horizontalScrollbar(); +} + +bool RenderLayerBacking::requiresVerticalScrollbarLayer() const +{ +#if !PLATFORM(CHROMIUM) + if (!m_owningLayer->hasOverlayScrollbars()) + return false; +#endif + return m_owningLayer->verticalScrollbar(); +} + +bool RenderLayerBacking::requiresScrollCornerLayer() const +{ +#if !PLATFORM(CHROMIUM) + if (!m_owningLayer->hasOverlayScrollbars()) + return false; +#endif + return !m_owningLayer->scrollCornerAndResizerRect().isEmpty(); +} + +bool RenderLayerBacking::updateOverflowControlsLayers(bool needsHorizontalScrollbarLayer, bool needsVerticalScrollbarLayer, bool needsScrollCornerLayer) +{ + bool layersChanged = false; + if (needsHorizontalScrollbarLayer) { + if (!m_layerForHorizontalScrollbar) { + m_layerForHorizontalScrollbar = GraphicsLayer::create(this); +#ifndef NDEBUG + m_layerForHorizontalScrollbar ->setName("horizontal scrollbar"); +#endif + layersChanged = true; + } + } else if (m_layerForHorizontalScrollbar) { + m_layerForHorizontalScrollbar.clear(); + layersChanged = true; + } + + if (needsVerticalScrollbarLayer) { + if (!m_layerForVerticalScrollbar) { + m_layerForVerticalScrollbar = GraphicsLayer::create(this); +#ifndef NDEBUG + m_layerForVerticalScrollbar->setName("vertical scrollbar"); +#endif + layersChanged = true; + } + } else if (m_layerForVerticalScrollbar) { + m_layerForVerticalScrollbar.clear(); + layersChanged = true; + } + + if (needsScrollCornerLayer) { + if (!m_layerForScrollCorner) { + m_layerForScrollCorner = GraphicsLayer::create(this); +#ifndef NDEBUG + m_layerForScrollCorner->setName("scroll corner"); +#endif + layersChanged = true; + } + } else if (m_layerForScrollCorner) { + m_layerForScrollCorner.clear(); + layersChanged = true; + } return layersChanged; } @@ -804,7 +899,7 @@ bool RenderLayerBacking::containsPaintedContent() const if (renderer()->isVideo() && toRenderVideo(renderer())->shouldDisplayVideo()) return hasBoxDecorationsOrBackground(renderer()); #endif -#if PLATFORM(MAC) && PLATFORM(CA) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) +#if PLATFORM(MAC) && USE(CA) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) #elif ENABLE(WEBGL) || ENABLE(ACCELERATED_2D_CANVAS) if (isAcceleratedCanvas(renderer())) return hasBoxDecorationsOrBackground(renderer()); @@ -933,7 +1028,7 @@ IntRect RenderLayerBacking::contentsBox() const bool RenderLayerBacking::paintingGoesToWindow() const { if (m_owningLayer->isRootLayer()) - return compositor()->rootLayerAttachment() != RenderLayerCompositor::RootLayerAttachedViaEnclosingIframe; + return compositor()->rootLayerAttachment() != RenderLayerCompositor::RootLayerAttachedViaEnclosingFrame; return false; } @@ -1110,9 +1205,9 @@ void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext* ASSERT(!m_owningLayer->m_usedTransparency); } -// Up-call from compositing layer drawing callback. -void RenderLayerBacking::paintContents(const GraphicsLayer* graphicsLayer, GraphicsContext& context, GraphicsLayerPaintingPhase paintingPhase, const IntRect& clip) +static void paintScrollbar(Scrollbar* scrollbar, GraphicsContext& context, const IntRect& clip) { +<<<<<<< HEAD InspectorInstrumentationCookie cookie = InspectorInstrumentation::willPaint(m_owningLayer->renderer()->frame(), clip); IntSize offset = graphicsLayer->offsetFromRenderer(); @@ -1130,11 +1225,54 @@ void RenderLayerBacking::paintContents(const GraphicsLayer* graphicsLayer, Graph dirtyRect.setSize(clip.size()); #endif dirtyRect.intersect(clipRect); +======= + if (!scrollbar) + return; +>>>>>>> WebKit.org at r84325 - // We have to use the same root as for hit testing, because both methods can compute and cache clipRects. - paintIntoLayer(m_owningLayer, &context, dirtyRect, PaintBehaviorNormal, paintingPhase, renderer()); + context.save(); + const IntRect& scrollbarRect = scrollbar->frameRect(); + context.translate(-scrollbarRect.x(), -scrollbarRect.y()); + IntRect transformedClip = clip; + transformedClip.move(scrollbarRect.x(), scrollbarRect.y()); + scrollbar->paint(&context, transformedClip); + context.restore(); +} - InspectorInstrumentation::didPaint(cookie); +// Up-call from compositing layer drawing callback. +void RenderLayerBacking::paintContents(const GraphicsLayer* graphicsLayer, GraphicsContext& context, GraphicsLayerPaintingPhase paintingPhase, const IntRect& clip) +{ + if (graphicsLayer == m_graphicsLayer.get() || graphicsLayer == m_foregroundLayer.get() || graphicsLayer == m_maskLayer.get()) { + InspectorInstrumentationCookie cookie = InspectorInstrumentation::willPaint(m_owningLayer->renderer()->frame(), clip); + + IntSize offset = graphicsLayer->offsetFromRenderer(); + context.translate(-offset); + + IntRect clipRect(clip); + clipRect.move(offset); + + // The dirtyRect is in the coords of the painting root. + IntRect dirtyRect = compositedBounds(); + dirtyRect.intersect(clipRect); + + // We have to use the same root as for hit testing, because both methods can compute and cache clipRects. + paintIntoLayer(m_owningLayer, &context, dirtyRect, PaintBehaviorNormal, paintingPhase, renderer()); + + InspectorInstrumentation::didPaint(cookie); + } else if (graphicsLayer == layerForHorizontalScrollbar()) { + paintScrollbar(m_owningLayer->horizontalScrollbar(), context, clip); + } else if (graphicsLayer == layerForVerticalScrollbar()) { + paintScrollbar(m_owningLayer->verticalScrollbar(), context, clip); + } else if (graphicsLayer == layerForScrollCorner()) { + const IntRect& scrollCornerAndResizer = m_owningLayer->scrollCornerAndResizerRect(); + context.save(); + context.translate(-scrollCornerAndResizer.x(), -scrollCornerAndResizer.y()); + IntRect transformedClip = clip; + transformedClip.move(scrollCornerAndResizer.x(), scrollCornerAndResizer.y()); + m_owningLayer->paintScrollCorner(&context, 0, 0, transformedClip); + m_owningLayer->paintResizer(&context, 0, 0, transformedClip); + context.restore(); + } } bool RenderLayerBacking::showDebugBorders() const diff --git a/Source/WebCore/rendering/RenderLayerBacking.h b/Source/WebCore/rendering/RenderLayerBacking.h index 8f0927d..f1b8972 100644 --- a/Source/WebCore/rendering/RenderLayerBacking.h +++ b/Source/WebCore/rendering/RenderLayerBacking.h @@ -69,7 +69,6 @@ public: // Update graphics layer position and bounds. void updateGraphicsLayerGeometry(); // make private // Update contents and clipping structure. - void updateInternalHierarchy(); // make private void updateDrawsContent(); GraphicsLayer* graphicsLayer() const { return m_graphicsLayer.get(); } @@ -139,6 +138,10 @@ public: void updateContentsScale(float); + GraphicsLayer* layerForHorizontalScrollbar() const { return m_layerForHorizontalScrollbar.get(); } + GraphicsLayer* layerForVerticalScrollbar() const { return m_layerForVerticalScrollbar.get(); } + GraphicsLayer* layerForScrollCorner() const { return m_layerForScrollCorner.get(); } + private: void createGraphicsLayer(); void destroyGraphicsLayer(); @@ -146,9 +149,14 @@ private: RenderBoxModelObject* renderer() const { return m_owningLayer->renderer(); } RenderLayerCompositor* compositor() const { return m_owningLayer->compositor(); } + void updateInternalHierarchy(); bool updateClippingLayers(bool needsAncestorClip, bool needsDescendantClip); + bool updateOverflowControlsLayers(bool needsHorizontalScrollbarLayer, bool needsVerticalScrollbarLayer, bool needsScrollCornerLayer); bool updateForegroundLayer(bool needsForegroundLayer); bool updateMaskLayer(bool needsMaskLayer); + bool requiresHorizontalScrollbarLayer() const; + bool requiresVerticalScrollbarLayer() const; + bool requiresScrollCornerLayer() const; GraphicsLayerPaintingPhase paintingPhaseForPrimaryLayer() const; @@ -196,6 +204,10 @@ private: OwnPtr<GraphicsLayer> m_clippingLayer; // only used if we have clipping on a stacking context, with compositing children OwnPtr<GraphicsLayer> m_maskLayer; // only used if we have a mask + OwnPtr<GraphicsLayer> m_layerForHorizontalScrollbar; + OwnPtr<GraphicsLayer> m_layerForVerticalScrollbar; + OwnPtr<GraphicsLayer> m_layerForScrollCorner; + IntRect m_compositedBounds; bool m_artificiallyInflatedBounds; // bounds had to be made non-zero to make transform-origin work diff --git a/Source/WebCore/rendering/RenderLayerCompositor.cpp b/Source/WebCore/rendering/RenderLayerCompositor.cpp index 6542ffd..03ae579 100644 --- a/Source/WebCore/rendering/RenderLayerCompositor.cpp +++ b/Source/WebCore/rendering/RenderLayerCompositor.cpp @@ -253,7 +253,7 @@ void RenderLayerCompositor::updateCompositingLayers(CompositingUpdateType update bool checkForHierarchyUpdate = m_compositingDependsOnGeometry; bool needGeometryUpdate = false; - + switch (updateType) { case CompositingUpdateAfterLayoutOrStyleChange: case CompositingUpdateOnPaitingOrHitTest: @@ -354,7 +354,7 @@ bool RenderLayerCompositor::updateBacking(RenderLayer* layer, CompositingChangeR layer->ensureBacking(); -#if PLATFORM(MAC) && PLATFORM(CA) +#if PLATFORM(MAC) && USE(CA) if (m_renderView->document()->settings()->acceleratedDrawingEnabled()) layer->backing()->graphicsLayer()->setAcceleratesDrawing(true); else if (layer->renderer()->isCanvas()) { @@ -399,8 +399,8 @@ bool RenderLayerCompositor::updateBacking(RenderLayer* layer, CompositingChangeR } #endif - if (layerChanged && layer->renderer()->isRenderIFrame()) { - RenderLayerCompositor* innerCompositor = iframeContentsCompositor(toRenderIFrame(layer->renderer())); + if (layerChanged && layer->renderer()->isRenderPart()) { + RenderLayerCompositor* innerCompositor = frameContentsCompositor(toRenderPart(layer->renderer())); if (innerCompositor && innerCompositor->inCompositingMode()) innerCompositor->updateRootLayerAttachment(); } @@ -915,9 +915,28 @@ void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, cons if (layerBacking) { bool parented = false; - if (layer->renderer()->isRenderIFrame()) - parented = parentIFrameContentLayers(toRenderIFrame(layer->renderer())); - + if (layer->renderer()->isRenderPart()) + parented = parentFrameContentLayers(toRenderPart(layer->renderer())); + + // If the layer has a clipping layer the overflow controls layers will be siblings of the clipping layer. + // Otherwise, the overflow control layers are normal children. + if (!layerBacking->hasClippingLayer()) { + if (GraphicsLayer* overflowControlLayer = layerBacking->layerForHorizontalScrollbar()) { + overflowControlLayer->removeFromParent(); + layerChildren.append(overflowControlLayer); + } + + if (GraphicsLayer* overflowControlLayer = layerBacking->layerForVerticalScrollbar()) { + overflowControlLayer->removeFromParent(); + layerChildren.append(overflowControlLayer); + } + + if (GraphicsLayer* overflowControlLayer = layerBacking->layerForScrollCorner()) { + overflowControlLayer->removeFromParent(); + layerChildren.append(overflowControlLayer); + } + } + if (!parented) layerBacking->parentForSublayers()->setChildren(layerChildren); @@ -932,15 +951,21 @@ void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, cons } } -void RenderLayerCompositor::frameViewDidChangeSize(const IntPoint& contentsOffset) +void RenderLayerCompositor::frameViewDidChangeLocation(const IntPoint& contentsOffset) +{ + if (m_overflowControlsHostLayer) + m_overflowControlsHostLayer->setPosition(contentsOffset); +} + +void RenderLayerCompositor::frameViewDidChangeSize() { if (m_clipLayer) { FrameView* frameView = m_renderView->frameView(); - m_clipLayer->setPosition(contentsOffset); - m_clipLayer->setSize(FloatSize(frameView->layoutWidth(), frameView->layoutHeight())); + m_clipLayer->setSize(frameView->visibleContentRect(false /* exclude scrollbars */).size()); IntPoint scrollPosition = frameView->scrollPosition(); m_scrollLayer->setPosition(FloatPoint(-scrollPosition.x(), -scrollPosition.y())); + updateOverflowControlsLayers(); } } @@ -963,9 +988,12 @@ String RenderLayerCompositor::layerTreeAsText(bool showDebugInfo) return m_rootPlatformLayer->layerTreeAsText(showDebugInfo ? LayerTreeAsTextDebug : LayerTreeAsTextBehaviorNormal); } -RenderLayerCompositor* RenderLayerCompositor::iframeContentsCompositor(RenderIFrame* renderer) +RenderLayerCompositor* RenderLayerCompositor::frameContentsCompositor(RenderPart* renderer) { - HTMLIFrameElement* element = static_cast<HTMLIFrameElement*>(renderer->node()); + if (!renderer->node()->isFrameOwnerElement()) + return 0; + + HTMLFrameOwnerElement* element = static_cast<HTMLFrameOwnerElement*>(renderer->node()); if (Document* contentDocument = element->contentDocument()) { if (RenderView* view = contentDocument->renderView()) return view->compositor(); @@ -973,10 +1001,10 @@ RenderLayerCompositor* RenderLayerCompositor::iframeContentsCompositor(RenderIFr return 0; } -bool RenderLayerCompositor::parentIFrameContentLayers(RenderIFrame* renderer) +bool RenderLayerCompositor::parentFrameContentLayers(RenderPart* renderer) { - RenderLayerCompositor* innerCompositor = iframeContentsCompositor(renderer); - if (!innerCompositor || !innerCompositor->inCompositingMode() || innerCompositor->rootLayerAttachment() != RootLayerAttachedViaEnclosingIframe) + RenderLayerCompositor* innerCompositor = frameContentsCompositor(renderer); + if (!innerCompositor || !innerCompositor->inCompositingMode() || innerCompositor->rootLayerAttachment() != RootLayerAttachedViaEnclosingFrame) return false; RenderLayer* layer = renderer->layer(); @@ -1146,7 +1174,9 @@ RenderLayer* RenderLayerCompositor::rootRenderLayer() const GraphicsLayer* RenderLayerCompositor::rootPlatformLayer() const { - return m_clipLayer ? m_clipLayer.get() : m_rootPlatformLayer.get(); + if (m_overflowControlsHostLayer) + return m_overflowControlsHostLayer.get(); + return m_rootPlatformLayer.get(); } void RenderLayerCompositor::didMoveOnscreen() @@ -1154,7 +1184,7 @@ void RenderLayerCompositor::didMoveOnscreen() if (!inCompositingMode() || m_rootLayerAttachment != RootLayerUnattached) return; - RootLayerAttachment attachment = shouldPropagateCompositingToEnclosingIFrame() ? RootLayerAttachedViaEnclosingIframe : RootLayerAttachedViaChromeClient; + RootLayerAttachment attachment = shouldPropagateCompositingToEnclosingFrame() ? RootLayerAttachedViaEnclosingFrame : RootLayerAttachedViaChromeClient; attachRootPlatformLayer(attachment); } @@ -1174,7 +1204,7 @@ void RenderLayerCompositor::updateRootLayerPosition() } if (m_clipLayer) { FrameView* frameView = m_renderView->frameView(); - m_clipLayer->setSize(FloatSize(frameView->layoutWidth(), frameView->layoutHeight())); + m_clipLayer->setSize(frameView->visibleContentRect(false /* exclude scrollbars */).size()); } } @@ -1192,43 +1222,52 @@ bool RenderLayerCompositor::has3DContent() const return layerHas3DContent(rootRenderLayer()); } -bool RenderLayerCompositor::allowsIndependentlyCompositedIFrames(const FrameView* view) +bool RenderLayerCompositor::allowsIndependentlyCompositedFrames(const FrameView* view) { #if PLATFORM(MAC) - // iframes are only independently composited in Mac pre-WebKit2. + // frames are only independently composited in Mac pre-WebKit2. return view->platformWidget(); #endif return false; } -bool RenderLayerCompositor::shouldPropagateCompositingToEnclosingIFrame() const +bool RenderLayerCompositor::shouldPropagateCompositingToEnclosingFrame() const { +<<<<<<< HEAD #if PLATFORM(ANDROID) if (enclosingIFrameElement() && !allowsIndependentlyCompositedIFrames(m_renderView->frameView())) return true; #endif // Parent document content needs to be able to render on top of a composited iframe, so correct behavior +======= + // Parent document content needs to be able to render on top of a composited frame, so correct behavior +>>>>>>> WebKit.org at r84325 // is to have the parent document become composited too. However, this can cause problems on platforms that // use native views for frames (like Mac), so disable that behavior on those platforms for now. - HTMLFrameOwnerElement* ownerElement = enclosingIFrameElement(); + HTMLFrameOwnerElement* ownerElement = enclosingFrameElement(); RenderObject* renderer = ownerElement ? ownerElement->renderer() : 0; - if (!renderer || !renderer->isRenderIFrame()) + + // If we are the top-level frame, don't propagate. + if (!ownerElement) return false; - if (!allowsIndependentlyCompositedIFrames(m_renderView->frameView())) + if (!allowsIndependentlyCompositedFrames(m_renderView->frameView())) return true; - // On Mac, only propagate compositing if the iframe is overlapped in the parent + if (!renderer || !renderer->isRenderPart()) + return false; + + // On Mac, only propagate compositing if the frame is overlapped in the parent // document, or the parent is already compositing, or the main frame is scaled. Frame* frame = m_renderView->frameView()->frame(); Page* page = frame ? frame->page() : 0; if (page->mainFrame()->pageScaleFactor() != 1) return true; - RenderIFrame* iframeRenderer = toRenderIFrame(renderer); - if (iframeRenderer->widget()) { - ASSERT(iframeRenderer->widget()->isFrameView()); - FrameView* view = static_cast<FrameView*>(iframeRenderer->widget()); + RenderPart* frameRenderer = toRenderPart(renderer); + if (frameRenderer->widget()) { + ASSERT(frameRenderer->widget()->isFrameView()); + FrameView* view = static_cast<FrameView*>(frameRenderer->widget()); if (view->isOverlappedIncludingAncestors() || view->hasCompositingAncestor()) return true; } @@ -1236,10 +1275,10 @@ bool RenderLayerCompositor::shouldPropagateCompositingToEnclosingIFrame() const return false; } -HTMLFrameOwnerElement* RenderLayerCompositor::enclosingIFrameElement() const +HTMLFrameOwnerElement* RenderLayerCompositor::enclosingFrameElement() const { if (HTMLFrameOwnerElement* ownerElement = m_renderView->document()->ownerElement()) - return ownerElement->hasTagName(iframeTag) ? ownerElement : 0; + return (ownerElement->hasTagName(iframeTag) || ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(objectTag)) ? ownerElement : 0; return 0; } @@ -1290,7 +1329,7 @@ bool RenderLayerCompositor::requiresCompositingLayer(const RenderLayer* layer) c || requiresCompositingForVideo(renderer) || requiresCompositingForCanvas(renderer) || requiresCompositingForPlugin(renderer) - || requiresCompositingForIFrame(renderer) + || requiresCompositingForFrame(renderer) || (canRender3DTransforms() && renderer->style()->backfaceVisibility() == BackfaceVisibilityHidden) || clipsCompositingDescendants(layer) || requiresCompositingForAnimation(renderer) @@ -1423,28 +1462,28 @@ bool RenderLayerCompositor::requiresCompositingForPlugin(RenderObject* renderer) return contentBox.height() * contentBox.width() > 1; } -bool RenderLayerCompositor::requiresCompositingForIFrame(RenderObject* renderer) const +bool RenderLayerCompositor::requiresCompositingForFrame(RenderObject* renderer) const { - if (!renderer->isRenderIFrame()) + if (!renderer->isRenderPart()) return false; - RenderIFrame* iframeRenderer = toRenderIFrame(renderer); + RenderPart* frameRenderer = toRenderPart(renderer); - if (!iframeRenderer->requiresAcceleratedCompositing()) + if (!frameRenderer->requiresAcceleratedCompositing()) return false; m_compositingDependsOnGeometry = true; - RenderLayerCompositor* innerCompositor = iframeContentsCompositor(iframeRenderer); - if (!innerCompositor->shouldPropagateCompositingToEnclosingIFrame()) + RenderLayerCompositor* innerCompositor = frameContentsCompositor(frameRenderer); + if (!innerCompositor || !innerCompositor->shouldPropagateCompositingToEnclosingFrame()) return false; // If we can't reliably know the size of the iframe yet, don't change compositing state. if (renderer->needsLayout()) - return iframeRenderer->hasLayer() && iframeRenderer->layer()->isComposited(); + return frameRenderer->hasLayer() && frameRenderer->layer()->isComposited(); // Don't go into compositing mode if height or width are zero. - IntRect contentBox = iframeRenderer->contentBoxRect(); + IntRect contentBox = frameRenderer->contentBoxRect(); return contentBox.height() * contentBox.width() > 0; } @@ -1487,12 +1526,119 @@ bool RenderLayerCompositor::requiresScrollLayer(RootLayerAttachment attachment) { // We need to handle our own scrolling if we're: return !m_renderView->frameView()->platformWidget() // viewless (i.e. non-Mac, or Mac in WebKit2) - || attachment == RootLayerAttachedViaEnclosingIframe; // a composited iframe on Mac + || attachment == RootLayerAttachedViaEnclosingFrame; // a composited frame on Mac +} + +static void paintScrollbar(Scrollbar* scrollbar, GraphicsContext& context, const IntRect& clip) +{ + if (!scrollbar) + return; + + context.save(); + const IntRect& scrollbarRect = scrollbar->frameRect(); + context.translate(-scrollbarRect.x(), -scrollbarRect.y()); + IntRect transformedClip = clip; + transformedClip.move(scrollbarRect.x(), scrollbarRect.y()); + scrollbar->paint(&context, transformedClip); + context.restore(); +} + +void RenderLayerCompositor::paintContents(const GraphicsLayer* graphicsLayer, GraphicsContext& context, GraphicsLayerPaintingPhase, const IntRect& clip) +{ + if (graphicsLayer == layerForHorizontalScrollbar()) + paintScrollbar(m_renderView->frameView()->horizontalScrollbar(), context, clip); + else if (graphicsLayer == layerForVerticalScrollbar()) + paintScrollbar(m_renderView->frameView()->verticalScrollbar(), context, clip); + else if (graphicsLayer == layerForScrollCorner()) { + const IntRect& scrollCorner = m_renderView->frameView()->scrollCornerRect(); + context.save(); + context.translate(-scrollCorner.x(), -scrollCorner.y()); + IntRect transformedClip = clip; + transformedClip.move(scrollCorner.x(), scrollCorner.y()); + m_renderView->frameView()->paintScrollCorner(&context, transformedClip); + context.restore(); + } +} + +static bool shouldCompositeOverflowControls(ScrollView* view) +{ + if (view->platformWidget()) + return false; +#if !PLATFORM(CHROMIUM) + if (!view->hasOverlayScrollbars()) + return false; +#endif + return true; +} + +bool RenderLayerCompositor::requiresHorizontalScrollbarLayer() const +{ + ScrollView* view = m_renderView->frameView(); + return shouldCompositeOverflowControls(view) && view->horizontalScrollbar(); +} + +bool RenderLayerCompositor::requiresVerticalScrollbarLayer() const +{ + ScrollView* view = m_renderView->frameView(); + return shouldCompositeOverflowControls(view) && view->verticalScrollbar(); +} + +bool RenderLayerCompositor::requiresScrollCornerLayer() const +{ + ScrollView* view = m_renderView->frameView(); + return shouldCompositeOverflowControls(view) && view->isScrollCornerVisible(); +} + +void RenderLayerCompositor::updateOverflowControlsLayers() +{ + bool layersChanged = false; + + if (requiresHorizontalScrollbarLayer()) { + m_layerForHorizontalScrollbar = GraphicsLayer::create(this); +#ifndef NDEBUG + m_layerForHorizontalScrollbar->setName("horizontal scrollbar"); +#endif + m_overflowControlsHostLayer->addChild(m_layerForHorizontalScrollbar.get()); + layersChanged = true; + } else if (m_layerForHorizontalScrollbar) { + m_layerForHorizontalScrollbar->removeFromParent(); + m_layerForHorizontalScrollbar = 0; + layersChanged = true; + } + + if (requiresVerticalScrollbarLayer()) { + m_layerForVerticalScrollbar = GraphicsLayer::create(this); +#ifndef NDEBUG + m_layerForVerticalScrollbar->setName("vertical scrollbar"); +#endif + m_overflowControlsHostLayer->addChild(m_layerForVerticalScrollbar.get()); + layersChanged = true; + } else if (m_layerForVerticalScrollbar) { + m_layerForVerticalScrollbar->removeFromParent(); + m_layerForVerticalScrollbar = 0; + layersChanged = true; + } + + if (requiresScrollCornerLayer()) { + m_layerForScrollCorner = GraphicsLayer::create(this); +#ifndef NDEBUG + m_layerForScrollCorner->setName("scroll corner"); +#endif + m_overflowControlsHostLayer->addChild(m_layerForScrollCorner.get()); + layersChanged = true; + } else if (m_layerForScrollCorner) { + m_layerForScrollCorner->removeFromParent(); + m_layerForScrollCorner = 0; + layersChanged = true; + } + + if (layersChanged) + m_renderView->frameView()->positionScrollbarLayers(); } void RenderLayerCompositor::ensureRootPlatformLayer() { - RootLayerAttachment expectedAttachment = shouldPropagateCompositingToEnclosingIFrame() ? RootLayerAttachedViaEnclosingIframe : RootLayerAttachedViaChromeClient; + RootLayerAttachment expectedAttachment = shouldPropagateCompositingToEnclosingFrame() ? RootLayerAttachedViaEnclosingFrame : RootLayerAttachedViaChromeClient; if (expectedAttachment == m_rootLayerAttachment) return; @@ -1509,8 +1655,16 @@ void RenderLayerCompositor::ensureRootPlatformLayer() } if (requiresScrollLayer(expectedAttachment)) { - if (!m_clipLayer) { + if (!m_overflowControlsHostLayer) { ASSERT(!m_scrollLayer); + ASSERT(!m_clipLayer); + + // Create a layer to host the clipping layer and the overflow controls layers. + m_overflowControlsHostLayer = GraphicsLayer::create(0); +#ifndef NDEBUG + m_overflowControlsHostLayer->setName("overflow controls host"); +#endif + // Create a clipping layer if this is an iframe m_clipLayer = GraphicsLayer::create(this); #ifndef NDEBUG @@ -1522,20 +1676,19 @@ void RenderLayerCompositor::ensureRootPlatformLayer() #ifndef NDEBUG m_scrollLayer->setName("iframe scrolling"); #endif + // Hook them up + m_overflowControlsHostLayer->addChild(m_clipLayer.get()); m_clipLayer->addChild(m_scrollLayer.get()); m_scrollLayer->addChild(m_rootPlatformLayer.get()); - + frameViewDidChangeSize(); frameViewDidScroll(m_renderView->frameView()->scrollPosition()); } } else { - if (m_clipLayer) { - m_clipLayer->removeAllChildren(); - m_clipLayer->removeFromParent(); + if (m_overflowControlsHostLayer) { + m_overflowControlsHostLayer = 0; m_clipLayer = 0; - - m_scrollLayer->removeAllChildren(); m_scrollLayer = 0; } } @@ -1553,11 +1706,29 @@ void RenderLayerCompositor::destroyRootPlatformLayer() return; detachRootPlatformLayer(); - if (m_clipLayer) { - m_clipLayer->removeAllChildren(); + + if (m_layerForHorizontalScrollbar) { + m_layerForHorizontalScrollbar->removeFromParent(); + m_layerForHorizontalScrollbar = 0; + if (Scrollbar* horizontalScrollbar = m_renderView->frameView()->verticalScrollbar()) + m_renderView->frameView()->invalidateScrollbar(horizontalScrollbar, IntRect(IntPoint(0, 0), horizontalScrollbar->frameRect().size())); + } + + if (m_layerForVerticalScrollbar) { + m_layerForVerticalScrollbar->removeFromParent(); + m_layerForVerticalScrollbar = 0; + if (Scrollbar* verticalScrollbar = m_renderView->frameView()->verticalScrollbar()) + m_renderView->frameView()->invalidateScrollbar(verticalScrollbar, IntRect(IntPoint(0, 0), verticalScrollbar->frameRect().size())); + } + + if (m_layerForScrollCorner) { + m_layerForScrollCorner = 0; + m_renderView->frameView()->invalidateScrollCorner(); + } + + if (m_overflowControlsHostLayer) { + m_overflowControlsHostLayer = 0; m_clipLayer = 0; - - m_scrollLayer->removeAllChildren(); m_scrollLayer = 0; } ASSERT(!m_scrollLayer); @@ -1582,9 +1753,9 @@ void RenderLayerCompositor::attachRootPlatformLayer(RootLayerAttachment attachme page->chrome()->client()->attachRootGraphicsLayer(frame, rootPlatformLayer()); break; } - case RootLayerAttachedViaEnclosingIframe: { + case RootLayerAttachedViaEnclosingFrame: { // The layer will get hooked up via RenderLayerBacking::updateGraphicsLayerConfiguration() - // for the iframe's renderer in the parent document. + // for the frame's renderer in the parent document. scheduleNeedsStyleRecalc(m_renderView->document()->ownerElement()); break; } @@ -1600,29 +1771,29 @@ void RenderLayerCompositor::detachRootPlatformLayer() return; switch (m_rootLayerAttachment) { - case RootLayerAttachedViaEnclosingIframe: { - // The layer will get unhooked up via RenderLayerBacking::updateGraphicsLayerConfiguration() - // for the iframe's renderer in the parent document. - if (m_clipLayer) - m_clipLayer->removeFromParent(); - else - m_rootPlatformLayer->removeFromParent(); - - if (HTMLFrameOwnerElement* ownerElement = m_renderView->document()->ownerElement()) - scheduleNeedsStyleRecalc(ownerElement); - break; - } - case RootLayerAttachedViaChromeClient: { - Frame* frame = m_renderView->frameView()->frame(); - Page* page = frame ? frame->page() : 0; - if (!page) - return; + case RootLayerAttachedViaEnclosingFrame: { + // The layer will get unhooked up via RenderLayerBacking::updateGraphicsLayerConfiguration() + // for the frame's renderer in the parent document. + if (m_overflowControlsHostLayer) + m_overflowControlsHostLayer->removeFromParent(); + else + m_rootPlatformLayer->removeFromParent(); + + if (HTMLFrameOwnerElement* ownerElement = m_renderView->document()->ownerElement()) + scheduleNeedsStyleRecalc(ownerElement); + break; + } + case RootLayerAttachedViaChromeClient: { + Frame* frame = m_renderView->frameView()->frame(); + Page* page = frame ? frame->page() : 0; + if (!page) + return; - page->chrome()->client()->attachRootGraphicsLayer(frame, 0); - } + page->chrome()->client()->attachRootGraphicsLayer(frame, 0); + } + break; + case RootLayerUnattached: break; - case RootLayerUnattached: - break; } m_rootLayerAttachment = RootLayerUnattached; diff --git a/Source/WebCore/rendering/RenderLayerCompositor.h b/Source/WebCore/rendering/RenderLayerCompositor.h index c3deb3f..0315050 100644 --- a/Source/WebCore/rendering/RenderLayerCompositor.h +++ b/Source/WebCore/rendering/RenderLayerCompositor.h @@ -36,7 +36,7 @@ namespace WebCore { class GraphicsLayer; class RenderEmbeddedObject; -class RenderIFrame; +class RenderPart; #if ENABLE(VIDEO) class RenderVideo; #endif @@ -138,7 +138,7 @@ public: enum RootLayerAttachment { RootLayerUnattached, RootLayerAttachedViaChromeClient, - RootLayerAttachedViaEnclosingIframe + RootLayerAttachedViaEnclosingFrame }; RootLayerAttachment rootLayerAttachment() const { return m_rootLayerAttachment; } @@ -161,18 +161,18 @@ public: // Most platforms connect compositing layer trees between iframes and their parent document. // Some (currently just Mac) allow iframes to do their own compositing. - static bool allowsIndependentlyCompositedIFrames(const FrameView*); - bool shouldPropagateCompositingToEnclosingIFrame() const; + static bool allowsIndependentlyCompositedFrames(const FrameView*); + bool shouldPropagateCompositingToEnclosingFrame() const; - // FIXME: This should be a RenderIFrame* - HTMLFrameOwnerElement* enclosingIFrameElement() const; + HTMLFrameOwnerElement* enclosingFrameElement() const; - static RenderLayerCompositor* iframeContentsCompositor(RenderIFrame*); + static RenderLayerCompositor* frameContentsCompositor(RenderPart*); // Return true if the layers changed. - static bool parentIFrameContentLayers(RenderIFrame*); + static bool parentFrameContentLayers(RenderPart*); // Update the geometry of the layers used for clipping and scrolling in frames. - void frameViewDidChangeSize(const IntPoint& contentsOffset = IntPoint()); + void frameViewDidChangeLocation(const IntPoint& contentsOffset); + void frameViewDidChangeSize(); void frameViewDidScroll(const IntPoint& = IntPoint()); String layerTreeAsText(bool showDebugInfo = false); @@ -184,11 +184,15 @@ public: void updateContentsScale(float, RenderLayer* = 0); + GraphicsLayer* layerForHorizontalScrollbar() const { return m_layerForHorizontalScrollbar.get(); } + GraphicsLayer* layerForVerticalScrollbar() const { return m_layerForVerticalScrollbar.get(); } + GraphicsLayer* layerForScrollCorner() const { return m_layerForScrollCorner.get(); } + private: // GraphicsLayerClient Implementation virtual void notifyAnimationStarted(const GraphicsLayer*, double) { } virtual void notifySyncRequired(const GraphicsLayer*) { scheduleLayerFlush(); } - virtual void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const IntRect&) { } + virtual void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const IntRect&); // These calls return false always. They are saying that the layers associated with this client // (the clipLayer and scrollLayer) should never show debugging info. @@ -236,7 +240,9 @@ private: void detachRootPlatformLayer(); void rootLayerAttachmentChanged(); - + + void updateOverflowControlsLayers(); + void scheduleNeedsStyleRecalc(Element*); void notifyIFramesOfCompositingChange(); @@ -246,7 +252,7 @@ private: bool requiresCompositingForVideo(RenderObject*) const; bool requiresCompositingForCanvas(RenderObject*) const; bool requiresCompositingForPlugin(RenderObject*) const; - bool requiresCompositingForIFrame(RenderObject*) const; + bool requiresCompositingForFrame(RenderObject*) const; bool requiresCompositingWhenDescendantsAreCompositing(RenderObject*) const; bool requiresCompositingForFullScreen(RenderObject*) const; @@ -256,7 +262,10 @@ private: #endif bool requiresScrollLayer(RootLayerAttachment) const; - + bool requiresHorizontalScrollbarLayer() const; + bool requiresVerticalScrollbarLayer() const; + bool requiresScrollCornerLayer() const; + private: RenderView* m_renderView; OwnPtr<GraphicsLayer> m_rootPlatformLayer; @@ -284,7 +293,14 @@ private: // Enclosing clipping layer for iframe content OwnPtr<GraphicsLayer> m_clipLayer; OwnPtr<GraphicsLayer> m_scrollLayer; - + + // Enclosing layer for overflow controls and the clipping layer + OwnPtr<GraphicsLayer> m_overflowControlsHostLayer; + + // Layers for overflow controls + OwnPtr<GraphicsLayer> m_layerForHorizontalScrollbar; + OwnPtr<GraphicsLayer> m_layerForVerticalScrollbar; + OwnPtr<GraphicsLayer> m_layerForScrollCorner; #if PROFILE_LAYER_REBUILD int m_rootLayerUpdateCount; #endif diff --git a/Source/WebCore/rendering/RenderLineBoxList.cpp b/Source/WebCore/rendering/RenderLineBoxList.cpp index 9a40baf..32f133c 100644 --- a/Source/WebCore/rendering/RenderLineBoxList.cpp +++ b/Source/WebCore/rendering/RenderLineBoxList.cpp @@ -177,10 +177,12 @@ bool RenderLineBoxList::anyLineIntersectsRect(RenderBoxModelObject* renderer, co // intersect. This is a quick short-circuit that we can take to avoid walking any lines. // FIXME: This check is flawed in the following extremely obscure way: // if some line in the middle has a huge overflow, it might actually extend below the last line. - int firstLineTop = firstLineBox()->logicalTopVisualOverflow(); + RootInlineBox* firstRootBox = firstLineBox()->root(); + RootInlineBox* lastRootBox = lastLineBox()->root(); + int firstLineTop = firstLineBox()->logicalTopVisualOverflow(firstRootBox->lineTop()); if (usePrintRect && !firstLineBox()->parent()) firstLineTop = min(firstLineTop, firstLineBox()->root()->lineTop()); - int lastLineBottom = lastLineBox()->logicalBottomVisualOverflow(); + int lastLineBottom = lastLineBox()->logicalBottomVisualOverflow(lastRootBox->lineBottom()); if (usePrintRect && !lastLineBox()->parent()) lastLineBottom = max(lastLineBottom, lastLineBox()->root()->lineBottom()); int logicalTop = firstLineTop - outlineSize; @@ -191,8 +193,9 @@ bool RenderLineBoxList::anyLineIntersectsRect(RenderBoxModelObject* renderer, co bool RenderLineBoxList::lineIntersectsDirtyRect(RenderBoxModelObject* renderer, InlineFlowBox* box, const PaintInfo& paintInfo, int tx, int ty) const { - int logicalTop = min(box->logicalTopVisualOverflow(), box->root()->selectionTop()) - renderer->maximalOutlineSize(paintInfo.phase); - int logicalBottom = box->logicalBottomVisualOverflow() + renderer->maximalOutlineSize(paintInfo.phase); + RootInlineBox* root = box->root(); + int logicalTop = min(box->logicalTopVisualOverflow(root->lineTop()), root->selectionTop()) - renderer->maximalOutlineSize(paintInfo.phase); + int logicalBottom = box->logicalBottomVisualOverflow(root->lineBottom()) + renderer->maximalOutlineSize(paintInfo.phase); return rangeIntersectsRect(renderer, logicalTop, logicalBottom, paintInfo.rect, tx, ty); } @@ -231,17 +234,18 @@ 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->minYVisualOverflow(); - int bottomForPaginationCheck = curr->maxYVisualOverflow(); + RootInlineBox* root = curr->root(); + int topForPaginationCheck = curr->logicalTopVisualOverflow(root->lineTop()); + int bottomForPaginationCheck = curr->logicalLeftVisualOverflow(); 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()); + topForPaginationCheck = min(topForPaginationCheck, root->lineTop()); + bottomForPaginationCheck = max(bottomForPaginationCheck, root->lineBottom()); } if (bottomForPaginationCheck - topForPaginationCheck <= v->printRect().height()) { if (ty + bottomForPaginationCheck > v->printRect().maxY()) { if (RootInlineBox* nextRootBox = curr->root()->nextRootBox()) - bottomForPaginationCheck = min(bottomForPaginationCheck, min(nextRootBox->minYVisualOverflow(), nextRootBox->lineTop())); + bottomForPaginationCheck = min(bottomForPaginationCheck, min(nextRootBox->logicalTopVisualOverflow(), nextRootBox->lineTop())); } if (ty + bottomForPaginationCheck > v->printRect().maxY()) { if (ty + topForPaginationCheck < v->truncatedAt()) @@ -253,8 +257,10 @@ void RenderLineBoxList::paint(RenderBoxModelObject* renderer, PaintInfo& paintIn } } - if (lineIntersectsDirtyRect(renderer, curr, info, tx, ty)) - curr->paint(info, tx, ty); + if (lineIntersectsDirtyRect(renderer, curr, info, tx, ty)) { + RootInlineBox* root = curr->root(); + curr->paint(info, tx, ty, root->lineTop(), root->lineBottom()); + } } if (info.phase == PaintPhaseOutline || info.phase == PaintPhaseSelfOutline || info.phase == PaintPhaseChildOutlines) { @@ -293,8 +299,9 @@ bool RenderLineBoxList::hitTest(RenderBoxModelObject* renderer, const HitTestReq // them further. Note that boxes can easily overlap, so we can't make any assumptions // based off positions of our first line box or our last line box. for (InlineFlowBox* curr = lastLineBox(); curr; curr = curr->prevLineBox()) { - if (rangeIntersectsRect(renderer, curr->logicalTopVisualOverflow(), curr->logicalBottomVisualOverflow(), rect, tx, ty)) { - bool inside = curr->nodeAtPoint(request, result, x, y, tx, ty); + RootInlineBox* root = curr->root(); + if (rangeIntersectsRect(renderer, curr->logicalTopVisualOverflow(root->lineTop()), curr->logicalBottomVisualOverflow(root->lineBottom()), rect, tx, ty)) { + bool inside = curr->nodeAtPoint(request, result, x, y, tx, ty, root->lineTop(), root->lineBottom()); if (inside) { renderer->updateHitTestResult(result, IntPoint(x - tx, y - ty)); return true; @@ -310,8 +317,11 @@ void RenderLineBoxList::dirtyLinesFromChangedChild(RenderObject* container, Rend if (!container->parent() || (container->isRenderBlock() && (container->selfNeedsLayout() || !container->isBlockFlow()))) return; + RenderInline* inlineContainer = container->isRenderInline() ? toRenderInline(container) : 0; + InlineBox* firstBox = inlineContainer ? inlineContainer->firstLineBoxIncludingCulling() : firstLineBox(); + // If we have no first line box, then just bail early. - if (!firstLineBox()) { + if (!firstBox) { // For an empty inline, go ahead and propagate the check up to our parent, unless the parent // is already dirty. if (container->isInline() && !container->parent()->selfNeedsLayout()) @@ -337,16 +347,16 @@ void RenderLineBoxList::dirtyLinesFromChangedChild(RenderObject* container, Rend if (textBox) box = textBox->root(); } else if (curr->isRenderInline()) { - InlineFlowBox* flowBox = toRenderInline(curr)->lastLineBox(); - if (flowBox) - box = flowBox->root(); + InlineBox* lastSiblingBox = toRenderInline(curr)->lastLineBoxIncludingCulling(); + if (lastSiblingBox) + box = lastSiblingBox->root(); } if (box) break; } if (!box) - box = firstLineBox()->root(); + box = firstBox->root(); // If we found a line box, then dirty it. if (box) { diff --git a/Source/WebCore/rendering/RenderListBox.cpp b/Source/WebCore/rendering/RenderListBox.cpp index ab3a832..d7798d5 100644 --- a/Source/WebCore/rendering/RenderListBox.cpp +++ b/Source/WebCore/rendering/RenderListBox.cpp @@ -273,14 +273,28 @@ void RenderListBox::paintObject(PaintInfo& paintInfo, int tx, int ty) // Paint the children. RenderBlock::paintObject(paintInfo, tx, ty); - if (paintInfo.phase == PaintPhaseBlockBackground) - paintScrollbar(paintInfo, tx, ty); - else if (paintInfo.phase == PaintPhaseChildBlockBackground || paintInfo.phase == PaintPhaseChildBlockBackgrounds) { + switch (paintInfo.phase) { + // Depending on whether we have overlay scrollbars they + // get rendered in the foreground or background phases + case PaintPhaseForeground: + if (m_vBar->isOverlayScrollbar()) + paintScrollbar(paintInfo, tx, ty); + break; + case PaintPhaseBlockBackground: + if (!m_vBar->isOverlayScrollbar()) + paintScrollbar(paintInfo, tx, ty); + break; + case PaintPhaseChildBlockBackground: + case PaintPhaseChildBlockBackgrounds: { int index = m_indexOffset; while (index < listItemsSize && index <= m_indexOffset + numVisibleItems()) { paintItemBackground(paintInfo, tx, ty, index); index++; } + break; + } + default: + break; } } @@ -599,7 +613,7 @@ void RenderListBox::scrollTo(int newOffset) m_indexOffset = newOffset; repaint(); - node()->document()->eventQueue()->enqueueScrollEvent(node(), EventQueue::ScrollEventElementTarget); + node()->document()->eventQueue()->enqueueOrDispatchScrollEvent(node(), EventQueue::ScrollEventElementTarget); } int RenderListBox::itemHeight() const diff --git a/Source/WebCore/rendering/RenderListBox.h b/Source/WebCore/rendering/RenderListBox.h index 0e2cfd6..d2de4a5 100644 --- a/Source/WebCore/rendering/RenderListBox.h +++ b/Source/WebCore/rendering/RenderListBox.h @@ -53,6 +53,8 @@ public: int scrollToward(const IntPoint&); // Returns the new index or -1 if no scroll occurred + int size() const; + private: virtual const char* renderName() const { return "RenderListBox"; } @@ -102,7 +104,9 @@ private: virtual void setScrollOffset(const IntPoint&); virtual void invalidateScrollbarRect(Scrollbar*, const IntRect&); virtual bool isActive() const; - virtual bool scrollbarCornerPresent() const { return false; } // We don't support resize on list boxes yet. If we did this would have to change. + virtual bool isScrollCornerVisible() const { return false; } // We don't support resize on list boxes yet. If we did these would have to change. + virtual IntRect scrollCornerRect() const { return IntRect(); } + virtual void invalidateScrollCornerRect(const IntRect&) { } virtual IntRect convertFromScrollbarToContainingView(const Scrollbar*, const IntRect&) const; virtual IntRect convertFromContainingViewToScrollbar(const Scrollbar*, const IntRect&) const; virtual IntPoint convertFromScrollbarToContainingView(const Scrollbar*, const IntPoint&) const; @@ -125,7 +129,6 @@ private: int itemHeight() const; void valueChanged(unsigned listIndex); - int size() const; int numVisibleItems() const; int numItems() const; int listHeight() const; diff --git a/Source/WebCore/rendering/RenderListItem.cpp b/Source/WebCore/rendering/RenderListItem.cpp index 5cfb522..eaf68e6 100644 --- a/Source/WebCore/rendering/RenderListItem.cpp +++ b/Source/WebCore/rendering/RenderListItem.cpp @@ -264,6 +264,10 @@ void RenderListItem::positionListMarker() int markerLogicalLeft; RootInlineBox* root = m_marker->inlineBoxWrapper()->root(); bool hitSelfPaintingLayer = false; + + RootInlineBox* rootBox = m_marker->inlineBoxWrapper()->root(); + int lineTop = rootBox->lineTop(); + int lineBottom = rootBox->lineBottom(); // FIXME: Need to account for relative positioning in the layout overflow. if (style()->isLeftToRightDirection()) { @@ -271,21 +275,21 @@ void RenderListItem::positionListMarker() markerLogicalLeft = leftLineOffset - lineOffset - paddingStart() - borderStart() + m_marker->marginStart(); m_marker->inlineBoxWrapper()->adjustLineDirectionPosition(markerLogicalLeft - markerOldLogicalLeft); for (InlineFlowBox* box = m_marker->inlineBoxWrapper()->parent(); box; box = box->parent()) { - IntRect newLogicalVisualOverflowRect = box->logicalVisualOverflowRect(); - IntRect newLogicalLayoutOverflowRect = box->logicalLayoutOverflowRect(); + IntRect newLogicalVisualOverflowRect = box->logicalVisualOverflowRect(lineTop, lineBottom); + IntRect newLogicalLayoutOverflowRect = box->logicalLayoutOverflowRect(lineTop, lineBottom); if (markerLogicalLeft < newLogicalVisualOverflowRect.x() && !hitSelfPaintingLayer) { + newLogicalVisualOverflowRect.setWidth(newLogicalVisualOverflowRect.maxX() - markerLogicalLeft); newLogicalVisualOverflowRect.setX(markerLogicalLeft); - newLogicalVisualOverflowRect.setWidth(box->logicalRightVisualOverflow() - newLogicalVisualOverflowRect.x()); if (box == root) adjustOverflow = true; } if (markerLogicalLeft < newLogicalLayoutOverflowRect.x()) { + newLogicalLayoutOverflowRect.setWidth(newLogicalLayoutOverflowRect.maxX() - markerLogicalLeft); newLogicalLayoutOverflowRect.setX(markerLogicalLeft); - newLogicalLayoutOverflowRect.setWidth(box->logicalRightLayoutOverflow() - newLogicalLayoutOverflowRect.x()); if (box == root) adjustOverflow = true; } - box->setOverflowFromLogicalRects(newLogicalLayoutOverflowRect, newLogicalVisualOverflowRect); + box->setOverflowFromLogicalRects(newLogicalLayoutOverflowRect, newLogicalVisualOverflowRect, lineTop, lineBottom); if (box->boxModelObject()->hasSelfPaintingLayer()) hitSelfPaintingLayer = true; } @@ -295,19 +299,19 @@ void RenderListItem::positionListMarker() markerLogicalLeft = rightLineOffset - lineOffset + paddingStart() + borderStart() + m_marker->marginEnd(); m_marker->inlineBoxWrapper()->adjustLineDirectionPosition(markerLogicalLeft - markerOldLogicalLeft); for (InlineFlowBox* box = m_marker->inlineBoxWrapper()->parent(); box; box = box->parent()) { - IntRect newLogicalVisualOverflowRect = box->logicalVisualOverflowRect(); - IntRect newLogicalLayoutOverflowRect = box->logicalLayoutOverflowRect(); + IntRect newLogicalVisualOverflowRect = box->logicalVisualOverflowRect(lineTop, lineBottom); + IntRect newLogicalLayoutOverflowRect = box->logicalLayoutOverflowRect(lineTop, lineBottom); if (markerLogicalLeft + m_marker->logicalWidth() > newLogicalVisualOverflowRect.maxX() && !hitSelfPaintingLayer) { - newLogicalVisualOverflowRect.setWidth(markerLogicalLeft + m_marker->logicalWidth() - box->logicalLeftVisualOverflow()); + newLogicalVisualOverflowRect.setWidth(markerLogicalLeft + m_marker->logicalWidth() - newLogicalVisualOverflowRect.x()); if (box == root) adjustOverflow = true; } if (markerLogicalLeft + m_marker->logicalWidth() > newLogicalLayoutOverflowRect.maxX()) { - newLogicalLayoutOverflowRect.setWidth(markerLogicalLeft + m_marker->logicalWidth() - box->logicalLeftLayoutOverflow()); + newLogicalLayoutOverflowRect.setWidth(markerLogicalLeft + m_marker->logicalWidth() - newLogicalLayoutOverflowRect.x()); if (box == root) adjustOverflow = true; } - box->setOverflowFromLogicalRects(newLogicalLayoutOverflowRect, newLogicalVisualOverflowRect); + box->setOverflowFromLogicalRects(newLogicalLayoutOverflowRect, newLogicalVisualOverflowRect, lineTop, lineBottom); if (box->boxModelObject()->hasSelfPaintingLayer()) hitSelfPaintingLayer = true; diff --git a/Source/WebCore/rendering/RenderMedia.cpp b/Source/WebCore/rendering/RenderMedia.cpp index 69d71ec..3f56865 100644 --- a/Source/WebCore/rendering/RenderMedia.cpp +++ b/Source/WebCore/rendering/RenderMedia.cpp @@ -29,22 +29,18 @@ #include "RenderMedia.h" #include "HTMLMediaElement.h" -#include "MediaControlElements.h" -#include "MediaControls.h" #include "RenderView.h" namespace WebCore { RenderMedia::RenderMedia(HTMLMediaElement* video) : RenderImage(video) - , m_controls(new MediaControls(video)) { setImageResource(RenderImageResource::create()); } RenderMedia::RenderMedia(HTMLMediaElement* video, const IntSize& intrinsicSize) : RenderImage(video) - , m_controls(new MediaControls(video)) { setImageResource(RenderImageResource::create()); setIntrinsicSize(intrinsicSize); @@ -54,32 +50,21 @@ RenderMedia::~RenderMedia() { } -void RenderMedia::destroy() -{ - m_controls->destroy(); - RenderImage::destroy(); -} - HTMLMediaElement* RenderMedia::mediaElement() const { return static_cast<HTMLMediaElement*>(node()); } -void RenderMedia::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) -{ - RenderImage::styleDidChange(diff, oldStyle); - m_controls->updateStyle(); -} - void RenderMedia::layout() { IntSize oldSize = contentBoxRect().size(); RenderImage::layout(); - RenderBox* controlsRenderer = m_controls->renderBox(); + RenderBox* controlsRenderer = toRenderBox(m_children.firstChild()); if (!controlsRenderer) return; + IntSize newSize = contentBoxRect().size(); if (newSize == oldSize && !controlsRenderer->needsLayout()) return; @@ -99,11 +84,6 @@ void RenderMedia::layout() statePusher.pop(); } -void RenderMedia::updateFromElement() -{ - m_controls->update(); -} - } // namespace WebCore #endif diff --git a/Source/WebCore/rendering/RenderMedia.h b/Source/WebCore/rendering/RenderMedia.h index 7658ef6..78e36c4 100644 --- a/Source/WebCore/rendering/RenderMedia.h +++ b/Source/WebCore/rendering/RenderMedia.h @@ -33,7 +33,6 @@ namespace WebCore { class HTMLMediaElement; -class MediaControls; class RenderMedia : public RenderImage { public: @@ -45,9 +44,6 @@ public: RenderObjectChildList* children() { return &m_children; } HTMLMediaElement* mediaElement() const; - MediaControls* controls() const; - - virtual void updateFromElement(); protected: virtual void layout(); @@ -56,18 +52,12 @@ private: virtual RenderObjectChildList* virtualChildren() { return children(); } virtual const RenderObjectChildList* virtualChildren() const { return children(); } - virtual void destroy(); - virtual const char* renderName() const { return "RenderMedia"; } virtual bool isMedia() const { return true; } virtual bool isImage() const { return false; } - - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); - virtual bool requiresForcedStyleRecalcPropagation() const { return true; } - OwnPtr<MediaControls> m_controls; RenderObjectChildList m_children; }; @@ -77,11 +67,6 @@ 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/RenderMediaControls.cpp b/Source/WebCore/rendering/RenderMediaControls.cpp index dd58cd2..928b5b8 100644 --- a/Source/WebCore/rendering/RenderMediaControls.cpp +++ b/Source/WebCore/rendering/RenderMediaControls.cpp @@ -32,6 +32,7 @@ #include "GraphicsContext.h" #include "HTMLMediaElement.h" #include "HTMLNames.h" +#include "PaintInfo.h" #include "RenderTheme.h" // FIXME: Unify more of the code for Mac and Win. diff --git a/Source/WebCore/rendering/RenderMediaControlsChromium.cpp b/Source/WebCore/rendering/RenderMediaControlsChromium.cpp index 71fca91..40ee9b0 100644 --- a/Source/WebCore/rendering/RenderMediaControlsChromium.cpp +++ b/Source/WebCore/rendering/RenderMediaControlsChromium.cpp @@ -242,28 +242,6 @@ static bool paintMediaTimelineContainer(RenderObject* object, const PaintInfo& p return true; } -bool RenderMediaControlsChromium::shouldRenderMediaControlPart(ControlPart part, Element* e) -{ - UNUSED_PARAM(e); - - switch (part) { - case MediaMuteButtonPart: - case MediaPlayButtonPart: - case MediaSliderPart: - case MediaSliderThumbPart: - case MediaVolumeSliderContainerPart: - case MediaVolumeSliderPart: - case MediaVolumeSliderThumbPart: - case MediaControlsBackgroundPart: - case MediaCurrentTimePart: - case MediaTimeRemainingPart: - return true; - default: - ; - } - return false; -} - bool RenderMediaControlsChromium::paintMediaControlsPart(MediaControlElementType part, RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect) { switch (part) { diff --git a/Source/WebCore/rendering/RenderMediaControlsChromium.h b/Source/WebCore/rendering/RenderMediaControlsChromium.h index 060a9d4..895ac43 100644 --- a/Source/WebCore/rendering/RenderMediaControlsChromium.h +++ b/Source/WebCore/rendering/RenderMediaControlsChromium.h @@ -36,7 +36,6 @@ namespace WebCore { class HTMLMediaElement; class RenderMediaControlsChromium { public: - static bool shouldRenderMediaControlPart(ControlPart, Element*); static bool paintMediaControlsPart(MediaControlElementType, RenderObject*, const PaintInfo&, const IntRect&); static void adjustMediaSliderThumbSize(RenderObject*); }; diff --git a/Source/WebCore/rendering/RenderMeter.cpp b/Source/WebCore/rendering/RenderMeter.cpp index f3ada0b..683bcc4 100644 --- a/Source/WebCore/rendering/RenderMeter.cpp +++ b/Source/WebCore/rendering/RenderMeter.cpp @@ -35,98 +35,13 @@ namespace WebCore { using namespace HTMLNames; -class MeterPartElement : public ShadowBlockElement { -public: - static PassRefPtr<MeterPartElement> createForPart(HTMLElement*, PseudoId); - - void hide(); - void restoreVisibility(); - - virtual void updateStyleForPart(PseudoId); - -private: - MeterPartElement(HTMLElement*); - void saveVisibility(); - - EVisibility m_originalVisibility; -}; - -MeterPartElement::MeterPartElement(HTMLElement* shadowParent) - : ShadowBlockElement(shadowParent) -{ -} - -PassRefPtr<MeterPartElement> MeterPartElement::createForPart(HTMLElement* shadowParent, PseudoId pseudoId) -{ - RefPtr<MeterPartElement> ret = adoptRef(new MeterPartElement(shadowParent)); - ret->initAsPart(pseudoId); - ret->saveVisibility(); - return ret; -} - -void MeterPartElement::hide() -{ - if (renderer()) - renderer()->style()->setVisibility(HIDDEN); -} - -void MeterPartElement::restoreVisibility() -{ - if (renderer()) - renderer()->style()->setVisibility(m_originalVisibility); -} - -void MeterPartElement::updateStyleForPart(PseudoId pseudoId) -{ - if (renderer()->style()->styleType() == pseudoId) - return; - - ShadowBlockElement::updateStyleForPart(pseudoId); - saveVisibility(); -} - -void MeterPartElement::saveVisibility() -{ - m_originalVisibility = renderer()->style()->visibility(); -} - RenderMeter::RenderMeter(HTMLMeterElement* element) - : RenderIndicator(element) + : RenderBlock(element) { } RenderMeter::~RenderMeter() { - if (shadowAttached()) { - m_verticalValuePart->detach(); - m_verticalBarPart->detach(); - m_horizontalValuePart->detach(); - m_horizontalBarPart->detach(); - } -} - -PassRefPtr<MeterPartElement> RenderMeter::createPart(PseudoId pseudoId) -{ - RefPtr<MeterPartElement> element = MeterPartElement::createForPart(toHTMLElement(node()), pseudoId); - if (element->renderer()) - addChild(element->renderer()); - return element; -} - -void RenderMeter::updateFromElement() -{ - if (!shadowAttached()) { - m_horizontalBarPart = createPart(barPseudoId(HORIZONTAL)); - m_horizontalValuePart = createPart(valuePseudoId(HORIZONTAL)); - m_verticalBarPart = createPart(barPseudoId(VERTICAL)); - m_verticalValuePart = createPart(valuePseudoId(VERTICAL)); - } - - m_horizontalBarPart->updateStyleForPart(barPseudoId(HORIZONTAL)); - m_horizontalValuePart->updateStyleForPart(valuePseudoId(HORIZONTAL)); - m_verticalBarPart->updateStyleForPart(barPseudoId(VERTICAL)); - m_verticalValuePart->updateStyleForPart(valuePseudoId(VERTICAL)); - RenderIndicator::updateFromElement(); } void RenderMeter::computeLogicalWidth() @@ -141,119 +56,9 @@ void RenderMeter::computeLogicalHeight() setHeight(theme()->meterSizeForBounds(this, frameRect()).height()); } -void RenderMeter::layoutParts() -{ - m_horizontalBarPart->layoutAsPart(barPartRect()); - m_horizontalValuePart->layoutAsPart(valuePartRect(HORIZONTAL)); - m_verticalBarPart->layoutAsPart(barPartRect()); - m_verticalValuePart->layoutAsPart(valuePartRect(VERTICAL)); - - if (shouldHaveParts()) { - if (HORIZONTAL == orientation()) { - m_verticalBarPart->hide(); - m_verticalValuePart->hide(); - m_horizontalBarPart->restoreVisibility(); - m_horizontalValuePart->restoreVisibility(); - } else { - m_verticalBarPart->restoreVisibility(); - m_verticalValuePart->restoreVisibility(); - m_horizontalBarPart->hide(); - m_horizontalValuePart->hide(); - } - } else { - m_verticalBarPart->hide(); - m_verticalValuePart->hide(); - m_horizontalBarPart->hide(); - m_horizontalValuePart->hide(); - } -} - -bool RenderMeter::shouldHaveParts() const -{ - EBoxOrient currentOrientation = orientation(); - bool hasTheme = theme()->supportsMeter(style()->appearance(), HORIZONTAL == currentOrientation); - if (!hasTheme) - return true; - bool shadowsHaveStyle = ShadowBlockElement::partShouldHaveStyle(this, barPseudoId(currentOrientation)) || ShadowBlockElement::partShouldHaveStyle(this, valuePseudoId(currentOrientation)); - if (shadowsHaveStyle) - return true; - return false; -} - double RenderMeter::valueRatio() const { - HTMLMeterElement* element = static_cast<HTMLMeterElement*>(node()); - double min = element->min(); - double max = element->max(); - double value = element->value(); - - if (max <= min) - return 0; - return (value - min) / (max - min); -} - -IntRect RenderMeter::barPartRect() const -{ - return IntRect(borderLeft() + paddingLeft(), borderTop() + paddingTop(), lround(width() - borderLeft() - paddingLeft() - borderRight() - paddingRight()), height() - borderTop() - paddingTop() - borderBottom() - paddingBottom()); -} - -IntRect RenderMeter::valuePartRect(EBoxOrient asOrientation) const -{ - IntRect rect = barPartRect(); - - if (HORIZONTAL == asOrientation) { - int width = static_cast<int>(rect.width()*valueRatio()); - if (!style()->isLeftToRightDirection()) { - rect.setX(rect.x() + (rect.width() - width)); - rect.setWidth(width); - } else - rect.setWidth(width); - } else { - int height = static_cast<int>(rect.height()*valueRatio()); - rect.setY(rect.y() + (rect.height() - height)); - rect.setHeight(height); - } - - return rect; -} - -EBoxOrient RenderMeter::orientation() const -{ - IntRect rect = barPartRect(); - return rect.height() <= rect.width() ? HORIZONTAL : VERTICAL; -} - -PseudoId RenderMeter::valuePseudoId(EBoxOrient asOrientation) const -{ - HTMLMeterElement* element = static_cast<HTMLMeterElement*>(node()); - - if (HORIZONTAL == asOrientation) { - switch (element->gaugeRegion()) { - case HTMLMeterElement::GaugeRegionOptimum: - return METER_HORIZONTAL_OPTIMUM; - case HTMLMeterElement::GaugeRegionSuboptimal: - return METER_HORIZONTAL_SUBOPTIMAL; - case HTMLMeterElement::GaugeRegionEvenLessGood: - return METER_HORIZONTAL_EVEN_LESS_GOOD; - } - } else { - switch (element->gaugeRegion()) { - case HTMLMeterElement::GaugeRegionOptimum: - return METER_VERTICAL_OPTIMUM; - case HTMLMeterElement::GaugeRegionSuboptimal: - return METER_VERTICAL_SUBOPTIMAL; - case HTMLMeterElement::GaugeRegionEvenLessGood: - return METER_VERTICAL_EVEN_LESS_GOOD; - } - } - - ASSERT_NOT_REACHED(); - return NOPSEUDO; -} - -PseudoId RenderMeter::barPseudoId(EBoxOrient asOrientation) const -{ - return HORIZONTAL == asOrientation ? METER_HORIZONTAL_BAR : METER_VERTICAL_BAR; + return static_cast<HTMLMeterElement*>(node())->valueRatio(); } } // namespace WebCore diff --git a/Source/WebCore/rendering/RenderMeter.h b/Source/WebCore/rendering/RenderMeter.h index 2f5f5f5..12ab6ba 100644 --- a/Source/WebCore/rendering/RenderMeter.h +++ b/Source/WebCore/rendering/RenderMeter.h @@ -23,44 +23,28 @@ #if ENABLE(METER_TAG) #include "RenderBlock.h" -#include "RenderIndicator.h" #include "RenderWidget.h" namespace WebCore { class HTMLMeterElement; -class MeterPartElement; -class RenderMeter : public RenderIndicator { +class RenderMeter : public RenderBlock { public: RenderMeter(HTMLMeterElement*); virtual ~RenderMeter(); private: - virtual const char* renderName() const { return "RenderMeter"; } - virtual bool isMeter() const { return true; } - virtual void updateFromElement(); virtual void computeLogicalWidth(); virtual void computeLogicalHeight(); - virtual void layoutParts(); - - bool shadowAttached() const { return m_horizontalBarPart; } - IntRect valuePartRect(EBoxOrient) const; - PseudoId valuePseudoId(EBoxOrient) const; - IntRect barPartRect() const; - PseudoId barPseudoId(EBoxOrient) const; - EBoxOrient orientation() const; + virtual const char* renderName() const { return "RenderMeter"; } + virtual bool isMeter() const { return true; } + virtual bool requiresForcedStyleRecalcPropagation() const { return true; } + virtual bool canHaveChildren() const { return false; } double valueRatio() const; - bool shouldHaveParts() const; - PassRefPtr<MeterPartElement> createPart(PseudoId); - - RefPtr<MeterPartElement> m_horizontalBarPart; - RefPtr<MeterPartElement> m_horizontalValuePart; - RefPtr<MeterPartElement> m_verticalBarPart; - RefPtr<MeterPartElement> m_verticalValuePart; }; inline RenderMeter* toRenderMeter(RenderObject* object) diff --git a/Source/WebCore/rendering/RenderObject.cpp b/Source/WebCore/rendering/RenderObject.cpp index 7cc6f1f..b050539 100644 --- a/Source/WebCore/rendering/RenderObject.cpp +++ b/Source/WebCore/rendering/RenderObject.cpp @@ -707,10 +707,10 @@ bool RenderObject::mustRepaintBackgroundOrBorder() const } void RenderObject::drawLineForBoxSide(GraphicsContext* graphicsContext, int x1, int y1, int x2, int y2, - BoxSide s, Color c, EBorderStyle style, - int adjbw1, int adjbw2) + BoxSide side, Color color, EBorderStyle style, + int adjacentWidth1, int adjacentWidth2, bool antialias) { - int width = (s == BSTop || s == BSBottom ? y2 - y1 : x2 - x1); + int width = (side == BSTop || side == BSBottom ? y2 - y1 : x2 - x1); if (style == DOUBLE && width < 3) style = SOLID; @@ -721,12 +721,15 @@ void RenderObject::drawLineForBoxSide(GraphicsContext* graphicsContext, int x1, return; case DOTTED: case DASHED: - graphicsContext->setStrokeColor(c, m_style->colorSpace()); + graphicsContext->setStrokeColor(color, m_style->colorSpace()); graphicsContext->setStrokeThickness(width); graphicsContext->setStrokeStyle(style == DASHED ? DashedStroke : DottedStroke); - if (width > 0) - switch (s) { + if (width > 0) { + bool wasAntialiased = graphicsContext->shouldAntialias(); + graphicsContext->setShouldAntialias(antialias); + + switch (side) { case BSBottom: case BSTop: graphicsContext->drawLine(IntPoint(x1, (y1 + y2) / 2), IntPoint(x2, (y1 + y2) / 2)); @@ -736,14 +739,20 @@ void RenderObject::drawLineForBoxSide(GraphicsContext* graphicsContext, int x1, graphicsContext->drawLine(IntPoint((x1 + x2) / 2, y1), IntPoint((x1 + x2) / 2, y2)); break; } + graphicsContext->setShouldAntialias(wasAntialiased); + } break; case DOUBLE: { int third = (width + 1) / 3; - if (adjbw1 == 0 && adjbw2 == 0) { + if (adjacentWidth1 == 0 && adjacentWidth2 == 0) { graphicsContext->setStrokeStyle(NoStroke); - graphicsContext->setFillColor(c, m_style->colorSpace()); - switch (s) { + graphicsContext->setFillColor(color, m_style->colorSpace()); + + bool wasAntialiased = graphicsContext->shouldAntialias(); + graphicsContext->setShouldAntialias(antialias); + + switch (side) { case BSTop: case BSBottom: graphicsContext->drawRect(IntRect(x1, y1, x2 - x1, third)); @@ -758,42 +767,44 @@ void RenderObject::drawLineForBoxSide(GraphicsContext* graphicsContext, int x1, graphicsContext->drawRect(IntRect(x2 - third, y1 + 1, third, y2 - y1 - 1)); break; } + + graphicsContext->setShouldAntialias(wasAntialiased); } else { - int adjbw1bigthird = ((adjbw1 > 0) ? adjbw1 + 1 : adjbw1 - 1) / 3; - int adjbw2bigthird = ((adjbw2 > 0) ? adjbw2 + 1 : adjbw2 - 1) / 3; + int adjacent1BigThird = ((adjacentWidth1 > 0) ? adjacentWidth1 + 1 : adjacentWidth1 - 1) / 3; + int adjacent2BigThird = ((adjacentWidth2 > 0) ? adjacentWidth2 + 1 : adjacentWidth2 - 1) / 3; - switch (s) { + switch (side) { case BSTop: - drawLineForBoxSide(graphicsContext, x1 + max((-adjbw1 * 2 + 1) / 3, 0), - y1, x2 - max((-adjbw2 * 2 + 1) / 3, 0), y1 + third, - s, c, SOLID, adjbw1bigthird, adjbw2bigthird); - drawLineForBoxSide(graphicsContext, x1 + max((adjbw1 * 2 + 1) / 3, 0), - y2 - third, x2 - max((adjbw2 * 2 + 1) / 3, 0), y2, - s, c, SOLID, adjbw1bigthird, adjbw2bigthird); + drawLineForBoxSide(graphicsContext, x1 + max((-adjacentWidth1 * 2 + 1) / 3, 0), + y1, x2 - max((-adjacentWidth2 * 2 + 1) / 3, 0), y1 + third, + side, color, SOLID, adjacent1BigThird, adjacent2BigThird, antialias); + drawLineForBoxSide(graphicsContext, x1 + max((adjacentWidth1 * 2 + 1) / 3, 0), + y2 - third, x2 - max((adjacentWidth2 * 2 + 1) / 3, 0), y2, + side, color, SOLID, adjacent1BigThird, adjacent2BigThird, antialias); break; case BSLeft: - drawLineForBoxSide(graphicsContext, x1, y1 + max((-adjbw1 * 2 + 1) / 3, 0), - x1 + third, y2 - max((-adjbw2 * 2 + 1) / 3, 0), - s, c, SOLID, adjbw1bigthird, adjbw2bigthird); - drawLineForBoxSide(graphicsContext, x2 - third, y1 + max((adjbw1 * 2 + 1) / 3, 0), - x2, y2 - max((adjbw2 * 2 + 1) / 3, 0), - s, c, SOLID, adjbw1bigthird, adjbw2bigthird); + drawLineForBoxSide(graphicsContext, x1, y1 + max((-adjacentWidth1 * 2 + 1) / 3, 0), + x1 + third, y2 - max((-adjacentWidth2 * 2 + 1) / 3, 0), + side, color, SOLID, adjacent1BigThird, adjacent2BigThird, antialias); + drawLineForBoxSide(graphicsContext, x2 - third, y1 + max((adjacentWidth1 * 2 + 1) / 3, 0), + x2, y2 - max((adjacentWidth2 * 2 + 1) / 3, 0), + side, color, SOLID, adjacent1BigThird, adjacent2BigThird, antialias); break; case BSBottom: - drawLineForBoxSide(graphicsContext, x1 + max((adjbw1 * 2 + 1) / 3, 0), - y1, x2 - max((adjbw2 * 2 + 1) / 3, 0), y1 + third, - s, c, SOLID, adjbw1bigthird, adjbw2bigthird); - drawLineForBoxSide(graphicsContext, x1 + max((-adjbw1 * 2 + 1) / 3, 0), - y2 - third, x2 - max((-adjbw2 * 2 + 1) / 3, 0), y2, - s, c, SOLID, adjbw1bigthird, adjbw2bigthird); + drawLineForBoxSide(graphicsContext, x1 + max((adjacentWidth1 * 2 + 1) / 3, 0), + y1, x2 - max((adjacentWidth2 * 2 + 1) / 3, 0), y1 + third, + side, color, SOLID, adjacent1BigThird, adjacent2BigThird, antialias); + drawLineForBoxSide(graphicsContext, x1 + max((-adjacentWidth1 * 2 + 1) / 3, 0), + y2 - third, x2 - max((-adjacentWidth2 * 2 + 1) / 3, 0), y2, + side, color, SOLID, adjacent1BigThird, adjacent2BigThird, antialias); break; case BSRight: - drawLineForBoxSide(graphicsContext, x1, y1 + max((adjbw1 * 2 + 1) / 3, 0), - x1 + third, y2 - max((adjbw2 * 2 + 1) / 3, 0), - s, c, SOLID, adjbw1bigthird, adjbw2bigthird); - drawLineForBoxSide(graphicsContext, x2 - third, y1 + max((-adjbw1 * 2 + 1) / 3, 0), - x2, y2 - max((-adjbw2 * 2 + 1) / 3, 0), - s, c, SOLID, adjbw1bigthird, adjbw2bigthird); + drawLineForBoxSide(graphicsContext, x1, y1 + max((adjacentWidth1 * 2 + 1) / 3, 0), + x1 + third, y2 - max((adjacentWidth2 * 2 + 1) / 3, 0), + side, color, SOLID, adjacent1BigThird, adjacent2BigThird, antialias); + drawLineForBoxSide(graphicsContext, x2 - third, y1 + max((-adjacentWidth1 * 2 + 1) / 3, 0), + x2, y2 - max((-adjacentWidth2 * 2 + 1) / 3, 0), + side, color, SOLID, adjacent1BigThird, adjacent2BigThird, antialias); break; default: break; @@ -802,8 +813,7 @@ void RenderObject::drawLineForBoxSide(GraphicsContext* graphicsContext, int x1, break; } case RIDGE: - case GROOVE: - { + case GROOVE: { EBorderStyle s1; EBorderStyle s2; if (style == GROOVE) { @@ -814,82 +824,90 @@ void RenderObject::drawLineForBoxSide(GraphicsContext* graphicsContext, int x1, s2 = INSET; } - int adjbw1bighalf = ((adjbw1 > 0) ? adjbw1 + 1 : adjbw1 - 1) / 2; - int adjbw2bighalf = ((adjbw2 > 0) ? adjbw2 + 1 : adjbw2 - 1) / 2; + int adjacent1BigHalf = ((adjacentWidth1 > 0) ? adjacentWidth1 + 1 : adjacentWidth1 - 1) / 2; + int adjacent2BigHalf = ((adjacentWidth2 > 0) ? adjacentWidth2 + 1 : adjacentWidth2 - 1) / 2; - switch (s) { + switch (side) { case BSTop: - drawLineForBoxSide(graphicsContext, x1 + max(-adjbw1, 0) / 2, y1, x2 - max(-adjbw2, 0) / 2, (y1 + y2 + 1) / 2, - s, c, s1, adjbw1bighalf, adjbw2bighalf); - drawLineForBoxSide(graphicsContext, x1 + max(adjbw1 + 1, 0) / 2, (y1 + y2 + 1) / 2, x2 - max(adjbw2 + 1, 0) / 2, y2, - s, c, s2, adjbw1 / 2, adjbw2 / 2); + drawLineForBoxSide(graphicsContext, x1 + max(-adjacentWidth1, 0) / 2, y1, x2 - max(-adjacentWidth2, 0) / 2, (y1 + y2 + 1) / 2, + side, color, s1, adjacent1BigHalf, adjacent2BigHalf, antialias); + drawLineForBoxSide(graphicsContext, x1 + max(adjacentWidth1 + 1, 0) / 2, (y1 + y2 + 1) / 2, x2 - max(adjacentWidth2 + 1, 0) / 2, y2, + side, color, s2, adjacentWidth1 / 2, adjacentWidth2 / 2, antialias); break; case BSLeft: - drawLineForBoxSide(graphicsContext, x1, y1 + max(-adjbw1, 0) / 2, (x1 + x2 + 1) / 2, y2 - max(-adjbw2, 0) / 2, - s, c, s1, adjbw1bighalf, adjbw2bighalf); - drawLineForBoxSide(graphicsContext, (x1 + x2 + 1) / 2, y1 + max(adjbw1 + 1, 0) / 2, x2, y2 - max(adjbw2 + 1, 0) / 2, - s, c, s2, adjbw1 / 2, adjbw2 / 2); + drawLineForBoxSide(graphicsContext, x1, y1 + max(-adjacentWidth1, 0) / 2, (x1 + x2 + 1) / 2, y2 - max(-adjacentWidth2, 0) / 2, + side, color, s1, adjacent1BigHalf, adjacent2BigHalf, antialias); + drawLineForBoxSide(graphicsContext, (x1 + x2 + 1) / 2, y1 + max(adjacentWidth1 + 1, 0) / 2, x2, y2 - max(adjacentWidth2 + 1, 0) / 2, + side, color, s2, adjacentWidth1 / 2, adjacentWidth2 / 2, antialias); break; case BSBottom: - drawLineForBoxSide(graphicsContext, x1 + max(adjbw1, 0) / 2, y1, x2 - max(adjbw2, 0) / 2, (y1 + y2 + 1) / 2, - s, c, s2, adjbw1bighalf, adjbw2bighalf); - drawLineForBoxSide(graphicsContext, x1 + max(-adjbw1 + 1, 0) / 2, (y1 + y2 + 1) / 2, x2 - max(-adjbw2 + 1, 0) / 2, y2, - s, c, s1, adjbw1 / 2, adjbw2 / 2); + drawLineForBoxSide(graphicsContext, x1 + max(adjacentWidth1, 0) / 2, y1, x2 - max(adjacentWidth2, 0) / 2, (y1 + y2 + 1) / 2, + side, color, s2, adjacent1BigHalf, adjacent2BigHalf, antialias); + drawLineForBoxSide(graphicsContext, x1 + max(-adjacentWidth1 + 1, 0) / 2, (y1 + y2 + 1) / 2, x2 - max(-adjacentWidth2 + 1, 0) / 2, y2, + side, color, s1, adjacentWidth1 / 2, adjacentWidth2 / 2, antialias); break; case BSRight: - drawLineForBoxSide(graphicsContext, x1, y1 + max(adjbw1, 0) / 2, (x1 + x2 + 1) / 2, y2 - max(adjbw2, 0) / 2, - s, c, s2, adjbw1bighalf, adjbw2bighalf); - drawLineForBoxSide(graphicsContext, (x1 + x2 + 1) / 2, y1 + max(-adjbw1 + 1, 0) / 2, x2, y2 - max(-adjbw2 + 1, 0) / 2, - s, c, s1, adjbw1 / 2, adjbw2 / 2); + drawLineForBoxSide(graphicsContext, x1, y1 + max(adjacentWidth1, 0) / 2, (x1 + x2 + 1) / 2, y2 - max(adjacentWidth2, 0) / 2, + side, color, s2, adjacent1BigHalf, adjacent2BigHalf, antialias); + drawLineForBoxSide(graphicsContext, (x1 + x2 + 1) / 2, y1 + max(-adjacentWidth1 + 1, 0) / 2, x2, y2 - max(-adjacentWidth2 + 1, 0) / 2, + side, color, s1, adjacentWidth1 / 2, adjacentWidth2 / 2, antialias); break; } break; } case INSET: - if (s == BSTop || s == BSLeft) - c = c.dark(); + // FIXME: Maybe we should lighten the colors on one side like Firefox. + // https://bugs.webkit.org/show_bug.cgi?id=58608 + if (side == BSTop || side == BSLeft) + color = color.dark(); // fall through case OUTSET: - if (style == OUTSET && (s == BSBottom || s == BSRight)) - c = c.dark(); + if (style == OUTSET && (side == BSBottom || side == BSRight)) + color = color.dark(); // fall through case SOLID: { graphicsContext->setStrokeStyle(NoStroke); - graphicsContext->setFillColor(c, m_style->colorSpace()); + graphicsContext->setFillColor(color, m_style->colorSpace()); ASSERT(x2 >= x1); ASSERT(y2 >= y1); - if (!adjbw1 && !adjbw2) { + if (!adjacentWidth1 && !adjacentWidth2) { + // Turn off antialiasing to match the behavior of drawConvexPolygon(); + // this matters for rects in transformed contexts. + bool wasAntialiased = graphicsContext->shouldAntialias(); + graphicsContext->setShouldAntialias(antialias); graphicsContext->drawRect(IntRect(x1, y1, x2 - x1, y2 - y1)); + graphicsContext->setShouldAntialias(wasAntialiased); return; } FloatPoint quad[4]; - switch (s) { + switch (side) { case BSTop: - quad[0] = FloatPoint(x1 + max(-adjbw1, 0), y1); - quad[1] = FloatPoint(x1 + max(adjbw1, 0), y2); - quad[2] = FloatPoint(x2 - max(adjbw2, 0), y2); - quad[3] = FloatPoint(x2 - max(-adjbw2, 0), y1); + quad[0] = FloatPoint(x1 + max(-adjacentWidth1, 0), y1); + quad[1] = FloatPoint(x1 + max(adjacentWidth1, 0), y2); + quad[2] = FloatPoint(x2 - max(adjacentWidth2, 0), y2); + quad[3] = FloatPoint(x2 - max(-adjacentWidth2, 0), y1); break; case BSBottom: - quad[0] = FloatPoint(x1 + max(adjbw1, 0), y1); - quad[1] = FloatPoint(x1 + max(-adjbw1, 0), y2); - quad[2] = FloatPoint(x2 - max(-adjbw2, 0), y2); - quad[3] = FloatPoint(x2 - max(adjbw2, 0), y1); + quad[0] = FloatPoint(x1 + max(adjacentWidth1, 0), y1); + quad[1] = FloatPoint(x1 + max(-adjacentWidth1, 0), y2); + quad[2] = FloatPoint(x2 - max(-adjacentWidth2, 0), y2); + quad[3] = FloatPoint(x2 - max(adjacentWidth2, 0), y1); break; case BSLeft: - quad[0] = FloatPoint(x1, y1 + max(-adjbw1, 0)); - quad[1] = FloatPoint(x1, y2 - max(-adjbw2, 0)); - quad[2] = FloatPoint(x2, y2 - max(adjbw2, 0)); - quad[3] = FloatPoint(x2, y1 + max(adjbw1, 0)); + quad[0] = FloatPoint(x1, y1 + max(-adjacentWidth1, 0)); + quad[1] = FloatPoint(x1, y2 - max(-adjacentWidth2, 0)); + quad[2] = FloatPoint(x2, y2 - max(adjacentWidth2, 0)); + quad[3] = FloatPoint(x2, y1 + max(adjacentWidth1, 0)); break; case BSRight: - quad[0] = FloatPoint(x1, y1 + max(adjbw1, 0)); - quad[1] = FloatPoint(x1, y2 - max(adjbw2, 0)); - quad[2] = FloatPoint(x2, y2 - max(-adjbw2, 0)); - quad[3] = FloatPoint(x2, y1 + max(-adjbw1, 0)); + quad[0] = FloatPoint(x1, y1 + max(adjacentWidth1, 0)); + quad[1] = FloatPoint(x1, y2 - max(adjacentWidth2, 0)); + quad[2] = FloatPoint(x2, y2 - max(-adjacentWidth2, 0)); + quad[3] = FloatPoint(x2, y1 + max(-adjacentWidth1, 0)); break; } - graphicsContext->drawConvexPolygon(4, quad); + + graphicsContext->drawConvexPolygon(4, quad, antialias); break; } } @@ -904,156 +922,9 @@ IntRect RenderObject::borderInnerRect(const IntRect& borderRect, unsigned short borderRect.height() - topWidth - bottomWidth); } -#if HAVE(PATH_BASED_BORDER_RADIUS_DRAWING) -void RenderObject::drawBoxSideFromPath(GraphicsContext* graphicsContext, const IntRect& borderRect, const Path& borderPath, - float thickness, float drawThickness, BoxSide s, const RenderStyle* style, - Color c, EBorderStyle borderStyle) -{ - if (thickness <= 0) - return; - - if (borderStyle == DOUBLE && thickness < 3) - borderStyle = SOLID; - - switch (borderStyle) { - case BNONE: - case BHIDDEN: - return; - case DOTTED: - case DASHED: { - graphicsContext->setStrokeColor(c, style->colorSpace()); - - // The stroke is doubled here because the provided path is the - // outside edge of the border so half the stroke is clipped off. - // The extra multiplier is so that the clipping mask can antialias - // the edges to prevent jaggies. - graphicsContext->setStrokeThickness(drawThickness * 2 * 1.1f); - graphicsContext->setStrokeStyle(borderStyle == DASHED ? DashedStroke : DottedStroke); - - // If the number of dashes that fit in the path is odd and non-integral then we - // will have an awkwardly-sized dash at the end of the path. To try to avoid that - // here, we simply make the whitespace dashes ever so slightly bigger. - // FIXME: This could be even better if we tried to manipulate the dash offset - // and possibly the whiteSpaceWidth to get the corners dash-symmetrical. - float patWidth = thickness * ((borderStyle == DASHED) ? 3.0f : 1.0f); - float whiteSpaceWidth = patWidth; - float numberOfDashes = borderPath.length() / patWidth; - bool evenNumberOfFullDashes = !((int)numberOfDashes % 2); - bool integralNumberOfDashes = !(numberOfDashes - (int)numberOfDashes); - if (!evenNumberOfFullDashes && !integralNumberOfDashes) { - float numberOfWhitespaceDashes = numberOfDashes / 2; - whiteSpaceWidth += (patWidth / numberOfWhitespaceDashes); - } - - DashArray lineDash; - lineDash.append(patWidth); - lineDash.append(whiteSpaceWidth); - graphicsContext->setLineDash(lineDash, patWidth); - graphicsContext->strokePath(borderPath); - return; - } - case DOUBLE: { - int outerBorderTopWidth = style->borderTopWidth() / 3; - int outerBorderRightWidth = style->borderRightWidth() / 3; - int outerBorderBottomWidth = style->borderBottomWidth() / 3; - int outerBorderLeftWidth = style->borderLeftWidth() / 3; - - int innerBorderTopWidth = style->borderTopWidth() * 2 / 3; - int innerBorderRightWidth = style->borderRightWidth() * 2 / 3; - int innerBorderBottomWidth = style->borderBottomWidth() * 2 / 3; - int innerBorderLeftWidth = style->borderLeftWidth() * 2 / 3; - - // We need certain integer rounding results - if (style->borderTopWidth() % 3 == 2) - outerBorderTopWidth += 1; - if (style->borderRightWidth() % 3 == 2) - outerBorderRightWidth += 1; - if (style->borderBottomWidth() % 3 == 2) - outerBorderBottomWidth += 1; - if (style->borderLeftWidth() % 3 == 2) - outerBorderLeftWidth += 1; - - if (style->borderTopWidth() % 3 == 1) - innerBorderTopWidth += 1; - if (style->borderRightWidth() % 3 == 1) - innerBorderRightWidth += 1; - if (style->borderBottomWidth() % 3 == 1) - innerBorderBottomWidth += 1; - if (style->borderLeftWidth() % 3 == 1) - innerBorderLeftWidth += 1; - - // Get the inner border rects for both the outer border line and the inner border line - - // Draw inner border line - graphicsContext->save(); - IntRect innerBorderInnerRect = borderInnerRect(borderRect, innerBorderTopWidth, innerBorderBottomWidth, - innerBorderLeftWidth, innerBorderRightWidth); - RoundedIntRect innerClip = style->getRoundedInnerBorderWithBorderWidths(innerBorderInnerRect, innerBorderTopWidth, innerBorderBottomWidth, - innerBorderLeftWidth, innerBorderRightWidth); - graphicsContext->addRoundedRectClip(innerClip); - drawBoxSideFromPath(graphicsContext, borderRect, borderPath, thickness, drawThickness, s, style, c, SOLID); - graphicsContext->restore(); - - // Draw outer border line - graphicsContext->save(); - IntRect outerBorderInnerRect = borderInnerRect(borderRect, outerBorderTopWidth, outerBorderBottomWidth, - outerBorderLeftWidth, outerBorderRightWidth); - RoundedIntRect outerClip = style->getRoundedInnerBorderWithBorderWidths(outerBorderInnerRect, outerBorderTopWidth, outerBorderBottomWidth, - outerBorderLeftWidth, outerBorderRightWidth); - graphicsContext->clipOutRoundedRect(outerClip); - drawBoxSideFromPath(graphicsContext, borderRect, borderPath, thickness, drawThickness, s, style, c, SOLID); - graphicsContext->restore(); - - return; - } - case RIDGE: - case GROOVE: - { - EBorderStyle s1; - EBorderStyle s2; - if (borderStyle == GROOVE) { - s1 = INSET; - s2 = OUTSET; - } else { - s1 = OUTSET; - s2 = INSET; - } - - IntRect halfBorderRect = borderInnerRect(borderRect, style->borderLeftWidth() / 2, style->borderBottomWidth() / 2, - style->borderLeftWidth() / 2, style->borderRightWidth() / 2); - - // Paint full border - drawBoxSideFromPath(graphicsContext, borderRect, borderPath, thickness, drawThickness, s, style, c, s1); - - // Paint inner only - graphicsContext->save(); - RoundedIntRect clipRect = style->getRoundedInnerBorderWithBorderWidths(halfBorderRect, style->borderLeftWidth() / 2, style->borderBottomWidth() / 2, - style->borderLeftWidth() / 2, style->borderRightWidth() / 2); - graphicsContext->addRoundedRectClip(clipRect); - drawBoxSideFromPath(graphicsContext, borderRect, borderPath, thickness, drawThickness, s, style, c, s2); - graphicsContext->restore(); - - return; - } - case INSET: - if (s == BSTop || s == BSLeft) - c = c.dark(); - break; - case OUTSET: - if (s == BSBottom || s == BSRight) - c = c.dark(); - break; - default: - break; - } - - graphicsContext->setStrokeStyle(NoStroke); - graphicsContext->setFillColor(c, style->colorSpace()); - graphicsContext->drawRect(borderRect); -} -#else +#if !HAVE(PATH_BASED_BORDER_RADIUS_DRAWING) void RenderObject::drawArcForBoxSide(GraphicsContext* graphicsContext, int x, int y, float thickness, const IntSize& radius, - int angleStart, int angleSpan, BoxSide s, Color c, + int angleStart, int angleSpan, BoxSide s, Color color, EBorderStyle style, bool firstCorner) { // FIXME: This function should be removed when all ports implement GraphicsContext::clipConvexPolygon()!! @@ -1067,7 +938,7 @@ void RenderObject::drawArcForBoxSide(GraphicsContext* graphicsContext, int x, in return; case DOTTED: case DASHED: - graphicsContext->setStrokeColor(c, m_style->colorSpace()); + graphicsContext->setStrokeColor(color, m_style->colorSpace()); graphicsContext->setStrokeStyle(style == DOTTED ? DottedStroke : DashedStroke); graphicsContext->setStrokeThickness(thickness); graphicsContext->strokeArc(IntRect(x, y, radius.width() * 2, radius.height() * 2), angleStart, angleSpan); @@ -1089,7 +960,7 @@ void RenderObject::drawArcForBoxSide(GraphicsContext* graphicsContext, int x, in } graphicsContext->setStrokeStyle(SolidStroke); - graphicsContext->setStrokeColor(c, m_style->colorSpace()); + graphicsContext->setStrokeColor(color, m_style->colorSpace()); graphicsContext->setStrokeThickness(third); graphicsContext->strokeArc(IntRect(x, outerY, radius.width() * 2, outerHeight), angleStart, angleSpan); graphicsContext->setStrokeThickness(innerThird > 2 ? innerThird - 1 : innerThird); @@ -1101,14 +972,14 @@ void RenderObject::drawArcForBoxSide(GraphicsContext* graphicsContext, int x, in Color c2; if ((style == RIDGE && (s == BSTop || s == BSLeft)) || (style == GROOVE && (s == BSBottom || s == BSRight))) - c2 = c.dark(); + c2 = color.dark(); else { - c2 = c; - c = c.dark(); + c2 = color; + color = color.dark(); } graphicsContext->setStrokeStyle(SolidStroke); - graphicsContext->setStrokeColor(c, m_style->colorSpace()); + graphicsContext->setStrokeColor(color, m_style->colorSpace()); graphicsContext->setStrokeThickness(thickness); graphicsContext->strokeArc(IntRect(x, y, radius.width() * 2, radius.height() * 2), angleStart, angleSpan); @@ -1122,13 +993,13 @@ void RenderObject::drawArcForBoxSide(GraphicsContext* graphicsContext, int x, in } case INSET: if (s == BSTop || s == BSLeft) - c = c.dark(); + color = color.dark(); case OUTSET: if (style == OUTSET && (s == BSBottom || s == BSRight)) - c = c.dark(); + color = color.dark(); case SOLID: graphicsContext->setStrokeStyle(SolidStroke); - graphicsContext->setStrokeColor(c, m_style->colorSpace()); + graphicsContext->setStrokeColor(color, m_style->colorSpace()); graphicsContext->setStrokeThickness(thickness); graphicsContext->strokeArc(IntRect(x, y, radius.width() * 2, radius.height() * 2), angleStart, angleSpan); break; diff --git a/Source/WebCore/rendering/RenderObject.h b/Source/WebCore/rendering/RenderObject.h index 41564dd..cf4d61b 100644 --- a/Source/WebCore/rendering/RenderObject.h +++ b/Source/WebCore/rendering/RenderObject.h @@ -37,7 +37,7 @@ #include "TransformationMatrix.h" #include <wtf/UnusedParam.h> -#if PLATFORM(CG) || PLATFORM(CAIRO) || PLATFORM(QT) +#if USE(CG) || USE(CAIRO) || PLATFORM(QT) #define HAVE_PATH_BASED_BORDER_RADIUS_DRAWING 1 #endif @@ -79,13 +79,12 @@ enum HitTestAction { HitTestForeground }; -// Sides used when drawing borders and outlines. This is in RenderObject rather than RenderBoxModelObject since outlines can -// be drawn by SVG around bounding boxes. +// Sides used when drawing borders and outlines. The values should run clockwise from top. enum BoxSide { BSTop, + BSRight, BSBottom, - BSLeft, - BSRight + BSLeft }; const int caretWidth = 1; @@ -433,13 +432,9 @@ public: bool hasTransform() const { return m_hasTransform; } bool hasMask() const { return style() && style()->hasMask(); } - void drawLineForBoxSide(GraphicsContext*, int x1, int y1, int x2, int y2, BoxSide, - Color, EBorderStyle, int adjbw1, int adjbw2); -#if HAVE(PATH_BASED_BORDER_RADIUS_DRAWING) - void drawBoxSideFromPath(GraphicsContext*, const IntRect&, const Path&, - float thickness, float drawThickness, BoxSide, const RenderStyle*, - Color, EBorderStyle); -#else + inline bool preservesNewline() const; + +#if !HAVE(PATH_BASED_BORDER_RADIUS_DRAWING) // FIXME: This function should be removed when all ports implement GraphicsContext::clipConvexPolygon()!! // At that time, everyone can use RenderObject::drawBoxSideFromPath() instead. This should happen soon. void drawArcForBoxSide(GraphicsContext*, int x, int y, float thickness, const IntSize& radius, int angleStart, @@ -782,6 +777,9 @@ protected: // Overrides should call the superclass at the start virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + void drawLineForBoxSide(GraphicsContext*, int x1, int y1, int x2, int y2, BoxSide, + Color, EBorderStyle, int adjbw1, int adjbw2, bool antialias = false); + void paintFocusRing(GraphicsContext*, int tx, int ty, RenderStyle*); void paintOutline(GraphicsContext*, int tx, int ty, int w, int h); void addPDFURLRect(GraphicsContext*, const IntRect&); @@ -958,8 +956,9 @@ inline void RenderObject::setChildNeedsLayout(bool b, bool markParents) inline void RenderObject::setNeedsPositionedMovementLayout() { - bool alreadyNeededLayout = needsLayout(); + bool alreadyNeededLayout = m_needsPositionedMovementLayout; m_needsPositionedMovementLayout = true; + ASSERT(!isSetNeedsLayoutForbidden()); if (!alreadyNeededLayout) { markContainingBlocksForLayout(); if (hasLayer()) @@ -969,8 +968,9 @@ inline void RenderObject::setNeedsPositionedMovementLayout() inline void RenderObject::setNeedsSimplifiedNormalFlowLayout() { - bool alreadyNeededLayout = needsLayout(); + bool alreadyNeededLayout = m_needsSimplifiedNormalFlowLayout; m_needsSimplifiedNormalFlowLayout = true; + ASSERT(!isSetNeedsLayoutForbidden()); if (!alreadyNeededLayout) { markContainingBlocksForLayout(); if (hasLayer()) @@ -1037,6 +1037,16 @@ inline void RenderObject::markContainingBlocksForLayout(bool scheduleRelayout, R last->scheduleRelayout(); } +inline bool RenderObject::preservesNewline() const +{ +#if ENABLE(SVG) + if (isSVGInlineText()) + return false; +#endif + + return style()->preserveNewline(); +} + inline void makeMatrixRenderable(TransformationMatrix& matrix, bool has3DRendering) { #if !ENABLE(3D_RENDERING) @@ -1079,6 +1089,33 @@ inline void adjustFloatRectForAbsoluteZoom(FloatRect& rect, RenderObject* render rect.setHeight(adjustFloatForAbsoluteZoom(rect.height(), style)); } +inline FloatPoint adjustFloatPointForPageScale(const FloatPoint& point, float pageScale) +{ + if (pageScale == 1) + return point; + return FloatPoint(point.x() / pageScale, point.y() / pageScale); +} + +inline void adjustFloatQuadForPageScale(FloatQuad& quad, float pageScale) +{ + if (pageScale == 1) + return; + quad.setP1(adjustFloatPointForPageScale(quad.p1(), pageScale)); + quad.setP2(adjustFloatPointForPageScale(quad.p2(), pageScale)); + quad.setP3(adjustFloatPointForPageScale(quad.p3(), pageScale)); + quad.setP4(adjustFloatPointForPageScale(quad.p4(), pageScale)); +} + +inline void adjustFloatRectForPageScale(FloatRect& rect, float pageScale) +{ + if (pageScale == 1) + return; + rect.setX(rect.x() / pageScale); + rect.setY(rect.y() / pageScale); + rect.setWidth(rect.width() / pageScale); + rect.setHeight(rect.height() / pageScale); +} + } // namespace WebCore #ifndef NDEBUG diff --git a/Source/WebCore/rendering/RenderObjectChildList.cpp b/Source/WebCore/rendering/RenderObjectChildList.cpp index 617067a..e26f221 100644 --- a/Source/WebCore/rendering/RenderObjectChildList.cpp +++ b/Source/WebCore/rendering/RenderObjectChildList.cpp @@ -456,6 +456,12 @@ void RenderObjectChildList::updateBeforeAfterContent(RenderObject* owner, Pseudo 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); + if (!owner->isChildAllowed(generatedContentContainer, pseudoElementStyle)) { + // The generated content container is not allowed here -> abort. + generatedContentContainer->destroy(); + renderer->destroy(); + return; + } owner->addChild(generatedContentContainer, insertBefore); } if (generatedContentContainer->isChildAllowed(renderer, pseudoElementStyle)) diff --git a/Source/WebCore/rendering/RenderPart.cpp b/Source/WebCore/rendering/RenderPart.cpp index 3262961..59b9795 100644 --- a/Source/WebCore/rendering/RenderPart.cpp +++ b/Source/WebCore/rendering/RenderPart.cpp @@ -24,10 +24,11 @@ #include "config.h" #include "RenderPart.h" -#include "RenderView.h" #include "Frame.h" #include "FrameView.h" #include "HTMLFrameElementBase.h" +#include "PluginViewBase.h" +#include "RenderView.h" namespace WebCore { @@ -58,4 +59,35 @@ void RenderPart::viewCleared() { } +#if USE(ACCELERATED_COMPOSITING) +bool RenderPart::requiresLayer() const +{ + if (RenderWidget::requiresLayer()) + return true; + + return requiresAcceleratedCompositing(); +} + +bool RenderPart::requiresAcceleratedCompositing() const +{ + // There are two general cases in which we can return true. First, if this is a plugin + // renderer and the plugin has a layer, then we need a layer. Second, if this is + // a renderer with a contentDocument and that document needs a layer, then we need + // a layer. + if (widget() && widget()->isPluginViewBase() && static_cast<PluginViewBase*>(widget())->platformLayer()) + return true; + + if (!node() || !node()->isFrameOwnerElement()) + return false; + + HTMLFrameOwnerElement* element = static_cast<HTMLFrameOwnerElement*>(node()); + if (Document* contentDocument = element->contentDocument()) { + if (RenderView* view = contentDocument->renderView()) + return view->usesCompositing(); + } + + return false; +} +#endif + } diff --git a/Source/WebCore/rendering/RenderPart.h b/Source/WebCore/rendering/RenderPart.h index 18f2346..9a22b30 100644 --- a/Source/WebCore/rendering/RenderPart.h +++ b/Source/WebCore/rendering/RenderPart.h @@ -36,6 +36,15 @@ public: virtual void setWidget(PassRefPtr<Widget>); virtual void viewCleared(); +#if USE(ACCELERATED_COMPOSITING) + bool requiresAcceleratedCompositing() const; +#endif + +protected: +#if USE(ACCELERATED_COMPOSITING) + virtual bool requiresLayer() const; +#endif + private: virtual bool isRenderPart() const { return true; } virtual const char* renderName() const { return "RenderPart"; } diff --git a/Source/WebCore/rendering/RenderProgress.cpp b/Source/WebCore/rendering/RenderProgress.cpp index 2a8e6f3..f687589 100644 --- a/Source/WebCore/rendering/RenderProgress.cpp +++ b/Source/WebCore/rendering/RenderProgress.cpp @@ -36,19 +36,9 @@ 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) + : RenderBlock(element) + , m_position(HTMLProgressElement::InvalidPosition) , m_animationStartTime(0) , m_animationRepeatInterval(0) , m_animationDuration(0) @@ -69,7 +59,7 @@ void RenderProgress::updateFromElement() m_position = element->position(); updateAnimationState(); - RenderIndicator::updateFromElement(); + RenderBlock::updateFromElement(); } double RenderProgress::animationProgress() const @@ -79,36 +69,15 @@ double RenderProgress::animationProgress() const bool RenderProgress::isDeterminate() const { - return 0 <= position(); + return (HTMLProgressElement::IndeterminatePosition != position() + && HTMLProgressElement::InvalidPosition != position()); } void RenderProgress::animationTimerFired(Timer<RenderProgress>*) { repaint(); -} - -void RenderProgress::paint(PaintInfo& paintInfo, int tx, int ty) -{ - if (paintInfo.phase == PaintPhaseBlockBackground) { - if (!m_animationTimer.isActive() && m_animating) - m_animationTimer.startOneShot(m_animationRepeatInterval); - } - - RenderIndicator::paint(paintInfo, tx, ty); -} - -void RenderProgress::layoutParts() -{ - for (RenderObject* child = firstChild(); child; child = child->nextSibling()) - child->layout(); - updateAnimationState(); -} - -bool RenderProgress::shouldHaveParts() const -{ - if (!style()->hasAppearance()) - return true; - return false; + if (!m_animationTimer.isActive() && m_animating) + m_animationTimer.startOneShot(m_animationRepeatInterval); } void RenderProgress::updateAnimationState() @@ -128,14 +97,6 @@ void RenderProgress::updateAnimationState() m_animationTimer.stop(); } -IntRect RenderProgress::valuePartRect() const -{ - IntRect rect(borderLeft() + paddingLeft(), borderTop() + paddingTop(), lround((width() - borderLeft() - paddingLeft() - borderRight() - paddingRight()) * position()), height() - borderTop() - paddingTop() - borderBottom() - paddingBottom()); - if (!style()->isLeftToRightDirection()) - rect.setX(width() - borderRight() - paddingRight() - rect.width()); - return rect; -} - HTMLProgressElement* RenderProgress::progressElement() const { return static_cast<HTMLProgressElement*>(node()); diff --git a/Source/WebCore/rendering/RenderProgress.h b/Source/WebCore/rendering/RenderProgress.h index 78cf359..62436fd 100644 --- a/Source/WebCore/rendering/RenderProgress.h +++ b/Source/WebCore/rendering/RenderProgress.h @@ -23,21 +23,12 @@ #if ENABLE(PROGRESS_TAG) #include "RenderBlock.h" -#include "RenderIndicator.h" namespace WebCore { class HTMLProgressElement; -class RenderProgressBarValuePart : public RenderIndicatorPart { -public: - RenderProgressBarValuePart(Node* node) : RenderIndicatorPart(node) {} -private: - virtual IntRect preferredFrameRect(); - virtual bool shouldBeHidden(); -}; - -class RenderProgress : public RenderIndicator { +class RenderProgress : public RenderBlock { public: RenderProgress(HTMLProgressElement*); virtual ~RenderProgress(); @@ -47,17 +38,15 @@ public: double animationStartTime() const { return m_animationStartTime; } bool isDeterminate() const; - IntRect valuePartRect() const; - bool shouldHaveParts() const; HTMLProgressElement* progressElement() const; private: virtual const char* renderName() const { return "RenderProgress"; } virtual bool isProgress() const { return true; } + virtual bool requiresForcedStyleRecalcPropagation() const { return true; } + virtual bool canHaveChildren() const { return false; } virtual void updateFromElement(); - virtual void paint(PaintInfo&, int tx, int ty); - virtual void layoutParts(); void animationTimerFired(Timer<RenderProgress>*); void updateAnimationState(); diff --git a/Source/WebCore/rendering/RenderRuby.cpp b/Source/WebCore/rendering/RenderRuby.cpp index 1c5cfaf..0b51384 100644 --- a/Source/WebCore/rendering/RenderRuby.cpp +++ b/Source/WebCore/rendering/RenderRuby.cpp @@ -33,17 +33,51 @@ #include "RenderRuby.h" #include "RenderRubyRun.h" +#include "RenderStyle.h" +#include <wtf/RefPtr.h> namespace WebCore { //=== generic helper functions to avoid excessive code duplication === +static inline bool isAnonymousRubyInlineBlock(RenderObject* object) +{ + ASSERT(!object->parent()->isRuby() + || object->isRubyRun() + || (object->isInline() && (object->isBeforeContent() || object->isAfterContent())) + || (object->isAnonymous() && object->isRenderBlock() && object->style()->display() == INLINE_BLOCK)); + return object->parent()->isRuby() && object->isRenderBlock() && !object->isRubyRun(); +} + +static inline RenderBlock* rubyBeforeBlock(const RenderObject* ruby) +{ + RenderObject* child = ruby->firstChild(); + return child && !child->isRubyRun() && child->isRenderBlock() && child->style()->styleType() == BEFORE ? static_cast<RenderBlock*>(child) : 0; +} + +static inline RenderBlock* rubyAfterBlock(const RenderObject* ruby) +{ + RenderObject* child = ruby->lastChild(); + return child && !child->isRubyRun() && child->isRenderBlock() && child->style()->styleType() == AFTER ? static_cast<RenderBlock*>(child) : 0; +} + +static RenderBlock* createAnonymousRubyInlineBlock(RenderObject* ruby, PseudoId styleType) +{ + RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyle(ruby->style()); + newStyle->setDisplay(INLINE_BLOCK); + newStyle->setStyleType(styleType); + + RenderBlock* newBlock = new (ruby->renderArena()) RenderBlock(ruby->document() /* anonymous box */); + newBlock->setStyle(newStyle.release()); + return newBlock; +} + static RenderRubyRun* lastRubyRun(const RenderObject* ruby) { RenderObject* child = ruby->lastChild(); - if (child && ruby->isAfterContent(child)) + if (child && !child->isRubyRun()) child = child->previousSibling(); - ASSERT(!child || child->isRubyRun() || child->isBeforeContent()); + ASSERT(!child || child->isRubyRun() || child->isBeforeContent() || child == rubyBeforeBlock(ruby)); return child && child->isRubyRun() ? static_cast<RenderRubyRun*>(child) : 0; } @@ -65,18 +99,37 @@ RenderRubyAsInline::~RenderRubyAsInline() { } -bool RenderRubyAsInline::isChildAllowed(RenderObject* child, RenderStyle*) const -{ - return child->isRubyText() - || child->isRubyRun() - || child->isInline(); -} - void RenderRubyAsInline::addChild(RenderObject* child, RenderObject* beforeChild) { - // Insert :before and :after content outside of ruby runs. - if (child->isBeforeContent() || child->isAfterContent()) { - RenderInline::addChild(child, beforeChild); + // Insert :before and :after content before/after the RenderRubyRun(s) + if (child->isBeforeContent()) { + if (child->isInline()) { + // Add generated inline content normally + RenderInline::addChild(child, firstChild()); + } else { + // Wrap non-inline content with an anonymous inline-block. + RenderBlock* beforeBlock = rubyBeforeBlock(this); + if (!beforeBlock) { + beforeBlock = createAnonymousRubyInlineBlock(this, BEFORE); + RenderInline::addChild(beforeBlock, firstChild()); + } + beforeBlock->addChild(child); + } + return; + } + if (child->isAfterContent()) { + if (child->isInline()) { + // Add generated inline content normally + RenderInline::addChild(child); + } else { + // Wrap non-inline content with an anonymous inline-block. + RenderBlock* afterBlock = rubyAfterBlock(this); + if (!afterBlock) { + afterBlock = createAnonymousRubyInlineBlock(this, AFTER); + RenderInline::addChild(afterBlock); + } + afterBlock->addChild(child); + } return; } @@ -113,15 +166,23 @@ void RenderRubyAsInline::addChild(RenderObject* child, RenderObject* beforeChild void RenderRubyAsInline::removeChild(RenderObject* child) { - // If the child's parent is *this (a ruby run or :before or :after content), + // If the child's parent is *this (must be a ruby run or generated content or anonymous block), // just use the normal remove method. - if (child->isRubyRun() || child->isBeforeContent() || child->isAfterContent()) { + if (child->parent() == this) { + ASSERT(child->isRubyRun() || child->isBeforeContent() || child->isAfterContent() || isAnonymousRubyInlineBlock(child)); RenderInline::removeChild(child); return; } + // If the child's parent is an anoymous block (must be generated :before/:after content) + // just use the block's remove method. + if (isAnonymousRubyInlineBlock(child->parent())) { + ASSERT(child->isBeforeContent() || child->isAfterContent()); + child->parent()->removeChild(child); + removeChild(child->parent()); + return; + } // Otherwise find the containing run and remove it from there. - ASSERT(child->parent() != this); RenderRubyRun* run = findRubyRunParent(child); ASSERT(run); run->removeChild(child); @@ -139,18 +200,37 @@ RenderRubyAsBlock::~RenderRubyAsBlock() { } -bool RenderRubyAsBlock::isChildAllowed(RenderObject* child, RenderStyle*) const -{ - return child->isRubyText() - || child->isRubyRun() - || child->isInline(); -} - void RenderRubyAsBlock::addChild(RenderObject* child, RenderObject* beforeChild) { - // Insert :before and :after content outside of ruby runs. - if (child->isBeforeContent() || child->isAfterContent()) { - RenderBlock::addChild(child, beforeChild); + // Insert :before and :after content before/after the RenderRubyRun(s) + if (child->isBeforeContent()) { + if (child->isInline()) { + // Add generated inline content normally + RenderBlock::addChild(child, firstChild()); + } else { + // Wrap non-inline content with an anonymous inline-block. + RenderBlock* beforeBlock = rubyBeforeBlock(this); + if (!beforeBlock) { + beforeBlock = createAnonymousRubyInlineBlock(this, BEFORE); + RenderBlock::addChild(beforeBlock, firstChild()); + } + beforeBlock->addChild(child); + } + return; + } + if (child->isAfterContent()) { + if (child->isInline()) { + // Add generated inline content normally + RenderBlock::addChild(child); + } else { + // Wrap non-inline content with an anonymous inline-block. + RenderBlock* afterBlock = rubyAfterBlock(this); + if (!afterBlock) { + afterBlock = createAnonymousRubyInlineBlock(this, AFTER); + RenderBlock::addChild(afterBlock); + } + afterBlock->addChild(child); + } return; } @@ -187,15 +267,23 @@ void RenderRubyAsBlock::addChild(RenderObject* child, RenderObject* beforeChild) void RenderRubyAsBlock::removeChild(RenderObject* child) { - // If the child's parent is *this (a ruby run or :before or :after content), + // If the child's parent is *this (must be a ruby run or generated content or anonymous block), // just use the normal remove method. - if (child->isRubyRun() || child->isBeforeContent() || child->isAfterContent()) { + if (child->parent() == this) { + ASSERT(child->isRubyRun() || child->isBeforeContent() || child->isAfterContent() || isAnonymousRubyInlineBlock(child)); RenderBlock::removeChild(child); return; } + // If the child's parent is an anoymous block (must be generated :before/:after content) + // just use the block's remove method. + if (isAnonymousRubyInlineBlock(child->parent())) { + ASSERT(child->isBeforeContent() || child->isAfterContent()); + child->parent()->removeChild(child); + removeChild(child->parent()); + return; + } // Otherwise find the containing run and remove it from there. - ASSERT(child->parent() != this); RenderRubyRun* run = findRubyRunParent(child); ASSERT(run); run->removeChild(child); diff --git a/Source/WebCore/rendering/RenderRuby.h b/Source/WebCore/rendering/RenderRuby.h index 49a84d8..24ac0db 100644 --- a/Source/WebCore/rendering/RenderRuby.h +++ b/Source/WebCore/rendering/RenderRuby.h @@ -47,6 +47,8 @@ namespace WebCore { // 1-n inline object(s) // // Note: <rp> elements are defined as having 'display:none' and thus normally are not assigned a renderer. +// +// Generated :before/:after content is shunted into anonymous inline blocks // <ruby> when used as 'display:inline' class RenderRubyAsInline : public RenderInline { @@ -54,7 +56,6 @@ public: RenderRubyAsInline(Node*); virtual ~RenderRubyAsInline(); - virtual bool isChildAllowed(RenderObject*, RenderStyle*) const; virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0); virtual void removeChild(RenderObject* child); @@ -71,7 +72,6 @@ public: RenderRubyAsBlock(Node*); virtual ~RenderRubyAsBlock(); - virtual bool isChildAllowed(RenderObject*, RenderStyle*) const; virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0); virtual void removeChild(RenderObject* child); diff --git a/Source/WebCore/rendering/RenderRubyRun.cpp b/Source/WebCore/rendering/RenderRubyRun.cpp index 3504ccf..1329d65 100644 --- a/Source/WebCore/rendering/RenderRubyRun.cpp +++ b/Source/WebCore/rendering/RenderRubyRun.cpp @@ -268,4 +268,41 @@ void RenderRubyRun::layout() computeOverflow(clientLogicalBottom()); } +void RenderRubyRun::getOverhang(bool firstLine, RenderObject* startRenderer, RenderObject* endRenderer, int& startOverhang, int& endOverhang) const +{ + ASSERT(!needsLayout()); + + startOverhang = 0; + endOverhang = 0; + + RenderRubyBase* rubyBase = this->rubyBase(); + RenderRubyText* rubyText = this->rubyText(); + + if (!rubyBase || !rubyText) + return; + + if (!rubyBase->firstRootBox()) + return; + + int logicalWidth = this->logicalWidth(); + + // No more than half a ruby is allowed to overhang. + int logicalLeftOverhang = rubyText->style(firstLine)->fontSize() / 2; + int logicalRightOverhang = logicalLeftOverhang; + + for (RootInlineBox* rootInlineBox = rubyBase->firstRootBox(); rootInlineBox; rootInlineBox = rootInlineBox->nextRootBox()) { + logicalLeftOverhang = min<int>(logicalLeftOverhang, rootInlineBox->logicalLeft()); + logicalRightOverhang = min<int>(logicalRightOverhang, logicalWidth - rootInlineBox->logicalRight()); + } + + startOverhang = style()->isLeftToRightDirection() ? logicalLeftOverhang : logicalRightOverhang; + endOverhang = style()->isLeftToRightDirection() ? logicalRightOverhang : logicalLeftOverhang; + + if (!startRenderer || !startRenderer->isText() || startRenderer->style(firstLine)->fontSize() > rubyBase->style(firstLine)->fontSize()) + startOverhang = 0; + + if (!endRenderer || !endRenderer->isText() || endRenderer->style(firstLine)->fontSize() > rubyBase->style(firstLine)->fontSize()) + endOverhang = 0; +} + } // namespace WebCore diff --git a/Source/WebCore/rendering/RenderRubyRun.h b/Source/WebCore/rendering/RenderRubyRun.h index 53209bc..f65ad86 100644 --- a/Source/WebCore/rendering/RenderRubyRun.h +++ b/Source/WebCore/rendering/RenderRubyRun.h @@ -63,6 +63,8 @@ public: virtual RenderBlock* firstLineBlock() const; virtual void updateFirstLetter(); + void getOverhang(bool firstLine, RenderObject* startRenderer, RenderObject* endRenderer, int& startOverhang, int& endOverhang) const; + static RenderRubyRun* staticCreateRubyRun(const RenderObject* parentRuby); protected: @@ -75,6 +77,20 @@ private: virtual void removeLeftoverAnonymousBlock(RenderBlock*) { } }; +inline RenderRubyRun* toRenderRubyRun(RenderObject* object) +{ + ASSERT(!object || object->isRubyRun()); + return static_cast<RenderRubyRun*>(object); +} + +inline const RenderRubyRun* toRenderRubyRun(const RenderObject* object) +{ + ASSERT(!object || object->isBox()); + return static_cast<const RenderRubyRun*>(object); +} + +void toRenderRubyRun(const RenderRubyRun*); + } // namespace WebCore #endif // RenderRubyRun_h diff --git a/Source/WebCore/rendering/RenderSlider.cpp b/Source/WebCore/rendering/RenderSlider.cpp index 1661b7a..ad5ab1a 100644 --- a/Source/WebCore/rendering/RenderSlider.cpp +++ b/Source/WebCore/rendering/RenderSlider.cpp @@ -33,6 +33,7 @@ #include "HTMLParserIdioms.h" #include "MediaControlElements.h" #include "MouseEvent.h" +#include "Node.h" #include "RenderLayer.h" #include "RenderTheme.h" #include "RenderView.h" @@ -101,7 +102,7 @@ void RenderSlider::computePreferredLogicalWidths() IntRect RenderSlider::thumbRect() { - SliderThumbElement* thumbElement = sliderThumbElement(); + SliderThumbElement* thumbElement = shadowSliderThumb(); if (!thumbElement) return IntRect(); @@ -128,7 +129,7 @@ void RenderSlider::layout() { ASSERT(needsLayout()); - SliderThumbElement* thumbElement = sliderThumbElement(); + SliderThumbElement* thumbElement = shadowSliderThumb(); RenderBox* thumb = thumbElement ? toRenderBox(thumbElement->renderer()) : 0; IntSize baseSize(borderAndPaddingWidth(), borderAndPaddingHeight()); @@ -176,14 +177,15 @@ void RenderSlider::layout() setNeedsLayout(false); } -SliderThumbElement* RenderSlider::sliderThumbElement() const +SliderThumbElement* RenderSlider::shadowSliderThumb() const { - return toSliderThumbElement(static_cast<Element*>(node())->shadowRoot()); + Node* shadow = static_cast<Element*>(node())->shadowRoot(); + return shadow ? toSliderThumbElement(shadow->firstChild()) : 0; } bool RenderSlider::inDragMode() const { - SliderThumbElement* thumbElement = sliderThumbElement(); + SliderThumbElement* thumbElement = shadowSliderThumb(); return thumbElement && thumbElement->inDragMode(); } diff --git a/Source/WebCore/rendering/RenderSlider.h b/Source/WebCore/rendering/RenderSlider.h index 0162b71..4e17f30 100644 --- a/Source/WebCore/rendering/RenderSlider.h +++ b/Source/WebCore/rendering/RenderSlider.h @@ -46,8 +46,8 @@ namespace WebCore { virtual void layout(); // FIXME: Eventually, the logic of manipulating slider thumb should move to - // SliderThumbElement and accessing sliderThumbElement should not be necessary in this class. - SliderThumbElement* sliderThumbElement() const; + // SliderThumbElement and accessing shadowSliderThumb should not be necessary in this class. + SliderThumbElement* shadowSliderThumb() const; virtual bool requiresForcedStyleRecalcPropagation() const { return true; } }; diff --git a/Source/WebCore/rendering/RenderTableRow.cpp b/Source/WebCore/rendering/RenderTableRow.cpp index a29f218..2edcfc4 100644 --- a/Source/WebCore/rendering/RenderTableRow.cpp +++ b/Source/WebCore/rendering/RenderTableRow.cpp @@ -63,17 +63,23 @@ void RenderTableRow::styleWillChange(StyleDifference diff, const RenderStyle* ne RenderBox::styleWillChange(diff, newStyle); } -void RenderTableRow::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) +void RenderTableRow::updateBeforeAndAfterContent() { - RenderBox::styleDidChange(diff, oldStyle); - - // Update pseudos for :before and :after now. if (!isAnonymous() && document()->usesBeforeAfterRules()) { children()->updateBeforeAfterContent(this, BEFORE); children()->updateBeforeAfterContent(this, AFTER); } } +void RenderTableRow::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) +{ + RenderBox::styleDidChange(diff, oldStyle); + + if (parent()) + updateBeforeAndAfterContent(); + +} + void RenderTableRow::addChild(RenderObject* child, RenderObject* beforeChild) { // Make sure we don't append things after :after-generated content if we have it. diff --git a/Source/WebCore/rendering/RenderTableRow.h b/Source/WebCore/rendering/RenderTableRow.h index 2af8dcb..570a7f2 100644 --- a/Source/WebCore/rendering/RenderTableRow.h +++ b/Source/WebCore/rendering/RenderTableRow.h @@ -39,6 +39,8 @@ public: RenderTableSection* section() const { return toRenderTableSection(parent()); } RenderTable* table() const { return toRenderTable(parent()->parent()); } + void updateBeforeAndAfterContent(); + private: virtual RenderObjectChildList* virtualChildren() { return children(); } virtual const RenderObjectChildList* virtualChildren() const { return children(); } diff --git a/Source/WebCore/rendering/RenderTableSection.cpp b/Source/WebCore/rendering/RenderTableSection.cpp index 7c0a768..06d326f 100644 --- a/Source/WebCore/rendering/RenderTableSection.cpp +++ b/Source/WebCore/rendering/RenderTableSection.cpp @@ -148,6 +148,7 @@ void RenderTableSection::addChild(RenderObject* child, RenderObject* beforeChild ASSERT(!beforeChild || beforeChild->isTableRow()); RenderBox::addChild(child, beforeChild); + toRenderTableRow(child)->updateBeforeAndAfterContent(); } void RenderTableSection::removeChild(RenderObject* oldChild) diff --git a/Source/WebCore/rendering/RenderText.cpp b/Source/WebCore/rendering/RenderText.cpp index e660875..b35820a 100644 --- a/Source/WebCore/rendering/RenderText.cpp +++ b/Source/WebCore/rendering/RenderText.cpp @@ -177,7 +177,7 @@ void RenderText::styleDidChange(StyleDifference diff, const RenderStyle* oldStyl } } -void RenderText::destroy() +void RenderText::removeAndDestroyTextBoxes() { if (!documentBeingDestroyed()) { if (firstTextBox()) { @@ -192,6 +192,11 @@ void RenderText::destroy() parent()->dirtyLinesFromChangedChild(this); } deleteTextBoxes(); +} + +void RenderText::destroy() +{ + removeAndDestroyTextBoxes(); RenderObject::destroy(); } @@ -268,7 +273,7 @@ PassRefPtr<StringImpl> RenderText::originalText() const void RenderText::absoluteRects(Vector<IntRect>& rects, int tx, int ty) { for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) - rects.append(IntRect(tx + box->x(), ty + box->y(), box->logicalWidth(), box->logicalHeight())); + rects.append(enclosingIntRect(FloatRect(tx + box->x(), ty + box->y(), box->width(), box->height()))); } void RenderText::absoluteRectsForRange(Vector<IntRect>& rects, unsigned start, unsigned end, bool useSelectionHeight) @@ -1300,15 +1305,38 @@ IntRect RenderText::linesBoundingBox() const return result; } -IntRect RenderText::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) +IntRect RenderText::linesVisualOverflowBoundingBox() const { - RenderObject* cb = containingBlock(); - // The containing block may be an ancestor of repaintContainer, but we need to do a repaintContainer-relative repaint. - if (repaintContainer && repaintContainer != cb) { - if (!cb->isDescendantOf(repaintContainer)) - return repaintContainer->clippedOverflowRectForRepaint(repaintContainer); + if (!firstTextBox()) + return IntRect(); + + // Return the width of the minimal left side and the maximal right side. + int logicalLeftSide = numeric_limits<int>::max(); + int logicalRightSide = numeric_limits<int>::min(); + for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBox()) { + logicalLeftSide = min(logicalLeftSide, curr->logicalLeftVisualOverflow()); + logicalRightSide = max(logicalRightSide, curr->logicalRightVisualOverflow()); } - return cb->clippedOverflowRectForRepaint(repaintContainer); + + int logicalTop = firstTextBox()->logicalTopVisualOverflow(); + int logicalWidth = logicalRightSide - logicalLeftSide; + int logicalHeight = lastTextBox()->logicalBottomVisualOverflow() - logicalTop; + + IntRect rect(logicalLeftSide, logicalTop, logicalWidth, logicalHeight); + if (!style()->isHorizontalWritingMode()) + rect = rect.transposedRect(); + return rect; +} + +IntRect RenderText::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) +{ + bool repaintContainerSkipped; + RenderObject* container = this->container(repaintContainer, &repaintContainerSkipped); + // The container may be an ancestor of repaintContainer, but we need to do a repaintContainer-relative repaint. + if (repaintContainerSkipped) + return repaintContainer->clippedOverflowRectForRepaint(repaintContainer); + + return container->clippedOverflowRectForRepaint(repaintContainer); } IntRect RenderText::selectionRectForRepaint(RenderBoxModelObject* repaintContainer, bool clipToVisibleContent) diff --git a/Source/WebCore/rendering/RenderText.h b/Source/WebCore/rendering/RenderText.h index 7fa3518..2008dad 100644 --- a/Source/WebCore/rendering/RenderText.h +++ b/Source/WebCore/rendering/RenderText.h @@ -85,6 +85,7 @@ public: float& minW, float& maxW, bool& stripFrontSpaces); virtual IntRect linesBoundingBox() const; + IntRect linesVisualOverflowBoundingBox() const; FloatPoint firstRunOrigin() const; float firstRunX() const; @@ -127,6 +128,8 @@ public: bool knownToHaveNoOverflowAndNoFallbackFonts() const { return m_knownToHaveNoOverflowAndNoFallbackFonts; } + void removeAndDestroyTextBoxes(); + protected: virtual void styleWillChange(StyleDifference, const RenderStyle*) { } virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); diff --git a/Source/WebCore/rendering/RenderTextControlSingleLine.cpp b/Source/WebCore/rendering/RenderTextControlSingleLine.cpp index b9697ff..c5a47fb 100644 --- a/Source/WebCore/rendering/RenderTextControlSingleLine.cpp +++ b/Source/WebCore/rendering/RenderTextControlSingleLine.cpp @@ -424,10 +424,6 @@ void RenderTextControlSingleLine::forwardEvent(Event* event) m_resultsButton->defaultEventHandler(event); else if (m_cancelButton && localPoint.x() > textRight) m_cancelButton->defaultEventHandler(event); - else if (m_innerSpinButton && localPoint.x() > textRight && m_innerSpinButton->renderBox() && localPoint.x() < textRight + m_innerSpinButton->renderBox()->width()) - m_innerSpinButton->defaultEventHandler(event); - else if (m_outerSpinButton && localPoint.x() > textRight) - m_outerSpinButton->defaultEventHandler(event); else RenderTextControl::forwardEvent(event); } diff --git a/Source/WebCore/rendering/RenderTheme.cpp b/Source/WebCore/rendering/RenderTheme.cpp index f254c99..6617d18 100644 --- a/Source/WebCore/rendering/RenderTheme.cpp +++ b/Source/WebCore/rendering/RenderTheme.cpp @@ -485,33 +485,6 @@ bool RenderTheme::paintDecorations(RenderObject* o, const PaintInfo& paintInfo, } #if ENABLE(VIDEO) -bool RenderTheme::hitTestMediaControlPart(RenderObject* o, const IntPoint& absPoint) -{ - if (!o->isBox()) - return false; - - FloatPoint localPoint = o->absoluteToLocal(absPoint, false, true); // respect transforms - return toRenderBox(o)->borderBoxRect().contains(roundedIntPoint(localPoint)); -} - -bool RenderTheme::shouldRenderMediaControlPart(ControlPart part, Element* e) -{ - HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(e); - switch (part) { - case MediaMuteButtonPart: - return mediaElement->hasAudio(); - case MediaRewindButtonPart: - return mediaElement->movieLoadType() != MediaPlayer::LiveStream; - case MediaReturnToRealtimeButtonPart: - return mediaElement->movieLoadType() == MediaPlayer::LiveStream; - case MediaFullscreenButtonPart: - return mediaElement->supportsFullscreen(); - case MediaToggleClosedCaptionsButtonPart: - return mediaElement->hasClosedCaptions(); - default: - return true; - } -} String RenderTheme::formatMediaControlsTime(float time) const { @@ -968,7 +941,7 @@ IntSize RenderTheme::meterSizeForBounds(const RenderMeter*, const IntRect& bound return bounds.size(); } -bool RenderTheme::supportsMeter(ControlPart, bool) const +bool RenderTheme::supportsMeter(ControlPart) const { return false; } diff --git a/Source/WebCore/rendering/RenderTheme.h b/Source/WebCore/rendering/RenderTheme.h index 53c23e3..f18e247 100644 --- a/Source/WebCore/rendering/RenderTheme.h +++ b/Source/WebCore/rendering/RenderTheme.h @@ -181,9 +181,10 @@ public: #if ENABLE(VIDEO) // Media controls - virtual bool hitTestMediaControlPart(RenderObject*, const IntPoint& absPoint); - virtual bool shouldRenderMediaControlPart(ControlPart, Element*); + virtual bool supportsClosedCaptioning() const { return false; } + virtual bool hasOwnDisabledStateHandlingFor(ControlPart) const { return false; } virtual bool usesMediaControlStatusDisplay() { return false; } + virtual bool usesMediaControlVolumeSlider() const { return true; } virtual double mediaControlsFadeInDuration() { return 0.1; } virtual double mediaControlsFadeOutDuration() { return 0.3; } virtual String formatMediaControlsTime(float time) const; @@ -196,7 +197,7 @@ public: #if ENABLE(METER_TAG) virtual IntSize meterSizeForBounds(const RenderMeter*, const IntRect&) const; - virtual bool supportsMeter(ControlPart, bool isHorizontal) const; + virtual bool supportsMeter(ControlPart) const; #endif virtual bool shouldShowPlaceholderWhenFocused() const { return false; } diff --git a/Source/WebCore/rendering/RenderThemeChromiumLinux.cpp b/Source/WebCore/rendering/RenderThemeChromiumLinux.cpp index 72ea7cb..c3f15c8 100644 --- a/Source/WebCore/rendering/RenderThemeChromiumLinux.cpp +++ b/Source/WebCore/rendering/RenderThemeChromiumLinux.cpp @@ -274,7 +274,8 @@ bool RenderThemeChromiumLinux::paintMenuList(RenderObject* o, const PaintInfo& i // Match Chromium Win behaviour of showing all borders if any are shown. extraParams.menuList.hasBorder = box->borderRight() || box->borderLeft() || box->borderTop() || box->borderBottom(); extraParams.menuList.hasBorderRadius = o->style()->hasBorderRadius(); - extraParams.menuList.backgroundColor = SkColorSetRGB(0xdd, 0xdd, 0xdd); + // Fallback to transparent if the specified color object is invalid. + extraParams.menuList.backgroundColor = Color::transparent; if (o->hasBackground()) extraParams.menuList.backgroundColor = o->style()->visitedDependentColor(CSSPropertyBackgroundColor).rgb(); diff --git a/Source/WebCore/rendering/RenderThemeChromiumMac.h b/Source/WebCore/rendering/RenderThemeChromiumMac.h index 4fd371f..dcb23dd 100644 --- a/Source/WebCore/rendering/RenderThemeChromiumMac.h +++ b/Source/WebCore/rendering/RenderThemeChromiumMac.h @@ -38,16 +38,18 @@ protected: virtual bool paintMediaMuteButton(RenderObject*, const PaintInfo&, const IntRect&); virtual bool paintMediaSliderTrack(RenderObject*, const PaintInfo&, const IntRect&); virtual bool paintMediaControlsBackground(RenderObject*, const PaintInfo&, const IntRect&); - virtual bool shouldRenderMediaControlPart(ControlPart, Element*); virtual String extraMediaControlsStyleSheet(); - +#if ENABLE(FULLSCREEN_API) + virtual String extraFullScreenStyleSheet(); +#endif + virtual bool paintMediaSliderThumb(RenderObject*, const PaintInfo&, const IntRect&); virtual bool paintMediaVolumeSliderContainer(RenderObject*, const PaintInfo&, const IntRect&); virtual bool paintMediaVolumeSliderTrack(RenderObject*, const PaintInfo&, const IntRect&); virtual bool paintMediaVolumeSliderThumb(RenderObject*, const PaintInfo&, const IntRect&); virtual IntPoint volumeSliderOffsetFromMuteButton(RenderBox*, const IntSize&) const; virtual bool usesMediaControlStatusDisplay() { return false; } - + virtual bool hasOwnDisabledStateHandlingFor(ControlPart) const { return true; } #endif virtual bool usesTestModeFocusRingColor() const; diff --git a/Source/WebCore/rendering/RenderThemeChromiumMac.mm b/Source/WebCore/rendering/RenderThemeChromiumMac.mm index a7d59a9..e4a10ae 100644 --- a/Source/WebCore/rendering/RenderThemeChromiumMac.mm +++ b/Source/WebCore/rendering/RenderThemeChromiumMac.mm @@ -105,11 +105,6 @@ void RenderThemeChromiumMac::adjustMediaSliderThumbSize(RenderObject* o) const RenderMediaControlsChromium::adjustMediaSliderThumbSize(o); } -bool RenderThemeChromiumMac::shouldRenderMediaControlPart(ControlPart part, Element* e) -{ - return RenderMediaControlsChromium::shouldRenderMediaControlPart(part, e); -} - bool RenderThemeChromiumMac::paintMediaPlayButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect) { return RenderMediaControlsChromium::paintMediaControlsPart(MediaPlayButton, object, paintInfo, rect); @@ -135,6 +130,14 @@ String RenderThemeChromiumMac::extraMediaControlsStyleSheet() return String(mediaControlsChromiumUserAgentStyleSheet, sizeof(mediaControlsChromiumUserAgentStyleSheet)); } +#if ENABLE(FULLSCREEN_API) +String RenderThemeChromiumMac::extraFullScreenStyleSheet() +{ + // FIXME: Chromium may wish to style its default media controls differently in fullscreen. + return String(); +} +#endif + bool RenderThemeChromiumMac::paintMediaVolumeSliderContainer(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect) { return true; diff --git a/Source/WebCore/rendering/RenderThemeChromiumSkia.cpp b/Source/WebCore/rendering/RenderThemeChromiumSkia.cpp index 9691876..cafc34d 100644 --- a/Source/WebCore/rendering/RenderThemeChromiumSkia.cpp +++ b/Source/WebCore/rendering/RenderThemeChromiumSkia.cpp @@ -501,13 +501,6 @@ int RenderThemeChromiumSkia::popupInternalPaddingBottom(RenderStyle* style) cons return menuListInternalPadding(style, BottomPadding); } -#if ENABLE(VIDEO) -bool RenderThemeChromiumSkia::shouldRenderMediaControlPart(ControlPart part, Element* e) -{ - return RenderMediaControlsChromium::shouldRenderMediaControlPart(part, e); -} -#endif - // static void RenderThemeChromiumSkia::setDefaultFontSize(int fontSize) { diff --git a/Source/WebCore/rendering/RenderThemeChromiumSkia.h b/Source/WebCore/rendering/RenderThemeChromiumSkia.h index bf0af34..2faf064 100644 --- a/Source/WebCore/rendering/RenderThemeChromiumSkia.h +++ b/Source/WebCore/rendering/RenderThemeChromiumSkia.h @@ -123,7 +123,7 @@ class RenderThemeChromiumSkia : public RenderTheme { #if ENABLE(VIDEO) // Media controls - virtual bool shouldRenderMediaControlPart(ControlPart, Element*); + virtual bool hasOwnDisabledStateHandlingFor(ControlPart) const { return true; } #endif // Provide a way to pass the default font size from the Settings object diff --git a/Source/WebCore/rendering/RenderThemeMac.h b/Source/WebCore/rendering/RenderThemeMac.h index d64944b..8a17acf 100644 --- a/Source/WebCore/rendering/RenderThemeMac.h +++ b/Source/WebCore/rendering/RenderThemeMac.h @@ -83,7 +83,7 @@ public: #if ENABLE(METER_TAG) virtual IntSize meterSizeForBounds(const RenderMeter*, const IntRect&) const; virtual bool paintMeter(RenderObject*, const PaintInfo&, const IntRect&); - virtual bool supportsMeter(ControlPart, bool isHorizontal) const; + virtual bool supportsMeter(ControlPart) const; #endif #if ENABLE(PROGRESS_TAG) @@ -166,8 +166,10 @@ protected: virtual String extraFullScreenStyleSheet(); #endif - virtual bool shouldRenderMediaControlPart(ControlPart, Element*); + virtual bool supportsClosedCaptioning() const { return true; } + virtual bool hasOwnDisabledStateHandlingFor(ControlPart) const; virtual bool usesMediaControlStatusDisplay(); + virtual bool usesMediaControlVolumeSlider() const; virtual void adjustMediaSliderThumbSize(RenderObject*) const; virtual IntPoint volumeSliderOffsetFromMuteButton(RenderBox*, const IntSize&) const; #endif diff --git a/Source/WebCore/rendering/RenderThemeMac.mm b/Source/WebCore/rendering/RenderThemeMac.mm index 0e23c89..a6f999a 100644 --- a/Source/WebCore/rendering/RenderThemeMac.mm +++ b/Source/WebCore/rendering/RenderThemeMac.mm @@ -830,10 +830,6 @@ bool RenderThemeMac::paintMeter(RenderObject* renderObject, const PaintInfo& pai LocalCurrentGraphicsContext localContext(paintInfo.context); - // Becaue NSLevelIndicatorCell doesn't support vertical gauge, we use a portable version - if (rect.width() < rect.height()) - return RenderTheme::paintMeter(renderObject, paintInfo, rect); - NSLevelIndicatorCell* cell = levelIndicatorFor(toRenderMeter(renderObject)); paintInfo.context->save(); [cell drawWithFrame:rect inView:documentViewFor(renderObject)]; @@ -843,7 +839,7 @@ bool RenderThemeMac::paintMeter(RenderObject* renderObject, const PaintInfo& pai return false; } -bool RenderThemeMac::supportsMeter(ControlPart part, bool isHorizontal) const +bool RenderThemeMac::supportsMeter(ControlPart part) const { switch (part) { case RelevancyLevelIndicatorPart: @@ -851,7 +847,7 @@ bool RenderThemeMac::supportsMeter(ControlPart part, bool isHorizontal) const case RatingLevelIndicatorPart: case MeterPart: case ContinuousCapacityLevelIndicatorPart: - return isHorizontal; + return true; default: return false; } @@ -1976,35 +1972,12 @@ String RenderThemeMac::extraFullScreenStyleSheet() } #endif -bool RenderThemeMac::shouldRenderMediaControlPart(ControlPart part, Element* element) +bool RenderThemeMac::hasOwnDisabledStateHandlingFor(ControlPart part) const { - HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(element); - switch (part) { - case MediaVolumeSliderContainerPart: - case MediaVolumeSliderPart: - case MediaVolumeSliderMuteButtonPart: - case MediaVolumeSliderThumbPart: { - return mediaControllerTheme() == MediaControllerThemeQuickTime && mediaElement->hasAudio(); - } - case MediaToggleClosedCaptionsButtonPart: - // We rely on QTKit to render captions so don't enable the button unless it will be able to do so. - if (!element->hasTagName(videoTag)) - return false; - break; - case MediaRewindButtonPart: - if (mediaElement->isFullscreen()) - return mediaElement->movieLoadType() == MediaPlayer::LiveStream - || mediaElement->movieLoadType() == MediaPlayer::StoredStream; - case MediaSeekForwardButtonPart: - case MediaSeekBackButtonPart: - if (mediaElement->isFullscreen()) - return mediaElement->movieLoadType() != MediaPlayer::StoredStream - && mediaElement->movieLoadType() != MediaPlayer::LiveStream; - default: - break; - } + if (part == MediaMuteButtonPart) + return false; - return RenderTheme::shouldRenderMediaControlPart(part, element); + return mediaControllerTheme() == MediaControllerThemeClassic; } bool RenderThemeMac::usesMediaControlStatusDisplay() @@ -2012,6 +1985,11 @@ bool RenderThemeMac::usesMediaControlStatusDisplay() return mediaControllerTheme() == MediaControllerThemeQuickTime; } +bool RenderThemeMac::usesMediaControlVolumeSlider() const +{ + return mediaControllerTheme() == MediaControllerThemeQuickTime; +} + IntPoint RenderThemeMac::volumeSliderOffsetFromMuteButton(RenderBox* muteButtonBox, const IntSize& size) const { return RenderMediaControls::volumeSliderOffsetFromMuteButton(muteButtonBox, size); diff --git a/Source/WebCore/rendering/RenderThemeWin.cpp b/Source/WebCore/rendering/RenderThemeWin.cpp index af100b7..15f64c5 100644 --- a/Source/WebCore/rendering/RenderThemeWin.cpp +++ b/Source/WebCore/rendering/RenderThemeWin.cpp @@ -1029,22 +1029,16 @@ String RenderThemeWin::extraMediaControlsStyleSheet() return String(mediaControlsQuickTimeUserAgentStyleSheet, sizeof(mediaControlsQuickTimeUserAgentStyleSheet)); } -bool RenderThemeWin::shouldRenderMediaControlPart(ControlPart part, Element* element) +bool RenderThemeWin::supportsClosedCaptioning() const { - if (part == MediaToggleClosedCaptionsButtonPart) { // We rely on QuickTime to render captions so only enable the button for a video element. #if SAFARI_THEME_VERSION >= 4 - if (!element->hasTagName(videoTag)) - return false; + return true; #else - return false; + return false; #endif - } - - return RenderTheme::shouldRenderMediaControlPart(part, element); } - bool RenderThemeWin::paintMediaFullscreenButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) { return RenderMediaControls::paintMediaControlsPart(MediaFullscreenButton, o, paintInfo, r); diff --git a/Source/WebCore/rendering/RenderThemeWin.h b/Source/WebCore/rendering/RenderThemeWin.h index 7e0223a..7e8a491 100644 --- a/Source/WebCore/rendering/RenderThemeWin.h +++ b/Source/WebCore/rendering/RenderThemeWin.h @@ -124,7 +124,7 @@ public: #if ENABLE(VIDEO) virtual String extraMediaControlsStyleSheet(); - virtual bool shouldRenderMediaControlPart(ControlPart, Element*); + virtual bool supportsClosedCaptioning() const; virtual bool paintMediaControlsBackground(RenderObject*, const PaintInfo&, const IntRect&); virtual bool paintMediaFullscreenButton(RenderObject*, const PaintInfo&, const IntRect&); virtual bool paintMediaMuteButton(RenderObject*, const PaintInfo&, const IntRect&); diff --git a/Source/WebCore/rendering/RenderTreeAsText.cpp b/Source/WebCore/rendering/RenderTreeAsText.cpp index 8857391..2f5bd74 100644 --- a/Source/WebCore/rendering/RenderTreeAsText.cpp +++ b/Source/WebCore/rendering/RenderTreeAsText.cpp @@ -722,7 +722,10 @@ static String nodePosition(Node* node) result += "body"; break; } - result += "child " + String::number(n->nodeIndex()) + " {" + getTagName(n) + "}"; + if (n->isShadowBoundary()) + result += "{" + getTagName(n) + "}"; + else + result += "child " + String::number(n->nodeIndex()) + " {" + getTagName(n) + "}"; } else result += "document"; } diff --git a/Source/WebCore/rendering/RenderView.cpp b/Source/WebCore/rendering/RenderView.cpp index d25240b..20afefa 100644 --- a/Source/WebCore/rendering/RenderView.cpp +++ b/Source/WebCore/rendering/RenderView.cpp @@ -226,13 +226,17 @@ void RenderView::paintBoxDecorations(PaintInfo& paintInfo, int, int) RenderBox* rootBox = rootRenderer->isBox() ? toRenderBox(rootRenderer) : 0; rootFillsViewport = rootBox && !rootBox->x() && !rootBox->y() && rootBox->width() >= width() && rootBox->height() >= height(); } - + + float pageScaleFactor = 1; + if (Frame* frame = m_frameView->frame()) + pageScaleFactor = frame->pageScaleFactor(); + // If painting will entirely fill the view, no need to fill the background. - if (rootFillsViewport && rendererObscuresBackground(firstChild())) + if (rootFillsViewport && rendererObscuresBackground(firstChild()) && pageScaleFactor >= 1) return; // This code typically only executes if the root element's visibility has been set to hidden, - // or there is a transform on the <html>. + // if there is a transform on the <html>, or if there is a page scale factor less than 1. // Only fill with the base background color (typically white) if we're the root document, // since iframes/frames with no background in the child document should show the parent's background. if (frameView()->isTransparent()) // FIXME: This needs to be dynamic. We should be able to go back to blitting if we ever stop being transparent. diff --git a/Source/WebCore/rendering/RenderWidget.cpp b/Source/WebCore/rendering/RenderWidget.cpp index 33f6436..894d689 100644 --- a/Source/WebCore/rendering/RenderWidget.cpp +++ b/Source/WebCore/rendering/RenderWidget.cpp @@ -207,8 +207,10 @@ void RenderWidget::setWidget(PassRefPtr<Widget> widget) setWidgetGeometry(IntRect(localToAbsoluteQuad(FloatQuad(contentBoxRect())).boundingBox()), contentBoxRect().size()); if (style()->visibility() != VISIBLE) m_widget->hide(); - else + else { m_widget->show(); + repaint(); + } } moveWidgetToParentSoon(m_widget.get(), m_frameView); } diff --git a/Source/WebCore/rendering/RenderingAllInOne.cpp b/Source/WebCore/rendering/RenderingAllInOne.cpp index c9f6707..d0bb843 100644 --- a/Source/WebCore/rendering/RenderingAllInOne.cpp +++ b/Source/WebCore/rendering/RenderingAllInOne.cpp @@ -35,7 +35,6 @@ #include "InlineFlowBox.cpp" #include "InlineTextBox.cpp" #include "LayoutState.cpp" -#include "MediaControlElements.cpp" #include "PointerEventsHitRules.cpp" #include "RenderApplet.cpp" #include "RenderArena.cpp" @@ -62,7 +61,6 @@ #include "RenderImage.cpp" #include "RenderImageResource.cpp" #include "RenderImageResourceStyleImage.cpp" -#include "RenderIndicator.cpp" #include "RenderInline.cpp" #include "RenderLayer.cpp" #include "RenderLayerCompositor.cpp" diff --git a/Source/WebCore/rendering/RootInlineBox.cpp b/Source/WebCore/rendering/RootInlineBox.cpp index c6f1bd8..b504684 100644 --- a/Source/WebCore/rendering/RootInlineBox.cpp +++ b/Source/WebCore/rendering/RootInlineBox.cpp @@ -133,11 +133,11 @@ float RootInlineBox::placeEllipsisBox(bool ltr, float blockLeftEdge, float block return result; } -void RootInlineBox::paintEllipsisBox(PaintInfo& paintInfo, int tx, int ty) const +void RootInlineBox::paintEllipsisBox(PaintInfo& paintInfo, int tx, int ty, int lineTop, int lineBottom) const { if (hasEllipsisBox() && paintInfo.shouldPaintWithinRoot(renderer()) && renderer()->style()->visibility() == VISIBLE && paintInfo.phase == PaintPhaseForeground) - ellipsisBox()->paint(paintInfo, tx, ty); + ellipsisBox()->paint(paintInfo, tx, ty, lineTop, lineBottom); } #if PLATFORM(MAC) @@ -154,7 +154,7 @@ void RootInlineBox::addHighlightOverflow() // Highlight acts as a selection inflation. FloatRect rootRect(0, selectionTop(), logicalWidth(), selectionHeight()); IntRect inflatedRect = enclosingIntRect(page->chrome()->client()->customHighlightRect(renderer()->node(), renderer()->style()->highlight(), rootRect)); - setOverflowFromLogicalRects(inflatedRect, inflatedRect); + setOverflowFromLogicalRects(inflatedRect, inflatedRect, lineTop(), lineBottom()); } void RootInlineBox::paintCustomHighlight(PaintInfo& paintInfo, int tx, int ty, const AtomicString& highlightType) @@ -178,10 +178,10 @@ void RootInlineBox::paintCustomHighlight(PaintInfo& paintInfo, int tx, int ty, c #endif -void RootInlineBox::paint(PaintInfo& paintInfo, int tx, int ty) +void RootInlineBox::paint(PaintInfo& paintInfo, int tx, int ty, int lineTop, int lineBottom) { - InlineFlowBox::paint(paintInfo, tx, ty); - paintEllipsisBox(paintInfo, tx, ty); + InlineFlowBox::paint(paintInfo, tx, ty, lineTop, lineBottom); + paintEllipsisBox(paintInfo, tx, ty, lineTop, lineBottom); #if PLATFORM(MAC) RenderStyle* styleToUse = renderer()->style(m_firstLine); if (styleToUse->highlight() != nullAtom && !paintInfo.context->paintingDisabled()) @@ -189,15 +189,15 @@ void RootInlineBox::paint(PaintInfo& paintInfo, int tx, int ty) #endif } -bool RootInlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty) +bool RootInlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, int lineTop, int lineBottom) { if (hasEllipsisBox() && visibleToHitTesting()) { - if (ellipsisBox()->nodeAtPoint(request, result, x, y, tx, ty)) { + if (ellipsisBox()->nodeAtPoint(request, result, x, y, tx, ty, lineTop, lineBottom)) { renderer()->updateHitTestResult(result, IntPoint(x - tx, y - ty)); return true; } } - return InlineFlowBox::nodeAtPoint(request, result, x, y, tx, ty); + return InlineFlowBox::nodeAtPoint(request, result, x, y, tx, ty, lineTop, lineBottom); } void RootInlineBox::adjustPosition(float dx, float dy) @@ -529,7 +529,7 @@ void RootInlineBox::attachLineBoxToRenderObject() IntRect RootInlineBox::paddedLayoutOverflowRect(int endPadding) const { - IntRect lineLayoutOverflow = layoutOverflowRect(); + IntRect lineLayoutOverflow = layoutOverflowRect(lineTop(), lineBottom()); if (!endPadding) return lineLayoutOverflow; @@ -785,7 +785,7 @@ bool RootInlineBox::includesRootLineBoxFontOrLeading() const return (lineBoxContain & LineBoxContainBlock) || (lineBoxContain & LineBoxContainInline) || (lineBoxContain & LineBoxContainFont); } -Node* RootInlineBox::getLogicalStartBoxWithNode(InlineBox*& startBox) +Node* RootInlineBox::getLogicalStartBoxWithNode(InlineBox*& startBox) const { Vector<InlineBox*> leafBoxesInLogicalOrder; collectLeafBoxesInLogicalOrder(leafBoxesInLogicalOrder); @@ -799,7 +799,7 @@ Node* RootInlineBox::getLogicalStartBoxWithNode(InlineBox*& startBox) return 0; } -Node* RootInlineBox::getLogicalEndBoxWithNode(InlineBox*& endBox) +Node* RootInlineBox::getLogicalEndBoxWithNode(InlineBox*& endBox) const { Vector<InlineBox*> leafBoxesInLogicalOrder; collectLeafBoxesInLogicalOrder(leafBoxesInLogicalOrder); diff --git a/Source/WebCore/rendering/RootInlineBox.h b/Source/WebCore/rendering/RootInlineBox.h index 0ff5704..2564d85 100644 --- a/Source/WebCore/rendering/RootInlineBox.h +++ b/Source/WebCore/rendering/RootInlineBox.h @@ -83,8 +83,7 @@ public: EllipsisBox* ellipsisBox() const; - void paintEllipsisBox(PaintInfo&, int tx, int ty) const; - bool hitTestEllipsisBox(HitTestResult&, int x, int y, int tx, int ty, HitTestAction, bool); + void paintEllipsisBox(PaintInfo&, int tx, int ty, int lineTop, int lineBottom) const; virtual void clearTruncation(); @@ -96,8 +95,8 @@ public: void paintCustomHighlight(PaintInfo&, int tx, int ty, const AtomicString& highlightType); #endif - virtual void paint(PaintInfo&, int tx, int ty); - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int, int, int, int); + virtual void paint(PaintInfo&, int tx, int ty, int lineTop, int lineBottom); + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, int lineTop, int lineBottom); bool hasSelectedChildren() const { return m_hasSelectedChildrenOrCanHaveLeadingExpansion; } void setHasSelectedChildren(bool hasSelectedChildren) { m_hasSelectedChildrenOrCanHaveLeadingExpansion = hasSelectedChildren; } @@ -112,12 +111,13 @@ public: InlineBox* closestLeafChildForLogicalLeftPosition(int, bool onlyEditableLeaves = false); - Vector<RenderBox*>& floats() + void appendFloat(RenderBox* floatingBox) { ASSERT(!isDirty()); - if (!m_floats) - m_floats= adoptPtr(new Vector<RenderBox*>); - return *m_floats; + if (m_floats) + m_floats->append(floatingBox); + else + m_floats= adoptPtr(new Vector<RenderBox*>(1, floatingBox)); } Vector<RenderBox*>* floatsPtr() { ASSERT(!isDirty()); return m_floats.get(); } @@ -141,9 +141,26 @@ public: bool includeMarginForBox(InlineBox*) const; bool fitsToGlyphs() const; bool includesRootLineBoxFontOrLeading() const; + + int logicalTopVisualOverflow() const + { + return InlineFlowBox::logicalTopVisualOverflow(lineTop()); + } + int logicalBottomVisualOverflow() const + { + return InlineFlowBox::logicalBottomVisualOverflow(lineBottom()); + } + int logicalTopLayoutOverflow() const + { + return InlineFlowBox::logicalTopLayoutOverflow(lineTop()); + } + int logicalBottomLayoutOverflow() const + { + return InlineFlowBox::logicalBottomLayoutOverflow(lineBottom()); + } - Node* getLogicalStartBoxWithNode(InlineBox*&); - Node* getLogicalEndBoxWithNode(InlineBox*&); + Node* getLogicalStartBoxWithNode(InlineBox*&) const; + Node* getLogicalEndBoxWithNode(InlineBox*&) const; private: bool hasEllipsisBox() const { return m_hasEllipsisBoxOrHyphen; } void setHasEllipsisBox(bool hasEllipsisBox) { m_hasEllipsisBoxOrHyphen = hasEllipsisBox; } diff --git a/Source/WebCore/rendering/ShadowElement.cpp b/Source/WebCore/rendering/ShadowElement.cpp index 5b1a962..955384a 100644 --- a/Source/WebCore/rendering/ShadowElement.cpp +++ b/Source/WebCore/rendering/ShadowElement.cpp @@ -29,85 +29,6 @@ namespace WebCore { using namespace HTMLNames; -PassRefPtr<ShadowBlockElement> ShadowBlockElement::create(HTMLElement* shadowParent) -{ - return adoptRef(new ShadowBlockElement(shadowParent)); -} - -ShadowBlockElement::ShadowBlockElement(HTMLElement* shadowParent) - : ShadowElement<HTMLDivElement>(divTag, shadowParent) -{ -} - -void ShadowBlockElement::layoutAsPart(const IntRect& partRect) -{ - RenderBox* parentRenderer = toRenderBox(renderer()->parent()); - RenderBox* selfRenderer = toRenderBox(renderer()); - IntRect oldRect = selfRenderer->frameRect(); - - LayoutStateMaintainer statePusher(parentRenderer->view(), parentRenderer, parentRenderer->size(), parentRenderer->style()->isFlippedBlocksWritingMode()); - - if (oldRect.size() != partRect.size()) - selfRenderer->setChildNeedsLayout(true, false); - - selfRenderer->layoutIfNeeded(); - selfRenderer->setFrameRect(partRect); - - if (selfRenderer->checkForRepaintDuringLayout()) - selfRenderer->repaintDuringLayoutIfMoved(oldRect); - - statePusher.pop(); - parentRenderer->addOverflowFromChild(selfRenderer); -} - -void ShadowBlockElement::updateStyleForPart(PseudoId pseudoId) -{ - if (renderer()->style()->styleType() != pseudoId) - renderer()->setStyle(createStyleForPart(renderer()->parent(), pseudoId)); -} - -PassRefPtr<ShadowBlockElement> ShadowBlockElement::createForPart(HTMLElement* shadowParent, PseudoId pseudoId) -{ - RefPtr<ShadowBlockElement> part = create(shadowParent); - part->initAsPart(pseudoId); - return part.release(); -} - -void ShadowBlockElement::initAsPart(PseudoId pseudoId) -{ - RenderObject* parentRenderer = shadowHost()->renderer(); - RefPtr<RenderStyle> styleForPart = createStyleForPart(parentRenderer, pseudoId); - setRenderer(createRenderer(parentRenderer->renderArena(), styleForPart.get())); - renderer()->setStyle(styleForPart.release()); - setAttached(); - setInDocument(); -} - -PassRefPtr<RenderStyle> ShadowBlockElement::createStyleForPart(RenderObject* parentRenderer, PseudoId pseudoId) -{ - RefPtr<RenderStyle> styleForPart; - RenderStyle* pseudoStyle = parentRenderer->getCachedPseudoStyle(pseudoId); - if (pseudoStyle) - styleForPart = RenderStyle::clone(pseudoStyle); - else - styleForPart = RenderStyle::create(); - - styleForPart->inheritFrom(parentRenderer->style()); - styleForPart->setDisplay(BLOCK); - styleForPart->setAppearance(NoControlPart); - return styleForPart.release(); -} - -bool ShadowBlockElement::partShouldHaveStyle(const RenderObject* parentRenderer, PseudoId pseudoId) -{ - // We have some -webkit-appearance values for default styles of parts and - // that appearance get turned off during RenderStyle creation - // if they have background styles specified. - // So !hasAppearance() implies that there are something to be styled. - RenderStyle* pseudoStyle = parentRenderer->getCachedPseudoStyle(pseudoId); - return !(pseudoStyle && pseudoStyle->hasAppearance()); -} - PassRefPtr<ShadowInputElement> ShadowInputElement::create(HTMLElement* shadowParent) { return adoptRef(new ShadowInputElement(shadowParent)); diff --git a/Source/WebCore/rendering/ShadowElement.h b/Source/WebCore/rendering/ShadowElement.h index 9a5d118..0db6a83 100644 --- a/Source/WebCore/rendering/ShadowElement.h +++ b/Source/WebCore/rendering/ShadowElement.h @@ -61,21 +61,6 @@ void ShadowElement<BaseElement>::detach() BaseElement::setShadowHost(0); } -class ShadowBlockElement : public ShadowElement<HTMLDivElement> { -public: - static PassRefPtr<ShadowBlockElement> create(HTMLElement*); - static PassRefPtr<ShadowBlockElement> createForPart(HTMLElement*, PseudoId); - static bool partShouldHaveStyle(const RenderObject* parentRenderer, PseudoId pseudoId); - void layoutAsPart(const IntRect& partRect); - virtual void updateStyleForPart(PseudoId); - -protected: - ShadowBlockElement(HTMLElement*); - void initAsPart(PseudoId pasuedId); -private: - static PassRefPtr<RenderStyle> createStyleForPart(RenderObject*, PseudoId); -}; - class ShadowInputElement : public ShadowElement<HTMLInputElement> { public: static PassRefPtr<ShadowInputElement> create(HTMLElement*); diff --git a/Source/WebCore/rendering/style/RenderStyle.cpp b/Source/WebCore/rendering/style/RenderStyle.cpp index 34e972d..60518f7 100644 --- a/Source/WebCore/rendering/style/RenderStyle.cpp +++ b/Source/WebCore/rendering/style/RenderStyle.cpp @@ -176,17 +176,17 @@ RenderStyle::~RenderStyle() bool RenderStyle::operator==(const RenderStyle& o) const { // compare everything except the pseudoStyle pointer - return inherited_flags == o.inherited_flags && - noninherited_flags == o.noninherited_flags && - m_box == o.m_box && - visual == o.visual && - m_background == o.m_background && - surround == o.surround && - rareNonInheritedData == o.rareNonInheritedData && - rareInheritedData == o.rareInheritedData && - inherited == o.inherited + return inherited_flags == o.inherited_flags + && noninherited_flags == o.noninherited_flags + && m_box == o.m_box + && visual == o.visual + && m_background == o.m_background + && surround == o.surround + && rareNonInheritedData == o.rareNonInheritedData + && rareInheritedData == o.rareInheritedData + && inherited == o.inherited #if ENABLE(SVG) - && m_svgStyle == o.m_svgStyle + && m_svgStyle == o.m_svgStyle #endif ; } @@ -272,22 +272,22 @@ void RenderStyle::removeCachedPseudoStyle(PseudoId pid) bool RenderStyle::inheritedNotEqual(const RenderStyle* other) const { - return inherited_flags != other->inherited_flags || - inherited != other->inherited || + return inherited_flags != other->inherited_flags + || inherited != other->inherited #if ENABLE(SVG) - m_svgStyle->inheritedNotEqual(other->m_svgStyle.get()) || + || m_svgStyle->inheritedNotEqual(other->m_svgStyle.get()) #endif - rareInheritedData != other->rareInheritedData; + || rareInheritedData != other->rareInheritedData; } static bool positionedObjectMoved(const LengthBox& a, const LengthBox& b) { // If any unit types are different, then we can't guarantee // that this was just a movement. - if (a.left().type() != b.left().type() || - a.right().type() != b.right().type() || - a.top().type() != b.top().type() || - a.bottom().type() != b.bottom().type()) + if (a.left().type() != b.left().type() + || a.right().type() != b.right().type() + || a.top().type() != b.top().type() + || a.bottom().type() != b.bottom().type()) return false; // Only one unit can be non-auto in the horizontal direction and @@ -316,12 +316,12 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon } #endif - if (m_box->width() != other->m_box->width() || - m_box->minWidth() != other->m_box->minWidth() || - m_box->maxWidth() != other->m_box->maxWidth() || - m_box->height() != other->m_box->height() || - m_box->minHeight() != other->m_box->minHeight() || - m_box->maxHeight() != other->m_box->maxHeight()) + if (m_box->width() != other->m_box->width() + || m_box->minWidth() != other->m_box->minWidth() + || m_box->maxWidth() != other->m_box->maxWidth() + || m_box->height() != other->m_box->height() + || m_box->minHeight() != other->m_box->minHeight() + || m_box->maxHeight() != other->m_box->maxHeight()) return StyleDifferenceLayout; if (m_box->verticalAlign() != other->m_box->verticalAlign() || noninherited_flags._vertical_align != other->noninherited_flags._vertical_align) @@ -337,15 +337,15 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon return StyleDifferenceLayout; if (rareNonInheritedData.get() != other->rareNonInheritedData.get()) { - if (rareNonInheritedData->m_appearance != other->rareNonInheritedData->m_appearance || - rareNonInheritedData->marginBeforeCollapse != other->rareNonInheritedData->marginBeforeCollapse || - rareNonInheritedData->marginAfterCollapse != other->rareNonInheritedData->marginAfterCollapse || - rareNonInheritedData->lineClamp != other->rareNonInheritedData->lineClamp || - rareNonInheritedData->textOverflow != other->rareNonInheritedData->textOverflow) + if (rareNonInheritedData->m_appearance != other->rareNonInheritedData->m_appearance + || rareNonInheritedData->marginBeforeCollapse != other->rareNonInheritedData->marginBeforeCollapse + || rareNonInheritedData->marginAfterCollapse != other->rareNonInheritedData->marginAfterCollapse + || rareNonInheritedData->lineClamp != other->rareNonInheritedData->lineClamp + || rareNonInheritedData->textOverflow != other->rareNonInheritedData->textOverflow) return StyleDifferenceLayout; - if (rareNonInheritedData->flexibleBox.get() != other->rareNonInheritedData->flexibleBox.get() && - *rareNonInheritedData->flexibleBox.get() != *other->rareNonInheritedData->flexibleBox.get()) + if (rareNonInheritedData->flexibleBox.get() != other->rareNonInheritedData->flexibleBox.get() + && *rareNonInheritedData->flexibleBox.get() != *other->rareNonInheritedData->flexibleBox.get()) return StyleDifferenceLayout; // FIXME: We should add an optimized form of layout that just recomputes visual overflow. @@ -355,12 +355,12 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon if (!rareNonInheritedData->reflectionDataEquivalent(*other->rareNonInheritedData.get())) return StyleDifferenceLayout; - if (rareNonInheritedData->m_multiCol.get() != other->rareNonInheritedData->m_multiCol.get() && - *rareNonInheritedData->m_multiCol.get() != *other->rareNonInheritedData->m_multiCol.get()) + if (rareNonInheritedData->m_multiCol.get() != other->rareNonInheritedData->m_multiCol.get() + && *rareNonInheritedData->m_multiCol.get() != *other->rareNonInheritedData->m_multiCol.get()) return StyleDifferenceLayout; - if (rareNonInheritedData->m_transform.get() != other->rareNonInheritedData->m_transform.get() && - *rareNonInheritedData->m_transform.get() != *other->rareNonInheritedData->m_transform.get()) { + if (rareNonInheritedData->m_transform.get() != other->rareNonInheritedData->m_transform.get() + && *rareNonInheritedData->m_transform.get() != *other->rareNonInheritedData->m_transform.get()) { #if USE(ACCELERATED_COMPOSITING) changedContextSensitiveProperties |= ContextSensitivePropertyTransform; // Don't return; keep looking for another change @@ -371,11 +371,11 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon #if !USE(ACCELERATED_COMPOSITING) if (rareNonInheritedData.get() != other->rareNonInheritedData.get()) { - if (rareNonInheritedData->m_transformStyle3D != other->rareNonInheritedData->m_transformStyle3D || - rareNonInheritedData->m_backfaceVisibility != other->rareNonInheritedData->m_backfaceVisibility || - rareNonInheritedData->m_perspective != other->rareNonInheritedData->m_perspective || - rareNonInheritedData->m_perspectiveOriginX != other->rareNonInheritedData->m_perspectiveOriginX || - rareNonInheritedData->m_perspectiveOriginY != other->rareNonInheritedData->m_perspectiveOriginY) + if (rareNonInheritedData->m_transformStyle3D != other->rareNonInheritedData->m_transformStyle3D + || rareNonInheritedData->m_backfaceVisibility != other->rareNonInheritedData->m_backfaceVisibility + || rareNonInheritedData->m_perspective != other->rareNonInheritedData->m_perspective + || rareNonInheritedData->m_perspectiveOriginX != other->rareNonInheritedData->m_perspectiveOriginX + || rareNonInheritedData->m_perspectiveOriginY != other->rareNonInheritedData->m_perspectiveOriginY) return StyleDifferenceLayout; } #endif @@ -388,24 +388,24 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon } if (rareInheritedData.get() != other->rareInheritedData.get()) { - if (rareInheritedData->highlight != other->rareInheritedData->highlight || - rareInheritedData->indent != other->rareInheritedData->indent || - rareInheritedData->m_effectiveZoom != other->rareInheritedData->m_effectiveZoom || - rareInheritedData->textSizeAdjust != other->rareInheritedData->textSizeAdjust || - rareInheritedData->wordBreak != other->rareInheritedData->wordBreak || - rareInheritedData->wordWrap != other->rareInheritedData->wordWrap || - rareInheritedData->nbspMode != other->rareInheritedData->nbspMode || - rareInheritedData->khtmlLineBreak != other->rareInheritedData->khtmlLineBreak || - rareInheritedData->textSecurity != other->rareInheritedData->textSecurity || - rareInheritedData->hyphens != other->rareInheritedData->hyphens || - rareInheritedData->hyphenationLimitBefore != other->rareInheritedData->hyphenationLimitBefore || - rareInheritedData->hyphenationLimitAfter != other->rareInheritedData->hyphenationLimitAfter || - rareInheritedData->hyphenationString != other->rareInheritedData->hyphenationString || - rareInheritedData->locale != other->rareInheritedData->locale || - rareInheritedData->textEmphasisMark != other->rareInheritedData->textEmphasisMark || - rareInheritedData->textEmphasisPosition != other->rareInheritedData->textEmphasisPosition || - rareInheritedData->textEmphasisCustomMark != other->rareInheritedData->textEmphasisCustomMark || - rareInheritedData->m_lineBoxContain != other->rareInheritedData->m_lineBoxContain) + if (rareInheritedData->highlight != other->rareInheritedData->highlight + || rareInheritedData->indent != other->rareInheritedData->indent + || rareInheritedData->m_effectiveZoom != other->rareInheritedData->m_effectiveZoom + || rareInheritedData->textSizeAdjust != other->rareInheritedData->textSizeAdjust + || rareInheritedData->wordBreak != other->rareInheritedData->wordBreak + || rareInheritedData->wordWrap != other->rareInheritedData->wordWrap + || rareInheritedData->nbspMode != other->rareInheritedData->nbspMode + || rareInheritedData->khtmlLineBreak != other->rareInheritedData->khtmlLineBreak + || rareInheritedData->textSecurity != other->rareInheritedData->textSecurity + || rareInheritedData->hyphens != other->rareInheritedData->hyphens + || rareInheritedData->hyphenationLimitBefore != other->rareInheritedData->hyphenationLimitBefore + || rareInheritedData->hyphenationLimitAfter != other->rareInheritedData->hyphenationLimitAfter + || rareInheritedData->hyphenationString != other->rareInheritedData->hyphenationString + || rareInheritedData->locale != other->rareInheritedData->locale + || rareInheritedData->textEmphasisMark != other->rareInheritedData->textEmphasisMark + || rareInheritedData->textEmphasisPosition != other->rareInheritedData->textEmphasisPosition + || rareInheritedData->textEmphasisCustomMark != other->rareInheritedData->textEmphasisCustomMark + || rareInheritedData->m_lineBoxContain != other->rareInheritedData->m_lineBoxContain) return StyleDifferenceLayout; if (!rareInheritedData->shadowDataEquivalent(*other->rareInheritedData.get())) @@ -415,52 +415,52 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon return StyleDifferenceLayout; } - if (inherited->line_height != other->inherited->line_height || - inherited->list_style_image != other->inherited->list_style_image || - inherited->font != other->inherited->font || - inherited->horizontal_border_spacing != other->inherited->horizontal_border_spacing || - inherited->vertical_border_spacing != other->inherited->vertical_border_spacing || - inherited_flags._box_direction != other->inherited_flags._box_direction || - inherited_flags._visuallyOrdered != other->inherited_flags._visuallyOrdered || - noninherited_flags._position != other->noninherited_flags._position || - noninherited_flags._floating != other->noninherited_flags._floating || - noninherited_flags._originalDisplay != other->noninherited_flags._originalDisplay) + if (inherited->line_height != other->inherited->line_height + || inherited->list_style_image != other->inherited->list_style_image + || inherited->font != other->inherited->font + || inherited->horizontal_border_spacing != other->inherited->horizontal_border_spacing + || inherited->vertical_border_spacing != other->inherited->vertical_border_spacing + || inherited_flags._box_direction != other->inherited_flags._box_direction + || inherited_flags._visuallyOrdered != other->inherited_flags._visuallyOrdered + || noninherited_flags._position != other->noninherited_flags._position + || noninherited_flags._floating != other->noninherited_flags._floating + || noninherited_flags._originalDisplay != other->noninherited_flags._originalDisplay) return StyleDifferenceLayout; if (((int)noninherited_flags._effectiveDisplay) >= TABLE) { - if (inherited_flags._border_collapse != other->inherited_flags._border_collapse || - inherited_flags._empty_cells != other->inherited_flags._empty_cells || - inherited_flags._caption_side != other->inherited_flags._caption_side || - noninherited_flags._table_layout != other->noninherited_flags._table_layout) + if (inherited_flags._border_collapse != other->inherited_flags._border_collapse + || inherited_flags._empty_cells != other->inherited_flags._empty_cells + || inherited_flags._caption_side != other->inherited_flags._caption_side + || noninherited_flags._table_layout != other->noninherited_flags._table_layout) return StyleDifferenceLayout; // In the collapsing border model, 'hidden' suppresses other borders, while 'none' // does not, so these style differences can be width differences. - if (inherited_flags._border_collapse && - ((borderTopStyle() == BHIDDEN && other->borderTopStyle() == BNONE) || - (borderTopStyle() == BNONE && other->borderTopStyle() == BHIDDEN) || - (borderBottomStyle() == BHIDDEN && other->borderBottomStyle() == BNONE) || - (borderBottomStyle() == BNONE && other->borderBottomStyle() == BHIDDEN) || - (borderLeftStyle() == BHIDDEN && other->borderLeftStyle() == BNONE) || - (borderLeftStyle() == BNONE && other->borderLeftStyle() == BHIDDEN) || - (borderRightStyle() == BHIDDEN && other->borderRightStyle() == BNONE) || - (borderRightStyle() == BNONE && other->borderRightStyle() == BHIDDEN))) + if (inherited_flags._border_collapse + && ((borderTopStyle() == BHIDDEN && other->borderTopStyle() == BNONE) + || (borderTopStyle() == BNONE && other->borderTopStyle() == BHIDDEN) + || (borderBottomStyle() == BHIDDEN && other->borderBottomStyle() == BNONE) + || (borderBottomStyle() == BNONE && other->borderBottomStyle() == BHIDDEN) + || (borderLeftStyle() == BHIDDEN && other->borderLeftStyle() == BNONE) + || (borderLeftStyle() == BNONE && other->borderLeftStyle() == BHIDDEN) + || (borderRightStyle() == BHIDDEN && other->borderRightStyle() == BNONE) + || (borderRightStyle() == BNONE && other->borderRightStyle() == BHIDDEN))) return StyleDifferenceLayout; } if (noninherited_flags._effectiveDisplay == LIST_ITEM) { - if (inherited_flags._list_style_type != other->inherited_flags._list_style_type || - inherited_flags._list_style_position != other->inherited_flags._list_style_position) + if (inherited_flags._list_style_type != other->inherited_flags._list_style_type + || inherited_flags._list_style_position != other->inherited_flags._list_style_position) return StyleDifferenceLayout; } - if (inherited_flags._text_align != other->inherited_flags._text_align || - 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._unicodeBidi != other->noninherited_flags._unicodeBidi) + if (inherited_flags._text_align != other->inherited_flags._text_align + || 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._unicodeBidi != other->noninherited_flags._unicodeBidi) return StyleDifferenceLayout; // Check block flow direction. @@ -472,16 +472,16 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon return StyleDifferenceLayout; // Overflow returns a layout hint. - if (noninherited_flags._overflowX != other->noninherited_flags._overflowX || - noninherited_flags._overflowY != other->noninherited_flags._overflowY) + if (noninherited_flags._overflowX != other->noninherited_flags._overflowX + || noninherited_flags._overflowY != other->noninherited_flags._overflowY) return StyleDifferenceLayout; // If our border widths change, then we need to layout. Other changes to borders // only necessitate a repaint. - if (borderLeftWidth() != other->borderLeftWidth() || - borderTopWidth() != other->borderTopWidth() || - borderBottomWidth() != other->borderBottomWidth() || - borderRightWidth() != other->borderRightWidth()) + if (borderLeftWidth() != other->borderLeftWidth() + || borderTopWidth() != other->borderTopWidth() + || borderBottomWidth() != other->borderBottomWidth() + || borderRightWidth() != other->borderRightWidth()) return StyleDifferenceLayout; // If the counter directives change, trigger a relayout to re-calculate counter values and rebuild the counter node tree. @@ -489,15 +489,15 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon const CounterDirectiveMap* mapB = other->rareNonInheritedData->m_counterDirectives.get(); if (!(mapA == mapB || (mapA && mapB && *mapA == *mapB))) return StyleDifferenceLayout; - if (rareNonInheritedData->m_counterIncrement != other->rareNonInheritedData->m_counterIncrement || - rareNonInheritedData->m_counterReset != other->rareNonInheritedData->m_counterReset) + if (rareNonInheritedData->m_counterIncrement != other->rareNonInheritedData->m_counterIncrement + || rareNonInheritedData->m_counterReset != other->rareNonInheritedData->m_counterReset) return StyleDifferenceLayout; if ((visibility() == COLLAPSE) != (other->visibility() == COLLAPSE)) return StyleDifferenceLayout; - if ((rareNonInheritedData->opacity == 1 && other->rareNonInheritedData->opacity < 1) || - (rareNonInheritedData->opacity < 1 && other->rareNonInheritedData->opacity == 1)) { + if ((rareNonInheritedData->opacity == 1 && other->rareNonInheritedData->opacity < 1) + || (rareNonInheritedData->opacity < 1 && other->rareNonInheritedData->opacity == 1)) { // FIXME: We would like to use SimplifiedLayout here, but we can't quite do that yet. // We need to make sure SimplifiedLayout can operate correctly on RenderInlines (we will need // to add a selfNeedsSimplifiedLayout bit in order to not get confused and taint every line). @@ -527,8 +527,8 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon // We need to make sure SimplifiedLayout can operate correctly on RenderInlines (we will need // to add a selfNeedsSimplifiedLayout bit in order to not get confused and taint every line). return StyleDifferenceLayout; - } else if (m_box->zIndex() != other->m_box->zIndex() || m_box->hasAutoZIndex() != other->m_box->hasAutoZIndex() || - visual->clip != other->visual->clip || visual->hasClip != other->visual->hasClip) + } else if (m_box->zIndex() != other->m_box->zIndex() || m_box->hasAutoZIndex() != other->m_box->hasAutoZIndex() + || visual->clip != other->visual->clip || visual->hasClip != other->visual->hasClip) return StyleDifferenceRepaintLayer; } @@ -541,35 +541,35 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon #endif } - if (rareNonInheritedData->m_mask != other->rareNonInheritedData->m_mask || - rareNonInheritedData->m_maskBoxImage != other->rareNonInheritedData->m_maskBoxImage) + if (rareNonInheritedData->m_mask != other->rareNonInheritedData->m_mask + || rareNonInheritedData->m_maskBoxImage != other->rareNonInheritedData->m_maskBoxImage) return StyleDifferenceRepaintLayer; - if (inherited->color != other->inherited->color || - inherited_flags._visibility != other->inherited_flags._visibility || - inherited_flags._text_decorations != other->inherited_flags._text_decorations || - inherited_flags._force_backgrounds_to_white != other->inherited_flags._force_backgrounds_to_white || - inherited_flags._insideLink != other->inherited_flags._insideLink || - surround->border != other->surround->border || - *m_background.get() != *other->m_background.get() || - visual->textDecoration != other->visual->textDecoration || - rareInheritedData->userModify != other->rareInheritedData->userModify || - rareInheritedData->userSelect != other->rareInheritedData->userSelect || - rareNonInheritedData->userDrag != other->rareNonInheritedData->userDrag || - rareNonInheritedData->m_borderFit != other->rareNonInheritedData->m_borderFit || - rareInheritedData->textFillColor != other->rareInheritedData->textFillColor || - rareInheritedData->textStrokeColor != other->rareInheritedData->textStrokeColor || - rareInheritedData->textEmphasisColor != other->rareInheritedData->textEmphasisColor || - rareInheritedData->textEmphasisFill != other->rareInheritedData->textEmphasisFill) + if (inherited->color != other->inherited->color + || inherited_flags._visibility != other->inherited_flags._visibility + || inherited_flags._text_decorations != other->inherited_flags._text_decorations + || inherited_flags._force_backgrounds_to_white != other->inherited_flags._force_backgrounds_to_white + || inherited_flags._insideLink != other->inherited_flags._insideLink + || surround->border != other->surround->border + || *m_background.get() != *other->m_background.get() + || visual->textDecoration != other->visual->textDecoration + || rareInheritedData->userModify != other->rareInheritedData->userModify + || rareInheritedData->userSelect != other->rareInheritedData->userSelect + || rareNonInheritedData->userDrag != other->rareNonInheritedData->userDrag + || rareNonInheritedData->m_borderFit != other->rareNonInheritedData->m_borderFit + || rareInheritedData->textFillColor != other->rareInheritedData->textFillColor + || rareInheritedData->textStrokeColor != other->rareInheritedData->textStrokeColor + || rareInheritedData->textEmphasisColor != other->rareInheritedData->textEmphasisColor + || rareInheritedData->textEmphasisFill != other->rareInheritedData->textEmphasisFill) return StyleDifferenceRepaint; #if USE(ACCELERATED_COMPOSITING) if (rareNonInheritedData.get() != other->rareNonInheritedData.get()) { - if (rareNonInheritedData->m_transformStyle3D != other->rareNonInheritedData->m_transformStyle3D || - rareNonInheritedData->m_backfaceVisibility != other->rareNonInheritedData->m_backfaceVisibility || - rareNonInheritedData->m_perspective != other->rareNonInheritedData->m_perspective || - rareNonInheritedData->m_perspectiveOriginX != other->rareNonInheritedData->m_perspectiveOriginX || - rareNonInheritedData->m_perspectiveOriginY != other->rareNonInheritedData->m_perspectiveOriginY) + if (rareNonInheritedData->m_transformStyle3D != other->rareNonInheritedData->m_transformStyle3D + || rareNonInheritedData->m_backfaceVisibility != other->rareNonInheritedData->m_backfaceVisibility + || rareNonInheritedData->m_perspective != other->rareNonInheritedData->m_perspective + || rareNonInheritedData->m_perspectiveOriginX != other->rareNonInheritedData->m_perspectiveOriginX + || rareNonInheritedData->m_perspectiveOriginY != other->rareNonInheritedData->m_perspectiveOriginY) return StyleDifferenceRecompositeLayer; } #endif @@ -693,11 +693,11 @@ void RenderStyle::applyTransform(TransformationMatrix& transform, const IntSize& if (applyOrigin == IncludeTransformOrigin) { for (i = 0; i < s; i++) { TransformOperation::OperationType type = rareNonInheritedData->m_transform->m_operations.operations()[i]->getOperationType(); - if (type != TransformOperation::TRANSLATE_X && - type != TransformOperation::TRANSLATE_Y && - type != TransformOperation::TRANSLATE && - type != TransformOperation::TRANSLATE_Z && - type != TransformOperation::TRANSLATE_3D + if (type != TransformOperation::TRANSLATE_X + && type != TransformOperation::TRANSLATE_Y + && type != TransformOperation::TRANSLATE + && type != TransformOperation::TRANSLATE_Z + && type != TransformOperation::TRANSLATE_3D ) { applyTransformOrigin = true; break; @@ -778,41 +778,66 @@ static float calcConstraintScaleFor(const IntRect& rect, const RoundedIntRect::R // top radiiSum = static_cast<unsigned>(radii.topLeft().width()) + static_cast<unsigned>(radii.topRight().width()); // Casts to avoid integer overflow. if (radiiSum > static_cast<unsigned>(rect.width())) - factor = std::min(static_cast<float>(rect.width()) / radiiSum, factor); + factor = min(static_cast<float>(rect.width()) / radiiSum, factor); // bottom radiiSum = static_cast<unsigned>(radii.bottomLeft().width()) + static_cast<unsigned>(radii.bottomRight().width()); if (radiiSum > static_cast<unsigned>(rect.width())) - factor = std::min(static_cast<float>(rect.width()) / radiiSum, factor); + factor = min(static_cast<float>(rect.width()) / radiiSum, factor); // left radiiSum = static_cast<unsigned>(radii.topLeft().height()) + static_cast<unsigned>(radii.bottomLeft().height()); if (radiiSum > static_cast<unsigned>(rect.height())) - factor = std::min(static_cast<float>(rect.height()) / radiiSum, factor); + factor = min(static_cast<float>(rect.height()) / radiiSum, factor); // right radiiSum = static_cast<unsigned>(radii.topRight().height()) + static_cast<unsigned>(radii.bottomRight().height()); if (radiiSum > static_cast<unsigned>(rect.height())) - factor = std::min(static_cast<float>(rect.height()) / radiiSum, factor); + factor = min(static_cast<float>(rect.height()) / radiiSum, factor); ASSERT(factor <= 1); return factor; } -RoundedIntRect RenderStyle::getRoundedBorderFor(const IntRect& rect) const +RoundedIntRect RenderStyle::getRoundedBorderFor(const IntRect& borderRect, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const { - RoundedIntRect::Radii radii = calcRadiiFor(surround->border, rect.width(), rect.height()); - radii.scale(calcConstraintScaleFor(rect, radii)); - return RoundedIntRect(rect, radii); + RoundedIntRect roundedRect(borderRect); + if (hasBorderRadius()) { + RoundedIntRect::Radii radii = calcRadiiFor(surround->border, borderRect.width(), borderRect.height()); + radii.scale(calcConstraintScaleFor(borderRect, radii)); + roundedRect.includeLogicalEdges(radii, isHorizontalWritingMode(), includeLogicalLeftEdge, includeLogicalRightEdge); + } + return roundedRect; } -RoundedIntRect RenderStyle::getRoundedInnerBorderWithBorderWidths(const IntRect& innerRect, unsigned short topWidth, - unsigned short bottomWidth, unsigned short leftWidth, unsigned short rightWidth) const +RoundedIntRect RenderStyle::getRoundedInnerBorderFor(const IntRect& borderRect, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const { - RoundedIntRect::Radii radii = calcRadiiFor(surround->border, innerRect.width(), innerRect.height()); - radii.shrink(topWidth, bottomWidth, leftWidth, rightWidth); - radii.scale(calcConstraintScaleFor(innerRect, radii)); - return RoundedIntRect(innerRect, radii); + bool horizontal = isHorizontalWritingMode(); + + int leftWidth = (!horizontal || includeLogicalLeftEdge) ? borderLeftWidth() : 0; + int rightWidth = (!horizontal || includeLogicalRightEdge) ? borderRightWidth() : 0; + int topWidth = (horizontal || includeLogicalLeftEdge) ? borderTopWidth() : 0; + int bottomWidth = (horizontal || includeLogicalRightEdge) ? borderBottomWidth() : 0; + + return getRoundedInnerBorderFor(borderRect, topWidth, bottomWidth, leftWidth, rightWidth, includeLogicalLeftEdge, includeLogicalRightEdge); +} + +RoundedIntRect RenderStyle::getRoundedInnerBorderFor(const IntRect& borderRect, + int topWidth, int bottomWidth, int leftWidth, int rightWidth, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const +{ + IntRect innerRect(borderRect.x() + leftWidth, + borderRect.y() + topWidth, + borderRect.width() - leftWidth - rightWidth, + borderRect.height() - topWidth - bottomWidth); + + RoundedIntRect roundedRect(innerRect); + + if (hasBorderRadius()) { + RoundedIntRect::Radii radii = getRoundedBorderFor(borderRect).radii(); + radii.shrink(topWidth, bottomWidth, leftWidth, rightWidth); + roundedRect.includeLogicalEdges(radii, isHorizontalWritingMode(), includeLogicalLeftEdge, includeLogicalRightEdge); + } + return roundedRect; } const CounterDirectiveMap* RenderStyle::counterDirectives() const @@ -1146,6 +1171,14 @@ const Color RenderStyle::visitedDependentColor(int colorProperty) const return unvisitedColor; Color visitedColor = visitedStyle->colorIncludingFallback(colorProperty, borderStyle); + // FIXME: Technically someone could explicitly specify the color transparent, but for now we'll just + // assume that if the background color is transparent that it wasn't set. Note that it's weird that + // we're returning unvisited info for a visited link, but given our restriction that the alpha values + // have to match, it makes more sense to return the unvisited background color if specified than it + // does to return black. This behavior matches what Firefox 4 does as well. + if (colorProperty == CSSPropertyBackgroundColor && visitedColor == Color::transparent) + return unvisitedColor; + // Take the alpha from the unvisited color, but get the RGB values from the visited color. return Color(visitedColor.red(), visitedColor.green(), visitedColor.blue(), unvisitedColor.alpha()); } diff --git a/Source/WebCore/rendering/style/RenderStyle.h b/Source/WebCore/rendering/style/RenderStyle.h index 859348f..fad5a7b 100644 --- a/Source/WebCore/rendering/style/RenderStyle.h +++ b/Source/WebCore/rendering/style/RenderStyle.h @@ -62,6 +62,7 @@ #include "TextOrientation.h" #include "ThemeTypes.h" #include "TransformOperations.h" +#include "UnicodeBidi.h" #include <wtf/Forward.h> #include <wtf/OwnPtr.h> #include <wtf/RefCounted.h> @@ -160,24 +161,24 @@ protected: struct InheritedFlags { bool operator==(const InheritedFlags& other) const { - return (_empty_cells == other._empty_cells) && - (_caption_side == other._caption_side) && - (_list_style_type == other._list_style_type) && - (_list_style_position == other._list_style_position) && - (_visibility == other._visibility) && - (_text_align == other._text_align) && - (_text_transform == other._text_transform) && - (_text_decorations == other._text_decorations) && - (_cursor_style == other._cursor_style) && - (_direction == other._direction) && - (_border_collapse == other._border_collapse) && - (_white_space == other._white_space) && - (_box_direction == other._box_direction) && - (_visuallyOrdered == other._visuallyOrdered) && - (_force_backgrounds_to_white == other._force_backgrounds_to_white) && - (_pointerEvents == other._pointerEvents) && - (_insideLink == other._insideLink) && - (m_writingMode == other.m_writingMode); + return (_empty_cells == other._empty_cells) + && (_caption_side == other._caption_side) + && (_list_style_type == other._list_style_type) + && (_list_style_position == other._list_style_position) + && (_visibility == other._visibility) + && (_text_align == other._text_align) + && (_text_transform == other._text_transform) + && (_text_decorations == other._text_decorations) + && (_cursor_style == other._cursor_style) + && (_direction == other._direction) + && (_border_collapse == other._border_collapse) + && (_white_space == other._white_space) + && (_box_direction == other._box_direction) + && (_visuallyOrdered == other._visuallyOrdered) + && (_force_backgrounds_to_white == other._force_backgrounds_to_white) + && (_pointerEvents == other._pointerEvents) + && (_insideLink == other._insideLink) + && (m_writingMode == other.m_writingMode); } bool operator!=(const InheritedFlags& other) const { return !(*this == other); } @@ -563,7 +564,6 @@ public: return wordBreak() == BreakWordBreak || wordWrap() == BreakWordWrap; } - StyleImage* backgroundImage() const { return m_background->background().image(); } EFillRepeat backgroundRepeatX() const { return static_cast<EFillRepeat>(m_background->background().repeatX()); } EFillRepeat backgroundRepeatY() const { return static_cast<EFillRepeat>(m_background->background().repeatY()); } CompositeOperator backgroundComposite() const { return static_cast<CompositeOperator>(m_background->background().composite()); } @@ -881,9 +881,11 @@ public: setBorderRadius(LengthSize(Length(s.width(), Fixed), Length(s.height(), Fixed))); } - RoundedIntRect getRoundedBorderFor(const IntRect&) const; - RoundedIntRect getRoundedInnerBorderWithBorderWidths(const IntRect&, unsigned short topWidth, - unsigned short bottomWidth, unsigned short leftWidth, unsigned short rightWidth) const; + RoundedIntRect getRoundedBorderFor(const IntRect& borderRect, bool includeLogicalLeftEdge = true, bool includeLogicalRightEdge = true) const; + RoundedIntRect getRoundedInnerBorderFor(const IntRect& borderRect, bool includeLogicalLeftEdge = true, bool includeLogicalRightEdge = true) const; + + RoundedIntRect getRoundedInnerBorderFor(const IntRect& borderRect, + int topWidth, int bottomWidth, int leftWidth, int rightWidth, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const; void setBorderLeftWidth(unsigned short v) { SET_VAR(surround, border.m_left.m_width, v) } void setBorderLeftStyle(EBorderStyle v) { SET_VAR(surround, border.m_left.m_style, v) } @@ -1205,8 +1207,8 @@ public: bool isOriginalDisplayInlineType() const { - return originalDisplay() == INLINE || originalDisplay() == INLINE_BLOCK || - originalDisplay() == INLINE_BOX || originalDisplay() == INLINE_TABLE; + return originalDisplay() == INLINE || originalDisplay() == INLINE_BLOCK + || originalDisplay() == INLINE_BOX || originalDisplay() == INLINE_TABLE; } void setWritingMode(WritingMode v) { inherited_flags.m_writingMode = v; } diff --git a/Source/WebCore/rendering/style/RenderStyleConstants.h b/Source/WebCore/rendering/style/RenderStyleConstants.h index 08f2c15..5ad42ce 100644 --- a/Source/WebCore/rendering/style/RenderStyleConstants.h +++ b/Source/WebCore/rendering/style/RenderStyleConstants.h @@ -72,8 +72,7 @@ enum PseudoId { 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, + METER_BAR, METER_OPTIMUM, METER_SUBOPTIMAL, METER_EVEN_LESS_GOOD, AFTER_LAST_INTERNAL_PSEUDOID, FULL_SCREEN, FULL_SCREEN_DOCUMENT, FIRST_PUBLIC_PSEUDOID = FIRST_LINE, @@ -120,10 +119,6 @@ enum ETableLayout { TAUTO, TFIXED }; -enum EUnicodeBidi { - UBNormal, Embed, Override, Isolate -}; - // CSS Text Layout Module Level 3: Vertical writing support enum WritingMode { TopToBottomWritingMode, RightToLeftWritingMode, LeftToRightWritingMode, BottomToTopWritingMode diff --git a/Source/WebCore/rendering/svg/RenderSVGInline.cpp b/Source/WebCore/rendering/svg/RenderSVGInline.cpp index 543d14b..02a85ce 100644 --- a/Source/WebCore/rendering/svg/RenderSVGInline.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGInline.cpp @@ -33,6 +33,7 @@ namespace WebCore { RenderSVGInline::RenderSVGInline(Node* n) : RenderInline(n) { + setAlwaysCreateLineBoxes(); } InlineFlowBox* RenderSVGInline::createInlineFlowBox() diff --git a/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp b/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp index a8aa0c8..c8539c6 100644 --- a/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp @@ -179,8 +179,11 @@ VisiblePosition RenderSVGInlineText::positionForPoint(const IntPoint& point) const SVGTextFragment* closestDistanceFragment = 0; SVGInlineTextBox* closestDistanceBox = 0; + AffineTransform fragmentTransform; for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) { - ASSERT(box->isSVGInlineTextBox()); + if (!box->isSVGInlineTextBox()) + continue; + SVGInlineTextBox* textBox = static_cast<SVGInlineTextBox*>(box); Vector<SVGTextFragment>& fragments = textBox->textFragments(); @@ -188,8 +191,9 @@ VisiblePosition RenderSVGInlineText::positionForPoint(const IntPoint& point) for (unsigned i = 0; i < textFragmentsSize; ++i) { const SVGTextFragment& fragment = fragments.at(i); FloatRect fragmentRect(fragment.x, fragment.y - baseline, fragment.width, fragment.height); - if (!fragment.transform.isIdentity()) - fragmentRect = fragment.transform.mapRect(fragmentRect); + fragment.buildFragmentTransform(fragmentTransform); + if (!fragmentTransform.isIdentity()) + fragmentRect = fragmentTransform.mapRect(fragmentRect); float distance = powf(fragmentRect.x() - absolutePoint.x(), 2) + powf(fragmentRect.y() + fragmentRect.height() / 2 - absolutePoint.y(), 2); diff --git a/Source/WebCore/rendering/svg/RenderSVGPath.cpp b/Source/WebCore/rendering/svg/RenderSVGPath.cpp index 1d9eca1..cc7c86e 100644 --- a/Source/WebCore/rendering/svg/RenderSVGPath.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGPath.cpp @@ -128,8 +128,10 @@ void RenderSVGPath::layout() updateCachedBoundariesInParents = true; // Invalidate all resources of this client if our layout changed. - if (m_everHadLayout && selfNeedsLayout()) + if (m_everHadLayout && selfNeedsLayout()) { SVGResourcesCache::clientLayoutChanged(this); + m_markerLayoutInfo.clear(); + } // At this point LayoutRepainter already grabbed the old bounds, // recalculate them now so repaintAfterLayout() uses the new bounds. diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp index 96514af..09195f5 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp @@ -278,7 +278,7 @@ void RenderSVGResourceFilter::postApplyResource(RenderObject* object, GraphicsCo context = filterData->savedContext; filterData->savedContext = 0; -#if !PLATFORM(CG) +#if !USE(CG) if (filterData->sourceGraphicBuffer) filterData->sourceGraphicBuffer->transformColorSpace(ColorSpaceDeviceRGB, ColorSpaceLinearRGB); #endif @@ -296,7 +296,7 @@ void RenderSVGResourceFilter::postApplyResource(RenderObject* object, GraphicsCo // Always true if filterData is just built (filterData->builded is false). if (!lastEffect->hasResult()) { lastEffect->apply(); -#if !PLATFORM(CG) +#if !USE(CG) ImageBuffer* resultImage = lastEffect->asImageBuffer(); if (resultImage) resultImage->transformColorSpace(ColorSpaceLinearRGB, ColorSpaceDeviceRGB); diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.cpp index 64df700..f077bfd 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.cpp @@ -1,6 +1,7 @@ /* * Copyright (C) 2010 University of Szeged * Copyright (C) 2010 Zoltan Herczeg + * Copyright (C) 2011 Renata Hodovan (reni@webkit.org) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,9 +33,35 @@ #include "RenderSVGResource.h" #include "SVGFEImage.h" #include "SVGFilter.h" +#include "SVGNames.h" namespace WebCore { + +void RenderSVGResourceFilterPrimitive::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) +{ + RenderSVGHiddenContainer::styleDidChange(diff, oldStyle); + + RenderObject* filter = parent(); + if (!filter) + return; + ASSERT(filter->isSVGResourceFilter()); + + if (diff == StyleDifferenceEqual || !oldStyle) + return; + + const SVGRenderStyle* newStyle = this->style()->svgStyle(); + if (node()->hasTagName(SVGNames::feFloodTag)) { + if (newStyle->floodColor() != oldStyle->svgStyle()->floodColor()) + static_cast<RenderSVGResourceFilter*>(filter)->primitiveAttributeChanged(this, SVGNames::flood_colorAttr); + if (newStyle->floodOpacity() != oldStyle->svgStyle()->floodOpacity()) + static_cast<RenderSVGResourceFilter*>(filter)->primitiveAttributeChanged(this, SVGNames::flood_opacityAttr); + } else if (node()->hasTagName(SVGNames::feDiffuseLightingTag) || node()->hasTagName(SVGNames::feSpecularLightingTag)) { + if (newStyle->lightingColor() != oldStyle->svgStyle()->lightingColor()) + static_cast<RenderSVGResourceFilter*>(filter)->primitiveAttributeChanged(this, SVGNames::lighting_colorAttr); + } +} + FloatRect RenderSVGResourceFilterPrimitive::determineFilterPrimitiveSubregion(FilterEffect* effect) { FloatRect uniteRect; diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.h b/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.h index 8176d29..e8e4efc 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.h +++ b/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.h @@ -43,6 +43,8 @@ public: { } + virtual void styleDidChange(StyleDifference, const RenderStyle*); + virtual const char* renderName() const { return "RenderSVGResourceFilterPrimitive"; } virtual bool isSVGResourceFilterPrimitive() const { return true; } diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceGradient.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceGradient.cpp index 9f2bb8d..a42a227 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceGradient.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGResourceGradient.cpp @@ -37,7 +37,7 @@ namespace WebCore { RenderSVGResourceGradient::RenderSVGResourceGradient(SVGGradientElement* node) : RenderSVGResourceContainer(node) , m_shouldCollectGradientAttributes(true) -#if PLATFORM(CG) +#if USE(CG) , m_savedContext(0) #endif { @@ -73,7 +73,7 @@ void RenderSVGResourceGradient::removeClientFromCache(RenderObject* client, bool markClientForInvalidation(client, markForInvalidation ? RepaintInvalidation : ParentOnlyInvalidation); } -#if PLATFORM(CG) +#if USE(CG) static inline bool createMaskAndSwapContextForTextGradient(GraphicsContext*& context, GraphicsContext*& savedContext, OwnPtr<ImageBuffer>& imageBuffer, @@ -178,7 +178,7 @@ bool RenderSVGResourceGradient::applyResource(RenderObject* object, RenderStyle* // CG platforms will handle the gradient space transform for text after applying the // resource, so don't apply it here. For non-CG platforms, we want the text bounding // box applied to the gradient space transform now, so the gradient shader can use it. -#if PLATFORM(CG) +#if USE(CG) if (boundingBoxMode() && !objectBoundingBox.isEmpty() && !isPaintingText) { #else if (boundingBoxMode() && !objectBoundingBox.isEmpty()) { @@ -201,7 +201,7 @@ bool RenderSVGResourceGradient::applyResource(RenderObject* object, RenderStyle* context->save(); if (isPaintingText) { -#if PLATFORM(CG) +#if USE(CG) if (!createMaskAndSwapContextForTextGradient(context, m_savedContext, m_imageBuffer, object)) { context->restore(); return false; @@ -235,7 +235,7 @@ void RenderSVGResourceGradient::postApplyResource(RenderObject* object, Graphics ASSERT(resourceMode != ApplyToDefaultMode); if (resourceMode & ApplyToTextMode) { -#if PLATFORM(CG) +#if USE(CG) // CG requires special handling for gradient on text if (m_savedContext && m_gradient.contains(object)) { GradientData* gradientData = m_gradient.get(object); diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceGradient.h b/Source/WebCore/rendering/svg/RenderSVGResourceGradient.h index ad40b53..a71b6c5 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceGradient.h +++ b/Source/WebCore/rendering/svg/RenderSVGResourceGradient.h @@ -65,7 +65,7 @@ private: bool m_shouldCollectGradientAttributes : 1; HashMap<RenderObject*, GradientData*> m_gradient; -#if PLATFORM(CG) +#if USE(CG) GraphicsContext* m_savedContext; OwnPtr<ImageBuffer> m_imageBuffer; #endif diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceMasker.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceMasker.cpp index 7b24248..dc0df08 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceMasker.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGResourceMasker.cpp @@ -154,7 +154,7 @@ void RenderSVGResourceMasker::drawContentIntoMaskImage(MaskerData* maskerData, c maskImageContext->restore(); -#if !PLATFORM(CG) +#if !USE(CG) maskerData->maskImage->transformColorSpace(ColorSpaceDeviceRGB, ColorSpaceLinearRGB); #endif diff --git a/Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp b/Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp index b82be1b..fc26978 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp @@ -166,13 +166,13 @@ bool RenderSVGResourcePattern::applyResource(RenderObject* object, RenderStyle* if (resourceMode & ApplyToFillMode) { context->setTextDrawingMode(TextModeFill); -#if PLATFORM(CG) +#if USE(CG) context->applyFillPattern(); #endif } else if (resourceMode & ApplyToStrokeMode) { context->setTextDrawingMode(TextModeStroke); -#if PLATFORM(CG) +#if USE(CG) context->applyStrokePattern(); #endif } diff --git a/Source/WebCore/rendering/svg/RenderSVGShadowTreeRootContainer.cpp b/Source/WebCore/rendering/svg/RenderSVGShadowTreeRootContainer.cpp index 5736333..d2a1103 100644 --- a/Source/WebCore/rendering/svg/RenderSVGShadowTreeRootContainer.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGShadowTreeRootContainer.cpp @@ -38,7 +38,7 @@ RenderSVGShadowTreeRootContainer::~RenderSVGShadowTreeRootContainer() { if (m_shadowRoot && m_shadowRoot->attached()) { m_shadowRoot->detach(); - m_shadowRoot->clearShadowHost(); + m_shadowRoot->clearSVGShadowHost(); } } @@ -59,7 +59,7 @@ void RenderSVGShadowTreeRootContainer::updateFromElement() useElement->buildPendingResource(); } - ASSERT(m_shadowRoot->shadowHost() == useElement); + ASSERT(m_shadowRoot->svgShadowHost() == useElement); bool shouldRecreateTree = m_recreateTree; if (m_recreateTree) { diff --git a/Source/WebCore/rendering/svg/RenderSVGText.cpp b/Source/WebCore/rendering/svg/RenderSVGText.cpp index 8ca3d58..7af6cc6 100644 --- a/Source/WebCore/rendering/svg/RenderSVGText.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGText.cpp @@ -57,6 +57,11 @@ RenderSVGText::RenderSVGText(SVGTextElement* node) { } +bool RenderSVGText::isChildAllowed(RenderObject* child, RenderStyle*) const +{ + return child->isInline(); +} + RenderSVGText* RenderSVGText::locateRenderSVGTextAncestor(RenderObject* start) { ASSERT(start); diff --git a/Source/WebCore/rendering/svg/RenderSVGText.h b/Source/WebCore/rendering/svg/RenderSVGText.h index 93fc5f8..15ace2b 100644 --- a/Source/WebCore/rendering/svg/RenderSVGText.h +++ b/Source/WebCore/rendering/svg/RenderSVGText.h @@ -36,6 +36,8 @@ class RenderSVGText : public RenderSVGBlock { public: RenderSVGText(SVGTextElement*); + virtual bool isChildAllowed(RenderObject*, RenderStyle*) const; + void setNeedsPositioningValuesUpdate() { m_needsPositioningValuesUpdate = true; } virtual void setNeedsTransformUpdate() { m_needsTransformUpdate = true; } virtual FloatRect repaintRectInLocalCoordinates() const; diff --git a/Source/WebCore/rendering/svg/SVGInlineFlowBox.cpp b/Source/WebCore/rendering/svg/SVGInlineFlowBox.cpp index 10735f6..85707da 100644 --- a/Source/WebCore/rendering/svg/SVGInlineFlowBox.cpp +++ b/Source/WebCore/rendering/svg/SVGInlineFlowBox.cpp @@ -48,7 +48,7 @@ void SVGInlineFlowBox::paintSelectionBackground(PaintInfo& paintInfo) } } -void SVGInlineFlowBox::paint(PaintInfo& paintInfo, int, int) +void SVGInlineFlowBox::paint(PaintInfo& paintInfo, int, int, int, int) { ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection); ASSERT(!paintInfo.context->paintingDisabled()); @@ -64,7 +64,7 @@ void SVGInlineFlowBox::paint(PaintInfo& paintInfo, int, int) if (child->isSVGInlineTextBox()) computeTextMatchMarkerRectForRenderer(toRenderSVGInlineText(static_cast<SVGInlineTextBox*>(child)->textRenderer())); - child->paint(childPaintInfo, 0, 0); + child->paint(childPaintInfo, 0, 0, 0, 0); } } @@ -91,6 +91,7 @@ void SVGInlineFlowBox::computeTextMatchMarkerRectForRenderer(RenderSVGInlineText RenderStyle* style = textRenderer->style(); ASSERT(style); + AffineTransform fragmentTransform; Document* document = textRenderer->document(); Vector<DocumentMarker> markers = document->markers()->markersForNode(textRenderer->node()); @@ -104,7 +105,9 @@ void SVGInlineFlowBox::computeTextMatchMarkerRectForRenderer(RenderSVGInlineText FloatRect markerRect; for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) { - ASSERT(box->isSVGInlineTextBox()); + if (!box->isSVGInlineTextBox()) + continue; + SVGInlineTextBox* textBox = static_cast<SVGInlineTextBox*>(box); int markerStartPosition = max<int>(marker.startOffset - textBox->start(), 0); @@ -127,8 +130,9 @@ void SVGInlineFlowBox::computeTextMatchMarkerRectForRenderer(RenderSVGInlineText continue; FloatRect fragmentRect = textBox->selectionRectForTextFragment(fragment, fragmentStartPosition, fragmentEndPosition, style); - if (!fragment.transform.isIdentity()) - fragmentRect = fragment.transform.mapRect(fragmentRect); + fragment.buildFragmentTransform(fragmentTransform); + if (!fragmentTransform.isIdentity()) + fragmentRect = fragmentTransform.mapRect(fragmentRect); markerRect.unite(fragmentRect); } diff --git a/Source/WebCore/rendering/svg/SVGInlineFlowBox.h b/Source/WebCore/rendering/svg/SVGInlineFlowBox.h index 0e56c9f..304c616 100644 --- a/Source/WebCore/rendering/svg/SVGInlineFlowBox.h +++ b/Source/WebCore/rendering/svg/SVGInlineFlowBox.h @@ -41,7 +41,7 @@ public: void setLogicalHeight(int h) { m_logicalHeight = h; } void paintSelectionBackground(PaintInfo&); - virtual void paint(PaintInfo&, int tx, int ty); + virtual void paint(PaintInfo&, int tx, int ty, int lineTop, int lineBottom); virtual IntRect calculateBoundaries() const; diff --git a/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp b/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp index 17bbfaa..bc550a6 100644 --- a/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp +++ b/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp @@ -70,8 +70,10 @@ int SVGInlineTextBox::offsetForPositionInFragment(const SVGTextFragment& fragmen // Eventually handle lengthAdjust="spacingAndGlyphs". // FIXME: Handle vertical text. - if (!fragment.transform.isIdentity()) - textRun.setHorizontalGlyphStretch(narrowPrecisionToFloat(fragment.transform.xScale())); + AffineTransform fragmentTransform; + fragment.buildFragmentTransform(fragmentTransform); + if (!fragmentTransform.isIdentity()) + textRun.setHorizontalGlyphStretch(narrowPrecisionToFloat(fragmentTransform.xScale())); return fragment.characterOffset - start() + textRenderer->scaledFont().offsetForPosition(textRun, position * scalingFactor, includePartialGlyphs); } @@ -124,6 +126,7 @@ IntRect SVGInlineTextBox::selectionRect(int, int, int startPosition, int endPosi RenderStyle* style = text->style(); ASSERT(style); + AffineTransform fragmentTransform; FloatRect selectionRect; int fragmentStartPosition = 0; int fragmentEndPosition = 0; @@ -138,8 +141,9 @@ IntRect SVGInlineTextBox::selectionRect(int, int, int startPosition, int endPosi continue; FloatRect fragmentRect = selectionRectForTextFragment(fragment, fragmentStartPosition, fragmentEndPosition, style); - if (!fragment.transform.isIdentity()) - fragmentRect = fragment.transform.mapRect(fragmentRect); + fragment.buildFragmentTransform(fragmentTransform); + if (!fragmentTransform.isIdentity()) + fragmentRect = fragmentTransform.mapRect(fragmentRect); selectionRect.unite(fragmentRect); } @@ -211,6 +215,7 @@ void SVGInlineTextBox::paintSelectionBackground(PaintInfo& paintInfo) int fragmentStartPosition = 0; int fragmentEndPosition = 0; + AffineTransform fragmentTransform; unsigned textFragmentsSize = m_textFragments.size(); for (unsigned i = 0; i < textFragmentsSize; ++i) { SVGTextFragment& fragment = m_textFragments.at(i); @@ -222,9 +227,9 @@ void SVGInlineTextBox::paintSelectionBackground(PaintInfo& paintInfo) continue; paintInfo.context->save(); - - if (!fragment.transform.isIdentity()) - paintInfo.context->concatCTM(fragment.transform); + fragment.buildFragmentTransform(fragmentTransform); + if (!fragmentTransform.isIdentity()) + paintInfo.context->concatCTM(fragmentTransform); paintInfo.context->setFillColor(backgroundColor, style->colorSpace()); paintInfo.context->fillRect(selectionRectForTextFragment(fragment, fragmentStartPosition, fragmentEndPosition, style), backgroundColor, style->colorSpace()); @@ -236,7 +241,7 @@ void SVGInlineTextBox::paintSelectionBackground(PaintInfo& paintInfo) ASSERT(!m_paintingResource); } -void SVGInlineTextBox::paint(PaintInfo& paintInfo, int, int) +void SVGInlineTextBox::paint(PaintInfo& paintInfo, int, int, int, int) { ASSERT(paintInfo.shouldPaintWithinRoot(renderer())); ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection); @@ -285,15 +290,16 @@ void SVGInlineTextBox::paint(PaintInfo& paintInfo, int, int) selectionStyle = style; } + AffineTransform fragmentTransform; unsigned textFragmentsSize = m_textFragments.size(); for (unsigned i = 0; i < textFragmentsSize; ++i) { SVGTextFragment& fragment = m_textFragments.at(i); ASSERT(!m_paintingResource); paintInfo.context->save(); - - if (!fragment.transform.isIdentity()) - paintInfo.context->concatCTM(fragment.transform); + fragment.buildFragmentTransform(fragmentTransform); + if (!fragmentTransform.isIdentity()) + paintInfo.context->concatCTM(fragmentTransform); // Spec: All text decorations except line-through should be drawn before the text is filled and stroked; thus, the text is rendered on top of these decorations. int decorations = style->textDecorationsInEffect(); @@ -694,13 +700,14 @@ IntRect SVGInlineTextBox::calculateBoundaries() const float baseline = textRenderer->scaledFont().fontMetrics().floatAscent() / scalingFactor; + AffineTransform fragmentTransform; 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); - - if (!fragment.transform.isIdentity()) - fragmentRect = fragment.transform.mapRect(fragmentRect); + fragment.buildFragmentTransform(fragmentTransform); + if (!fragmentTransform.isIdentity()) + fragmentRect = fragmentTransform.mapRect(fragmentRect); textRect.unite(fragmentRect); } diff --git a/Source/WebCore/rendering/svg/SVGInlineTextBox.h b/Source/WebCore/rendering/svg/SVGInlineTextBox.h index 79c836f..ce48019 100644 --- a/Source/WebCore/rendering/svg/SVGInlineTextBox.h +++ b/Source/WebCore/rendering/svg/SVGInlineTextBox.h @@ -46,7 +46,7 @@ public: virtual float positionForOffset(int offset) const; void paintSelectionBackground(PaintInfo&); - virtual void paint(PaintInfo&, int tx, int ty); + virtual void paint(PaintInfo&, int tx, int ty, int lineTop, int lineBottom); virtual IntRect selectionRect(int absx, int absy, int startPosition, int endPosition); bool mapStartEndPositionsIntoFragmentCoordinates(const SVGTextFragment&, int& startPosition, int& endPosition) const; diff --git a/Source/WebCore/rendering/svg/SVGMarkerLayoutInfo.cpp b/Source/WebCore/rendering/svg/SVGMarkerLayoutInfo.cpp index dea5a0c..27b37f1 100644 --- a/Source/WebCore/rendering/svg/SVGMarkerLayoutInfo.cpp +++ b/Source/WebCore/rendering/svg/SVGMarkerLayoutInfo.cpp @@ -98,6 +98,15 @@ FloatRect SVGMarkerLayoutInfo::calculateBoundaries(RenderSVGResourceMarker* star return bounds; } +void SVGMarkerLayoutInfo::clear() +{ + m_midMarker = 0; + m_elementIndex = 0; + m_strokeWidth = 0; + m_markerData.updateTypeAndMarker(SVGMarkerData::Unknown, 0); + m_layout.clear(); +} + void SVGMarkerLayoutInfo::drawMarkers(PaintInfo& paintInfo) { if (m_layout.isEmpty()) diff --git a/Source/WebCore/rendering/svg/SVGMarkerLayoutInfo.h b/Source/WebCore/rendering/svg/SVGMarkerLayoutInfo.h index 32317b9..c2301cc 100644 --- a/Source/WebCore/rendering/svg/SVGMarkerLayoutInfo.h +++ b/Source/WebCore/rendering/svg/SVGMarkerLayoutInfo.h @@ -57,6 +57,7 @@ public: RenderSVGResourceMarker* midMarker() const { return m_midMarker; } int& elementIndex() { return m_elementIndex; } void addLayoutedMarker(RenderSVGResourceMarker*, const FloatPoint& origin, float angle); + void clear(); private: RenderSVGResourceMarker* m_midMarker; diff --git a/Source/WebCore/rendering/svg/SVGRenderTreeAsText.cpp b/Source/WebCore/rendering/svg/SVGRenderTreeAsText.cpp index a099f87..7d3f909 100644 --- a/Source/WebCore/rendering/svg/SVGRenderTreeAsText.cpp +++ b/Source/WebCore/rendering/svg/SVGRenderTreeAsText.cpp @@ -506,8 +506,12 @@ static inline void writeSVGInlineTextBox(TextStream& ts, SVGInlineTextBox* textB static inline void writeSVGInlineTextBoxes(TextStream& ts, const RenderText& text, int indent) { - for (InlineTextBox* box = text.firstTextBox(); box; box = box->nextTextBox()) + for (InlineTextBox* box = text.firstTextBox(); box; box = box->nextTextBox()) { + if (!box->isSVGInlineTextBox()) + continue; + writeSVGInlineTextBox(ts, static_cast<SVGInlineTextBox*>(box), indent); + } } static void writeStandardPrefix(TextStream& ts, const RenderObject& object, int indent) diff --git a/Source/WebCore/rendering/svg/SVGResourcesCache.cpp b/Source/WebCore/rendering/svg/SVGResourcesCache.cpp index 886f76a..74d2950 100644 --- a/Source/WebCore/rendering/svg/SVGResourcesCache.cpp +++ b/Source/WebCore/rendering/svg/SVGResourcesCache.cpp @@ -126,6 +126,10 @@ void SVGResourcesCache::clientStyleChanged(RenderObject* renderer, StyleDifferen if (diff == StyleDifferenceEqual) return; + // In this case the proper SVGFE*Element will imply whether the modifided CSS properties implies a relayout or repaint. + if (renderer->isSVGResourceFilterPrimitive() && diff == StyleDifferenceRepaint) + return; + clientUpdatedFromElement(renderer, newStyle); RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer, false); } diff --git a/Source/WebCore/rendering/svg/SVGRootInlineBox.cpp b/Source/WebCore/rendering/svg/SVGRootInlineBox.cpp index ddbd3ea..cc6cb75 100644 --- a/Source/WebCore/rendering/svg/SVGRootInlineBox.cpp +++ b/Source/WebCore/rendering/svg/SVGRootInlineBox.cpp @@ -35,7 +35,7 @@ namespace WebCore { -void SVGRootInlineBox::paint(PaintInfo& paintInfo, int, int) +void SVGRootInlineBox::paint(PaintInfo& paintInfo, int, int, int, int) { ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection); ASSERT(!paintInfo.context->paintingDisabled()); @@ -63,7 +63,7 @@ void SVGRootInlineBox::paint(PaintInfo& paintInfo, int, int) if (child->isSVGInlineTextBox()) SVGInlineFlowBox::computeTextMatchMarkerRectForRenderer(toRenderSVGInlineText(static_cast<SVGInlineTextBox*>(child)->textRenderer())); - child->paint(childPaintInfo, 0, 0); + child->paint(childPaintInfo, 0, 0, 0, 0); } } @@ -103,13 +103,13 @@ void SVGRootInlineBox::layoutCharactersInTextBoxes(InlineFlowBox* start, SVGText SVGInlineTextBox* textBox = static_cast<SVGInlineTextBox*>(child); characterLayout.layoutInlineTextBox(textBox); } else { - ASSERT(child->isInlineFlowBox()); - // Skip generated content. Node* node = child->renderer()->node(); if (!node) continue; + ASSERT(child->isInlineFlowBox()); + SVGInlineFlowBox* flowBox = static_cast<SVGInlineFlowBox*>(child); bool isTextPath = node->hasTagName(SVGNames::textPathTag); if (isTextPath) { @@ -146,12 +146,12 @@ void SVGRootInlineBox::layoutChildBoxes(InlineFlowBox* start) textBox->setLogicalWidth(boxRect.width()); textBox->setLogicalHeight(boxRect.height()); } else { - ASSERT(child->isInlineFlowBox()); - // Skip generated content. if (!child->renderer()->node()) continue; + ASSERT(child->isInlineFlowBox()); + SVGInlineFlowBox* flowBox = static_cast<SVGInlineFlowBox*>(child); layoutChildBoxes(flowBox); @@ -214,6 +214,8 @@ InlineBox* SVGRootInlineBox::closestLeafChildForPosition(const IntPoint& point) // FIXME: Check for vertical text! InlineBox* closestLeaf = 0; for (InlineBox* leaf = firstLeaf; leaf; leaf = leaf->nextLeafChild()) { + if (!leaf->isSVGInlineTextBox()) + continue; if (point.y() < leaf->m_y) continue; if (point.y() > leaf->m_y + leaf->virtualLogicalHeight()) @@ -274,8 +276,13 @@ static inline void reverseInlineBoxRangeAndValueListsIfNeeded(void* userData, Ve if (first == last || first == --last) return; - ASSERT((*first)->isSVGInlineTextBox()); - ASSERT((*last)->isSVGInlineTextBox()); + if (!(*last)->isSVGInlineTextBox() || !(*first)->isSVGInlineTextBox()) { + InlineBox* temp = *first; + *first = *last; + *last = temp; + ++first; + continue; + } SVGInlineTextBox* firstTextBox = static_cast<SVGInlineTextBox*>(*first); SVGInlineTextBox* lastTextBox = static_cast<SVGInlineTextBox*>(*last); diff --git a/Source/WebCore/rendering/svg/SVGRootInlineBox.h b/Source/WebCore/rendering/svg/SVGRootInlineBox.h index 39612e7..a83af64 100644 --- a/Source/WebCore/rendering/svg/SVGRootInlineBox.h +++ b/Source/WebCore/rendering/svg/SVGRootInlineBox.h @@ -45,7 +45,7 @@ public: virtual int virtualLogicalHeight() const { return m_logicalHeight; } void setLogicalHeight(int height) { m_logicalHeight = height; } - virtual void paint(PaintInfo&, int tx, int ty); + virtual void paint(PaintInfo&, int tx, int ty, int lineTop, int lineBottom); void computePerCharacterLayoutInformation(); diff --git a/Source/WebCore/rendering/svg/SVGShadowTreeElements.cpp b/Source/WebCore/rendering/svg/SVGShadowTreeElements.cpp index 9ccdef0..ac4a63e 100644 --- a/Source/WebCore/rendering/svg/SVGShadowTreeElements.cpp +++ b/Source/WebCore/rendering/svg/SVGShadowTreeElements.cpp @@ -53,21 +53,21 @@ PassRefPtr<Element> SVGShadowTreeContainerElement::cloneElementWithoutAttributes } // SVGShadowTreeRootElement -inline SVGShadowTreeRootElement::SVGShadowTreeRootElement(Document* document, SVGUseElement* shadowParent) +inline SVGShadowTreeRootElement::SVGShadowTreeRootElement(Document* document, SVGUseElement* host) : SVGShadowTreeContainerElement(document) { - setShadowHost(shadowParent); + setParent(host); setInDocument(); } -PassRefPtr<SVGShadowTreeRootElement> SVGShadowTreeRootElement::create(Document* document, SVGUseElement* shadowParent) +PassRefPtr<SVGShadowTreeRootElement> SVGShadowTreeRootElement::create(Document* document, SVGUseElement* host) { - return adoptRef(new SVGShadowTreeRootElement(document, shadowParent)); + return adoptRef(new SVGShadowTreeRootElement(document, host)); } void SVGShadowTreeRootElement::attachElement(PassRefPtr<RenderStyle> style, RenderArena* arena) { - ASSERT(shadowHost()); + ASSERT(svgShadowHost()); // Create the renderer with the specified style RenderObject* renderer = createRenderer(arena, style.get()); @@ -81,12 +81,12 @@ void SVGShadowTreeRootElement::attachElement(PassRefPtr<RenderStyle> style, Rend // Add the renderer to the render tree if (renderer) - shadowHost()->renderer()->addChild(renderer); + svgShadowHost()->renderer()->addChild(renderer); } -void SVGShadowTreeRootElement::clearShadowHost() +void SVGShadowTreeRootElement::clearSVGShadowHost() { - setShadowHost(0); + setParent(0); } } diff --git a/Source/WebCore/rendering/svg/SVGShadowTreeElements.h b/Source/WebCore/rendering/svg/SVGShadowTreeElements.h index 2952e35..8cbd4b7 100644 --- a/Source/WebCore/rendering/svg/SVGShadowTreeElements.h +++ b/Source/WebCore/rendering/svg/SVGShadowTreeElements.h @@ -53,13 +53,15 @@ private: class SVGShadowTreeRootElement : public SVGShadowTreeContainerElement { public: - static PassRefPtr<SVGShadowTreeRootElement> create(Document*, SVGUseElement* shadowParent); + static PassRefPtr<SVGShadowTreeRootElement> create(Document*, SVGUseElement* host); void attachElement(PassRefPtr<RenderStyle>, RenderArena*); - void clearShadowHost(); + void clearSVGShadowHost(); + + virtual bool isSVGShadowRoot() const { return true; } private: - SVGShadowTreeRootElement(Document*, SVGUseElement* shadowParent); + SVGShadowTreeRootElement(Document*, SVGUseElement* host); }; } diff --git a/Source/WebCore/rendering/svg/SVGTextChunkBuilder.cpp b/Source/WebCore/rendering/svg/SVGTextChunkBuilder.cpp index 47311bd..4391013 100644 --- a/Source/WebCore/rendering/svg/SVGTextChunkBuilder.cpp +++ b/Source/WebCore/rendering/svg/SVGTextChunkBuilder.cpp @@ -53,7 +53,7 @@ void SVGTextChunkBuilder::buildTextChunks(Vector<SVGInlineTextBox*>& lineLayoutB unsigned boxPosition = 0; unsigned boxCount = lineLayoutBoxes.size(); for (; boxPosition < boxCount; ++boxPosition) { - SVGInlineTextBox* textBox = lineLayoutBoxes.at(boxPosition); + SVGInlineTextBox* textBox = lineLayoutBoxes[boxPosition]; if (!textBox->startsNewTextChunk()) continue; @@ -82,14 +82,14 @@ void SVGTextChunkBuilder::layoutTextChunks(Vector<SVGInlineTextBox*>& lineLayout unsigned chunkCount = m_textChunks.size(); for (unsigned i = 0; i < chunkCount; ++i) - processTextChunk(m_textChunks.at(i)); + processTextChunk(m_textChunks[i]); m_textChunks.clear(); } void SVGTextChunkBuilder::addTextChunk(Vector<SVGInlineTextBox*>& lineLayoutBoxes, unsigned boxStart, unsigned boxCount) { - SVGInlineTextBox* textBox = lineLayoutBoxes.at(boxStart); + SVGInlineTextBox* textBox = lineLayoutBoxes[boxStart]; ASSERT(textBox); RenderSVGInlineText* textRenderer = toRenderSVGInlineText(textBox->textRenderer()); @@ -127,7 +127,7 @@ void SVGTextChunkBuilder::addTextChunk(Vector<SVGInlineTextBox*>& lineLayoutBoxe // Handle 'lengthAdjust' property. float desiredTextLength = 0; if (SVGTextContentElement* textContentElement = SVGTextContentElement::elementFromRenderer(textRenderer->parent())) { - desiredTextLength = textContentElement->textLength().value(textContentElement); + desiredTextLength = textContentElement->specifiedTextLength().value(textContentElement); switch (static_cast<SVGTextContentElement::SVGLengthAdjustType>(textContentElement->lengthAdjust())) { case SVGTextContentElement::LENGTHADJUST_UNKNOWN: @@ -145,7 +145,7 @@ void SVGTextChunkBuilder::addTextChunk(Vector<SVGInlineTextBox*>& lineLayoutBoxe Vector<SVGInlineTextBox*>& boxes = chunk.boxes(); for (unsigned i = boxStart; i < boxStart + boxCount; ++i) - boxes.append(lineLayoutBoxes.at(i)); + boxes.append(lineLayoutBoxes[i]); m_textChunks.append(chunk); } @@ -173,26 +173,26 @@ void SVGTextChunkBuilder::processTextChunk(const SVGTextChunk& chunk) float textLengthShift = (chunk.desiredTextLength() - chunkLength) / chunkCharacters; unsigned atCharacter = 0; for (unsigned boxPosition = 0; boxPosition < boxCount; ++boxPosition) { - Vector<SVGTextFragment>& fragments = boxes.at(boxPosition)->textFragments(); + Vector<SVGTextFragment>& fragments = boxes[boxPosition]->textFragments(); if (fragments.isEmpty()) - continue; + continue; processTextLengthSpacingCorrection(isVerticalText, textLengthShift, fragments, atCharacter); } } else { ASSERT(chunk.hasLengthAdjustSpacingAndGlyphs()); - float scale = chunk.desiredTextLength() / chunkLength; + float textLengthScale = chunk.desiredTextLength() / chunkLength; AffineTransform spacingAndGlyphsTransform; bool foundFirstFragment = false; for (unsigned boxPosition = 0; boxPosition < boxCount; ++boxPosition) { - SVGInlineTextBox* textBox = boxes.at(boxPosition); + SVGInlineTextBox* textBox = boxes[boxPosition]; Vector<SVGTextFragment>& fragments = textBox->textFragments(); if (fragments.isEmpty()) continue; - + if (!foundFirstFragment) { foundFirstFragment = true; - buildSpacingAndGlyphsTransform(isVerticalText, scale, fragments.first(), spacingAndGlyphsTransform); + buildSpacingAndGlyphsTransform(isVerticalText, textLengthScale, fragments.first(), spacingAndGlyphsTransform); } m_textBoxTransformations.set(textBox, spacingAndGlyphsTransform); @@ -212,7 +212,7 @@ void SVGTextChunkBuilder::processTextChunk(const SVGTextChunk& chunk) float textAnchorShift = chunk.calculateTextAnchorShift(chunkLength); for (unsigned boxPosition = 0; boxPosition < boxCount; ++boxPosition) { - Vector<SVGTextFragment>& fragments = boxes.at(boxPosition)->textFragments(); + Vector<SVGTextFragment>& fragments = boxes[boxPosition]->textFragments(); if (fragments.isEmpty()) continue; processTextAnchorCorrection(isVerticalText, textAnchorShift, fragments); @@ -223,7 +223,7 @@ void SVGTextChunkBuilder::processTextLengthSpacingCorrection(bool isVerticalText { unsigned fragmentCount = fragments.size(); for (unsigned i = 0; i < fragmentCount; ++i) { - SVGTextFragment& fragment = fragments.at(i); + SVGTextFragment& fragment = fragments[i]; if (isVerticalText) fragment.y += textLengthShift * atCharacter; @@ -238,7 +238,7 @@ void SVGTextChunkBuilder::processTextAnchorCorrection(bool isVerticalText, float { unsigned fragmentCount = fragments.size(); for (unsigned i = 0; i < fragmentCount; ++i) { - SVGTextFragment& fragment = fragments.at(i); + SVGTextFragment& fragment = fragments[i]; if (isVerticalText) fragment.y += textAnchorShift; diff --git a/Source/WebCore/rendering/svg/SVGTextFragment.h b/Source/WebCore/rendering/svg/SVGTextFragment.h index b5b3c57..a44d0fa 100644 --- a/Source/WebCore/rendering/svg/SVGTextFragment.h +++ b/Source/WebCore/rendering/svg/SVGTextFragment.h @@ -31,6 +31,7 @@ struct SVGTextFragment { : characterOffset(0) , metricsListOffset(0) , length(0) + , isTextOnPath(false) , x(0) , y(0) , width(0) @@ -38,19 +39,74 @@ struct SVGTextFragment { { } + enum TransformType { + TransformRespectingTextLength, + TransformIgnoringTextLength + }; + + void buildFragmentTransform(AffineTransform& result, TransformType type = TransformRespectingTextLength) const + { + if (type == TransformIgnoringTextLength) { + result = transform; + transformAroundOrigin(result); + return; + } + + if (isTextOnPath) + buildTransformForTextOnPath(result); + else + buildTransformForTextOnLine(result); + } + // The first rendered character starts at RenderSVGInlineText::characters() + characterOffset. unsigned characterOffset; unsigned metricsListOffset; - unsigned length; + unsigned length : 31; + bool isTextOnPath : 1; float x; float y; float width; float height; - // Includes rotation/glyph-orientation-(horizontal|vertical) transforms, lengthAdjust="spacingAndGlyphs" (for textPath only), - // as well as orientation related shifts (see SVGTextLayoutEngine, which builds this transformation). + // Includes rotation/glyph-orientation-(horizontal|vertical) transforms, as well as orientation related shifts + // (see SVGTextLayoutEngine, which builds this transformation). AffineTransform transform; + + // Contains lengthAdjust related transformations, which are not allowd to influence the SVGTextQuery code. + AffineTransform lengthAdjustTransform; + +private: + void transformAroundOrigin(AffineTransform& result) const + { + // Returns (translate(x, y) * result) * translate(-x, -y). + result.setE(result.e() + x); + result.setF(result.f() + y); + result.translate(-x, -y); + } + + void buildTransformForTextOnPath(AffineTransform& result) const + { + // For text-on-path layout, multiply the transform with the lengthAdjustTransform before orienting the resulting transform. + result = lengthAdjustTransform.isIdentity() ? transform : transform * lengthAdjustTransform; + if (!result.isIdentity()) + transformAroundOrigin(result); + } + + void buildTransformForTextOnLine(AffineTransform& result) const + { + // For text-on-line layout, orient the transform first, then multiply the lengthAdjustTransform with the oriented transform. + if (transform.isIdentity()) { + result = lengthAdjustTransform; + return; + } + + result = transform; + transformAroundOrigin(result); + + if (!lengthAdjustTransform.isIdentity()) + result = lengthAdjustTransform * result; + } }; } // namespace WebCore diff --git a/Source/WebCore/rendering/svg/SVGTextLayoutAttributes.cpp b/Source/WebCore/rendering/svg/SVGTextLayoutAttributes.cpp index 4c227b4..df2cffe 100644 --- a/Source/WebCore/rendering/svg/SVGTextLayoutAttributes.cpp +++ b/Source/WebCore/rendering/svg/SVGTextLayoutAttributes.cpp @@ -34,11 +34,44 @@ SVGTextLayoutAttributes::SVGTextLayoutAttributes(RenderSVGInlineText* context) void SVGTextLayoutAttributes::reserveCapacity(unsigned length) { - m_xValues.reserveCapacity(length); - m_yValues.reserveCapacity(length); - m_dxValues.reserveCapacity(length); - m_dyValues.reserveCapacity(length); - m_rotateValues.reserveCapacity(length); + m_positioningLists.xValues.reserveCapacity(length); + m_positioningLists.yValues.reserveCapacity(length); + m_positioningLists.dxValues.reserveCapacity(length); + m_positioningLists.dyValues.reserveCapacity(length); + m_positioningLists.rotateValues.reserveCapacity(length); + m_textMetricsValues.reserveCapacity(length); +} + +void SVGTextLayoutAttributes::PositioningLists::fillWithEmptyValues(unsigned length) +{ + xValues.fill(SVGTextLayoutAttributes::emptyValue(), length); + yValues.fill(SVGTextLayoutAttributes::emptyValue(), length); + dxValues.fill(SVGTextLayoutAttributes::emptyValue(), length); + dyValues.fill(SVGTextLayoutAttributes::emptyValue(), length); + rotateValues.fill(SVGTextLayoutAttributes::emptyValue(), length); +} + +void SVGTextLayoutAttributes::PositioningLists::appendEmptyValues() +{ + xValues.append(SVGTextLayoutAttributes::emptyValue()); + yValues.append(SVGTextLayoutAttributes::emptyValue()); + dxValues.append(SVGTextLayoutAttributes::emptyValue()); + dyValues.append(SVGTextLayoutAttributes::emptyValue()); + rotateValues.append(SVGTextLayoutAttributes::emptyValue()); +} + +static inline float safeValueAtPosition(const Vector<float>& values, unsigned position) +{ + return position < values.size() ? values[position] : SVGTextLayoutAttributes::emptyValue(); +} + +void SVGTextLayoutAttributes::PositioningLists::appendValuesFromPosition(const PositioningLists& source, unsigned position) +{ + xValues.append(safeValueAtPosition(source.xValues, position)); + yValues.append(safeValueAtPosition(source.yValues, position)); + dxValues.append(safeValueAtPosition(source.dxValues, position)); + dyValues.append(safeValueAtPosition(source.dyValues, position)); + rotateValues.append(safeValueAtPosition(source.rotateValues, position)); } float SVGTextLayoutAttributes::emptyValue() @@ -69,23 +102,23 @@ void SVGTextLayoutAttributes::dump() const fprintf(stderr, "context: %p\n", m_context); fprintf(stderr, "x values: "); - dumpLayoutVector(m_xValues); + dumpLayoutVector(m_positioningLists.xValues); fprintf(stderr, "\n"); fprintf(stderr, "y values: "); - dumpLayoutVector(m_yValues); + dumpLayoutVector(m_positioningLists.yValues); fprintf(stderr, "\n"); fprintf(stderr, "dx values: "); - dumpLayoutVector(m_dxValues); + dumpLayoutVector(m_positioningLists.dxValues); fprintf(stderr, "\n"); fprintf(stderr, "dy values: "); - dumpLayoutVector(m_dyValues); + dumpLayoutVector(m_positioningLists.dyValues); fprintf(stderr, "\n"); fprintf(stderr, "rotate values: "); - dumpLayoutVector(m_rotateValues); + dumpLayoutVector(m_positioningLists.rotateValues); fprintf(stderr, "\n"); fprintf(stderr, "character data values:\n"); diff --git a/Source/WebCore/rendering/svg/SVGTextLayoutAttributes.h b/Source/WebCore/rendering/svg/SVGTextLayoutAttributes.h index fc6bd10..8b45d3d 100644 --- a/Source/WebCore/rendering/svg/SVGTextLayoutAttributes.h +++ b/Source/WebCore/rendering/svg/SVGTextLayoutAttributes.h @@ -31,6 +31,18 @@ class RenderSVGInlineText; class SVGTextLayoutAttributes { public: + struct PositioningLists { + void fillWithEmptyValues(unsigned length); + void appendEmptyValues(); + void appendValuesFromPosition(const PositioningLists&, unsigned position); + + Vector<float> xValues; + Vector<float> yValues; + Vector<float> dxValues; + Vector<float> dyValues; + Vector<float> rotateValues; + }; + SVGTextLayoutAttributes(RenderSVGInlineText* context = 0); void reserveCapacity(unsigned length); @@ -40,31 +52,30 @@ public: RenderSVGInlineText* context() const { return m_context; } - Vector<float>& xValues() { return m_xValues; } - const Vector<float>& xValues() const { return m_xValues; } + PositioningLists& positioningLists() { return m_positioningLists; } + const PositioningLists& positioningLists() const { return m_positioningLists; } + + Vector<float>& xValues() { return m_positioningLists.xValues; } + const Vector<float>& xValues() const { return m_positioningLists.xValues; } - Vector<float>& yValues() { return m_yValues; } - const Vector<float>& yValues() const { return m_yValues; } + Vector<float>& yValues() { return m_positioningLists.yValues; } + const Vector<float>& yValues() const { return m_positioningLists.yValues; } - Vector<float>& dxValues() { return m_dxValues; } - const Vector<float>& dxValues() const { return m_dxValues; } + Vector<float>& dxValues() { return m_positioningLists.dxValues; } + const Vector<float>& dxValues() const { return m_positioningLists.dxValues; } - Vector<float>& dyValues() { return m_dyValues; } - const Vector<float>& dyValues() const { return m_dyValues; } + Vector<float>& dyValues() { return m_positioningLists.dyValues; } + const Vector<float>& dyValues() const { return m_positioningLists.dyValues; } - Vector<float>& rotateValues() { return m_rotateValues; } - const Vector<float>& rotateValues() const { return m_rotateValues; } + Vector<float>& rotateValues() { return m_positioningLists.rotateValues; } + const Vector<float>& rotateValues() const { return m_positioningLists.rotateValues; } Vector<SVGTextMetrics>& textMetricsValues() { return m_textMetricsValues; } const Vector<SVGTextMetrics>& textMetricsValues() const { return m_textMetricsValues; } private: RenderSVGInlineText* m_context; - Vector<float> m_xValues; - Vector<float> m_yValues; - Vector<float> m_dxValues; - Vector<float> m_dyValues; - Vector<float> m_rotateValues; + PositioningLists m_positioningLists; Vector<SVGTextMetrics> m_textMetricsValues; }; diff --git a/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.cpp b/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.cpp index 86be424..42eb8e8 100644 --- a/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.cpp +++ b/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * Copyright (C) Research In Motion Limited 2010-2011. 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 @@ -38,20 +38,19 @@ SVGTextLayoutAttributesBuilder::SVGTextLayoutAttributesBuilder() void SVGTextLayoutAttributesBuilder::buildLayoutAttributesForTextSubtree(RenderSVGText* textRoot) { ASSERT(textRoot); - m_scopes.clear(); // Build list of x/y/dx/dy/rotate values for each subtree element that may define these values (tspan/textPath etc). unsigned atCharacter = 0; UChar lastCharacter = '\0'; - buildLayoutScopes(textRoot, atCharacter, lastCharacter); + collectTextPositioningElements(textRoot, atCharacter, lastCharacter); if (!atCharacter) return; - // Build list of x/y/dx/dy/rotate values for the outermost <text> element. - buildOutermostLayoutScope(textRoot, atCharacter); + // Collect x/y/dx/dy/rotate values for each character, stored in the m_positioningLists.xValues()/etc. lists. + buildLayoutAttributesForAllCharacters(textRoot, atCharacter); - // Propagate layout attributes to each RenderSVGInlineText object. + // Propagate layout attributes to each RenderSVGInlineText object, and the whole list to the RenderSVGText root. Vector<SVGTextLayoutAttributes>& allAttributes = textRoot->layoutAttributes(); allAttributes.clear(); atCharacter = 0; @@ -85,40 +84,6 @@ static inline void extractFloatValuesFromSVGNumberList(const SVGNumberList& list floatValues.append(list.at(i)); } -void SVGTextLayoutAttributesBuilder::buildLayoutScope(LayoutScope& scope, RenderObject* renderer, unsigned textContentStart, unsigned textContentLength) const -{ - ASSERT(renderer); - ASSERT(renderer->style()); - - scope.textContentStart = textContentStart; - scope.textContentLength = textContentLength; - - SVGTextPositioningElement* element = SVGTextPositioningElement::elementFromRenderer(renderer); - if (!element) - return; - - SVGTextLayoutAttributes& attributes = scope.attributes; - extractFloatValuesFromSVGLengthList(element, element->x(), attributes.xValues(), textContentLength); - extractFloatValuesFromSVGLengthList(element, element->y(), attributes.yValues(), textContentLength); - extractFloatValuesFromSVGLengthList(element, element->dx(), attributes.dxValues(), textContentLength); - extractFloatValuesFromSVGLengthList(element, element->dy(), attributes.dyValues(), textContentLength); - extractFloatValuesFromSVGNumberList(element->rotate(), attributes.rotateValues(), textContentLength); - - // The last rotation value spans the whole scope. - Vector<float>& rotateValues = attributes.rotateValues(); - if (rotateValues.isEmpty()) - return; - - unsigned rotateValuesSize = rotateValues.size(); - if (rotateValuesSize == textContentLength) - return; - - float lastRotation = rotateValues.last(); - - rotateValues.resize(textContentLength); - for (unsigned i = rotateValuesSize; i < textContentLength; ++i) - rotateValues.at(i) = lastRotation; -} static inline bool characterIsSpace(const UChar& character) { @@ -136,56 +101,84 @@ static inline bool shouldPreserveAllWhiteSpace(RenderStyle* style) return style->whiteSpace() == PRE; } -void SVGTextLayoutAttributesBuilder::buildLayoutScopes(RenderObject* start, unsigned& atCharacter, UChar& lastCharacter) +static inline void processRenderSVGInlineText(RenderSVGInlineText* text, unsigned& atCharacter, UChar& lastCharacter) { - for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) { - if (child->isSVGInlineText()) { - RenderSVGInlineText* text = toRenderSVGInlineText(child); + if (shouldPreserveAllWhiteSpace(text->style())) { + atCharacter += text->textLength(); + return; + } - if (!shouldPreserveAllWhiteSpace(text->style())) { - const UChar* characters = text->characters(); - unsigned textLength = text->textLength(); - for (unsigned textPosition = 0; textPosition < textLength; ++textPosition) { - const UChar& currentCharacter = characters[textPosition]; - if (characterIsSpace(currentCharacter) && characterIsSpaceOrNull(lastCharacter)) - continue; + const UChar* characters = text->characters(); + unsigned textLength = text->textLength(); + for (unsigned textPosition = 0; textPosition < textLength; ++textPosition) { + const UChar& currentCharacter = characters[textPosition]; + if (characterIsSpace(currentCharacter) && characterIsSpaceOrNull(lastCharacter)) + continue; - lastCharacter = currentCharacter; - ++atCharacter; - } - } else - atCharacter += text->textLength(); + lastCharacter = currentCharacter; + ++atCharacter; + } +} + +void SVGTextLayoutAttributesBuilder::collectTextPositioningElements(RenderObject* start, unsigned& atCharacter, UChar& lastCharacter) +{ + ASSERT(!start->isSVGText() || m_textPositions.isEmpty()); + for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) { + if (child->isSVGInlineText()) { + processRenderSVGInlineText(toRenderSVGInlineText(child), atCharacter, lastCharacter); continue; } if (!child->isSVGInline()) continue; - unsigned textContentStart = atCharacter; - buildLayoutScopes(child, atCharacter, lastCharacter); + SVGTextPositioningElement* element = SVGTextPositioningElement::elementFromRenderer(child); + unsigned atPosition = m_textPositions.size(); + if (element) + m_textPositions.append(TextPosition(element, atCharacter)); + + collectTextPositioningElements(child, atCharacter, lastCharacter); + + if (!element) + continue; - LayoutScope scope; - buildLayoutScope(scope, child, textContentStart, atCharacter - textContentStart); - m_scopes.append(scope); + // Update text position, after we're back from recursion. + TextPosition& position = m_textPositions[atPosition]; + ASSERT(!position.length); + position.length = atCharacter - position.start; } } -void SVGTextLayoutAttributesBuilder::buildOutermostLayoutScope(RenderSVGText* textRoot, unsigned textLength) +void SVGTextLayoutAttributesBuilder::buildLayoutAttributesForAllCharacters(RenderSVGText* textRoot, unsigned textLength) { - LayoutScope scope; - buildLayoutScope(scope, textRoot, 0, textLength); + ASSERT(textLength); - // Handle <text> x/y default attributes. - Vector<float>& xValues = scope.attributes.xValues(); - if (xValues.isEmpty()) - xValues.append(0); + SVGTextPositioningElement* outermostTextElement = SVGTextPositioningElement::elementFromRenderer(textRoot); + ASSERT(outermostTextElement); - Vector<float>& yValues = scope.attributes.yValues(); - if (yValues.isEmpty()) - yValues.append(0); + // Fill the lists with the special emptyValue marker. + m_positioningLists.fillWithEmptyValues(textLength); - m_scopes.prepend(scope); + // Grab outermost <text> element value lists and insert them in the m_positioningLists. + TextPosition wholeTextPosition(outermostTextElement, 0, textLength); + fillAttributesAtPosition(wholeTextPosition); + + // Handle x/y default attributes. + float& xFirst = m_positioningLists.xValues.first(); + if (xFirst == SVGTextLayoutAttributes::emptyValue()) + xFirst = 0; + + float& yFirst = m_positioningLists.yValues.first(); + if (yFirst == SVGTextLayoutAttributes::emptyValue()) + yFirst = 0; + + // Fill m_positioningLists using child text positioning elements in top-down order. + unsigned size = m_textPositions.size(); + for (unsigned i = 0; i < size; ++i) + fillAttributesAtPosition(m_textPositions[i]); + + // Now m_positioningLists.contains a x/y/dx/dy/rotate value for each character in the <text> subtree. } void SVGTextLayoutAttributesBuilder::propagateLayoutAttributes(RenderObject* start, Vector<SVGTextLayoutAttributes>& allAttributes, unsigned& atCharacter, UChar& lastCharacter) const @@ -222,16 +215,19 @@ void SVGTextLayoutAttributesBuilder::propagateLayoutAttributes(RenderObject* sta metricsLength = currentMetrics.length(); if (!preserveWhiteSpace && characterIsSpace(currentCharacter) && characterIsSpaceOrNull(lastCharacter)) { - assignEmptyLayoutAttributesForCharacter(attributes); + attributes.positioningLists().appendEmptyValues(); attributes.textMetricsValues().append(SVGTextMetrics::emptyMetrics()); continue; } - assignLayoutAttributesForCharacter(attributes, currentMetrics, valueListPosition); + SVGTextLayoutAttributes::PositioningLists& positioningLists = attributes.positioningLists(); + positioningLists.appendValuesFromPosition(m_positioningLists, valueListPosition); + attributes.textMetricsValues().append(currentMetrics); + // Pad x/y/dx/dy/rotate value lists with empty values, if the metrics span more than one character. if (metricsLength > 1) { for (unsigned i = 0; i < metricsLength - 1; ++i) - assignEmptyLayoutAttributesForCharacter(attributes); + positioningLists.appendEmptyValues(); } lastCharacter = currentCharacter; @@ -257,67 +253,42 @@ void SVGTextLayoutAttributesBuilder::propagateLayoutAttributes(RenderObject* sta } } -float SVGTextLayoutAttributesBuilder::nextLayoutValue(LayoutValueType type, unsigned atCharacter) const +static inline void fillListAtPosition(Vector<float>& allValues, Vector<float>& values, unsigned start) { - for (int i = m_scopes.size() - 1; i >= 0; --i) { - const LayoutScope& scope = m_scopes.at(i); - if (scope.textContentStart > atCharacter || scope.textContentStart + scope.textContentLength < atCharacter) - continue; + unsigned valuesSize = values.size(); + for (unsigned i = 0; i < valuesSize; ++i) + allValues[start + i] = values[i]; +} - const Vector<float>* valuesPointer = 0; - switch (type) { - case XValueAttribute: - valuesPointer = &scope.attributes.xValues(); - break; - case YValueAttribute: - valuesPointer = &scope.attributes.yValues(); - break; - case DxValueAttribute: - valuesPointer = &scope.attributes.dxValues(); - break; - case DyValueAttribute: - valuesPointer = &scope.attributes.dyValues(); - break; - case RotateValueAttribute: - valuesPointer = &scope.attributes.rotateValues(); - break; - default: - ASSERT_NOT_REACHED(); - } +void SVGTextLayoutAttributesBuilder::fillAttributesAtPosition(const TextPosition& position) +{ + Vector<float> values; + extractFloatValuesFromSVGLengthList(position.element, position.element->x(), values, position.length); + fillListAtPosition(m_positioningLists.xValues, values, position.start); - ASSERT(valuesPointer); - const Vector<float>& values = *valuesPointer; - if (values.isEmpty()) - continue; + values.clear(); + extractFloatValuesFromSVGLengthList(position.element, position.element->y(), values, position.length); + fillListAtPosition(m_positioningLists.yValues, values, position.start); - unsigned position = atCharacter - scope.textContentStart; - if (position >= values.size()) - continue; + values.clear(); + extractFloatValuesFromSVGLengthList(position.element, position.element->dx(), values, position.length); + fillListAtPosition(m_positioningLists.dxValues, values, position.start); - return values.at(position); - } + values.clear(); + extractFloatValuesFromSVGLengthList(position.element, position.element->dy(), values, position.length); + fillListAtPosition(m_positioningLists.dyValues, values, position.start); - return SVGTextLayoutAttributes::emptyValue(); -} + values.clear(); + extractFloatValuesFromSVGNumberList(position.element->rotate(), values, position.length); + fillListAtPosition(m_positioningLists.rotateValues, values, position.start); -void SVGTextLayoutAttributesBuilder::assignLayoutAttributesForCharacter(SVGTextLayoutAttributes& attributes, SVGTextMetrics& metrics, unsigned valueListPosition) const -{ - attributes.xValues().append(nextLayoutValue(XValueAttribute, valueListPosition)); - attributes.yValues().append(nextLayoutValue(YValueAttribute, valueListPosition)); - attributes.dxValues().append(nextLayoutValue(DxValueAttribute, valueListPosition)); - attributes.dyValues().append(nextLayoutValue(DyValueAttribute, valueListPosition)); - attributes.rotateValues().append(nextLayoutValue(RotateValueAttribute, valueListPosition)); - attributes.textMetricsValues().append(metrics); -} + // The last rotation value always spans the whole scope. + if (values.isEmpty()) + return; -void SVGTextLayoutAttributesBuilder::assignEmptyLayoutAttributesForCharacter(SVGTextLayoutAttributes& attributes) const -{ - attributes.xValues().append(SVGTextLayoutAttributes::emptyValue()); - attributes.yValues().append(SVGTextLayoutAttributes::emptyValue()); - attributes.dxValues().append(SVGTextLayoutAttributes::emptyValue()); - attributes.dyValues().append(SVGTextLayoutAttributes::emptyValue()); - attributes.rotateValues().append(SVGTextLayoutAttributes::emptyValue()); - // This doesn't add an empty value to textMetricsValues() on purpose! + float lastValue = values.last(); + for (unsigned i = values.size(); i < position.length; ++i) + m_positioningLists.rotateValues[position.start + i] = lastValue; } } diff --git a/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.h b/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.h index b368c51..a5995c0 100644 --- a/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.h +++ b/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.h @@ -1,5 +1,5 @@ /* - * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * Copyright (C) Research In Motion Limited 2010-2011. 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 @@ -28,6 +28,7 @@ namespace WebCore { class RenderObject; class RenderSVGText; +class SVGTextPositioningElement; // SVGTextLayoutAttributesBuilder performs the first layout phase for SVG text. // @@ -45,37 +46,27 @@ public: void buildLayoutAttributesForTextSubtree(RenderSVGText*); private: - struct LayoutScope { - LayoutScope() - : textContentStart(0) - , textContentLength(0) + struct TextPosition { + TextPosition(SVGTextPositioningElement* newElement = 0, unsigned newStart = 0, unsigned newLength = 0) + : element(newElement) + , start(newStart) + , length(newLength) { } - unsigned textContentStart; - unsigned textContentLength; - SVGTextLayoutAttributes attributes; + SVGTextPositioningElement* element; + unsigned start; + unsigned length; }; - void buildLayoutScope(LayoutScope&, RenderObject*, unsigned textContentStart, unsigned textContentLength) const; - void buildLayoutScopes(RenderObject*, unsigned& atCharacter, UChar& lastCharacter); - void buildOutermostLayoutScope(RenderSVGText*, unsigned textLength); + void collectTextPositioningElements(RenderObject*, unsigned& atCharacter, UChar& lastCharacter); + void buildLayoutAttributesForAllCharacters(RenderSVGText*, unsigned textLength); void propagateLayoutAttributes(RenderObject*, Vector<SVGTextLayoutAttributes>& allAttributes, unsigned& atCharacter, UChar& lastCharacter) const; - - enum LayoutValueType { - XValueAttribute, - YValueAttribute, - DxValueAttribute, - DyValueAttribute, - RotateValueAttribute - }; - - float nextLayoutValue(LayoutValueType, unsigned atCharacter) const; - void assignLayoutAttributesForCharacter(SVGTextLayoutAttributes&, SVGTextMetrics&, unsigned valueListPosition) const; - void assignEmptyLayoutAttributesForCharacter(SVGTextLayoutAttributes&) const; + void fillAttributesAtPosition(const TextPosition&); private: - Vector<LayoutScope> m_scopes; + Vector<TextPosition> m_textPositions; + SVGTextLayoutAttributes::PositioningLists m_positioningLists; }; } // namespace WebCore diff --git a/Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp b/Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp index 71db2ea..2bc7e32 100644 --- a/Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp +++ b/Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp @@ -157,7 +157,7 @@ bool SVGTextLayoutEngine::parentDefinesTextLength(RenderObject* parent) const SVGTextContentElement* textContentElement = SVGTextContentElement::elementFromRenderer(currentParent); if (textContentElement) { SVGTextContentElement::SVGLengthAdjustType lengthAdjust = static_cast<SVGTextContentElement::SVGLengthAdjustType>(textContentElement->lengthAdjust()); - if (lengthAdjust == SVGTextContentElement::LENGTHADJUST_SPACING && textContentElement->textLength().value(textContentElement) > 0) + if (lengthAdjust == SVGTextContentElement::LENGTHADJUST_SPACING && textContentElement->specifiedTextLength().value(textContentElement) > 0) return true; } @@ -213,7 +213,7 @@ void SVGTextLayoutEngine::beginTextPathLayout(RenderObject* object, SVGTextLayou if (SVGTextContentElement* textContentElement = SVGTextContentElement::elementFromRenderer(textPath)) { lengthAdjust = static_cast<SVGTextContentElement::SVGLengthAdjustType>(textContentElement->lengthAdjust()); - desiredTextLength = textContentElement->textLength().value(textContentElement); + desiredTextLength = textContentElement->specifiedTextLength().value(textContentElement); } if (!desiredTextLength) @@ -261,34 +261,10 @@ void SVGTextLayoutEngine::layoutInlineTextBox(SVGInlineTextBox* textBox) m_lineLayoutBoxes.append(textBox); } -void SVGTextLayoutEngine::finishLayout() -{ - // After all text fragments are stored in their correpsonding SVGInlineTextBoxes, we can layout individual text chunks. - // Chunk layouting is only performed for line layout boxes, not for path layout, where it has already been done. - m_chunkLayoutBuilder.layoutTextChunks(m_lineLayoutBoxes); - - // Finalize transform matrices, after the chunk layout corrections have been applied, and all fragment x/y positions are finalized. - if (!m_lineLayoutBoxes.isEmpty()) { -#if DUMP_TEXT_FRAGMENTS > 0 - fprintf(stderr, "Line layout: "); -#endif - - finalizeTransformMatrices(m_lineLayoutBoxes); - } - - if (!m_pathLayoutBoxes.isEmpty()) { #if DUMP_TEXT_FRAGMENTS > 0 - fprintf(stderr, "Path layout: "); -#endif - finalizeTransformMatrices(m_pathLayoutBoxes); - } -} - -void SVGTextLayoutEngine::finalizeTransformMatrices(Vector<SVGInlineTextBox*>& boxes) +static inline void dumpTextBoxes(Vector<SVGInlineTextBox*>& boxes) { unsigned boxCount = boxes.size(); - -#if DUMP_TEXT_FRAGMENTS > 0 fprintf(stderr, "Dumping all text fragments in text sub tree, %i boxes\n", boxCount); for (unsigned boxPosition = 0; boxPosition < boxCount; ++boxPosition) { @@ -308,9 +284,12 @@ void SVGTextLayoutEngine::finalizeTransformMatrices(Vector<SVGInlineTextBox*>& b , i, fragment.x, fragment.y, fragment.width, fragment.height, fragment.characterOffset, fragment.length, fragmentString.utf8().data()); } } +} #endif - +void SVGTextLayoutEngine::finalizeTransformMatrices(Vector<SVGInlineTextBox*>& boxes) +{ + unsigned boxCount = boxes.size(); if (!boxCount) return; @@ -321,29 +300,48 @@ void SVGTextLayoutEngine::finalizeTransformMatrices(Vector<SVGInlineTextBox*>& b unsigned fragmentCount = fragments.size(); for (unsigned i = 0; i < fragmentCount; ++i) { - SVGTextFragment& fragment = fragments.at(i); - AffineTransform& transform = fragment.transform; - if (!transform.isIdentity()) { - transform = AffineTransform::translation(fragment.x, fragment.y) * transform; - transform.translate(-fragment.x, -fragment.y); - } - m_chunkLayoutBuilder.transformationForTextBox(textBox, textBoxTransformation); if (textBoxTransformation.isIdentity()) continue; - - if (transform.isIdentity()) - transform = textBoxTransformation; - else - transform = textBoxTransformation * transform; + ASSERT(fragments[i].lengthAdjustTransform.isIdentity()); + fragments[i].lengthAdjustTransform = textBoxTransformation; } } boxes.clear(); } +void SVGTextLayoutEngine::finishLayout() +{ + // After all text fragments are stored in their correpsonding SVGInlineTextBoxes, we can layout individual text chunks. + // Chunk layouting is only performed for line layout boxes, not for path layout, where it has already been done. + m_chunkLayoutBuilder.layoutTextChunks(m_lineLayoutBoxes); + + // Finalize transform matrices, after the chunk layout corrections have been applied, and all fragment x/y positions are finalized. + if (!m_lineLayoutBoxes.isEmpty()) { +#if DUMP_TEXT_FRAGMENTS > 0 + fprintf(stderr, "Line layout: "); + dumpTextBoxes(m_lineLayoutBoxes); +#endif + + finalizeTransformMatrices(m_lineLayoutBoxes); + } + + if (!m_pathLayoutBoxes.isEmpty()) { +#if DUMP_TEXT_FRAGMENTS > 0 + fprintf(stderr, "Path layout: "); + dumpTextBoxes(m_pathLayoutBoxes); +#endif + + finalizeTransformMatrices(m_pathLayoutBoxes); + } +} + bool SVGTextLayoutEngine::currentLogicalCharacterAttributes(SVGTextLayoutAttributes& logicalAttributes) { + if (m_layoutAttributes.isEmpty()) + return false; + logicalAttributes = m_layoutAttributes.first(); if (m_logicalCharacterOffset != logicalAttributes.xValues().size()) return true; @@ -374,6 +372,8 @@ bool SVGTextLayoutEngine::currentLogicalCharacterMetrics(SVGTextLayoutAttributes continue; } + ASSERT(textMetricsSize); + ASSERT(m_logicalMetricsListOffset < textMetricsSize); logicalMetrics = textMetricsValues.at(m_logicalMetricsListOffset); if (logicalMetrics == SVGTextMetrics::emptyMetrics() || (!logicalMetrics.width() && !logicalMetrics.height())) { advanceToNextLogicalCharacter(logicalMetrics); @@ -634,11 +634,12 @@ void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, Rend if (orientationAngle) m_currentTextFragment.transform.rotate(orientationAngle); - if (m_inPathLayout && m_textPathScaling != 1) { + m_currentTextFragment.isTextOnPath = m_inPathLayout && m_textPathScaling != 1; + if (m_currentTextFragment.isTextOnPath) { if (m_isVerticalText) - m_currentTextFragment.transform.scaleNonUniform(1, m_textPathScaling); + m_currentTextFragment.lengthAdjustTransform.scaleNonUniform(1, m_textPathScaling); else - m_currentTextFragment.transform.scaleNonUniform(m_textPathScaling, 1); + m_currentTextFragment.lengthAdjustTransform.scaleNonUniform(m_textPathScaling, 1); } } diff --git a/Source/WebCore/rendering/svg/SVGTextQuery.cpp b/Source/WebCore/rendering/svg/SVGTextQuery.cpp index 5f3523e..c141c11 100644 --- a/Source/WebCore/rendering/svg/SVGTextQuery.cpp +++ b/Source/WebCore/rendering/svg/SVGTextQuery.cpp @@ -80,17 +80,6 @@ static inline InlineFlowBox* flowBoxForRenderer(RenderObject* renderer) return 0; } -static inline float mapLengthThroughFragmentTransformation(const SVGTextFragment& fragment, bool isVerticalText, float length) -{ - if (fragment.transform.isIdentity()) - return length; - - if (isVerticalText) - return narrowPrecisionToFloat(static_cast<double>(length) * fragment.transform.yScale()); - - return narrowPrecisionToFloat(static_cast<double>(length) * fragment.transform.xScale()); -} - SVGTextQuery::SVGTextQuery(RenderObject* renderer) { collectTextBoxesInFlowBox(flowBoxForRenderer(renderer)); @@ -111,8 +100,8 @@ void SVGTextQuery::collectTextBoxesInFlowBox(InlineFlowBox* flowBox) continue; } - ASSERT(child->isSVGInlineTextBox()); - m_textBoxes.append(static_cast<SVGInlineTextBox*>(child)); + if (child->isSVGInlineTextBox()) + m_textBoxes.append(static_cast<SVGInlineTextBox*>(child)); } } @@ -273,9 +262,7 @@ struct TextLengthData : SVGTextQuery::Data { bool SVGTextQuery::textLengthCallback(Data* queryData, const SVGTextFragment& fragment) const { TextLengthData* data = static_cast<TextLengthData*>(queryData); - - float fragmentLength = queryData->isVerticalText ? fragment.height : fragment.width; - data->textLength += mapLengthThroughFragmentTransformation(fragment, queryData->isVerticalText, fragmentLength); + data->textLength += queryData->isVerticalText ? fragment.height : fragment.width; return false; } @@ -314,9 +301,7 @@ bool SVGTextQuery::subStringLengthCallback(Data* queryData, const SVGTextFragmen return false; SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.characterOffset + startPosition, endPosition - startPosition); - float fragmentLength = queryData->isVerticalText ? metrics.height() : metrics.width(); - - data->subStringLength += mapLengthThroughFragmentTransformation(fragment, queryData->isVerticalText, fragmentLength); + data->subStringLength += queryData->isVerticalText ? metrics.height() : metrics.width(); return false; } @@ -360,10 +345,12 @@ bool SVGTextQuery::startPositionOfCharacterCallback(Data* queryData, const SVGTe data->startPosition.move(metrics.width(), 0); } - if (fragment.transform.isIdentity()) + AffineTransform fragmentTransform; + fragment.buildFragmentTransform(fragmentTransform, SVGTextFragment::TransformIgnoringTextLength); + if (fragmentTransform.isIdentity()) return true; - data->startPosition = fragment.transform.mapPoint(data->startPosition); + data->startPosition = fragmentTransform.mapPoint(data->startPosition); return true; } @@ -405,10 +392,12 @@ bool SVGTextQuery::endPositionOfCharacterCallback(Data* queryData, const SVGText else data->endPosition.move(metrics.width(), 0); - if (fragment.transform.isIdentity()) + AffineTransform fragmentTransform; + fragment.buildFragmentTransform(fragmentTransform, SVGTextFragment::TransformIgnoringTextLength); + if (fragmentTransform.isIdentity()) return true; - data->endPosition = fragment.transform.mapPoint(data->endPosition); + data->endPosition = fragmentTransform.mapPoint(data->endPosition); return true; } @@ -443,9 +432,15 @@ bool SVGTextQuery::rotationOfCharacterCallback(Data* queryData, const SVGTextFra if (!mapStartEndPositionsIntoFragmentCoordinates(queryData, fragment, startPosition, endPosition)) return false; - AffineTransform newTransform(fragment.transform); - newTransform.scale(1 / fragment.transform.xScale(), 1 / fragment.transform.yScale()); - data->rotation = narrowPrecisionToFloat(rad2deg(atan2(newTransform.b(), newTransform.a()))); + AffineTransform fragmentTransform; + fragment.buildFragmentTransform(fragmentTransform, SVGTextFragment::TransformIgnoringTextLength); + if (fragmentTransform.isIdentity()) + data->rotation = 0; + else { + fragmentTransform.scale(1 / fragmentTransform.xScale(), 1 / fragmentTransform.yScale()); + data->rotation = narrowPrecisionToFloat(rad2deg(atan2(fragmentTransform.b(), fragmentTransform.a()))); + } + return true; } @@ -488,10 +483,12 @@ static inline void calculateGlyphBoundaries(SVGTextQuery::Data* queryData, const SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.characterOffset + startPosition, 1); extent.setSize(FloatSize(metrics.width(), metrics.height())); - if (fragment.transform.isIdentity()) + AffineTransform fragmentTransform; + fragment.buildFragmentTransform(fragmentTransform, SVGTextFragment::TransformIgnoringTextLength); + if (fragmentTransform.isIdentity()) return; - extent = fragment.transform.mapRect(extent); + extent = fragmentTransform.mapRect(extent); } bool SVGTextQuery::extentOfCharacterCallback(Data* queryData, const SVGTextFragment& fragment) const |