diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-05 14:34:32 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-05 14:34:32 -0800 |
commit | 635860845790a19bf50bbc51ba8fb66a96dde068 (patch) | |
tree | ef6ad9ff73a5b57f65249d4232a202fa77e6a140 /WebCore/rendering | |
parent | 8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2 (diff) | |
download | external_webkit-635860845790a19bf50bbc51ba8fb66a96dde068.zip external_webkit-635860845790a19bf50bbc51ba8fb66a96dde068.tar.gz external_webkit-635860845790a19bf50bbc51ba8fb66a96dde068.tar.bz2 |
auto import from //depot/cupcake/@136594
Diffstat (limited to 'WebCore/rendering')
176 files changed, 10387 insertions, 6235 deletions
diff --git a/WebCore/rendering/EllipsisBox.cpp b/WebCore/rendering/EllipsisBox.cpp index 7f563d5..fcce87d 100644 --- a/WebCore/rendering/EllipsisBox.cpp +++ b/WebCore/rendering/EllipsisBox.cpp @@ -32,9 +32,6 @@ void EllipsisBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty) { GraphicsContext* context = paintInfo.context; RenderStyle* style = m_object->style(m_firstLine); - if (style->font() != context->font()) - context->setFont(style->font()); - Color textColor = style->color(); if (textColor != context->fillColor()) context->setFillColor(textColor); @@ -46,7 +43,7 @@ void EllipsisBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty) } const String& str = m_str; - context->drawText(TextRun(str.characters(), str.length(), false, 0, 0, false, style->visuallyOrdered()), IntPoint(m_x + tx, m_y + ty + m_baseline)); + context->drawText(style->font(), TextRun(str.characters(), str.length(), false, 0, 0, false, style->visuallyOrdered()), IntPoint(m_x + tx, m_y + ty + m_baseline)); if (setShadow) context->clearShadow(); @@ -74,7 +71,7 @@ bool EllipsisBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu } } - if (object()->style()->visibility() == VISIBLE && IntRect(tx, ty, m_width, m_height).contains(x, y)) { + if (visibleToHitTesting() && IntRect(tx, ty, m_width, m_height).contains(x, y)) { object()->updateHitTestResult(result, IntPoint(x - tx, y - ty)); return true; } diff --git a/WebCore/rendering/FixedTableLayout.cpp b/WebCore/rendering/FixedTableLayout.cpp index 1dc66a9..d7c1293 100644 --- a/WebCore/rendering/FixedTableLayout.cpp +++ b/WebCore/rendering/FixedTableLayout.cpp @@ -79,7 +79,7 @@ FixedTableLayout::FixedTableLayout(RenderTable* table) { } -int FixedTableLayout::calcWidthArray(int tableWidth) +int FixedTableLayout::calcWidthArray(int) { int usedWidth = 0; diff --git a/WebCore/rendering/GapRects.h b/WebCore/rendering/GapRects.h index bf53d70..a762ae5 100644 --- a/WebCore/rendering/GapRects.h +++ b/WebCore/rendering/GapRects.h @@ -1,7 +1,5 @@ /* - This file is part of the KDE libraries - - Copyright (C) 2005, 2006 Apple Computer, Inc. + Copyright (C) 2005, 2006 Apple Inc. All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public diff --git a/WebCore/rendering/HitTestResult.cpp b/WebCore/rendering/HitTestResult.cpp index 53b376d..8126fc7 100644 --- a/WebCore/rendering/HitTestResult.cpp +++ b/WebCore/rendering/HitTestResult.cpp @@ -36,6 +36,11 @@ #include "XLinkNames.h" #endif +#if ENABLE(WML) +#include "WMLImageElement.h" +#include "WMLNames.h" +#endif + namespace WebCore { using namespace HTMLNames; @@ -172,9 +177,7 @@ String displayString(const String& string, const Node* node) { if (!node) return string; - String copy(string); - copy.replace('\\', node->document()->backslashAsCurrencySymbol()); - return copy; + return node->document()->displayStringModifiedByEncoding(string); } String HitTestResult::altDisplayString() const @@ -192,6 +195,13 @@ String HitTestResult::altDisplayString() const return displayString(input->alt(), m_innerNonSharedNode.get()); } +#if ENABLE(WML) + if (m_innerNonSharedNode->hasTagName(WMLNames::imgTag)) { + WMLImageElement* image = static_cast<WMLImageElement*>(m_innerNonSharedNode.get()); + return displayString(image->altText(), m_innerNonSharedNode.get()); + } +#endif + return String(); } @@ -214,7 +224,7 @@ IntRect HitTestResult::imageRect() const { if (!image()) return IntRect(); - return m_innerNonSharedNode->renderer()->absoluteContentBox(); + return m_innerNonSharedNode->renderBox()->absoluteContentBox(); } KURL HitTestResult::absoluteImageURL() const @@ -226,18 +236,22 @@ KURL HitTestResult::absoluteImageURL() const return KURL(); AtomicString urlString; - if (m_innerNonSharedNode->hasTagName(imgTag) || m_innerNonSharedNode->hasTagName(inputTag)) - urlString = static_cast<Element*>(m_innerNonSharedNode.get())->getAttribute(srcAttr); + if (m_innerNonSharedNode->hasTagName(embedTag) + || m_innerNonSharedNode->hasTagName(imgTag) + || m_innerNonSharedNode->hasTagName(inputTag) + || m_innerNonSharedNode->hasTagName(objectTag) #if ENABLE(SVG) - else if (m_innerNonSharedNode->hasTagName(SVGNames::imageTag)) - urlString = static_cast<Element*>(m_innerNonSharedNode.get())->getAttribute(XLinkNames::hrefAttr); + || m_innerNonSharedNode->hasTagName(SVGNames::imageTag) +#endif +#if ENABLE(WML) + || m_innerNonSharedNode->hasTagName(WMLNames::imgTag) #endif - else if (m_innerNonSharedNode->hasTagName(embedTag) || m_innerNonSharedNode->hasTagName(objectTag)) { + ) { Element* element = static_cast<Element*>(m_innerNonSharedNode.get()); urlString = element->getAttribute(element->imageSourceAttributeName()); } else return KURL(); - + return m_innerNonSharedNode->document()->completeURL(parseURL(urlString)); } @@ -253,6 +267,10 @@ KURL HitTestResult::absoluteLinkURL() const else if (m_innerURLElement->hasTagName(SVGNames::aTag)) urlString = m_innerURLElement->getAttribute(XLinkNames::hrefAttr); #endif +#if ENABLE(WML) + else if (m_innerURLElement->hasTagName(WMLNames::aTag)) + urlString = m_innerURLElement->getAttribute(hrefAttr); +#endif else return KURL(); @@ -270,7 +288,11 @@ bool HitTestResult::isLiveLink() const if (m_innerURLElement->hasTagName(SVGNames::aTag)) return m_innerURLElement->isLink(); #endif - +#if ENABLE(WML) + if (m_innerURLElement->hasTagName(WMLNames::aTag)) + return m_innerURLElement->isLink(); +#endif + return false; } diff --git a/WebCore/rendering/InlineBox.cpp b/WebCore/rendering/InlineBox.cpp index 5dc1f47..6f7324a 100644 --- a/WebCore/rendering/InlineBox.cpp +++ b/WebCore/rendering/InlineBox.cpp @@ -23,6 +23,7 @@ #include "HitTestResult.h" #include "InlineFlowBox.h" #include "RenderArena.h" +#include "RenderBox.h" #include "RootInlineBox.h" using namespace std; @@ -129,8 +130,10 @@ void InlineBox::adjustPosition(int dx, int dy) { m_x += dx; m_y += dy; - if (m_object->isReplaced() || m_object->isBR()) - m_object->setPos(m_object->xPos() + dx, m_object->yPos() + dy); + if (m_object->isReplaced()) { + RenderBox* box = toRenderBox(m_object); + box->move(dx, dy); + } } void InlineBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty) @@ -239,7 +242,7 @@ bool InlineBox::canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidt return !(boxRect.intersects(ellipsisRect)); } -int InlineBox::placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool&) +int InlineBox::placeEllipsisBox(bool, int, int, bool&) { // Use -1 to mean "we didn't set the position." return -1; diff --git a/WebCore/rendering/InlineBox.h b/WebCore/rendering/InlineBox.h index 48aab77..e17b6e8 100644 --- a/WebCore/rendering/InlineBox.h +++ b/WebCore/rendering/InlineBox.h @@ -21,7 +21,7 @@ #ifndef InlineBox_h #define InlineBox_h -#include "RenderObject.h" // needed for RenderObject::PaintInfo +#include "RenderBox.h" #include "TextDirection.h" namespace WebCore { @@ -237,6 +237,11 @@ public: int toAdd() const { return m_toAdd; } + bool visibleToHitTesting() const { return object()->style()->visibility() == VISIBLE && object()->style()->pointerEvents() != PE_NONE; } + + // Use with caution! The type is not checked! + RenderBox* renderBox() const { return toRenderBox(m_object); } + public: RenderObject* m_object; diff --git a/WebCore/rendering/InlineFlowBox.cpp b/WebCore/rendering/InlineFlowBox.cpp index 5f37ad6..74f4151 100644 --- a/WebCore/rendering/InlineFlowBox.cpp +++ b/WebCore/rendering/InlineFlowBox.cpp @@ -66,7 +66,7 @@ int InlineFlowBox::marginLeft() return 0; if (margin.isFixed()) return margin.value(); - return object()->marginLeft(); + return renderBox()->marginLeft(); } int InlineFlowBox::marginRight() @@ -79,7 +79,7 @@ int InlineFlowBox::marginRight() return 0; if (margin.isFixed()) return margin.value(); - return object()->marginRight(); + return renderBox()->marginRight(); } int InlineFlowBox::marginBorderPaddingLeft() @@ -249,11 +249,11 @@ void InlineFlowBox::determineSpacingForFlowBoxes(bool lastLine, RenderObject* en if (!flow->lastLineBox()->isConstructed()) { if (ltr) { if (!nextLineBox() && - ((lastLine && !object()->continuation()) || nextOnLineExists() || onEndChain(endObject))) + ((lastLine && !flow->continuation()) || nextOnLineExists() || onEndChain(endObject))) includeRightEdge = true; } else { if ((!prevLineBox() || prevLineBox()->isConstructed()) && - ((lastLine && !object()->continuation()) || prevOnLineExists() || onEndChain(endObject))) + ((lastLine && !flow->continuation()) || prevOnLineExists() || onEndChain(endObject))) includeLeftEdge = true; } } @@ -289,7 +289,7 @@ int InlineFlowBox::placeBoxesHorizontally(int x, int& leftPosition, int& rightPo for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { if (curr->object()->isText()) { InlineTextBox* text = static_cast<InlineTextBox*>(curr); - RenderText* rt = static_cast<RenderText*>(text->object()); + RenderText* rt = toRenderText(text->object()); if (rt->textLength()) { if (needsWordSpacing && isSpaceOrNewline(rt->characters()[text->start()])) x += rt->style(m_firstLine)->font().wordSpacing(); @@ -325,25 +325,20 @@ int InlineFlowBox::placeBoxesHorizontally(int x, int& leftPosition, int& rightPo // Our offset that we cache needs to be from the edge of the right border box and // not the left border box. We have to subtract |x| from the width of the block // (which can be obtained from the root line box). - curr->setXPos(root()->object()->width()-x); + curr->setXPos(root()->block()->width()-x); continue; // The positioned object has no effect on the width. } - if (curr->object()->isInlineFlow()) { + if (curr->object()->isRenderInline()) { InlineFlowBox* flow = static_cast<InlineFlowBox*>(curr); - if (curr->object()->isCompact()) { - int ignoredX = x; - flow->placeBoxesHorizontally(ignoredX, leftPosition, rightPosition, needsWordSpacing); - } else { - x += flow->marginLeft(); - x = flow->placeBoxesHorizontally(x, leftPosition, rightPosition, needsWordSpacing); - x += flow->marginRight(); - } - } else if (!curr->object()->isCompact() && (!curr->object()->isListMarker() || static_cast<RenderListMarker*>(curr->object())->isInside())) { - x += curr->object()->marginLeft(); + x += flow->marginLeft(); + x = flow->placeBoxesHorizontally(x, leftPosition, rightPosition, needsWordSpacing); + x += flow->marginRight(); + } else if (!curr->object()->isListMarker() || static_cast<RenderListMarker*>(curr->object())->isInside()) { + x += curr->renderBox()->marginLeft(); curr->setXPos(x); - leftPosition = min(x + curr->object()->overflowLeft(false), leftPosition); - rightPosition = max(x + curr->object()->overflowWidth(false), rightPosition); - x += curr->width() + curr->object()->marginRight(); + leftPosition = min(x + curr->renderBox()->overflowLeft(false), leftPosition); + rightPosition = max(x + curr->renderBox()->overflowWidth(false), rightPosition); + x += curr->width() + curr->renderBox()->marginRight(); } } } @@ -355,7 +350,7 @@ int InlineFlowBox::placeBoxesHorizontally(int x, int& leftPosition, int& rightPo return x; } -void InlineFlowBox::verticallyAlignBoxes(int& heightOfBlock) +int InlineFlowBox::verticallyAlignBoxes(int heightOfBlock) { int maxPositionTop = 0; int maxPositionBottom = 0; @@ -389,6 +384,8 @@ void InlineFlowBox::verticallyAlignBoxes(int& heightOfBlock) shrinkBoxesWithNoTextChildren(topPosition, bottomPosition); heightOfBlock += maxHeight; + + return heightOfBlock; } void InlineFlowBox::adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent, @@ -456,7 +453,7 @@ void InlineFlowBox::computeLogicalBoxHeights(int& maxPositionTop, int& maxPositi if (maxPositionBottom < curr->height()) maxPositionBottom = curr->height(); } - else if (curr->hasTextChildren() || curr->object()->hasHorizontalBordersOrPadding() || strictMode) { + else if (curr->hasTextChildren() || curr->renderBox()->hasHorizontalBordersOrPadding() || strictMode) { int ascent = curr->baseline() - curr->yPos(); int descent = curr->height() - ascent; if (maxAscent < ascent) @@ -491,7 +488,7 @@ void InlineFlowBox::placeBoxesVertically(int y, int maxHeight, int maxAscent, bo else if (curr->yPos() == PositionBottom) curr->setYPos(y + maxHeight - curr->height()); else { - if (!curr->hasTextChildren() && !curr->object()->hasHorizontalBordersOrPadding() && !strictMode) + if (!curr->hasTextChildren() && !curr->renderBox()->hasHorizontalBordersOrPadding() && !strictMode) childAffectsTopBottomPos = false; curr->setYPos(curr->yPos() + y + maxAscent - curr->baseline()); } @@ -522,21 +519,21 @@ void InlineFlowBox::placeBoxesVertically(int y, int maxHeight, int maxAscent, bo } if (curr->object()->hasReflection()) { - overflowTop = min(overflowTop, curr->object()->reflectionBox().y()); - overflowBottom = max(overflowBottom, curr->object()->reflectionBox().bottom()); + overflowTop = min(overflowTop, curr->renderBox()->reflectionBox().y()); + overflowBottom = max(overflowBottom, curr->renderBox()->reflectionBox().bottom()); } if (curr->isInlineFlowBox()) { - newHeight += curr->object()->borderTop() + curr->object()->paddingTop() + - curr->object()->borderBottom() + curr->object()->paddingBottom(); - newY -= curr->object()->borderTop() + curr->object()->paddingTop(); - newBaseline += curr->object()->borderTop() + curr->object()->paddingTop(); + newHeight += curr->renderBox()->borderTop() + curr->renderBox()->paddingTop() + + curr->renderBox()->borderBottom() + curr->renderBox()->paddingBottom(); + newY -= curr->renderBox()->borderTop() + curr->renderBox()->paddingTop(); + newBaseline += curr->renderBox()->borderTop() + curr->renderBox()->paddingTop(); } } else if (!curr->object()->isBR()) { - newY += curr->object()->marginTop(); - newHeight = curr->height() - (curr->object()->marginTop() + curr->object()->marginBottom()); - overflowTop = curr->object()->overflowTop(false); - overflowBottom = curr->object()->overflowHeight(false) - newHeight; + newY += curr->renderBox()->marginTop(); + newHeight = curr->height() - (curr->renderBox()->marginTop() + curr->renderBox()->marginBottom()); + overflowTop = curr->renderBox()->overflowTop(false); + overflowBottom = curr->renderBox()->overflowHeight(false) - newHeight; } curr->setYPos(newY); @@ -575,7 +572,7 @@ void InlineFlowBox::shrinkBoxesWithNoTextChildren(int topPos, int bottomPos) } // See if we have text children. If not, then we need to shrink ourselves to fit on the line. - if (!hasTextChildren() && !object()->hasHorizontalBordersOrPadding()) { + if (!hasTextChildren() && !renderBox()->hasHorizontalBordersOrPadding()) { if (yPos() < topPos) setYPos(topPos); if (yPos() + height() > bottomPos) @@ -597,7 +594,7 @@ bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re // Now check ourselves. IntRect rect(tx + m_x, ty + m_y, m_width, m_height); - if (object()->style()->visibility() == VISIBLE && rect.contains(x, y)) { + if (visibleToHitTesting() && rect.contains(x, y)) { object()->updateHitTestResult(result, IntPoint(x - tx, y - ty)); // Don't add in m_x or m_y here, we want coords in the containing block's space. return true; } @@ -628,7 +625,7 @@ void InlineFlowBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty) // Add ourselves to the paint info struct's list of inlines that need to paint their // outlines. if (object()->style()->visibility() == VISIBLE && object()->hasOutline() && !isRootInlineBox()) { - if ((object()->continuation() || object()->isInlineContinuation()) && !object()->hasLayer()) { + if ((flowObject()->continuation() || object()->isInlineContinuation()) && !object()->hasLayer()) { // Add ourselves to the containing block of the entire continuation so that it can // paint us atomically. RenderBlock* block = object()->containingBlock()->containingBlock(); @@ -855,7 +852,7 @@ void InlineFlowBox::paintMask(RenderObject::PaintInfo& paintInfo, int tx, int ty static bool shouldDrawTextDecoration(RenderObject* obj) { for (RenderObject* curr = obj->firstChild(); curr; curr = curr->nextSibling()) { - if (curr->isInlineFlow()) + if (curr->isRenderInline()) return true; if (curr->isText() && !curr->isBR()) { if (!curr->style()->collapseWhiteSpace()) diff --git a/WebCore/rendering/InlineFlowBox.h b/WebCore/rendering/InlineFlowBox.h index 9589603..62f8f69 100644 --- a/WebCore/rendering/InlineFlowBox.h +++ b/WebCore/rendering/InlineFlowBox.h @@ -97,10 +97,10 @@ public: int marginBorderPaddingRight(); int marginLeft(); int marginRight(); - int borderLeft() { if (includeLeftEdge()) return object()->borderLeft(); return 0; } - int borderRight() { if (includeRightEdge()) return object()->borderRight(); return 0; } - int paddingLeft() { if (includeLeftEdge()) return object()->paddingLeft(); return 0; } - int paddingRight() { if (includeRightEdge()) return object()->paddingRight(); return 0; } + int borderLeft() { if (includeLeftEdge()) return renderBox()->borderLeft(); return 0; } + int borderRight() { if (includeRightEdge()) return renderBox()->borderRight(); return 0; } + int paddingLeft() { if (includeLeftEdge()) return renderBox()->paddingLeft(); return 0; } + int paddingRight() { if (includeRightEdge()) return renderBox()->paddingRight(); return 0; } bool includeLeftEdge() { return m_includeLeftEdge; } bool includeRightEdge() { return m_includeRightEdge; } @@ -115,7 +115,7 @@ public: int getFlowSpacingWidth(); bool onEndChain(RenderObject* endObject); virtual int placeBoxesHorizontally(int x, int& leftPosition, int& rightPosition, bool& needsWordSpacing); - virtual void verticallyAlignBoxes(int& heightOfBlock); + virtual int verticallyAlignBoxes(int heightOfBlock); void computeLogicalBoxHeights(int& maxPositionTop, int& maxPositionBottom, int& maxAscent, int& maxDescent, bool strictMode); void adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent, @@ -124,8 +124,8 @@ public: int& topPosition, int& bottomPosition, int& selectionTop, int& selectionBottom); void shrinkBoxesWithNoTextChildren(int topPosition, int bottomPosition); - virtual void setVerticalOverflowPositions(int top, int bottom) { } - virtual void setVerticalSelectionPositions(int top, int bottom) { } + virtual void setVerticalOverflowPositions(int /*top*/, int /*bottom*/) { } + virtual void setVerticalSelectionPositions(int /*top*/, int /*bottom*/) { } int maxHorizontalVisualOverflow() const { return m_maxHorizontalVisualOverflow; } void removeChild(InlineBox* child); @@ -165,7 +165,7 @@ inline void InlineFlowBox::setHasBadChildList() #ifndef NDEBUG // Outside the WebCore namespace for ease of invocation from gdb. -void showTree(const WebCore::InlineBox*); +void showTree(const WebCore::InlineFlowBox*); #endif #endif // InlineFlowBox_h diff --git a/WebCore/rendering/InlineRunBox.h b/WebCore/rendering/InlineRunBox.h index a624a5b..0f7c29b 100644 --- a/WebCore/rendering/InlineRunBox.h +++ b/WebCore/rendering/InlineRunBox.h @@ -41,8 +41,8 @@ public: void setNextLineBox(InlineRunBox* n) { m_nextLine = n; } void setPreviousLineBox(InlineRunBox* p) { m_prevLine = p; } - virtual void paintBoxDecorations(RenderObject::PaintInfo&, int tx, int ty) { } - virtual void paintTextDecorations(RenderObject::PaintInfo&, int tx, int ty, bool paintedChildren = false) { } + virtual void paintBoxDecorations(RenderObject::PaintInfo&, int /*tx*/, int /*ty*/) { } + virtual void paintTextDecorations(RenderObject::PaintInfo&, int /*tx*/, int /*ty*/, bool /*paintedChildren*/ = false) { } protected: InlineRunBox* m_prevLine; // The previous box that also uses our RenderObject diff --git a/WebCore/rendering/InlineTextBox.cpp b/WebCore/rendering/InlineTextBox.cpp index a30920a..744c4c7 100644 --- a/WebCore/rendering/InlineTextBox.cpp +++ b/WebCore/rendering/InlineTextBox.cpp @@ -108,7 +108,7 @@ IntRect InlineTextBox::selectionRect(int tx, int ty, int startPos, int endPos) void InlineTextBox::deleteLine(RenderArena* arena) { - static_cast<RenderText*>(m_object)->removeTextBox(this); + toRenderText(m_object)->removeTextBox(this); destroy(arena); } @@ -117,7 +117,7 @@ void InlineTextBox::extractLine() if (m_extracted) return; - static_cast<RenderText*>(m_object)->extractTextBox(this); + toRenderText(m_object)->extractTextBox(this); } void InlineTextBox::attachLine() @@ -125,7 +125,7 @@ void InlineTextBox::attachLine() if (!m_extracted) return; - static_cast<RenderText*>(m_object)->attachTextBox(this); + toRenderText(m_object)->attachTextBox(this); } int InlineTextBox::placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool& foundBox) @@ -162,7 +162,7 @@ int InlineTextBox::placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, // Set the truncation index on the text run. The ellipsis needs to be placed just after the last visible character. m_truncation = offset; - return m_x + static_cast<RenderText*>(m_object)->width(m_start, offset, textPos(), m_firstLine); + return m_x + toRenderText(m_object)->width(m_start, offset, textPos(), m_firstLine); } } else { @@ -219,20 +219,20 @@ bool InlineTextBox::isLineBreak() const return object()->isBR() || (object()->style()->preserveNewline() && len() == 1 && (*textObject()->text())[start()] == '\n'); } -bool InlineTextBox::nodeAtPoint(const HitTestRequest& request, 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) { if (isLineBreak()) return false; IntRect rect(tx + m_x, ty + m_y, m_width, m_height); - if (m_truncation != cFullTruncation && object()->style()->visibility() == VISIBLE && rect.contains(x, y)) { + if (m_truncation != cFullTruncation && visibleToHitTesting() && rect.contains(x, y)) { object()->updateHitTestResult(result, IntPoint(x - tx, y - ty)); return true; } return false; } -static void paintTextWithShadows(GraphicsContext* context, const TextRun& textRun, int startOffset, int endOffset, const IntPoint& textOrigin, int x, int y, int w, int h, ShadowData* shadow, bool stroked) +static void paintTextWithShadows(GraphicsContext* context, const Font& font, const TextRun& textRun, int startOffset, int endOffset, const IntPoint& textOrigin, int x, int y, int w, int h, ShadowData* shadow, bool stroked) { do { IntSize extraOffset; @@ -256,12 +256,12 @@ static void paintTextWithShadows(GraphicsContext* context, const TextRun& textRu } if (startOffset <= endOffset) - context->drawText(textRun, textOrigin + extraOffset, startOffset, endOffset); + context->drawText(font, textRun, textOrigin + extraOffset, startOffset, endOffset); else { if (endOffset > 0) - context->drawText(textRun, textOrigin + extraOffset, 0, endOffset); + context->drawText(font, textRun, textOrigin + extraOffset, 0, endOffset); if (startOffset < textRun.length()) - context->drawText(textRun, textOrigin + extraOffset, startOffset); + context->drawText(font, textRun, textOrigin + extraOffset, startOffset); } if (!shadow) @@ -306,9 +306,7 @@ void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty) // Set our font. RenderStyle* styleToUse = object()->style(m_firstLine); int d = styleToUse->textDecorationsInEffect(); - const Font* font = &styleToUse->font(); - if (*font != context->font()) - context->setFont(*font); + const Font& font = styleToUse->font(); // 1. Paint backgrounds behind text if needed. Examples of such backgrounds include selection // and composition underlines. @@ -419,9 +417,9 @@ void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty) updateGraphicsContext(context, textFillColor, textStrokeColor, textStrokeWidth); if (!paintSelectedTextSeparately || ePos <= sPos) { // FIXME: Truncate right-to-left text correctly. - paintTextWithShadows(context, textRun, 0, m_truncation == cNoTruncation ? m_len : m_truncation, textOrigin, m_x + tx, m_y + ty, width(), height(), textShadow, textStrokeWidth > 0); + paintTextWithShadows(context, font, textRun, 0, m_truncation == cNoTruncation ? m_len : m_truncation, textOrigin, m_x + tx, m_y + ty, width(), height(), textShadow, textStrokeWidth > 0); } else - paintTextWithShadows(context, textRun, ePos, sPos, textOrigin, m_x + tx, m_y + ty, width(), height(), textShadow, textStrokeWidth > 0); + paintTextWithShadows(context, font, textRun, ePos, sPos, textOrigin, m_x + tx, m_y + ty, width(), height(), textShadow, textStrokeWidth > 0); if (textStrokeWidth > 0) context->restore(); @@ -433,7 +431,7 @@ void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty) context->save(); updateGraphicsContext(context, selectionFillColor, selectionStrokeColor, selectionStrokeWidth); - paintTextWithShadows(context, textRun, sPos, ePos, textOrigin, m_x + tx, m_y + ty, width(), height(), selectionShadow, selectionStrokeWidth > 0); + paintTextWithShadows(context, font, textRun, sPos, ePos, textOrigin, m_x + tx, m_y + ty, width(), height(), selectionShadow, selectionStrokeWidth > 0); if (selectionStrokeWidth > 0) context->restore(); @@ -493,7 +491,7 @@ void InlineTextBox::selectionStartEnd(int& sPos, int& ePos) ePos = min(endPos - m_start, (int)m_len); } -void InlineTextBox::paintSelection(GraphicsContext* context, int tx, int ty, RenderStyle* style, const Font* f) +void InlineTextBox::paintSelection(GraphicsContext* context, int tx, int ty, RenderStyle* style, const Font& font) { // See if we have a selection to paint at all. int sPos, ePos; @@ -527,12 +525,13 @@ void InlineTextBox::paintSelection(GraphicsContext* context, int tx, int ty, Ren int y = selectionTop(); int h = selectionHeight(); context->clip(IntRect(m_x + tx, y + ty, m_width, h)); - context->drawHighlightForText(TextRun(textObject()->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered()), - IntPoint(m_x + tx, y + ty), h, c, sPos, ePos); + context->drawHighlightForText(font, TextRun(textObject()->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, + direction() == RTL, m_dirOverride || style->visuallyOrdered()), + IntPoint(m_x + tx, y + ty), h, c, sPos, ePos); context->restore(); } -void InlineTextBox::paintCompositionBackground(GraphicsContext* context, int tx, int ty, RenderStyle* style, const Font* f, int startPos, int endPos) +void InlineTextBox::paintCompositionBackground(GraphicsContext* context, int tx, int ty, RenderStyle* style, const Font& font, int startPos, int endPos) { int offset = m_start; int sPos = max(startPos - offset, 0); @@ -549,8 +548,9 @@ void InlineTextBox::paintCompositionBackground(GraphicsContext* context, int tx, int y = selectionTop(); int h = selectionHeight(); - context->drawHighlightForText(TextRun(textObject()->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered()), - IntPoint(m_x + tx, y + ty), h, c, sPos, ePos); + context->drawHighlightForText(font, TextRun(textObject()->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, + direction() == RTL, m_dirOverride || style->visuallyOrdered()), + IntPoint(m_x + tx, y + ty), h, c, sPos, ePos); context->restore(); } @@ -583,7 +583,7 @@ void InlineTextBox::paintDecoration(GraphicsContext* context, int tx, int ty, in return; int width = (m_truncation == cNoTruncation) ? m_width - : static_cast<RenderText*>(m_object)->width(m_start, m_truncation, textPos(), m_firstLine); + : toRenderText(m_object)->width(m_start, m_truncation, textPos(), m_firstLine); // Get the text decoration colors. Color underline, overline, linethrough; @@ -648,7 +648,7 @@ void InlineTextBox::paintDecoration(GraphicsContext* context, int tx, int ty, in context->clearShadow(); } -void InlineTextBox::paintSpellingOrGrammarMarker(GraphicsContext* pt, int tx, int ty, DocumentMarker marker, RenderStyle* style, const Font* f, bool grammar) +void InlineTextBox::paintSpellingOrGrammarMarker(GraphicsContext* pt, int tx, int ty, DocumentMarker marker, RenderStyle* style, const Font& font, bool grammar) { // Never print spelling/grammar markers (5327887) if (textObject()->document()->printing()) @@ -681,7 +681,7 @@ void InlineTextBox::paintSpellingOrGrammarMarker(GraphicsContext* pt, int tx, in TextRun run(textObject()->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered()); int h = selectionHeight(); - IntRect markerRect = enclosingIntRect(f->selectionRectForText(run, startPoint, h, startPosition, endPosition)); + IntRect markerRect = enclosingIntRect(font.selectionRectForText(run, startPoint, h, startPosition, endPosition)); start = markerRect.x() - startPoint.x(); width = markerRect.width(); @@ -710,7 +710,7 @@ void InlineTextBox::paintSpellingOrGrammarMarker(GraphicsContext* pt, int tx, in pt->drawLineForMisspellingOrBadGrammar(IntPoint(tx + m_x + start, ty + m_y + underlineOffset), width, grammar); } -void InlineTextBox::paintTextMatchMarker(GraphicsContext* pt, int tx, int ty, DocumentMarker marker, RenderStyle* style, const Font* f) +void InlineTextBox::paintTextMatchMarker(GraphicsContext* pt, int tx, int ty, DocumentMarker marker, RenderStyle* style, const Font& font) { // Use same y positioning and height as for selection, so that when the selection and this highlight are on // the same word there are no pieces sticking out. @@ -723,7 +723,7 @@ void InlineTextBox::paintTextMatchMarker(GraphicsContext* pt, int tx, int ty, Do IntPoint startPoint = IntPoint(m_x + tx, y + ty); // Always compute and store the rect associated with this marker - IntRect markerRect = enclosingIntRect(f->selectionRectForText(run, startPoint, h, sPos, ePos)); + IntRect markerRect = enclosingIntRect(font.selectionRectForText(run, startPoint, h, sPos, ePos)); object()->document()->setRenderedRectForMarker(object()->node(), marker, markerRect); // Optionally highlight the text @@ -732,12 +732,12 @@ void InlineTextBox::paintTextMatchMarker(GraphicsContext* pt, int tx, int ty, Do pt->save(); updateGraphicsContext(pt, color, color, 0); // Don't draw text at all! pt->clip(IntRect(tx + m_x, ty + y, m_width, h)); - pt->drawHighlightForText(run, startPoint, h, color, sPos, ePos); + pt->drawHighlightForText(font, run, startPoint, h, color, sPos, ePos); pt->restore(); } } -void InlineTextBox::paintDocumentMarkers(GraphicsContext* pt, int tx, int ty, RenderStyle* style, const Font* f, bool background) +void InlineTextBox::paintDocumentMarkers(GraphicsContext* pt, int tx, int ty, RenderStyle* style, const Font& font, bool background) { Vector<DocumentMarker> markers = object()->document()->markersForNode(object()->node()); Vector<DocumentMarker>::iterator markerIt = markers.begin(); @@ -776,13 +776,13 @@ void InlineTextBox::paintDocumentMarkers(GraphicsContext* pt, int tx, int ty, Re // marker intersects this run. Paint it. switch (marker.type) { case DocumentMarker::Spelling: - paintSpellingOrGrammarMarker(pt, tx, ty, marker, style, f, false); + paintSpellingOrGrammarMarker(pt, tx, ty, marker, style, font, false); break; case DocumentMarker::Grammar: - paintSpellingOrGrammarMarker(pt, tx, ty, marker, style, f, true); + paintSpellingOrGrammarMarker(pt, tx, ty, marker, style, font, true); break; case DocumentMarker::TextMatch: - paintTextMatchMarker(pt, tx, ty, marker, style, f); + paintTextMatchMarker(pt, tx, ty, marker, style, font); break; default: ASSERT_NOT_REACHED(); @@ -808,7 +808,7 @@ void InlineTextBox::paintCompositionUnderline(GraphicsContext* ctx, int tx, int if (paintStart <= underline.startOffset) { paintStart = underline.startOffset; useWholeWidth = false; - start = static_cast<RenderText*>(m_object)->width(m_start, paintStart - m_start, textPos(), m_firstLine); + start = toRenderText(m_object)->width(m_start, paintStart - m_start, textPos(), m_firstLine); } if (paintEnd != underline.endOffset) { // end points at the last char, not past it paintEnd = min(paintEnd, (unsigned)underline.endOffset); @@ -819,7 +819,7 @@ void InlineTextBox::paintCompositionUnderline(GraphicsContext* ctx, int tx, int useWholeWidth = false; } if (!useWholeWidth) { - width = static_cast<RenderText*>(m_object)->width(paintStart, paintEnd - paintStart, textPos() + start, m_firstLine); + width = toRenderText(m_object)->width(paintStart, paintEnd - paintStart, textPos() + start, m_firstLine); } // Thick marked text underlines are 2px thick as long as there is room for the 2px line under the baseline. @@ -869,7 +869,7 @@ int InlineTextBox::offsetForPosition(int _x, bool includePartialGlyphs) const if (isLineBreak()) return 0; - RenderText* text = static_cast<RenderText*>(m_object); + RenderText* text = toRenderText(m_object); RenderStyle *style = text->style(m_firstLine); const Font* f = &style->font(); return f->offsetForPosition(TextRun(textObject()->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered()), @@ -884,7 +884,7 @@ int InlineTextBox::positionForOffset(int offset) const if (isLineBreak()) return m_x; - RenderText* text = static_cast<RenderText*>(m_object); + RenderText* text = toRenderText(m_object); const Font& f = text->style(m_firstLine)->font(); int from = direction() == RTL ? offset - m_start : 0; int to = direction() == RTL ? m_len : offset - m_start; diff --git a/WebCore/rendering/InlineTextBox.h b/WebCore/rendering/InlineTextBox.h index d8a250b..0c2dd8a 100644 --- a/WebCore/rendering/InlineTextBox.h +++ b/WebCore/rendering/InlineTextBox.h @@ -1,9 +1,7 @@ /* - * This file is part of the DOM implementation for KDE. - * * (C) 1999 Lars Knoll (knoll@kde.org) * (C) 2000 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. + * Copyright (C) 2004, 2005, 2006, 2009 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -25,22 +23,16 @@ #ifndef InlineTextBox_h #define InlineTextBox_h -#include "DocumentMarker.h" #include "InlineRunBox.h" -#include "RenderText.h" +#include "RenderText.h" // so textObject() can be inline namespace WebCore { +struct CompositionUnderline; + const unsigned short cNoTruncation = USHRT_MAX; const unsigned short cFullTruncation = USHRT_MAX - 1; -class String; -class StringImpl; -class HitTestResult; -class Position; - -struct CompositionUnderline; - // Helper functions shared by InlineTextBox / SVGRootInlineBox void updateGraphicsContext(GraphicsContext* context, const Color& fillColor, const Color& strokeColor, float strokeThickness); Color correctedTextColor(Color textColor, Color backgroundColor); @@ -67,46 +59,61 @@ public: void offsetRun(int d) { m_start += d; } +private: virtual int selectionTop(); virtual int selectionHeight(); +public: virtual IntRect selectionRect(int absx, int absy, int startPos, int endPos); bool isSelected(int startPos, int endPos) const; void selectionStartEnd(int& sPos, int& ePos); +private: virtual void paint(RenderObject::PaintInfo&, int tx, int ty); virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty); +public: RenderText* textObject() const; +private: virtual void deleteLine(RenderArena*); virtual void extractLine(); virtual void attachLine(); +public: virtual RenderObject::SelectionState selectionState(); +private: virtual void clearTruncation() { m_truncation = cNoTruncation; } virtual int placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool& foundBox); +public: virtual bool isLineBreak() const; void setSpaceAdd(int add) { m_width -= m_toAdd; m_toAdd = add; m_width += m_toAdd; } - int spaceAdd() { return m_toAdd; } +private: virtual bool isInlineTextBox() { return true; } + +public: virtual bool isText() const { return m_treatAsText; } void setIsText(bool b) { m_treatAsText = b; } virtual int caretMinOffset() const; virtual int caretMaxOffset() const; + +private: virtual unsigned caretMaxRenderedOffset() const; int textPos() const; + +public: virtual int offsetForPosition(int x, bool includePartialGlyphs = true) const; virtual int positionForOffset(int offset) const; bool containsCaretOffset(int offset) const; // false for offset after line break +private: int m_start; unsigned short m_len; @@ -114,24 +121,23 @@ public: // denote no truncation (the whole run paints) and full truncation (nothing paints at all). protected: - void paintCompositionBackground(GraphicsContext*, int tx, int ty, RenderStyle*, const Font*, int startPos, int endPos); - void paintDocumentMarkers(GraphicsContext*, int tx, int ty, RenderStyle*, const Font*, bool background); + void paintCompositionBackground(GraphicsContext*, int tx, int ty, RenderStyle*, const Font&, int startPos, int endPos); + void paintDocumentMarkers(GraphicsContext*, int tx, int ty, RenderStyle*, const Font&, bool background); void paintCompositionUnderline(GraphicsContext*, int tx, int ty, const CompositionUnderline&); #if PLATFORM(MAC) void paintCustomHighlight(int tx, int ty, const AtomicString& type); #endif private: - void paintDecoration(GraphicsContext*, int tx, int ty, int decoration, ShadowData* shadow); - void paintSelection(GraphicsContext*, int tx, int ty, RenderStyle*, const Font*); - void paintSpellingOrGrammarMarker(GraphicsContext*, int tx, int ty, DocumentMarker, RenderStyle*, const Font*, bool grammar); - void paintTextMatchMarker(GraphicsContext*, int tx, int ty, DocumentMarker, RenderStyle*, const Font*); - friend class RenderText; + void paintDecoration(GraphicsContext*, int tx, int ty, int decoration, ShadowData*); + void paintSelection(GraphicsContext*, int tx, int ty, RenderStyle*, const Font&); + void paintSpellingOrGrammarMarker(GraphicsContext*, int tx, int ty, DocumentMarker, RenderStyle*, const Font&, bool grammar); + void paintTextMatchMarker(GraphicsContext*, int tx, int ty, DocumentMarker, RenderStyle*, const Font&); }; inline RenderText* InlineTextBox::textObject() const { - return static_cast<RenderText*>(m_object); + return toRenderText(m_object); } } // namespace WebCore diff --git a/WebCore/rendering/LayoutState.cpp b/WebCore/rendering/LayoutState.cpp index b473f99..6c196ac 100644 --- a/WebCore/rendering/LayoutState.cpp +++ b/WebCore/rendering/LayoutState.cpp @@ -33,27 +33,24 @@ namespace WebCore { LayoutState::LayoutState(LayoutState* prev, RenderBox* renderer, const IntSize& offset) + : m_next(prev) +#ifndef NDEBUG + , m_renderer(renderer) +#endif { - ASSERT(prev); - - m_next = prev; + ASSERT(m_next); bool fixed = renderer->isPositioned() && renderer->style()->position() == FixedPosition; if (fixed) { - int fixedX = 0; - int fixedY = 0; - renderer->view()->absolutePosition(fixedX, fixedY, true); - m_offset = IntSize(fixedX, fixedY) + offset; + // FIXME: This doesn't work correctly with transforms. + FloatPoint fixedOffset = renderer->view()->localToAbsolute(FloatPoint(), true); + m_offset = IntSize(fixedOffset.x(), fixedOffset.y()) + offset; } else m_offset = prev->m_offset + offset; if (renderer->isRelPositioned()) { - if (renderer->hasLayer()) { - int relX = 0; - int relY = 0; - renderer->layer()->relativePositionOffset(relX, relY); - m_offset += IntSize(relX, relY); - } + if (renderer->hasLayer()) + m_offset += renderer->layer()->relativePositionOffset(); } else if (renderer->isPositioned() && !fixed) { if (RenderObject* container = renderer->container()) m_offset += renderer->offsetForPositionedInContainer(container); @@ -74,21 +71,25 @@ LayoutState::LayoutState(LayoutState* prev, RenderBox* renderer, const IntSize& m_clipRect = clipRect; m_clipped = true; } - layer->subtractScrollOffset(x, y); + layer->subtractScrolledContentOffset(x, y); m_offset = IntSize(x, y); } + + m_layoutDelta = m_next->m_layoutDelta; + // FIXME: <http://bugs.webkit.org/show_bug.cgi?id=13443> Apply control clip if present. } LayoutState::LayoutState(RenderObject* root) : m_clipped(false) + , m_next(0) +#ifndef NDEBUG + , m_renderer(root) +#endif { RenderObject* container = root->container(); - int x = 0; - int y = 0; - container->absolutePositionForContent(x, y); - m_offset = IntSize(x, y); - m_next = 0; + FloatPoint absContentPoint = container->localToAbsolute(FloatPoint(), false, true); + m_offset = IntSize(absContentPoint.x(), absContentPoint.y()); } #ifndef NDEBUG diff --git a/WebCore/rendering/LayoutState.h b/WebCore/rendering/LayoutState.h index 551c74a..afa2952 100644 --- a/WebCore/rendering/LayoutState.h +++ b/WebCore/rendering/LayoutState.h @@ -41,6 +41,9 @@ public: LayoutState() : m_clipped(false) , m_next(0) +#ifndef NDEBUG + , m_renderer(0) +#endif { } @@ -62,8 +65,14 @@ private: public: bool m_clipped; IntRect m_clipRect; - IntSize m_offset; + IntSize m_offset; // x/y offset from container. + IntSize m_layoutDelta; // Transient offset from the final position of the object + // used to ensure that repaints happen in the correct place. + // This is a total delta accumulated from the root. LayoutState* m_next; +#ifndef NDEBUG + RenderObject* m_renderer; +#endif }; } // namespace WebCore diff --git a/WebCore/rendering/MediaControlElements.cpp b/WebCore/rendering/MediaControlElements.cpp index 6164585..8ad2bd6 100644 --- a/WebCore/rendering/MediaControlElements.cpp +++ b/WebCore/rendering/MediaControlElements.cpp @@ -38,7 +38,10 @@ #include "FloatConversion.h" #include "Frame.h" #include "HTMLNames.h" +#include "MouseEvent.h" +#include "RenderMedia.h" #include "RenderSlider.h" +#include "RenderTheme.h" namespace WebCore { @@ -50,7 +53,7 @@ static const float cStepTime = 0.07f; static const float cSeekTime = 0.2f; MediaControlShadowRootElement::MediaControlShadowRootElement(Document* doc, HTMLMediaElement* mediaElement) - : HTMLDivElement(doc) + : HTMLDivElement(divTag, doc) , m_mediaElement(mediaElement) { RefPtr<RenderStyle> rootStyle = RenderStyle::create(); @@ -67,8 +70,42 @@ MediaControlShadowRootElement::MediaControlShadowRootElement(Document* doc, HTML // ---------------------------- +MediaTextDisplayElement::MediaTextDisplayElement(Document* doc, RenderStyle::PseudoId pseudo, HTMLMediaElement* mediaElement) + : HTMLDivElement(divTag, doc) + , m_mediaElement(mediaElement) +{ + RenderStyle* style = m_mediaElement->renderer()->getCachedPseudoStyle(pseudo); + RenderObject* renderer = createRenderer(m_mediaElement->renderer()->renderArena(), style); + if (renderer) { + setRenderer(renderer); + renderer->setStyle(style); + } + setAttached(); + setInDocument(true); +} + +void MediaTextDisplayElement::attachToParent(Element* parent) +{ + parent->addChild(this); + if (renderer()) + parent->renderer()->addChild(renderer()); +} + +void MediaTextDisplayElement::update() +{ + if (renderer()) + renderer()->updateFromElement(); +} + +MediaTimeDisplayElement::MediaTimeDisplayElement(Document* doc, HTMLMediaElement* element, bool currentTime) + : MediaTextDisplayElement(doc, currentTime ? RenderStyle::MEDIA_CONTROLS_CURRENT_TIME_DISPLAY : RenderStyle::MEDIA_CONTROLS_TIME_REMAINING_DISPLAY, element) +{ +} + +// ---------------------------- + MediaControlInputElement::MediaControlInputElement(Document* doc, RenderStyle::PseudoId pseudo, const String& type, HTMLMediaElement* mediaElement) - : HTMLInputElement(doc) + : HTMLInputElement(inputTag, doc) , m_mediaElement(mediaElement) { setInputType(type); @@ -94,6 +131,14 @@ void MediaControlInputElement::update() renderer()->updateFromElement(); } +bool MediaControlInputElement::hitTest(const IntPoint& absPoint) +{ + if (renderer() && renderer()->style()->hasAppearance()) + return theme()->hitTestMediaControlPart(renderer(), absPoint); + + return false; +} + // ---------------------------- MediaControlMuteButtonElement::MediaControlMuteButtonElement(Document* doc, HTMLMediaElement* element) @@ -202,6 +247,7 @@ void MediaControlTimelineElement::defaultEventHandler(Event* event) ExceptionCode ec; m_mediaElement->setCurrentTime(time, ec); } + // Media element stays in non-paused state when it reaches end. If the slider is now dragged // to some other position the playback resumes which does not match usual media player UIs. // Get the expected behavior by pausing explicitly in this case. @@ -209,10 +255,13 @@ void MediaControlTimelineElement::defaultEventHandler(Event* event) ExceptionCode ec; m_mediaElement->pause(ec); } + // Pause playback during drag, but do it without using DOM API which would generate events bool inDragMode = slider && slider->inDragMode(); if (inDragMode != oldInDragMode) m_mediaElement->setPausedInternal(inDragMode); + if (inDragMode) + static_cast<RenderMedia*>(m_mediaElement->renderer())->updateTimeDisplay(); } void MediaControlTimelineElement::update(bool updateDuration) diff --git a/WebCore/rendering/MediaControlElements.h b/WebCore/rendering/MediaControlElements.h index 8ff726b..c1c9574 100644 --- a/WebCore/rendering/MediaControlElements.h +++ b/WebCore/rendering/MediaControlElements.h @@ -43,6 +43,13 @@ namespace WebCore { class Event; class Frame; +enum MediaControlElements { + MediaFullscreenButton, MediaMuteButton, MediaPlayButton, + MediaSeekBackButton, MediaSeekForwardButton, MediaSlider, MediaSliderThumb, + MediaUnMuteButton, MediaPauseButton, MediaTimelineContainer, MediaCurrentTimeDisplay, + MediaTimeRemainingDisplay, MediaControlsPanel +}; + class MediaControlShadowRootElement : public HTMLDivElement { public: MediaControlShadowRootElement(Document*, HTMLMediaElement*); @@ -54,6 +61,25 @@ private: HTMLMediaElement* m_mediaElement; }; + // ---------------------------- + +class MediaTextDisplayElement : public HTMLDivElement +{ +public: + MediaTextDisplayElement(Document*, RenderStyle::PseudoId, HTMLMediaElement*); + void attachToParent(Element*); + void update(); +protected: + HTMLMediaElement* m_mediaElement; +}; + +// ---------------------------- + +class MediaTimeDisplayElement : public MediaTextDisplayElement { +public: + MediaTimeDisplayElement(Document*, HTMLMediaElement*, bool currentTime); +}; + // ---------------------------- class MediaControlInputElement : public HTMLInputElement { @@ -61,6 +87,7 @@ public: MediaControlInputElement(Document*, RenderStyle::PseudoId, const String& type, HTMLMediaElement*); void attachToParent(Element*); void update(); + bool hitTest(const IntPoint& absPoint); protected: HTMLMediaElement* m_mediaElement; }; diff --git a/WebCore/rendering/PointerEventsHitRules.cpp b/WebCore/rendering/PointerEventsHitRules.cpp index bee13af..214fb09 100644 --- a/WebCore/rendering/PointerEventsHitRules.cpp +++ b/WebCore/rendering/PointerEventsHitRules.cpp @@ -20,12 +20,11 @@ */ #include "config.h" -#if ENABLE(SVG) #include "PointerEventsHitRules.h" namespace WebCore { -PointerEventsHitRules::PointerEventsHitRules(ESVGHitTesting hitTesting, EPointerEvents pointerEvents) +PointerEventsHitRules::PointerEventsHitRules(EHitTesting hitTesting, EPointerEvents pointerEvents) : requireVisible(false) , requireFill(false) , requireStroke(false) @@ -36,6 +35,7 @@ PointerEventsHitRules::PointerEventsHitRules(ESVGHitTesting hitTesting, EPointer switch (pointerEvents) { case PE_VISIBLE_PAINTED: + case PE_AUTO: // "auto" is like "visiblePainted" when in SVG content requireFill = true; requireStroke = true; case PE_VISIBLE: @@ -72,6 +72,7 @@ PointerEventsHitRules::PointerEventsHitRules(ESVGHitTesting hitTesting, EPointer switch (pointerEvents) { case PE_VISIBLE_PAINTED: + case PE_AUTO: // "auto" is like "visiblePainted" when in SVG content requireVisible = true; requireFill = true; requireStroke = true; @@ -107,4 +108,3 @@ PointerEventsHitRules::PointerEventsHitRules(ESVGHitTesting hitTesting, EPointer } // vim:ts=4:noet -#endif // ENABLE(SVG) diff --git a/WebCore/rendering/PointerEventsHitRules.h b/WebCore/rendering/PointerEventsHitRules.h index 825cae8..e2dae3b 100644 --- a/WebCore/rendering/PointerEventsHitRules.h +++ b/WebCore/rendering/PointerEventsHitRules.h @@ -21,21 +21,20 @@ #ifndef PointerEventsHitRules_h #define PointerEventsHitRules_h -#if ENABLE(SVG) -#include "SVGRenderStyle.h" +#include "RenderStyle.h" namespace WebCore { class PointerEventsHitRules { public: - enum ESVGHitTesting { + enum EHitTesting { SVG_IMAGE_HITTESTING, SVG_PATH_HITTESTING, SVG_TEXT_HITTESTING }; - PointerEventsHitRules(ESVGHitTesting, EPointerEvents); + PointerEventsHitRules(EHitTesting, EPointerEvents); bool requireVisible; bool requireFill; @@ -46,7 +45,6 @@ public: } -#endif // ENABLE(SVG) #endif // vim:ts=4:noet diff --git a/WebCore/rendering/RenderApplet.cpp b/WebCore/rendering/RenderApplet.cpp index 7483943..8a5088a 100644 --- a/WebCore/rendering/RenderApplet.cpp +++ b/WebCore/rendering/RenderApplet.cpp @@ -66,10 +66,10 @@ void RenderApplet::createWidgetIfNecessary() // In order to work around this problem and have a correct size from the start, we will // use fixed widths/heights from the style system when we can, since the widget might // not have an accurate m_width/m_height. - int width = style()->width().isFixed() ? style()->width().value() : - m_width - borderLeft() - borderRight() - paddingLeft() - paddingRight(); - int height = style()->height().isFixed() ? style()->height().value() : - m_height - borderTop() - borderBottom() - paddingTop() - paddingBottom(); + int contentWidth = style()->width().isFixed() ? style()->width().value() : + width() - borderLeft() - borderRight() - paddingLeft() - paddingRight(); + int contentHeight = style()->height().isFixed() ? style()->height().value() : + height() - borderTop() - borderBottom() - paddingTop() - paddingBottom(); for (Node* child = element->firstChild(); child; child = child->nextSibling()) { if (child->hasTagName(paramTag)) { HTMLParamElement* p = static_cast<HTMLParamElement*>(child); @@ -80,7 +80,7 @@ void RenderApplet::createWidgetIfNecessary() Frame* frame = document()->frame(); ASSERT(frame); - setWidget(frame->loader()->createJavaAppletWidget(IntSize(width, height), element, m_args)); + setWidget(frame->loader()->createJavaAppletWidget(IntSize(contentWidth, contentHeight), element, m_args)); } void RenderApplet::layout() diff --git a/WebCore/rendering/RenderArena.cpp b/WebCore/rendering/RenderArena.cpp index 69d08a5..c490d2b 100644 --- a/WebCore/rendering/RenderArena.cpp +++ b/WebCore/rendering/RenderArena.cpp @@ -76,7 +76,7 @@ void* RenderArena::allocate(size_t size) // Use standard malloc so that memory debugging tools work. ASSERT(this); void* block = ::malloc(sizeof(RenderArenaDebugHeader) + size); - RenderArenaDebugHeader* header = (RenderArenaDebugHeader*)block; + RenderArenaDebugHeader* header = static_cast<RenderArenaDebugHeader*>(block); header->arena = this; header->size = size; header->signature = signature; @@ -112,7 +112,7 @@ void RenderArena::free(size_t size, void* ptr) { #ifndef NDEBUG // Use standard free so that memory debugging tools work. - RenderArenaDebugHeader* header = (RenderArenaDebugHeader*)ptr - 1; + RenderArenaDebugHeader* header = static_cast<RenderArenaDebugHeader*>(ptr) - 1; ASSERT(header->signature == signature); ASSERT(header->size == size); ASSERT(header->arena == this); @@ -132,4 +132,11 @@ void RenderArena::free(size_t size, void* ptr) #endif } +#ifdef ANDROID_INSTRUMENT +size_t RenderArena::reportPoolSize() const +{ + return ReportPoolSize(&m_pool); +} +#endif + } // namespace WebCore diff --git a/WebCore/rendering/RenderArena.h b/WebCore/rendering/RenderArena.h index 3c27d15..ca35361 100644 --- a/WebCore/rendering/RenderArena.h +++ b/WebCore/rendering/RenderArena.h @@ -50,6 +50,10 @@ public: void* allocate(size_t); void free(size_t, void*); +#ifdef ANDROID_INSTRUMENT + size_t reportPoolSize() const; +#endif + private: // Underlying arena pool ArenaPool m_pool; diff --git a/WebCore/rendering/RenderBR.cpp b/WebCore/rendering/RenderBR.cpp index 82b008a..2532c5b 100644 --- a/WebCore/rendering/RenderBR.cpp +++ b/WebCore/rendering/RenderBR.cpp @@ -56,7 +56,7 @@ int RenderBR::baselinePosition(bool firstLine, bool isRootLineBox) const return RenderText::baselinePosition(firstLine, isRootLineBox); } -int RenderBR::lineHeight(bool firstLine, bool isRootLineBox) const +int RenderBR::lineHeight(bool firstLine, bool /*isRootLineBox*/) const { if (firstTextBox() && !firstTextBox()->isText()) return 0; diff --git a/WebCore/rendering/RenderBlock.cpp b/WebCore/rendering/RenderBlock.cpp index 9dabacd..6d18ba1 100644 --- a/WebCore/rendering/RenderBlock.cpp +++ b/WebCore/rendering/RenderBlock.cpp @@ -32,6 +32,7 @@ #include "HitTestResult.h" #include "InlineTextBox.h" #include "RenderImage.h" +#include "RenderInline.h" #include "RenderMarquee.h" #include "RenderReplica.h" #include "RenderTableCell.h" @@ -39,6 +40,7 @@ #include "RenderTheme.h" #include "RenderView.h" #include "SelectionController.h" +#include <wtf/StdLibExtras.h> #ifdef ANDROID_LAYOUT #include "Settings.h" @@ -74,6 +76,8 @@ static PercentHeightDescendantsMap* gPercentHeightDescendantsMap = 0; typedef WTF::HashMap<const RenderBox*, HashSet<RenderBlock*>*> PercentHeightContainerMap; static PercentHeightContainerMap* gPercentHeightContainerMap = 0; + +typedef WTF::HashMap<RenderBlock*, ListHashSet<RenderFlow*>*> ContinuationOutlineTableMap; // Our MarginInfo state used when laying out block children. RenderBlock::MarginInfo::MarginInfo(RenderBlock* block, int top, int bottom) @@ -153,6 +157,29 @@ RenderBlock::~RenderBlock() void RenderBlock::styleWillChange(RenderStyle::Diff diff, const RenderStyle* newStyle) { setReplaced(newStyle->isDisplayReplacedType()); + + if (style() && parent() && diff == RenderStyle::Layout && style()->position() != newStyle->position()) { + if (newStyle->position() == StaticPosition) + // Clear our positioned objects list. Our absolutely positioned descendants will be + // inserted into our containing block's positioned objects list during layout. + removePositionedObjects(0); + else if (style()->position() == StaticPosition) { + // Remove our absolutely positioned descendants from their current containing block. + // They will be inserted into our positioned objects list during layout. + RenderObject* cb = parent(); + while (cb && (cb->style()->position() == StaticPosition || (cb->isInline() && !cb->isReplaced())) && !cb->isRenderView()) { + if (cb->style()->position() == RelativePosition && cb->isInline() && !cb->isReplaced()) { + cb = cb->containingBlock(); + break; + } + cb = cb->parent(); + } + + if (cb->isRenderBlock()) + static_cast<RenderBlock*>(cb)->removePositionedObjects(this); + } + } + RenderFlow::styleWillChange(diff, newStyle); } @@ -173,7 +200,7 @@ void RenderBlock::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldS m_lineHeight = -1; // Update pseudos for :before and :after now. - if (!isAnonymous() && canHaveChildren()) { + if (!isAnonymous() && document()->usesBeforeAfterRules() && canHaveChildren()) { updateBeforeAfterContent(RenderStyle::BEFORE); updateBeforeAfterContent(RenderStyle::AFTER); } @@ -373,7 +400,7 @@ void RenderBlock::removeChild(RenderObject *oldChild) RenderObject* prev = oldChild->previousSibling(); RenderObject* next = oldChild->nextSibling(); bool canDeleteAnonymousBlocks = !documentBeingDestroyed() && !isInline() && !oldChild->isInline() && - !oldChild->continuation() && + !oldChild->virtualContinuation() && (!prev || (prev->isAnonymousBlock() && prev->childrenInline())) && (!next || (next->isAnonymousBlock() && next->childrenInline())); if (canDeleteAnonymousBlocks && prev && next) { @@ -423,10 +450,10 @@ int RenderBlock::overflowHeight(bool includeInterior) const int shadowHeight = 0; for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next) shadowHeight = max(boxShadow->y + boxShadow->blur, shadowHeight); - int height = m_height + shadowHeight; + int inflatedHeight = height() + shadowHeight; if (hasReflection()) - height = max(height, reflectionBox().bottom()); - return height; + inflatedHeight = max(inflatedHeight, reflectionBox().bottom()); + return inflatedHeight; } return m_overflowHeight; } @@ -437,10 +464,10 @@ int RenderBlock::overflowWidth(bool includeInterior) const int shadowWidth = 0; for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next) shadowWidth = max(boxShadow->x + boxShadow->blur, shadowWidth); - int width = m_width + shadowWidth; + int inflatedWidth = width() + shadowWidth; if (hasReflection()) - width = max(width, reflectionBox().right()); - return width; + inflatedWidth = max(inflatedWidth, reflectionBox().right()); + return inflatedWidth; } return m_overflowWidth; } @@ -476,7 +503,7 @@ int RenderBlock::overflowTop(bool includeInterior) const IntRect RenderBlock::overflowRect(bool includeInterior) const { if (!includeInterior && hasOverflowClip()) { - IntRect box = borderBox(); + IntRect box = borderBoxRect(); int shadowLeft = 0; int shadowRight = 0; int shadowTop = 0; @@ -509,10 +536,10 @@ IntRect RenderBlock::overflowRect(bool includeInterior) const } if (!includeInterior && hasOverflowClip()) - return borderBox(); + return borderBoxRect(); int l = overflowLeft(includeInterior); - int t = min(overflowTop(includeInterior), -borderTopExtra()); - return IntRect(l, t, overflowWidth(includeInterior) - l, max(overflowHeight(includeInterior), height() + borderBottomExtra()) - t); + int t = overflowTop(includeInterior); + return IntRect(l, t, overflowWidth(includeInterior) - l, max(overflowHeight(includeInterior), height()) - t); } bool RenderBlock::isSelfCollapsingBlock() const @@ -523,7 +550,7 @@ bool RenderBlock::isSelfCollapsingBlock() const // (c) have border/padding, // (d) have a min-height // (e) have specified that one of our margins can't collapse using a CSS extension - if (m_height > 0 || + if (height() > 0 || isTable() || (borderBottom() + paddingBottom() + borderTop() + paddingTop()) != 0 || style()->minHeight().isPositive() || style()->marginTopCollapse() == MSEPARATE || style()->marginBottomCollapse() == MSEPARATE) @@ -548,7 +575,7 @@ bool RenderBlock::isSelfCollapsingBlock() const // Whether or not we collapse is dependent on whether all our normal flow children // are also self-collapsing. - for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { + for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { if (child->isFloatingOrPositioned()) continue; if (!child->isSelfCollapsingBlock()) @@ -571,8 +598,8 @@ void RenderBlock::layout() // It's safe to check for control clip here, since controls can never be table cells. if (hasControlClip()) { // Because of the lightweight clip, there can never be any overflow from children. - m_overflowWidth = m_width; - m_overflowHeight = m_height; + m_overflowWidth = width(); + m_overflowHeight = height(); m_overflowLeft = 0; m_overflowTop = 0; } @@ -593,16 +620,12 @@ void RenderBlock::layoutBlock(bool relayoutChildren) bool checkForRepaint = m_everHadLayout && checkForRepaintDuringLayout(); if (checkForRepaint) { oldBounds = absoluteClippedOverflowRect(); - oldOutlineBox = absoluteOutlineBox(); + oldOutlineBox = absoluteOutlineBounds(); } - bool hadColumns = m_hasColumns; - if (!hadColumns && !hasReflection()) - view()->pushLayoutState(this, IntSize(xPos(), yPos())); - else - view()->disableLayoutState(); + LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), m_hasColumns || hasTransform() || hasReflection()); - int oldWidth = m_width; + int oldWidth = width(); int oldColumnWidth = desiredColumnWidth(); #ifdef ANDROID_LAYOUT @@ -612,10 +635,10 @@ void RenderBlock::layoutBlock(bool relayoutChildren) calcWidth(); calcColumnWidth(); - m_overflowWidth = m_width; + m_overflowWidth = width(); m_overflowLeft = 0; - if (oldWidth != m_width || oldColumnWidth != desiredColumnWidth()) + if (oldWidth != width() || oldColumnWidth != desiredColumnWidth()) relayoutChildren = true; #ifdef ANDROID_LAYOUT @@ -628,8 +651,9 @@ void RenderBlock::layoutBlock(bool relayoutChildren) clearFloats(); - int previousHeight = m_height; - m_height = 0; + int previousHeight = height(); + setHeight(0); + m_overflowHeight = 0; // We use four values, maxTopPos, maxPosNeg, maxBottomPos, and maxBottomNeg, to track @@ -675,25 +699,24 @@ void RenderBlock::layoutBlock(bool relayoutChildren) // Expand our intrinsic height to encompass floats. int toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight(); - if (floatBottom() > (m_height - toAdd) && (isInlineBlockOrInlineTable() || isFloatingOrPositioned() || hasOverflowClip() || - (parent() && parent()->isFlexibleBox() || m_hasColumns))) - m_height = floatBottom() + toAdd; + if (floatBottom() > (height() - toAdd) && expandsToEncloseOverhangingFloats()) + setHeight(floatBottom() + toAdd); // Now lay out our columns within this intrinsic height, since they can slightly affect the intrinsic height as // we adjust for clean column breaks. int singleColumnBottom = layoutColumns(); // Calculate our new height. - int oldHeight = m_height; + int oldHeight = height(); calcHeight(); - if (oldHeight != m_height) { - if (oldHeight > m_height && maxFloatBottom > m_height && !childrenInline()) { + if (oldHeight != height()) { + if (oldHeight > height() && maxFloatBottom > height() && !childrenInline()) { // One of our children's floats may have become an overhanging float for us. We need to look for it. for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { if (child->isBlockFlow() && !child->isFloatingOrPositioned()) { RenderBlock* block = static_cast<RenderBlock*>(child); - if (block->floatBottom() + block->yPos() > m_height) - addOverhangingFloats(block, -block->xPos(), -block->yPos(), false); + if (block->floatBottom() + block->y() > height()) + addOverhangingFloats(block, -block->x(), -block->y(), false); } } } @@ -701,21 +724,14 @@ void RenderBlock::layoutBlock(bool relayoutChildren) layoutColumns(singleColumnBottom); // If the block got expanded in size, then increase our overflowheight to match. - if (m_overflowHeight > m_height) + if (m_overflowHeight > height()) m_overflowHeight -= toAdd; - if (m_overflowHeight < m_height) - m_overflowHeight = m_height; + if (m_overflowHeight < height()) + m_overflowHeight = height(); } - if (previousHeight != m_height) + if (previousHeight != height()) relayoutChildren = true; - // Some classes of objects (floats and fieldsets with no specified heights and table cells) expand to encompass - // overhanging floats. - if (hasOverhangingFloats() && expandsToEncloseOverhangingFloats()) { - m_height = floatBottom(); - m_height += borderBottom() + paddingBottom(); - } - if ((isCell || isInline() || isFloatingOrPositioned() || isRoot()) && !hasOverflowClip() && !hasControlClip()) addVisualOverflow(floatRect()); @@ -724,15 +740,15 @@ void RenderBlock::layoutBlock(bool relayoutChildren) positionListMarker(); // Always ensure our overflow width/height are at least as large as our width/height. - m_overflowWidth = max(m_overflowWidth, m_width); - m_overflowHeight = max(m_overflowHeight, m_height); + m_overflowWidth = max(m_overflowWidth, width()); + m_overflowHeight = max(m_overflowHeight, height()); if (!hasOverflowClip()) { for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next) { m_overflowLeft = min(m_overflowLeft, boxShadow->x - boxShadow->blur); - m_overflowWidth = max(m_overflowWidth, m_width + boxShadow->x + boxShadow->blur); + m_overflowWidth = max(m_overflowWidth, width() + boxShadow->x + boxShadow->blur); m_overflowTop = min(m_overflowTop, boxShadow->y - boxShadow->blur); - m_overflowHeight = max(m_overflowHeight, m_height + boxShadow->y + boxShadow->blur); + m_overflowHeight = max(m_overflowHeight, height() + boxShadow->y + boxShadow->blur); } if (hasReflection()) { @@ -741,10 +757,7 @@ void RenderBlock::layoutBlock(bool relayoutChildren) } } - if (!hadColumns && !hasReflection()) - view()->popLayoutState(); - else - view()->enableLayoutState(); + statePusher.pop(); // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if // we overflow or not. @@ -767,12 +780,12 @@ void RenderBlock::layoutBlock(bool relayoutChildren) // Adjust repaint rect for scroll offset int x = repaintRect.x(); int y = repaintRect.y(); - layer()->subtractScrollOffset(x, y); + layer()->subtractScrolledContentOffset(x, y); repaintRect.setX(x); repaintRect.setY(y); // Don't allow this rect to spill out of our overflow box. - repaintRect.intersect(IntRect(0, 0, m_width, m_height)); + repaintRect.intersect(IntRect(0, 0, width(), height())); } // Make sure the rect is still non-empty after intersecting for overflow above @@ -785,7 +798,12 @@ void RenderBlock::layoutBlock(bool relayoutChildren) setNeedsLayout(false); } -void RenderBlock::adjustPositionedBlock(RenderObject* child, const MarginInfo& marginInfo) +bool RenderBlock::expandsToEncloseOverhangingFloats() const +{ + return isInlineBlockOrInlineTable() || isFloatingOrPositioned() || hasOverflowClip() || (parent() && parent()->isFlexibleBox()) || m_hasColumns || isTableCell() || isFieldset(); +} + +void RenderBlock::adjustPositionedBlock(RenderBox* child, const MarginInfo& marginInfo) { if (child->hasStaticX()) { if (style()->direction() == LTR) @@ -795,7 +813,7 @@ void RenderBlock::adjustPositionedBlock(RenderObject* child, const MarginInfo& m } if (child->hasStaticY()) { - int y = m_height; + int y = height(); if (!marginInfo.canCollapseWithTop()) { child->calcVerticalMargins(); int marginTop = child->marginTop(); @@ -830,143 +848,99 @@ void RenderBlock::adjustFloatingBlock(const MarginInfo& marginInfo) // http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for // an example of this scenario. int marginOffset = marginInfo.canCollapseWithTop() ? 0 : marginInfo.margin(); - m_height += marginOffset; + setHeight(height() + marginOffset); positionNewFloats(); - m_height -= marginOffset; + setHeight(height() - marginOffset); } -RenderObject* RenderBlock::handleSpecialChild(RenderObject* child, const MarginInfo& marginInfo, CompactInfo& compactInfo, bool& handled) +RenderBox* RenderBlock::handleSpecialChild(RenderBox* child, const MarginInfo& marginInfo, bool& handled) { // Handle positioned children first. - RenderObject* next = handlePositionedChild(child, marginInfo, handled); + RenderBox* next = handlePositionedChild(child, marginInfo, handled); if (handled) return next; // Handle floating children next. next = handleFloatingChild(child, marginInfo, handled); if (handled) return next; - // See if we have a compact element. If we do, then try to tuck the compact element into the margin space of the next block. - next = handleCompactChild(child, compactInfo, handled); - if (handled) return next; - // Finally, see if we have a run-in element. return handleRunInChild(child, handled); } -RenderObject* RenderBlock::handlePositionedChild(RenderObject* child, const MarginInfo& marginInfo, bool& handled) +RenderBox* RenderBlock::handlePositionedChild(RenderBox* child, const MarginInfo& marginInfo, bool& handled) { if (child->isPositioned()) { handled = true; child->containingBlock()->insertPositionedObject(child); adjustPositionedBlock(child, marginInfo); - return child->nextSibling(); + return child->nextSiblingBox(); } return 0; } -RenderObject* RenderBlock::handleFloatingChild(RenderObject* child, const MarginInfo& marginInfo, bool& handled) +RenderBox* RenderBlock::handleFloatingChild(RenderBox* child, const MarginInfo& marginInfo, bool& handled) { if (child->isFloating()) { handled = true; insertFloatingObject(child); adjustFloatingBlock(marginInfo); - return child->nextSibling(); + return child->nextSiblingBox(); } return 0; } -RenderObject* RenderBlock::handleCompactChild(RenderObject* child, CompactInfo& compactInfo, bool& handled) -{ - // FIXME: We only deal with one compact at a time. It is unclear what should be - // done if multiple contiguous compacts are encountered. For now we assume that - // compact A followed by another compact B should simply be treated as block A. - if (child->isCompact() && !compactInfo.compact() && (child->childrenInline() || child->isReplaced())) { - // Get the next non-positioned/non-floating RenderBlock. - RenderObject* next = child->nextSibling(); - RenderObject* curr = next; - while (curr && curr->isFloatingOrPositioned()) - curr = curr->nextSibling(); - if (curr && curr->isRenderBlock() && !curr->isCompact() && !curr->isRunIn()) { - curr->calcWidth(); // So that horizontal margins are correct. - - child->setInline(true); // Need to compute the margins/width for the child as though it is an inline, so that it won't try to puff up the margins to - // fill the containing block width. - child->calcWidth(); - int childMargins = child->marginLeft() + child->marginRight(); - int margin = style()->direction() == LTR ? curr->marginLeft() : curr->marginRight(); - if (margin >= (childMargins + child->maxPrefWidth())) { - // The compact will fit in the margin. - handled = true; - compactInfo.set(child, curr); - child->setPos(0,0); // This position will be updated to reflect the compact's - // desired position and the line box for the compact will - // pick that position up. - - // Remove the child. - RenderObject* next = child->nextSibling(); - removeChildNode(child); - - // Now insert the child under |curr|. - curr->insertChildNode(child, curr->firstChild()); - return next; - } - else - child->setInline(false); // We didn't fit, so we remain a block-level element. - } - } - return 0; -} - -void RenderBlock::insertCompactIfNeeded(RenderObject* child, CompactInfo& compactInfo) -{ - if (compactInfo.matches(child)) { - // We have a compact child to squeeze in. - RenderObject* compactChild = compactInfo.compact(); - int compactXPos = borderLeft() + paddingLeft() + compactChild->marginLeft(); - if (style()->direction() == RTL) { - compactChild->calcWidth(); // have to do this because of the capped maxwidth - compactXPos = width() - borderRight() - paddingRight() - marginRight() - - compactChild->width() - compactChild->marginRight(); - } - compactXPos -= child->xPos(); // Put compactXPos into the child's coordinate space. - compactChild->setPos(compactXPos, compactChild->yPos()); // Set the x position. - compactInfo.clear(); - } -} - -RenderObject* RenderBlock::handleRunInChild(RenderObject* child, bool& handled) +RenderBox* RenderBlock::handleRunInChild(RenderBox* blockRunIn, bool& handled) { // See if we have a run-in element with inline children. If the // children aren't inline, then just treat the run-in as a normal // block. - if (child->isRunIn() && (child->childrenInline() || child->isReplaced())) { + if (blockRunIn->isRunIn() && (blockRunIn->childrenInline() || blockRunIn->isReplaced())) { // Get the next non-positioned/non-floating RenderBlock. - RenderObject* curr = child->nextSibling(); + RenderObject* curr = blockRunIn->nextSibling(); while (curr && curr->isFloatingOrPositioned()) curr = curr->nextSibling(); - if (curr && (curr->isRenderBlock() && curr->childrenInline() && !curr->isCompact() && !curr->isRunIn())) { + if (curr && (curr->isRenderBlock() && curr->childrenInline() && !curr->isRunIn())) { // The block acts like an inline, so just null out its // position. handled = true; - child->setInline(true); - child->setPos(0,0); - // Remove the child. - RenderObject* next = child->nextSibling(); - removeChildNode(child); + // Remove the old child. + RenderBox* next = blockRunIn->nextSiblingBox(); + removeChildNode(blockRunIn); + + // Create an inline. + RenderInline* inlineRunIn = new (renderArena()) RenderInline(blockRunIn->node()); + inlineRunIn->setStyle(blockRunIn->style()); + + // Move the nodes from the old child to the new child, but skip any :before/:after content. It has already + // been regenerated by the new inline. + for (RenderObject* runInChild = blockRunIn->firstChild(); runInChild; runInChild = runInChild->nextSibling()) { + if (runInChild->style()->styleType() != RenderStyle::BEFORE && runInChild->style()->styleType() != RenderStyle::AFTER) { + blockRunIn->removeChildNode(runInChild, false); + inlineRunIn->addChild(runInChild); // Use addChild instead of appendChildNode since it handles correct placement of the children relative to :after-generated content. + } + } + + // Now insert the new child under |curr|. + curr->insertChildNode(inlineRunIn, curr->firstChild()); + + // If the run-in had an element, we need to set the new renderer. + if (blockRunIn->element()) + blockRunIn->element()->setRenderer(inlineRunIn); - // Now insert the child under |curr|. - curr->insertChildNode(child, curr->firstChild()); + // Destroy the block run-in. + blockRunIn->destroy(); + return next; } } return 0; } -void RenderBlock::collapseMargins(RenderObject* child, MarginInfo& marginInfo, int yPosEstimate) +void RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo, int yPosEstimate) { // Get our max pos and neg top margins. int posTop = child->maxTopMargin(true); @@ -1011,7 +985,7 @@ void RenderBlock::collapseMargins(RenderObject* child, MarginInfo& marginInfo, i if (marginInfo.quirkContainer() && marginInfo.atTopOfBlock() && (posTop - negTop)) marginInfo.setTopQuirk(topQuirk); - int ypos = m_height; + int ypos = height(); if (child->isSelfCollapsingBlock()) { // This child has no height. We need to compute our // position before we collapse the child's margins together, @@ -1030,20 +1004,20 @@ void RenderBlock::collapseMargins(RenderObject* child, MarginInfo& marginInfo, i // is correct, since it could have overflowing content // that needs to be positioned correctly (e.g., a block that // had a specified height of 0 but that actually had subcontent). - ypos = m_height + collapsedTopPos - collapsedTopNeg; + ypos = height() + collapsedTopPos - collapsedTopNeg; } else { if (child->style()->marginTopCollapse() == MSEPARATE) { - m_height += marginInfo.margin() + child->marginTop(); - ypos = m_height; + setHeight(height() + marginInfo.margin() + child->marginTop()); + ypos = height(); } else if (!marginInfo.atTopOfBlock() || (!marginInfo.canCollapseTopWithChildren() && (!style()->htmlHacks() || !marginInfo.quirkContainer() || !marginInfo.topQuirk()))) { // We're collapsing with a previous sibling's margins and not // with the top of the block. - m_height += max(marginInfo.posMargin(), posTop) - max(marginInfo.negMargin(), negTop); - ypos = m_height; + setHeight(height() + max(marginInfo.posMargin(), posTop) - max(marginInfo.negMargin(), negTop)); + ypos = height(); } marginInfo.setPosMargin(child->maxBottomMargin(true)); @@ -1056,7 +1030,7 @@ void RenderBlock::collapseMargins(RenderObject* child, MarginInfo& marginInfo, i } view()->addLayoutDelta(IntSize(0, yPosEstimate - ypos)); - child->setPos(child->xPos(), ypos); + child->setLocation(child->x(), ypos); if (ypos != yPosEstimate) { if (child->shrinkToAvoidFloats()) // The child's width depends on the line width. @@ -1066,14 +1040,14 @@ void RenderBlock::collapseMargins(RenderObject* child, MarginInfo& marginInfo, i child->setChildNeedsLayout(true, false); if (!child->avoidsFloats() && child->containsFloats()) - child->markAllDescendantsWithFloatsForLayout(); + static_cast<RenderBlock*>(child)->markAllDescendantsWithFloatsForLayout(); // Our guess was wrong. Make the child lay itself out again. child->layoutIfNeeded(); } } -void RenderBlock::clearFloatsIfNeeded(RenderObject* child, MarginInfo& marginInfo, int oldTopPosMargin, int oldTopNegMargin) +void RenderBlock::clearFloatsIfNeeded(RenderBox* child, MarginInfo& marginInfo, int oldTopPosMargin, int oldTopNegMargin) { int heightIncrease = getClearDelta(child); if (!heightIncrease) @@ -1081,7 +1055,7 @@ void RenderBlock::clearFloatsIfNeeded(RenderObject* child, MarginInfo& marginInf // The child needs to be lowered. Move the child so that it just clears the float. view()->addLayoutDelta(IntSize(0, -heightIncrease)); - child->setPos(child->xPos(), child->yPos() + heightIncrease); + child->setLocation(child->x(), child->y() + heightIncrease); if (child->isSelfCollapsingBlock()) { // For self-collapsing blocks that clear, they can still collapse their @@ -1091,7 +1065,7 @@ void RenderBlock::clearFloatsIfNeeded(RenderObject* child, MarginInfo& marginInf marginInfo.setNegMargin(max(child->maxTopMargin(false), child->maxBottomMargin(false))); // Adjust our height such that we are ready to be collapsed with subsequent siblings. - m_height = child->yPos() - max(0, marginInfo.margin()); + setHeight(child->y() - max(0, marginInfo.margin())); // Set a flag that we cleared a float so that we know both to increase the height of the block // to compensate for the clear and to avoid collapsing our margins with the parent block's @@ -1099,7 +1073,7 @@ void RenderBlock::clearFloatsIfNeeded(RenderObject* child, MarginInfo& marginInf marginInfo.setSelfCollapsingBlockClearedFloat(true); } else // Increase our height by the amount we had to clear. - m_height += heightIncrease; + setHeight(height() + heightIncrease); if (marginInfo.canCollapseWithTop()) { // We can no longer collapse with the top of the block since a clear @@ -1121,15 +1095,15 @@ void RenderBlock::clearFloatsIfNeeded(RenderObject* child, MarginInfo& marginInf // So go ahead and mark the item as dirty. child->setChildNeedsLayout(true, false); if (!child->avoidsFloats() && child->containsFloats()) - child->markAllDescendantsWithFloatsForLayout(); + static_cast<RenderBlock*>(child)->markAllDescendantsWithFloatsForLayout(); child->layoutIfNeeded(); } -int RenderBlock::estimateVerticalPosition(RenderObject* child, const MarginInfo& marginInfo) +int RenderBlock::estimateVerticalPosition(RenderBox* child, const MarginInfo& marginInfo) { // FIXME: We need to eliminate the estimation of vertical position, because when it's wrong we sometimes trigger a pathological // relayout if there are intruding floats. - int yPosEstimate = m_height; + int yPosEstimate = height(); if (!marginInfo.canCollapseWithTop()) { int childMarginTop = child->selfNeedsLayout() ? child->marginTop() : child->collapsedMarginTop(); yPosEstimate += max(marginInfo.margin(), childMarginTop); @@ -1137,7 +1111,7 @@ int RenderBlock::estimateVerticalPosition(RenderObject* child, const MarginInfo& return yPosEstimate; } -void RenderBlock::determineHorizontalPosition(RenderObject* child) +void RenderBlock::determineHorizontalPosition(RenderBox* child) { if (style()->direction() == LTR) { int xPos = borderLeft() + paddingLeft(); @@ -1148,7 +1122,7 @@ void RenderBlock::determineHorizontalPosition(RenderObject* child) // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats. They need // to shift over as necessary to dodge any floats that might get in the way. if (child->avoidsFloats()) { - int leftOff = leftOffset(m_height); + int leftOff = leftOffset(height()); if (style()->textAlign() != WEBKIT_CENTER && child->style()->marginLeft().type() != Auto) { if (child->marginLeft() < 0) leftOff += child->marginLeft(); @@ -1160,17 +1134,17 @@ void RenderBlock::determineHorizontalPosition(RenderObject* child) // width computation will take into account the delta between |leftOff| and |xPos| // so that we can just pass the content width in directly to the |calcHorizontalMargins| // function. - static_cast<RenderBox*>(child)->calcHorizontalMargins(child->style()->marginLeft(), child->style()->marginRight(), lineWidth(child->yPos())); + child->calcHorizontalMargins(child->style()->marginLeft(), child->style()->marginRight(), lineWidth(child->y())); chPos = leftOff + child->marginLeft(); } } - view()->addLayoutDelta(IntSize(child->xPos() - chPos, 0)); - child->setPos(chPos, child->yPos()); + view()->addLayoutDelta(IntSize(child->x() - chPos, 0)); + child->setLocation(chPos, child->y()); } else { - int xPos = m_width - borderRight() - paddingRight() - verticalScrollbarWidth(); + int xPos = width() - borderRight() - paddingRight() - verticalScrollbarWidth(); int chPos = xPos - (child->width() + child->marginRight()); if (child->avoidsFloats()) { - int rightOff = rightOffset(m_height); + int rightOff = rightOffset(height()); if (style()->textAlign() != WEBKIT_CENTER && child->style()->marginRight().type() != Auto) { if (child->marginRight() < 0) rightOff -= child->marginRight(); @@ -1181,12 +1155,12 @@ void RenderBlock::determineHorizontalPosition(RenderObject* child) // width computation will take into account the delta between |rightOff| and |xPos| // so that we can just pass the content width in directly to the |calcHorizontalMargins| // function. - static_cast<RenderBox*>(child)->calcHorizontalMargins(child->style()->marginLeft(), child->style()->marginRight(), lineWidth(child->yPos())); + toRenderBox(child)->calcHorizontalMargins(child->style()->marginLeft(), child->style()->marginRight(), lineWidth(child->y())); chPos = rightOff - child->marginRight() - child->width(); } } - view()->addLayoutDelta(IntSize(child->xPos() - chPos, 0)); - child->setPos(chPos, child->yPos()); + view()->addLayoutDelta(IntSize(child->x() - chPos, 0)); + child->setLocation(chPos, child->y()); } } @@ -1225,17 +1199,17 @@ void RenderBlock::handleBottomOfBlock(int top, int bottom, MarginInfo& marginInf // If we can't collapse with children then go ahead and add in the bottom margin. if (!marginInfo.canCollapseWithBottom() && !marginInfo.canCollapseWithTop() && (!style()->htmlHacks() || !marginInfo.quirkContainer() || !marginInfo.bottomQuirk())) - m_height += marginInfo.margin(); + setHeight(height() + marginInfo.margin()); // Now add in our bottom border/padding. - m_height += bottom; + setHeight(height() + bottom); // Negative margins can cause our height to shrink below our minimal height (border/padding). // If this happens, ensure that the computed height is increased to the minimal height. - m_height = max(m_height, top + bottom); + setHeight(max(height(), top + bottom)); // Always make sure our overflow height is at least our height. - m_overflowHeight = max(m_height, m_overflowHeight); + m_overflowHeight = max(height(), m_overflowHeight); // Update our bottom collapsed margin info. setCollapsedBottomMargin(marginInfo); @@ -1264,11 +1238,11 @@ void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom int top = borderTop() + paddingTop(); int bottom = borderBottom() + paddingBottom() + horizontalScrollbarHeight(); - m_height = m_overflowHeight = top; + m_overflowHeight = top; + setHeight(m_overflowHeight); // The margin struct caches all our current margin collapsing state. The compact struct caches state when we encounter compacts, MarginInfo marginInfo(this, top, bottom); - CompactInfo compactInfo; // Fieldsets need to find their legend and position it inside the border of the object. // The legend then gets skipped during normal layout. @@ -1277,10 +1251,10 @@ void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom int previousFloatBottom = 0; maxFloatBottom = 0; - RenderObject* child = firstChild(); + RenderBox* child = firstChildBox(); while (child) { if (legend == child) { - child = child->nextSibling(); + child = child->nextSiblingBox(); continue; // Skip the legend, since it has already been positioned up in the fieldset's border. } @@ -1300,7 +1274,7 @@ void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom // Handle the four types of special elements first. These include positioned content, floating content, compacts and // run-ins. When we encounter these four types of objects, we don't actually lay them out as normal flow blocks. bool handled = false; - RenderObject* next = handleSpecialChild(child, marginInfo, compactInfo, handled); + RenderBox* next = handleSpecialChild(child, marginInfo, handled); if (handled) { child = next; continue; @@ -1321,11 +1295,13 @@ void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom int yPosEstimate = estimateVerticalPosition(child, marginInfo); // Cache our old rect so that we can dirty the proper repaint rects if the child moves. - IntRect oldRect(child->xPos(), child->yPos() , child->width(), child->height()); - + IntRect oldRect(child->x(), child->y() , child->width(), child->height()); +#ifndef NDEBUG + IntSize oldLayoutDelta = view()->layoutDelta(); +#endif // Go ahead and position the child as though it didn't collapse with the top. - view()->addLayoutDelta(IntSize(0, child->yPos() - yPosEstimate)); - child->setPos(child->xPos(), yPosEstimate); + view()->addLayoutDelta(IntSize(0, child->y() - yPosEstimate)); + child->setLocation(child->x(), yPosEstimate); bool markDescendantsWithFloats = false; if (yPosEstimate != oldRect.y() && !child->avoidsFloats() && child->containsFloats()) @@ -1334,12 +1310,12 @@ void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom // If an element might be affected by the presence of floats, then always mark it for // layout. int fb = max(previousFloatBottom, floatBottom()); - if (fb > m_height || fb > yPosEstimate) + if (fb > height() || fb > yPosEstimate) markDescendantsWithFloats = true; } if (markDescendantsWithFloats) - child->markAllDescendantsWithFloatsForLayout(); + static_cast<RenderBlock*>(child)->markAllDescendantsWithFloatsForLayout(); if (child->isRenderBlock()) previousFloatBottom = max(previousFloatBottom, oldRect.y() + static_cast<RenderBlock*>(child)->floatBottom()); @@ -1365,25 +1341,22 @@ void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom determineHorizontalPosition(child); // Update our height now that the child has been placed in the correct position. - m_height += child->height(); + setHeight(height() + child->height()); if (child->style()->marginBottomCollapse() == MSEPARATE) { - m_height += child->marginBottom(); + setHeight(height() + child->marginBottom()); marginInfo.clearMargin(); } // If the child has overhanging floats that intrude into following siblings (or possibly out // of this block), then the parent gets notified of the floats now. - maxFloatBottom = max(maxFloatBottom, addOverhangingFloats(static_cast<RenderBlock *>(child), -child->xPos(), -child->yPos(), !childNeededLayout)); + maxFloatBottom = max(maxFloatBottom, addOverhangingFloats(static_cast<RenderBlock*>(child), -child->x(), -child->y(), !childNeededLayout)); // Update our overflow in case the child spills out the block. - m_overflowTop = min(m_overflowTop, child->yPos() + child->overflowTop(false)); - m_overflowHeight = max(m_overflowHeight, m_height + child->overflowHeight(false) - child->height()); - m_overflowWidth = max(child->xPos() + child->overflowWidth(false), m_overflowWidth); - m_overflowLeft = min(child->xPos() + child->overflowLeft(false), m_overflowLeft); - - // Insert our compact into the block margin if we have one. - insertCompactIfNeeded(child, compactInfo); + m_overflowTop = min(m_overflowTop, child->y() + child->overflowTop(false)); + m_overflowHeight = max(m_overflowHeight, height() + child->overflowHeight(false) - child->height()); + m_overflowWidth = max(child->x() + child->overflowWidth(false), m_overflowWidth); + m_overflowLeft = min(child->x() + child->overflowLeft(false), m_overflowLeft); - IntSize childOffset(child->xPos() - oldRect.x(), child->yPos() - oldRect.y()); + IntSize childOffset(child->x() - oldRect.x(), child->y() - oldRect.y()); if (childOffset.width() || childOffset.height()) { view()->addLayoutDelta(childOffset); @@ -1397,7 +1370,8 @@ void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom if (!childHadLayout && child->checkForRepaintDuringLayout()) child->repaint(); - child = child->nextSibling(); + ASSERT(oldLayoutDelta == view()->layoutDelta()); + child = child->nextSiblingBox(); } // Now do the handling of the bottom of the block, adding in our bottom border/padding and @@ -1410,10 +1384,7 @@ bool RenderBlock::layoutOnlyPositionedObjects() if (!posChildNeedsLayout() || normalChildNeedsLayout() || selfNeedsLayout()) return false; - if (!m_hasColumns) - view()->pushLayoutState(this, IntSize(xPos(), yPos())); - else - view()->disableLayoutState(); + LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), m_hasColumns || hasTransform() || hasReflection()); if (needsPositionedMovementLayout()) { tryLayoutDoingPositionedMovementOnly(); @@ -1424,10 +1395,7 @@ bool RenderBlock::layoutOnlyPositionedObjects() // All we have to is lay out our positioned objects. layoutPositionedObjects(false); - if (!m_hasColumns) - view()->popLayoutState(); - else - view()->enableLayoutState(); + statePusher.pop(); if (hasOverflowClip()) m_layer->updateScrollInfoAfterLayout(); @@ -1439,7 +1407,7 @@ bool RenderBlock::layoutOnlyPositionedObjects() void RenderBlock::layoutPositionedObjects(bool relayoutChildren) { if (m_positionedObjects) { - RenderObject* r; + RenderBox* r; Iterator end = m_positionedObjects->end(); for (Iterator it = m_positionedObjects->begin(); it != end; ++it) { r = *it; @@ -1466,7 +1434,7 @@ void RenderBlock::layoutPositionedObjects(bool relayoutChildren) void RenderBlock::markPositionedObjectsForLayout() { if (m_positionedObjects) { - RenderObject* r; + RenderBox* r; Iterator end = m_positionedObjects->end(); for (Iterator it = m_positionedObjects->begin(); it != end; ++it) { r = *it; @@ -1495,7 +1463,7 @@ void RenderBlock::repaintOverhangingFloats(bool paintAllDescendants) // Only repaint the object if it is overhanging, is not in its own layer, and // is our responsibility to paint (m_shouldPaint is set). When paintAllDescendants is true, the latter // condition is replaced with being a descendant of us. - if (r->m_bottom > m_height && (paintAllDescendants && r->m_renderer->isDescendantOf(this) || r->m_shouldPaint) && !r->m_renderer->hasLayer()) { + if (r->m_bottom > height() && (paintAllDescendants && r->m_renderer->isDescendantOf(this) || r->m_shouldPaint) && !r->m_renderer->hasLayer()) { r->m_renderer->repaint(); r->m_renderer->repaintOverhangingFloats(); } @@ -1506,15 +1474,15 @@ void RenderBlock::repaintOverhangingFloats(bool paintAllDescendants) void RenderBlock::paint(PaintInfo& paintInfo, int tx, int ty) { - tx += m_x; - ty += m_y; + tx += x(); + ty += y(); PaintPhase phase = paintInfo.phase; // Check if we need to do anything at all. // FIXME: Could eliminate the isRoot() check if we fix background painting so that the RenderView // paints the root's background. - if (!isInlineFlow() && !isRoot()) { + if (!isRoot()) { IntRect overflowBox = overflowRect(false); overflowBox.inflate(maximalOutlineSize(paintInfo.phase)); overflowBox.move(tx, ty); @@ -1642,12 +1610,12 @@ void RenderBlock::paintChildren(PaintInfo& paintInfo, int tx, int ty) info.paintingRoot = paintingRootForChildren(paintInfo); bool isPrinting = document()->printing(); - for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { + for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { // Check for page-break-before: always, and if it's set, break and bail. if (isPrinting && !childrenInline() && child->style()->pageBreakBefore() == PBALWAYS && - inRootBlockContext() && (ty + child->yPos()) > paintInfo.rect.y() && - (ty + child->yPos()) < paintInfo.rect.bottom()) { - view()->setBestTruncatedAt(ty + child->yPos(), this, true); + inRootBlockContext() && (ty + child->y()) > paintInfo.rect.y() && + (ty + child->y()) < paintInfo.rect.bottom()) { + view()->setBestTruncatedAt(ty + child->y(), this, true); return; } @@ -1656,28 +1624,29 @@ void RenderBlock::paintChildren(PaintInfo& paintInfo, int tx, int ty) // Check for page-break-after: always, and if it's set, break and bail. if (isPrinting && !childrenInline() && child->style()->pageBreakAfter() == PBALWAYS && - inRootBlockContext() && (ty + child->yPos() + child->height()) > paintInfo.rect.y() && - (ty + child->yPos() + child->height()) < paintInfo.rect.bottom()) { - view()->setBestTruncatedAt(ty + child->yPos() + child->height() + max(0, child->collapsedMarginBottom()), this, true); + inRootBlockContext() && (ty + child->y() + child->height()) > paintInfo.rect.y() && + (ty + child->y() + child->height()) < paintInfo.rect.bottom()) { + view()->setBestTruncatedAt(ty + child->y() + child->height() + max(0, child->collapsedMarginBottom()), this, true); return; } } } -void RenderBlock::paintCaret(PaintInfo& paintInfo, CaretType type) +void RenderBlock::paintCaret(PaintInfo& paintInfo, int tx, int ty, CaretType type) { SelectionController* selection = type == CursorCaret ? document()->frame()->selection() : document()->frame()->dragCaretController(); - Node* caretNode = selection->start().node(); - RenderObject* renderer = caretNode ? caretNode->renderer() : 0; - if (!renderer) - return; - // if caretNode is a block and caret is inside it then caret should be painted by that block - bool cursorInsideBlockCaretNode = renderer->isBlockFlow() && selection->isInsideNode(); - if ((cursorInsideBlockCaretNode ? renderer : renderer->containingBlock()) == this && selection->isContentEditable()) { + + // Ask the SelectionController if the caret should be painted by this block + RenderObject* caretPainter = selection->caretRenderer(); + if (caretPainter == this && selection->isContentEditable()) { + // Convert the painting offset into the local coordinate system of this renderer, + // to match the localCaretRect computed by the SelectionController + offsetForContents(tx, ty); + if (type == CursorCaret) - document()->frame()->paintCaret(paintInfo.context, paintInfo.rect); + document()->frame()->paintCaret(paintInfo.context, tx, ty, paintInfo.rect); else - document()->frame()->paintDragCaret(paintInfo.context, paintInfo.rect); + document()->frame()->paintDragCaret(paintInfo.context, tx, ty, paintInfo.rect); } } @@ -1685,12 +1654,8 @@ void RenderBlock::paintObject(PaintInfo& paintInfo, int tx, int ty) { PaintPhase paintPhase = paintInfo.phase; - // If we're a repositioned run-in or a compact, don't paint background/borders. - bool inlineFlow = isInlineFlow(); - // 1. paint background, borders etc - if (!inlineFlow && - (paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && + if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && hasBoxDecorations() && style()->visibility() == VISIBLE) { paintBoxDecorations(paintInfo, tx, ty); } @@ -1708,7 +1673,7 @@ void RenderBlock::paintObject(PaintInfo& paintInfo, int tx, int ty) int scrolledX = tx; int scrolledY = ty; if (hasOverflowClip()) - m_layer->subtractScrollOffset(scrolledX, scrolledY); + m_layer->subtractScrolledContentOffset(scrolledX, scrolledY); // 2. paint contents if (paintPhase != PaintPhaseSelfOutline) { @@ -1721,11 +1686,11 @@ void RenderBlock::paintObject(PaintInfo& paintInfo, int tx, int ty) // 3. paint selection // FIXME: Make this work with multi column layouts. For now don't fill gaps. bool isPrinting = document()->printing(); - if (!inlineFlow && !isPrinting && !m_hasColumns) + if (!isPrinting && !m_hasColumns) paintSelection(paintInfo, scrolledX, scrolledY); // Fill in gaps in selection on lines and between blocks. // 4. paint floats. - if (!inlineFlow && (paintPhase == PaintPhaseFloat || paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip)) { + if (paintPhase == PaintPhaseFloat || paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip) { if (m_hasColumns) paintColumns(paintInfo, scrolledX, scrolledY, true); else @@ -1733,18 +1698,18 @@ void RenderBlock::paintObject(PaintInfo& paintInfo, int tx, int ty) } // 5. paint outline. - if (!inlineFlow && (paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && hasOutline() && style()->visibility() == VISIBLE) - RenderObject::paintOutline(paintInfo.context, tx, ty, width(), height(), style()); + if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && hasOutline() && style()->visibility() == VISIBLE) + RenderBox::paintOutline(paintInfo.context, tx, ty, width(), height(), style()); // 6. paint continuation outlines. - if (!inlineFlow && (paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseChildOutlines)) { + if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseChildOutlines)) { if (continuation() && continuation()->hasOutline() && continuation()->style()->visibility() == VISIBLE) { RenderFlow* inlineFlow = static_cast<RenderFlow*>(continuation()->element()->renderer()); if (!inlineFlow->hasLayer()) containingBlock()->addContinuationWithOutline(inlineFlow); else if (!inlineFlow->firstLineBox()) - inlineFlow->paintOutline(paintInfo.context, tx - xPos() + inlineFlow->containingBlock()->xPos(), - ty - yPos() + inlineFlow->containingBlock()->yPos()); + inlineFlow->paintOutline(paintInfo.context, tx - x() + inlineFlow->containingBlock()->x(), + ty - y() + inlineFlow->containingBlock()->y()); } paintContinuationOutlines(paintInfo, tx, ty); } @@ -1752,9 +1717,9 @@ void RenderBlock::paintObject(PaintInfo& paintInfo, int tx, int ty) // 7. paint caret. // If the caret's node's render object's containing block is this block, and the paint action is PaintPhaseForeground, // then paint the caret. - if (!inlineFlow && paintPhase == PaintPhaseForeground) { - paintCaret(paintInfo, CursorCaret); - paintCaret(paintInfo, DragCaret); + if (paintPhase == PaintPhaseForeground) { + paintCaret(paintInfo, scrolledX, scrolledY, CursorCaret); + paintCaret(paintInfo, scrolledX, scrolledY, DragCaret); } } @@ -1770,8 +1735,8 @@ void RenderBlock::paintFloats(PaintInfo& paintInfo, int tx, int ty, bool preserv if (r->m_shouldPaint && !r->m_renderer->hasLayer()) { PaintInfo currentPaintInfo(paintInfo); currentPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground; - int currentTX = tx + r->m_left - r->m_renderer->xPos() + r->m_renderer->marginLeft(); - int currentTY = ty + r->m_top - r->m_renderer->yPos() + r->m_renderer->marginTop(); + int currentTX = tx + r->m_left - r->m_renderer->x() + r->m_renderer->marginLeft(); + int currentTY = ty + r->m_top - r->m_renderer->y() + r->m_renderer->marginTop(); r->m_renderer->paint(currentPaintInfo, currentTX, currentTY); if (!preservePhase) { currentPaintInfo.phase = PaintPhaseChildBlockBackgrounds; @@ -1812,9 +1777,9 @@ void RenderBlock::paintEllipsisBoxes(PaintInfo& paintInfo, int tx, int ty) } } -HashMap<RenderBlock*, RenderFlowSequencedSet*>* continuationOutlineTable() +static ContinuationOutlineTableMap* continuationOutlineTable() { - static HashMap<RenderBlock*, RenderFlowSequencedSet*> table; + DEFINE_STATIC_LOCAL(ContinuationOutlineTableMap, table, ()); return &table; } @@ -1824,10 +1789,10 @@ void RenderBlock::addContinuationWithOutline(RenderFlow* flow) // way of painting. ASSERT(!flow->layer()); - HashMap<RenderBlock*, RenderFlowSequencedSet*>* table = continuationOutlineTable(); - RenderFlowSequencedSet* continuations = table->get(this); + ContinuationOutlineTableMap* table = continuationOutlineTable(); + ListHashSet<RenderFlow*>* continuations = table->get(this); if (!continuations) { - continuations = new RenderFlowSequencedSet; + continuations = new ListHashSet<RenderFlow*>; table->set(this, continuations); } @@ -1836,23 +1801,23 @@ void RenderBlock::addContinuationWithOutline(RenderFlow* flow) void RenderBlock::paintContinuationOutlines(PaintInfo& info, int tx, int ty) { - HashMap<RenderBlock*, RenderFlowSequencedSet*>* table = continuationOutlineTable(); + ContinuationOutlineTableMap* table = continuationOutlineTable(); if (table->isEmpty()) return; - RenderFlowSequencedSet* continuations = table->get(this); + ListHashSet<RenderFlow*>* continuations = table->get(this); if (!continuations) return; // Paint each continuation outline. - RenderFlowSequencedSet::iterator end = continuations->end(); - for (RenderFlowSequencedSet::iterator it = continuations->begin(); it != end; ++it) { + ListHashSet<RenderFlow*>::iterator end = continuations->end(); + for (ListHashSet<RenderFlow*>::iterator it = continuations->begin(); it != end; ++it) { // Need to add in the coordinates of the intervening blocks. RenderFlow* flow = *it; RenderBlock* block = flow->containingBlock(); for ( ; block && block != this; block = block->containingBlock()) { - tx += block->xPos(); - ty += block->yPos(); + tx += block->x(); + ty += block->y(); } ASSERT(block); flow->paintOutline(info.context, tx, ty); @@ -1917,22 +1882,22 @@ GapRects RenderBlock::selectionGapRects() if (!shouldPaintSelectionGaps()) return GapRects(); - int tx, ty; - absolutePositionForContent(tx, ty); + // FIXME: this is broken with transforms + FloatPoint absContentPoint = localToAbsolute(FloatPoint()); if (hasOverflowClip()) - layer()->subtractScrollOffset(tx, ty); + absContentPoint -= layer()->scrolledContentOffset(); - int lastTop = -borderTopExtra(); + int lastTop = 0; int lastLeft = leftSelectionOffset(this, lastTop); int lastRight = rightSelectionOffset(this, lastTop); - return fillSelectionGaps(this, tx, ty, tx, ty, lastTop, lastLeft, lastRight); + return fillSelectionGaps(this, absContentPoint.x(), absContentPoint.y(), absContentPoint.x(), absContentPoint.y(), lastTop, lastLeft, lastRight); } void RenderBlock::paintSelection(PaintInfo& paintInfo, int tx, int ty) { if (shouldPaintSelectionGaps() && paintInfo.phase == PaintPhaseForeground) { - int lastTop = -borderTopExtra(); + int lastTop = 0; int lastLeft = leftSelectionOffset(this, lastTop); int lastRight = rightSelectionOffset(this, lastTop); paintInfo.context->save(); @@ -1941,15 +1906,15 @@ void RenderBlock::paintSelection(PaintInfo& paintInfo, int tx, int ty) } } -static void clipOutPositionedObjects(const RenderObject::PaintInfo* paintInfo, int tx, int ty, ListHashSet<RenderObject*>* positionedObjects) +static void clipOutPositionedObjects(const RenderObject::PaintInfo* paintInfo, int tx, int ty, ListHashSet<RenderBox*>* positionedObjects) { if (!positionedObjects) return; - ListHashSet<RenderObject*>::const_iterator end = positionedObjects->end(); - for (ListHashSet<RenderObject*>::const_iterator it = positionedObjects->begin(); it != end; ++it) { - RenderObject* r = *it; - paintInfo->context->clipOut(IntRect(tx + r->xPos(), ty + r->yPos(), r->width(), r->height())); + ListHashSet<RenderBox*>::const_iterator end = positionedObjects->end(); + for (ListHashSet<RenderBox*>::const_iterator it = positionedObjects->begin(); it != end; ++it) { + RenderBox* r = *it; + paintInfo->context->clipOut(IntRect(tx + r->x(), ty + r->y(), r->width(), r->height())); } } @@ -1963,7 +1928,7 @@ GapRects RenderBlock::fillSelectionGaps(RenderBlock* rootBlock, int blockX, int clipOutPositionedObjects(paintInfo, tx, ty, m_positionedObjects); if (isBody() || isRoot()) // The <body> must make sure to examine its containingBlock's positioned objects. for (RenderBlock* cb = containingBlock(); cb && !cb->isRenderView(); cb = cb->containingBlock()) - clipOutPositionedObjects(paintInfo, cb->xPos(), cb->yPos(), cb->m_positionedObjects); + clipOutPositionedObjects(paintInfo, cb->x(), cb->y(), cb->m_positionedObjects); if (m_floatingObjects) { for (DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); it.current(); ++it) { FloatingObject* r = it.current(); @@ -2006,7 +1971,7 @@ GapRects RenderBlock::fillSelectionGaps(RenderBlock* rootBlock, int blockX, int // Go ahead and fill the vertical gap all the way to the bottom of our block if the selection extends past our block. if (rootBlock == this && (m_selectionState != SelectionBoth && m_selectionState != SelectionEnd)) - result.uniteCenter(fillVerticalSelectionGap(lastTop, lastLeft, lastRight, ty + height() + borderBottomExtra(), + result.uniteCenter(fillVerticalSelectionGap(lastTop, lastLeft, lastRight, ty + height(), rootBlock, blockX, blockY, paintInfo)); return result; } @@ -2068,10 +2033,10 @@ GapRects RenderBlock::fillBlockSelectionGaps(RenderBlock* rootBlock, int blockX, GapRects result; // Go ahead and jump right to the first block child that contains some selected objects. - RenderObject* curr; - for (curr = firstChild(); curr && curr->selectionState() == SelectionNone; curr = curr->nextSibling()) { } + RenderBox* curr; + for (curr = firstChildBox(); curr && curr->selectionState() == SelectionNone; curr = curr->nextSiblingBox()) { } - for (bool sawSelectionEnd = false; curr && !sawSelectionEnd; curr = curr->nextSibling()) { + for (bool sawSelectionEnd = false; curr && !sawSelectionEnd; curr = curr->nextSiblingBox()) { SelectionState childState = curr->selectionState(); if (childState == SelectionBoth || childState == SelectionEnd) sawSelectionEnd = true; @@ -2082,10 +2047,8 @@ GapRects RenderBlock::fillBlockSelectionGaps(RenderBlock* rootBlock, int blockX, if (curr->isRelPositioned() && curr->hasLayer()) { // If the relposition offset is anything other than 0, then treat this just like an absolute positioned element. // Just disregard it completely. - int x = 0; - int y = 0; - curr->layer()->relativePositionOffset(x, y); - if (x || y) + IntSize relOffset = curr->layer()->relativePositionOffset(); + if (relOffset.width() || relOffset.height()) continue; } @@ -2096,7 +2059,7 @@ GapRects RenderBlock::fillBlockSelectionGaps(RenderBlock* rootBlock, int blockX, if (childState == SelectionEnd || childState == SelectionInside) // Fill the gap above the object. result.uniteCenter(fillVerticalSelectionGap(lastTop, lastLeft, lastRight, - ty + curr->yPos(), rootBlock, blockX, blockY, paintInfo)); + ty + curr->y(), rootBlock, blockX, blockY, paintInfo)); // Only fill side gaps for objects that paint their own selection if we know for sure the selection is going to extend all the way *past* // our object. We know this if the selection did not end inside our object. @@ -2108,19 +2071,19 @@ GapRects RenderBlock::fillBlockSelectionGaps(RenderBlock* rootBlock, int blockX, getHorizontalSelectionGapInfo(childState, leftGap, rightGap); if (leftGap) - result.uniteLeft(fillLeftSelectionGap(this, curr->xPos(), curr->yPos(), curr->height(), rootBlock, blockX, blockY, tx, ty, paintInfo)); + result.uniteLeft(fillLeftSelectionGap(this, curr->x(), curr->y(), curr->height(), rootBlock, blockX, blockY, tx, ty, paintInfo)); if (rightGap) - result.uniteRight(fillRightSelectionGap(this, curr->xPos() + curr->width(), curr->yPos(), curr->height(), rootBlock, blockX, blockY, tx, ty, paintInfo)); + result.uniteRight(fillRightSelectionGap(this, curr->x() + curr->width(), curr->y(), curr->height(), rootBlock, blockX, blockY, tx, ty, paintInfo)); // Update lastTop to be just underneath the object. lastLeft and lastRight extend as far as // they can without bumping into floating or positioned objects. Ideally they will go right up // to the border of the root selection block. - lastTop = (ty - blockY) + (curr->yPos() + curr->height()); - lastLeft = leftSelectionOffset(rootBlock, curr->yPos() + curr->height()); - lastRight = rightSelectionOffset(rootBlock, curr->yPos() + curr->height()); + lastTop = (ty - blockY) + (curr->y() + curr->height()); + lastLeft = leftSelectionOffset(rootBlock, curr->y() + curr->height()); + lastRight = rightSelectionOffset(rootBlock, curr->y() + curr->height()); } else if (childState != SelectionNone) // We must be a block that has some selected object inside it. Go ahead and recur. - result.unite(static_cast<RenderBlock*>(curr)->fillSelectionGaps(rootBlock, blockX, blockY, tx + curr->xPos(), ty + curr->yPos(), + result.unite(static_cast<RenderBlock*>(curr)->fillSelectionGaps(rootBlock, blockX, blockY, tx + curr->x(), ty + curr->y(), lastTop, lastLeft, lastRight, paintInfo)); } return result; @@ -2158,7 +2121,7 @@ IntRect RenderBlock::fillVerticalSelectionGap(int lastTop, int lastLeft, int las } IntRect RenderBlock::fillLeftSelectionGap(RenderObject* selObj, int xPos, int yPos, int height, RenderBlock* rootBlock, - int blockX, int blockY, int tx, int ty, const PaintInfo* paintInfo) + int blockX, int /*blockY*/, int tx, int ty, const PaintInfo* paintInfo) { int top = yPos + ty; int left = blockX + max(leftSelectionOffset(rootBlock, yPos), leftSelectionOffset(rootBlock, yPos + height)); @@ -2174,7 +2137,7 @@ IntRect RenderBlock::fillLeftSelectionGap(RenderObject* selObj, int xPos, int yP } IntRect RenderBlock::fillRightSelectionGap(RenderObject* selObj, int xPos, int yPos, int height, RenderBlock* rootBlock, - int blockX, int blockY, int tx, int ty, const PaintInfo* paintInfo) + int blockX, int /*blockY*/, int tx, int ty, const PaintInfo* paintInfo) { int left = max(xPos + tx, blockX + max(leftSelectionOffset(rootBlock, yPos), leftSelectionOffset(rootBlock, yPos + height))); int top = yPos + ty; @@ -2200,19 +2163,19 @@ void RenderBlock::getHorizontalSelectionGapInfo(SelectionState state, bool& left (state == RenderObject::SelectionEnd && !ltr); } -int RenderBlock::leftSelectionOffset(RenderBlock* rootBlock, int y) +int RenderBlock::leftSelectionOffset(RenderBlock* rootBlock, int yPos) { - int left = leftOffset(y); + int left = leftOffset(yPos); if (left == borderLeft() + paddingLeft()) { if (rootBlock != this) // The border can potentially be further extended by our containingBlock(). - return containingBlock()->leftSelectionOffset(rootBlock, y + yPos()); + return containingBlock()->leftSelectionOffset(rootBlock, yPos + y()); return left; } else { RenderBlock* cb = this; while (cb != rootBlock) { - left += cb->xPos(); + left += cb->x(); cb = cb->containingBlock(); } } @@ -2220,35 +2183,35 @@ int RenderBlock::leftSelectionOffset(RenderBlock* rootBlock, int y) return left; } -int RenderBlock::rightSelectionOffset(RenderBlock* rootBlock, int y) +int RenderBlock::rightSelectionOffset(RenderBlock* rootBlock, int yPos) { - int right = rightOffset(y); + int right = rightOffset(yPos); if (right == (contentWidth() + (borderLeft() + paddingLeft()))) { if (rootBlock != this) // The border can potentially be further extended by our containingBlock(). - return containingBlock()->rightSelectionOffset(rootBlock, y + yPos()); + return containingBlock()->rightSelectionOffset(rootBlock, yPos + y()); return right; } else { RenderBlock* cb = this; while (cb != rootBlock) { - right += cb->xPos(); + right += cb->x(); cb = cb->containingBlock(); } } return right; } -void RenderBlock::insertPositionedObject(RenderObject *o) +void RenderBlock::insertPositionedObject(RenderBox* o) { // Create the list of special objects if we don't aleady have one if (!m_positionedObjects) - m_positionedObjects = new ListHashSet<RenderObject*>; + m_positionedObjects = new ListHashSet<RenderBox*>; m_positionedObjects->add(o); } -void RenderBlock::removePositionedObject(RenderObject *o) +void RenderBlock::removePositionedObject(RenderBox* o) { if (m_positionedObjects) m_positionedObjects->remove(o); @@ -2259,11 +2222,11 @@ void RenderBlock::removePositionedObjects(RenderBlock* o) if (!m_positionedObjects) return; - RenderObject* r; + RenderBox* r; Iterator end = m_positionedObjects->end(); - Vector<RenderObject*, 16> deadObjects; + Vector<RenderBox*, 16> deadObjects; for (Iterator it = m_positionedObjects->begin(); it != end; ++it) { r = *it; @@ -2287,7 +2250,7 @@ void RenderBlock::removePositionedObjects(RenderBlock* o) m_positionedObjects->remove(deadObjects.at(i)); } -void RenderBlock::insertFloatingObject(RenderObject *o) +void RenderBlock::insertFloatingObject(RenderBox* o) { ASSERT(o->isFloating()); @@ -2321,7 +2284,7 @@ void RenderBlock::insertFloatingObject(RenderObject *o) m_floatingObjects->append(newObj); } -void RenderBlock::removeFloatingObject(RenderObject *o) +void RenderBlock::removeFloatingObject(RenderBox* o) { if (m_floatingObjects) { DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); @@ -2356,7 +2319,7 @@ bool RenderBlock::positionNewFloats() lastFloat = m_floatingObjects->getPrev(); } - int y = m_height; + int y = height(); // The float cannot start above the y position of the last positioned float. if (lastFloat) @@ -2371,7 +2334,7 @@ bool RenderBlock::positionNewFloats() continue; } - RenderObject* o = f->m_renderer; + RenderBox* o = f->m_renderer; int _height = o->height() + o->marginTop() + o->marginBottom(); int ro = rightOffset(); // Constant part of right offset. @@ -2380,7 +2343,7 @@ bool RenderBlock::positionNewFloats() if (ro - lo < fwidth) fwidth = ro - lo; // Never look for more than what will be available. - IntRect oldRect(o->xPos(), o->yPos() , o->width(), o->height()); + IntRect oldRect(o->x(), o->y() , o->width(), o->height()); if (o->style()->clear() & CLEFT) y = max(leftBottom(), y); @@ -2397,7 +2360,7 @@ bool RenderBlock::positionNewFloats() } fx = max(0, fx); f->m_left = fx; - o->setPos(fx + o->marginLeft(), y + o->marginTop()); + o->setLocation(fx + o->marginLeft(), y + o->marginTop()); } else { int heightRemainingLeft = 1; int heightRemainingRight = 1; @@ -2407,7 +2370,7 @@ bool RenderBlock::positionNewFloats() fx = rightRelOffset(y, ro, false, &heightRemainingRight); } f->m_left = fx - f->m_width; - o->setPos(fx - o->marginRight() - o->width(), y + o->marginTop()); + o->setLocation(fx - o->marginRight() - o->width(), y + o->marginTop()); } f->m_top = y; @@ -2440,8 +2403,8 @@ void RenderBlock::newLine(EClear clear) default: break; } - if (m_height < newY) - m_height = newY; + if (height() < newY) + setHeight(newY); } void RenderBlock::addPercentHeightDescendant(RenderBox* descendant) @@ -2526,13 +2489,12 @@ RenderBlock::leftRelOffset(int y, int fixedOffset, bool applyTextIndent, } if (applyTextIndent && m_firstLine && style()->direction() == LTR) { - int cw=0; + int cw = 0; if (style()->textIndent().isPercent()) cw = containingBlock()->availableWidth(); left += style()->textIndent().calcMinValue(cw); } - //kdDebug( 6040 ) << "leftOffset(" << y << ") = " << left << endl; return left; } @@ -2564,20 +2526,18 @@ RenderBlock::rightRelOffset(int y, int fixedOffset, bool applyTextIndent, } if (applyTextIndent && m_firstLine && style()->direction() == RTL) { - int cw=0; + int cw = 0; if (style()->textIndent().isPercent()) cw = containingBlock()->availableWidth(); right -= style()->textIndent().calcMinValue(cw); } - //kdDebug( 6040 ) << "rightOffset(" << y << ") = " << right << endl; return right; } int RenderBlock::lineWidth(int y) const { - //kdDebug( 6040 ) << "lineWidth(" << y << ")=" << rightOffset(y) - leftOffset(y) << endl; int result = rightOffset(y) - leftOffset(y); return (result < 0) ? 0 : result; } @@ -2631,7 +2591,23 @@ IntRect RenderBlock::floatRect() const int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf) const { - int bottom = RenderFlow::lowestPosition(includeOverflowInterior, includeSelf); + if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip())) + return includeSelf && width() > 0 ? overflowHeight(false) : 0; + + int bottom = includeSelf && width() > 0 ? height() : 0; + if (!hasColumns()) { + // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids. + // For now, we have to descend into all the children, since we may have a huge abs div inside + // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to + // the abs div. + for (RenderObject* c = firstChild(); c; c = c->nextSibling()) { + if (!c->isFloatingOrPositioned() && !c->isText() && !c->isRenderInline()) + bottom = max(bottom, toRenderBox(c)->y() + c->lowestPosition(false)); + } + } + + if (includeSelf && isRelPositioned()) + bottom += relativePositionOffsetY(); if (!includeOverflowInterior && hasOverflowClip()) return bottom; @@ -2641,7 +2617,7 @@ int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf) bottom = max(bottom, m_overflowHeight + relativeOffset); if (m_positionedObjects) { - RenderObject* r; + RenderBox* r; Iterator end = m_positionedObjects->end(); for (Iterator it = m_positionedObjects->begin(); it != end; ++it) { r = *it; @@ -2651,8 +2627,8 @@ int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf) // FIXME: Should work for overflow sections too. // If a positioned object lies completely to the left of the root it will be unreachable via scrolling. // Therefore we should not allow it to contribute to the lowest position. - if (!isRenderView() || r->xPos() + r->width() > 0 || r->xPos() + r->rightmostPosition(false) > 0) { - int lp = r->yPos() + r->lowestPosition(false); + if (!isRenderView() || r->x() + r->width() > 0 || r->x() + r->rightmostPosition(false) > 0) { + int lp = r->y() + r->lowestPosition(false); bottom = max(bottom, lp + relativeOffset); } } @@ -2677,7 +2653,6 @@ int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf) } } - if (!includeSelf && lastLineBox()) { int lp = lastLineBox()->yPos() + lastLineBox()->height(); bottom = max(bottom, lp); @@ -2688,7 +2663,25 @@ int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf) int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const { - int right = RenderFlow::rightmostPosition(includeOverflowInterior, includeSelf); + if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip())) + return includeSelf && height() > 0 ? overflowWidth(false) : 0; + + int right = includeSelf && height() > 0 ? width() : 0; + + if (!hasColumns()) { + // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids. + // For now, we have to descend into all the children, since we may have a huge abs div inside + // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to + // the abs div. + for (RenderObject* c = firstChild(); c; c = c->nextSibling()) { + if (!c->isFloatingOrPositioned() && c->isBox() && !c->isRenderInline()) + right = max(right, toRenderBox(c)->x() + c->rightmostPosition(false)); + } + } + + if (includeSelf && isRelPositioned()) + right += relativePositionOffsetX(); + if (!includeOverflowInterior && hasOverflowClip()) return right; @@ -2698,7 +2691,7 @@ int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSel right = max(right, m_overflowWidth + relativeOffset); if (m_positionedObjects) { - RenderObject* r; + RenderBox* r; Iterator end = m_positionedObjects->end(); for (Iterator it = m_positionedObjects->begin() ; it != end; ++it) { r = *it; @@ -2708,8 +2701,8 @@ int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSel // FIXME: Should work for overflow sections too. // If a positioned object lies completely above the root it will be unreachable via scrolling. // Therefore we should not allow it to contribute to the rightmost position. - if (!isRenderView() || r->yPos() + r->height() > 0 || r->yPos() + r->lowestPosition(false) > 0) { - int rp = r->xPos() + r->rightmostPosition(false); + if (!isRenderView() || r->y() + r->height() > 0 || r->y() + r->lowestPosition(false) > 0) { + int rp = r->x() + r->rightmostPosition(false); right = max(right, rp + relativeOffset); } } @@ -2750,7 +2743,24 @@ int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSel int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const { - int left = RenderFlow::leftmostPosition(includeOverflowInterior, includeSelf); + if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip())) + return includeSelf && height() > 0 ? overflowLeft(false) : width(); + + int left = includeSelf && height() > 0 ? 0 : width(); + if (!hasColumns()) { + // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids. + // For now, we have to descend into all the children, since we may have a huge abs div inside + // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to + // the abs div. + for (RenderObject* c = firstChild(); c; c = c->nextSibling()) { + if (!c->isFloatingOrPositioned() && c->isBox() && !c->isRenderInline()) + left = min(left, toRenderBox(c)->x() + c->leftmostPosition(false)); + } + } + + if (includeSelf && isRelPositioned()) + left += relativePositionOffsetX(); + if (!includeOverflowInterior && hasOverflowClip()) return left; @@ -2760,7 +2770,7 @@ int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf left = min(left, m_overflowLeft + relativeOffset); if (m_positionedObjects) { - RenderObject* r; + RenderBox* r; Iterator end = m_positionedObjects->end(); for (Iterator it = m_positionedObjects->begin(); it != end; ++it) { r = *it; @@ -2770,8 +2780,8 @@ int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf // FIXME: Should work for overflow sections too. // If a positioned object lies completely above the root it will be unreachable via scrolling. // Therefore we should not allow it to contribute to the leftmost position. - if (!isRenderView() || r->yPos() + r->height() > 0 || r->yPos() + r->lowestPosition(false) > 0) { - int lp = r->xPos() + r->leftmostPosition(false); + if (!isRenderView() || r->y() + r->height() > 0 || r->y() + r->lowestPosition(false) > 0) { + int lp = r->x() + r->leftmostPosition(false); left = min(left, lp + relativeOffset); } } @@ -2875,31 +2885,33 @@ void RenderBlock::clearFloats() // out of flow (like floating/positioned elements), and we also skip over any objects that may have shifted // to avoid floats. bool parentHasFloats = false; - RenderObject *prev = previousSibling(); - while (prev && (!prev->isRenderBlock() || prev->avoidsFloats() || prev->isFloatingOrPositioned())) { + RenderObject* prev = previousSibling(); + while (prev && (!prev->isBox() || !prev->isRenderBlock() || prev->avoidsFloats() || prev->isFloatingOrPositioned())) { if (prev->isFloating()) parentHasFloats = true; prev = prev->previousSibling(); } // First add in floats from the parent. - int offset = m_y; - if (parentHasFloats) - addIntrudingFloats(static_cast<RenderBlock *>(parent()), - parent()->borderLeft() + parent()->paddingLeft(), offset); - + int offset = y(); + if (parentHasFloats) { + RenderBlock* parentBlock = static_cast<RenderBlock *>(parent()); + addIntrudingFloats(parentBlock, parentBlock->borderLeft() + parentBlock->paddingLeft(), offset); + } + int xoffset = 0; if (prev) - offset -= prev->yPos(); - else { + offset -= toRenderBox(prev)->y(); + else if (parent()->isBox()) { prev = parent(); - xoffset += prev->borderLeft() + prev->paddingLeft(); + xoffset += toRenderBox(prev)->borderLeft() + toRenderBox(prev)->paddingLeft(); } // Add overhanging floats from the previous RenderBlock, but only if it has a float that intrudes into our space. - if (!prev->isRenderBlock()) return; + if (!prev || !prev->isRenderBlock()) + return; + RenderBlock* block = static_cast<RenderBlock *>(prev); - if (block->m_floatingObjects && block->floatBottom() > offset) addIntrudingFloats(block, xoffset, offset); @@ -2954,7 +2966,7 @@ int RenderBlock::addOverhangingFloats(RenderBlock* child, int xoff, int yoff, bo IntRect floatsOverflowRect; DeprecatedPtrListIterator<FloatingObject> it(*child->m_floatingObjects); for (FloatingObject* r; (r = it.current()); ++it) { - int bottom = child->yPos() + r->m_bottom; + int bottom = child->y() + r->m_bottom; lowestFloatBottom = max(lowestFloatBottom, bottom); if (bottom > height()) { @@ -3067,9 +3079,9 @@ bool RenderBlock::containsFloat(RenderObject* o) return false; } -void RenderBlock::markAllDescendantsWithFloatsForLayout(RenderObject* floatToRemove) +void RenderBlock::markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove, bool inLayout) { - setChildNeedsLayout(true); + setChildNeedsLayout(true, !inLayout); if (floatToRemove) removeFloatingObject(floatToRemove); @@ -3077,14 +3089,14 @@ void RenderBlock::markAllDescendantsWithFloatsForLayout(RenderObject* floatToRem // Iterate over our children and mark them as needed. if (!childrenInline()) { for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { - if (isBlockFlow() && !child->isFloatingOrPositioned() && + if (child->isRenderBlock() && !child->isFloatingOrPositioned() && ((floatToRemove ? child->containsFloat(floatToRemove) : child->containsFloats()) || child->shrinkToAvoidFloats())) - child->markAllDescendantsWithFloatsForLayout(floatToRemove); + static_cast<RenderBlock*>(child)->markAllDescendantsWithFloatsForLayout(floatToRemove, inLayout); } } } -int RenderBlock::getClearDelta(RenderObject *child) +int RenderBlock::getClearDelta(RenderBox* child) { // There is no need to compute clearance if we have no floats. if (!containsFloats()) @@ -3112,11 +3124,11 @@ int RenderBlock::getClearDelta(RenderObject *child) // to fit) and not all (we should be using nextFloatBottomBelow and looping). // Do not allow tables to wrap in quirks or even in almost strict mode // (ebay on the PLT, finance.yahoo.com in the real world, versiontracker.com forces even almost strict mode not to work) - int result = clearSet ? max(0, bottom - child->yPos()) : 0; + int result = clearSet ? max(0, bottom - child->y()) : 0; if (!result && child->avoidsFloats() && child->style()->width().isFixed() && - child->minPrefWidth() > lineWidth(child->yPos()) && child->minPrefWidth() <= availableWidth() && + child->minPrefWidth() > lineWidth(child->y()) && child->minPrefWidth() <= availableWidth() && document()->inStrictMode()) - result = max(0, floatBottom() - child->yPos()); + result = max(0, floatBottom() - child->y()); return result; } @@ -3130,7 +3142,7 @@ void RenderBlock::addVisualOverflow(const IntRect& r) m_overflowHeight = max(m_overflowHeight, r.bottom()); } -bool RenderBlock::isPointInOverflowControl(HitTestResult& result, int _x, int _y, int _tx, int _ty) +bool RenderBlock::isPointInOverflowControl(HitTestResult& result, int, int, int, int) { if (!scrollsOverflow()) return false; @@ -3140,12 +3152,10 @@ bool RenderBlock::isPointInOverflowControl(HitTestResult& result, int _x, int _y bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction) { - bool inlineFlow = isInlineFlow(); + int tx = _tx + x(); + int ty = _ty + y(); - int tx = _tx + m_x; - int ty = _ty + m_y + borderTopExtra(); - - if (!inlineFlow && !isRenderView()) { + if (!isRenderView()) { // Check if we need to do anything at all. IntRect overflowBox = overflowRect(false); overflowBox.move(tx, ty); @@ -3167,7 +3177,7 @@ bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu int scrolledX = tx; int scrolledY = ty; if (hasOverflowClip()) - m_layer->subtractScrollOffset(scrolledX, scrolledY); + m_layer->subtractScrolledContentOffset(scrolledX, scrolledY); // Hit test contents if we don't have columns. if (!m_hasColumns && hitTestContents(request, result, _x, _y, scrolledX, scrolledY, hitTestAction)) @@ -3188,8 +3198,8 @@ bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); for (it.toLast(); (o = it.current()); --it) { if (o->m_shouldPaint && !o->m_renderer->hasLayer()) { - int xoffset = scrolledX + o->m_left + o->m_renderer->marginLeft() - o->m_renderer->xPos(); - int yoffset = scrolledY + o->m_top + o->m_renderer->marginTop() - o->m_renderer->yPos(); + int xoffset = scrolledX + o->m_left + o->m_renderer->marginLeft() - o->m_renderer->x(); + int yoffset = scrolledY + o->m_top + o->m_renderer->marginTop() - o->m_renderer->y(); if (o->m_renderer->hitTest(request, result, IntPoint(_x, _y), xoffset, yoffset)) { updateHitTestResult(result, IntPoint(_x - xoffset, _y - yoffset)); return true; @@ -3199,12 +3209,11 @@ bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu } } - // Now hit test our background. - if (!inlineFlow && (hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground)) { - int topExtra = borderTopExtra(); - IntRect boundsRect(tx, ty - topExtra, m_width, m_height + topExtra + borderBottomExtra()); - if (style()->visibility() == VISIBLE && boundsRect.contains(_x, _y)) { - updateHitTestResult(result, IntPoint(_x - tx, _y - ty + topExtra)); + // Now hit test our background + if (hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) { + IntRect boundsRect(tx, ty, width(), height()); + if (visibleToHitTesting() && boundsRect.contains(_x, _y)) { + updateHitTestResult(result, IntPoint(_x - tx, _y - ty)); return true; } } @@ -3262,7 +3271,7 @@ bool RenderBlock::hitTestContents(const HitTestRequest& request, HitTestResult& for (RenderObject* child = lastChild(); child; child = child->previousSibling()) { // FIXME: We have to skip over inline flows, since they can show up inside RenderTables at the moment (a demoted inline <form> for example). If we ever implement a // table-specific hit-test method (which we should do for performance reasons anyway), then we can remove this check. - if (!child->hasLayer() && !child->isFloating() && !child->isInlineFlow() && child->nodeAtPoint(request, result, x, y, tx, ty, childHitTest)) { + if (!child->hasLayer() && !child->isFloating() && !child->isRenderInline() && child->nodeAtPoint(request, result, x, y, tx, ty, childHitTest)) { updateHitTestResult(result, IntPoint(x - tx, y - ty)); return true; } @@ -3312,7 +3321,7 @@ VisiblePosition RenderBlock::positionForCoordinates(int x, int y) return RenderFlow::positionForCoordinates(x, y); int top = borderTop(); - int bottom = top + borderTopExtra() + paddingTop() + contentHeight() + paddingBottom() + borderBottomExtra(); + int bottom = top + paddingTop() + contentHeight() + paddingBottom(); int left = borderLeft(); int right = left + paddingLeft() + contentWidth() + paddingRight(); @@ -3320,15 +3329,8 @@ VisiblePosition RenderBlock::positionForCoordinates(int x, int y) Node* n = element(); int contentsX = x; - int contentsY = y - borderTopExtra(); - if (hasOverflowClip()) - m_layer->scrollOffset(contentsX, contentsY); - if (m_hasColumns) { - IntPoint contentsPoint(contentsX, contentsY); - adjustPointToColumnContents(contentsPoint); - contentsX = contentsPoint.x(); - contentsY = contentsPoint.y(); - } + int contentsY = y; + offsetForContents(contentsX, contentsY); if (isReplaced()) { if (y < 0 || y < height() && x < 0) @@ -3345,8 +3347,8 @@ VisiblePosition RenderBlock::positionForCoordinates(int x, int y) if (y < top || (isEditableRoot && (y < bottom && x < left))) { if (!isEditableRoot) - if (RenderObject* c = firstChild()) { // FIXME: This code doesn't make any sense. This child could be an inline or a positioned element or a float or a compact, etc. - VisiblePosition p = c->positionForCoordinates(contentsX - c->xPos(), contentsY - c->yPos()); + if (RenderBox* c = firstChildBox()) { // FIXME: This code doesn't make any sense. This child could be an inline or a positioned element or a float, etc. + VisiblePosition p = c->positionForCoordinates(contentsX - c->x(), contentsY - c->y()); if (p.isNotNull()) return p; } @@ -3361,8 +3363,8 @@ VisiblePosition RenderBlock::positionForCoordinates(int x, int y) if (y >= bottom || (isEditableRoot && (y >= top && x >= right))) { if (!isEditableRoot) - if (RenderObject* c = lastChild()) { // FIXME: This code doesn't make any sense. This child could be an inline or a positioned element or a float or a compact, ect. - VisiblePosition p = c->positionForCoordinates(contentsX - c->xPos(), contentsY - c->yPos()); + if (RenderBox* c = lastChildBox()) { // FIXME: This code doesn't make any sense. This child could be an inline or a positioned element or a float, etc. + VisiblePosition p = c->positionForCoordinates(contentsX - c->x(), contentsY - c->y()); if (p.isNotNull()) return p; } @@ -3409,25 +3411,38 @@ VisiblePosition RenderBlock::positionForCoordinates(int x, int y) } // See if any child blocks exist at this y coordinate. - if (firstChild() && contentsY < firstChild()->yPos()) + if (firstChildBox() && contentsY < firstChildBox()->y()) return VisiblePosition(n, 0, DOWNSTREAM); - for (RenderObject* renderer = firstChild(); renderer; renderer = renderer->nextSibling()) { + for (RenderBox* renderer = firstChildBox(); renderer; renderer = renderer->nextSiblingBox()) { if (renderer->height() == 0 || renderer->style()->visibility() != VISIBLE || renderer->isFloatingOrPositioned()) continue; - RenderObject* next = renderer->nextSibling(); + RenderBox* next = renderer->nextSiblingBox(); while (next && next->isFloatingOrPositioned()) - next = next->nextSibling(); + next = next->nextSiblingBox(); if (next) - bottom = next->yPos(); + bottom = next->y(); else bottom = top + scrollHeight(); - if (contentsY >= renderer->yPos() && contentsY < bottom) - return renderer->positionForCoordinates(contentsX - renderer->xPos(), contentsY - renderer->yPos()); + if (contentsY >= renderer->y() && contentsY < bottom) + return renderer->positionForCoordinates(contentsX - renderer->x(), contentsY - renderer->y()); } return RenderFlow::positionForCoordinates(x, y); } +void RenderBlock::offsetForContents(int& tx, int& ty) const +{ + if (hasOverflowClip()) + m_layer->addScrolledContentOffset(tx, ty); + + if (m_hasColumns) { + IntPoint contentsPoint(tx, ty); + adjustPointToColumnContents(contentsPoint); + tx = contentsPoint.x(); + ty = contentsPoint.y(); + } +} + int RenderBlock::availableWidth() const { // If we have multiple columns, then the available width is reduced to our column width. @@ -3625,14 +3640,14 @@ int RenderBlock::layoutColumns(int endOfContent) colCount++; } - m_overflowWidth = max(m_width, currX - colGap); + m_overflowWidth = max(width(), currX - colGap); m_overflowLeft = min(0, currX + desiredColumnWidth + colGap); m_overflowHeight = maxColBottom; int toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight(); if (computeIntrinsicHeight) - m_height = m_overflowHeight + toAdd; + setHeight(m_overflowHeight + toAdd); v->setPrintRect(IntRect()); v->setTruncatedAt(0); @@ -3793,7 +3808,7 @@ RenderObject* InlineMinMaxIterator::next() result = current->firstChild(); if (!result) { // We hit the end of our inline. (It was empty, e.g., <span></span>.) - if (!oldEndOfInline && current->isInlineFlow()) { + if (!oldEndOfInline && current->isRenderInline()) { result = current; endOfInline = true; break; @@ -3803,7 +3818,7 @@ RenderObject* InlineMinMaxIterator::next() result = current->nextSibling(); if (result) break; current = current->parent(); - if (current && current != parent && current->isInlineFlow()) { + if (current && current != parent && current->isRenderInline()) { result = current; endOfInline = true; break; @@ -3814,7 +3829,7 @@ RenderObject* InlineMinMaxIterator::next() if (!result) break; - if (!result->isPositioned() && (result->isText() || result->isFloating() || result->isReplaced() || result->isInlineFlow())) + if (!result->isPositioned() && (result->isText() || result->isFloating() || result->isReplaced() || result->isRenderInline())) break; current = result; @@ -3833,7 +3848,7 @@ static int getBPMWidth(int childValue, Length cssUnit) return 0; } -static int getBorderPaddingMargin(const RenderObject* child, bool endOfInline) +static int getBorderPaddingMargin(const RenderBox* child, bool endOfInline) { RenderStyle* cstyle = child->style(); int result = 0; @@ -3853,7 +3868,7 @@ static inline void stripTrailingSpace(int& inlineMax, int& inlineMin, { if (trailingSpaceChild && trailingSpaceChild->isText()) { // Collapse away the trailing space at the end of a block. - RenderText* t = static_cast<RenderText*>(trailingSpaceChild); + RenderText* t = toRenderText(trailingSpaceChild); const UChar space = ' '; const Font& font = t->style()->font(); // FIXME: This ignores first-line. int spaceWidth = font.width(TextRun(&space, 1)); @@ -3933,10 +3948,10 @@ void RenderBlock::calcInlinePrefWidths() if (!child->isText()) { // Case (1) and (2). Inline replaced and inline flow elements. - if (child->isInlineFlow()) { + if (child->isRenderInline()) { // Add in padding/border/margin from the appropriate side of // the element. - int bpm = getBorderPaddingMargin(child, childIterator.endOfInline); + int bpm = getBorderPaddingMargin(static_cast<RenderFlow*>(child), childIterator.endOfInline); childMin += bpm; childMax += bpm; @@ -4019,7 +4034,7 @@ void RenderBlock::calcInlinePrefWidths() } } else if (child->isText()) { // Case (3). Text. - RenderText* t = static_cast<RenderText *>(child); + RenderText* t = toRenderText(child); if (t->isWordBreak()) { m_minPrefWidth = max(inlineMin, m_minPrefWidth); @@ -4114,7 +4129,7 @@ void RenderBlock::calcInlinePrefWidths() } oldAutoWrap = autoWrap; - if (!child->isInlineFlow()) + if (!child->isRenderInline()) previousLeaf = child; } @@ -4285,11 +4300,11 @@ int RenderBlock::getBaselineOfFirstLineBox() const return -1; } else { - for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { + for (RenderBox* curr = firstChildBox(); curr; curr = curr->nextSiblingBox()) { if (!curr->isFloatingOrPositioned()) { int result = curr->getBaselineOfFirstLineBox(); if (result != -1) - return curr->yPos() + result; // Translate to our coordinate space. + return curr->y() + result; // Translate to our coordinate space. } } } @@ -4311,12 +4326,12 @@ int RenderBlock::getBaselineOfLastLineBox() const } else { bool haveNormalFlowChild = false; - for (RenderObject* curr = lastChild(); curr; curr = curr->previousSibling()) { + for (RenderBox* curr = lastChildBox(); curr; curr = curr->previousSiblingBox()) { if (!curr->isFloatingOrPositioned()) { haveNormalFlowChild = true; int result = curr->getBaselineOfLastLineBox(); if (result != -1) - return curr->yPos() + result; // Translate to our coordinate space. + return curr->y() + result; // Translate to our coordinate space. } } if (!haveNormalFlowChild && hasLineIfEmpty()) @@ -4326,9 +4341,20 @@ int RenderBlock::getBaselineOfLastLineBox() const return -1; } +bool RenderBlock::containsNonZeroBidiLevel() const +{ + for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) { + for (InlineBox* box = root->firstLeafChild(); box; box = box->nextLeafChild()) { + if (box->bidiLevel()) + return true; + } + } + return false; +} + RenderBlock* RenderBlock::firstLineBlock() const { - const RenderObject* firstLineBlock = this; + RenderBlock* firstLineBlock = const_cast<RenderBlock*>(this); bool hasPseudo = false; while (true) { hasPseudo = firstLineBlock->style()->hasPseudoStyle(RenderStyle::FIRST_LINE); @@ -4338,13 +4364,14 @@ RenderBlock* RenderBlock::firstLineBlock() const if (firstLineBlock->isReplaced() || firstLineBlock->isFloating() || !parentBlock || parentBlock->firstChild() != firstLineBlock || !parentBlock->isBlockFlow()) break; - firstLineBlock = parentBlock; + ASSERT(parentBlock->isRenderBlock()); + firstLineBlock = static_cast<RenderBlock*>(parentBlock); } if (!hasPseudo) return 0; - return (RenderBlock*)(firstLineBlock); + return firstLineBlock; } void RenderBlock::updateFirstLetter() @@ -4415,7 +4442,7 @@ void RenderBlock::updateFirstLetter() // adding and removing children of firstLetterContainer. view()->disableLayoutState(); - RenderText* textObj = static_cast<RenderText*>(currChild); + RenderText* textObj = toRenderText(currChild); // Create our pseudo style now that we have our firstLetterContainer determined. RenderStyle* pseudoStyle = firstLetterBlock->getCachedPseudoStyle(RenderStyle::FIRST_LETTER, @@ -4486,7 +4513,7 @@ bool RenderBlock::inRootBlockContext() const // (crawling into blocks). static bool shouldCheckLines(RenderObject* obj) { - return !obj->isFloatingOrPositioned() && !obj->isCompact() && !obj->isRunIn() && + return !obj->isFloatingOrPositioned() && !obj->isRunIn() && obj->isBlockFlow() && obj->style()->height().isAuto() && (!obj->isFlexibleBox() || obj->style()->boxOrient() == VERTICAL); } @@ -4513,7 +4540,7 @@ static RootInlineBox* getLineAtIndex(RenderBlock* block, int i, int& count) return 0; } -int getHeightForLineCount(RenderBlock* block, int l, bool includeBottom, int& count) +static int getHeightForLineCount(RenderBlock* block, int l, bool includeBottom, int& count) { if (block->style()->visibility() == VISIBLE) { if (block->childrenInline()) { @@ -4523,18 +4550,18 @@ int getHeightForLineCount(RenderBlock* block, int l, bool includeBottom, int& co } } else { - RenderObject* normalFlowChildWithoutLines = 0; - for (RenderObject* obj = block->firstChild(); obj; obj = obj->nextSibling()) { + RenderBox* normalFlowChildWithoutLines = 0; + for (RenderBox* obj = block->firstChildBox(); obj; obj = obj->nextSiblingBox()) { if (shouldCheckLines(obj)) { int result = getHeightForLineCount(static_cast<RenderBlock*>(obj), l, false, count); if (result != -1) - return result + obj->yPos() + (includeBottom ? (block->borderBottom() + block->paddingBottom()) : 0); + return result + obj->y() + (includeBottom ? (block->borderBottom() + block->paddingBottom()) : 0); } - else if (!obj->isFloatingOrPositioned() && !obj->isCompact() && !obj->isRunIn()) + else if (!obj->isFloatingOrPositioned() && !obj->isRunIn()) normalFlowChildWithoutLines = obj; } if (normalFlowChildWithoutLines && l == 0) - return normalFlowChildWithoutLines->yPos() + normalFlowChildWithoutLines->height(); + return normalFlowChildWithoutLines->y() + normalFlowChildWithoutLines->height(); } } @@ -4582,14 +4609,14 @@ void RenderBlock::adjustForBorderFit(int x, int& left, int& right) const } } else { - for (RenderObject* obj = firstChild(); obj; obj = obj->nextSibling()) { + for (RenderBox* obj = firstChildBox(); obj; obj = obj->nextSiblingBox()) { if (!obj->isFloatingOrPositioned()) { if (obj->isBlockFlow() && !obj->hasOverflowClip()) - static_cast<RenderBlock*>(obj)->adjustForBorderFit(x + obj->xPos(), left, right); + static_cast<RenderBlock*>(obj)->adjustForBorderFit(x + obj->x(), left, right); else if (obj->style()->visibility() == VISIBLE) { // We are a replaced element or some kind of non-block-flow object. - left = min(left, x + obj->xPos()); - right = max(right, x + obj->xPos() + obj->width()); + left = min(left, x + obj->x()); + right = max(right, x + obj->x() + obj->width()); } } } @@ -4601,7 +4628,7 @@ void RenderBlock::adjustForBorderFit(int x, int& left, int& right) const for (; (r = it.current()); ++it) { // Only examine the object if our m_shouldPaint flag is set. if (r->m_shouldPaint) { - int floatLeft = r->m_left - r->m_renderer->xPos() + r->m_renderer->marginLeft(); + int floatLeft = r->m_left - r->m_renderer->x() + r->m_renderer->marginLeft(); int floatRight = floatLeft + r->m_renderer->width(); left = min(left, floatLeft); right = max(right, floatRight); @@ -4687,8 +4714,6 @@ const char* RenderBlock::renderName() const return "RenderBlock (generated)"; if (isRelPositioned()) return "RenderBlock (relative positioned)"; - if (isCompact()) - return "RenderBlock (compact)"; if (isRunIn()) return "RenderBlock (run-in)"; return "RenderBlock"; diff --git a/WebCore/rendering/RenderBlock.h b/WebCore/rendering/RenderBlock.h index d38de16..2e74e41 100644 --- a/WebCore/rendering/RenderBlock.h +++ b/WebCore/rendering/RenderBlock.h @@ -56,7 +56,6 @@ public: virtual bool isRenderBlock() const { return true; } virtual bool isBlockFlow() const { return (!isInline() || isReplaced()) && !isTable(); } - virtual bool isInlineFlow() const { return isInline() && !isReplaced(); } virtual bool isInlineBlockOrInlineTable() const { return isInline() && isReplaced(); } virtual bool childrenInline() const { return m_childrenInline; } @@ -112,9 +111,9 @@ public: void layoutInlineChildren(bool relayoutChildren, int& repaintTop, int& repaintBottom); void layoutPositionedObjects(bool relayoutChildren); - void insertPositionedObject(RenderObject*); - void removePositionedObject(RenderObject*); - virtual void removePositionedObjects(RenderBlock*); + void insertPositionedObject(RenderBox*); + void removePositionedObject(RenderBox*); + void removePositionedObjects(RenderBlock*); void addPercentHeightDescendant(RenderBox*); static void removePercentHeightDescendant(RenderBox*); @@ -124,17 +123,17 @@ public: virtual void borderFitAdjust(int& x, int& w) const; // Shrink the box in which the border paints if border-fit is set. // Called to lay out the legend for a fieldset. - virtual RenderObject* layoutLegend(bool relayoutChildren) { return 0; }; + virtual RenderObject* layoutLegend(bool /*relayoutChildren*/) { return 0; } // the implementation of the following functions is in bidi.cpp struct FloatWithRect { - FloatWithRect(RenderObject* f) + FloatWithRect(RenderBox* f) : object(f) - , rect(IntRect(f->xPos() - f->marginLeft(), f->yPos() - f->marginTop(), f->width() + f->marginLeft() + f->marginRight(), f->height() + f->marginTop() + f->marginBottom())) + , rect(IntRect(f->x() - f->marginLeft(), f->y() - f->marginTop(), f->width() + f->marginLeft() + f->marginRight(), f->height() + f->marginTop() + f->marginBottom())) { } - RenderObject* object; + RenderBox* object; IntRect rect; }; @@ -167,17 +166,17 @@ public: void paintChildren(PaintInfo&, int tx, int ty); void paintEllipsisBoxes(PaintInfo&, int tx, int ty); void paintSelection(PaintInfo&, int tx, int ty); - void paintCaret(PaintInfo&, CaretType); + void paintCaret(PaintInfo&, int tx, int ty, CaretType); - void insertFloatingObject(RenderObject*); - void removeFloatingObject(RenderObject*); + void insertFloatingObject(RenderBox*); + void removeFloatingObject(RenderBox*); // Called from lineWidth, to position the floats added in the last line. // Returns ture if and only if it has positioned any floats. bool positionNewFloats(); void clearFloats(); - int getClearDelta(RenderObject* child); - virtual void markAllDescendantsWithFloatsForLayout(RenderObject* floatToRemove = 0); + int getClearDelta(RenderBox* child); + void markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove = 0, bool inLayout = true); void markPositionedObjectsForLayout(); virtual bool containsFloats() { return m_floatingObjects && !m_floatingObjects->isEmpty(); } @@ -185,7 +184,7 @@ public: virtual bool avoidsFloats() const; - virtual bool hasOverhangingFloats() { return !hasColumns() && floatBottom() > m_height; } + virtual bool hasOverhangingFloats() { return !hasColumns() && floatBottom() > height(); } void addIntrudingFloats(RenderBlock* prev, int xoffset, int yoffset); int addOverhangingFloats(RenderBlock* child, int xoffset, int yoffset, bool makeChildPaintOtherFloats); @@ -229,6 +228,8 @@ public: RootInlineBox* firstRootBox() const { return static_cast<RootInlineBox*>(firstLineBox()); } RootInlineBox* lastRootBox() const { return static_cast<RootInlineBox*>(lastLineBox()); } + bool containsNonZeroBidiLevel() const; + // Obtains the nearest enclosing block (including this block) that contributes a first-line style to our inline // children. virtual RenderBlock* firstLineBlock() const; @@ -321,10 +322,14 @@ protected: private: Position positionForBox(InlineBox*, bool start = true) const; Position positionForRenderer(RenderObject*, bool start = true) const; -// columGap() is used by WebKit when hit-testing columns. It's called by -// CacheBuilder when it duplicates the hit-testing logic. + + // Adjust tx and ty from painting offsets to the local coords of this renderer + void offsetForContents(int& tx, int& ty) const; + + // columGap() is used by WebKit when hit-testing columns. It's called by + // CacheBuilder when it duplicates the hit-testing logic. #ifdef ANDROID_EXPOSE_COLUMN_GAP -public: + public: #endif int columnGap() const; #ifdef ANDROID_EXPOSE_COLUMN_GAP @@ -333,6 +338,8 @@ private: void calcColumnWidth(); int layoutColumns(int endOfContent = -1); + bool expandsToEncloseOverhangingFloats() const; + protected: struct FloatingObject { enum Type { @@ -354,7 +361,7 @@ protected: Type type() { return static_cast<Type>(m_type); } - RenderObject* m_renderer; + RenderBox* m_renderer; int m_top; int m_bottom; int m_left; @@ -364,25 +371,6 @@ protected: bool m_isDescendant : 1; }; - // The following helper functions and structs are used by layoutBlockChildren. - class CompactInfo { - // A compact child that needs to be collapsed into the margin of the following block. - RenderObject* m_compact; - - // The block with the open margin that the compact child is going to place itself within. - RenderObject* m_block; - - public: - RenderObject* compact() const { return m_compact; } - RenderObject* block() const { return m_block; } - bool matches(RenderObject* child) const { return m_compact && m_block == child; } - - void clear() { set(0, 0); } - void set(RenderObject* c, RenderObject* b) { m_compact = c; m_block = b; } - - CompactInfo() { clear(); } - }; - class MarginInfo { // Collapsing flags for whether we can collapse our margins with our children's margins. bool m_canCollapseWithChildren : 1; @@ -449,26 +437,24 @@ protected: int margin() const { return m_posMargin - m_negMargin; } }; - void adjustPositionedBlock(RenderObject* child, const MarginInfo&); + void adjustPositionedBlock(RenderBox* child, const MarginInfo&); void adjustFloatingBlock(const MarginInfo&); - RenderObject* handleSpecialChild(RenderObject* child, const MarginInfo&, CompactInfo&, bool& handled); - RenderObject* handleFloatingChild(RenderObject* child, const MarginInfo&, bool& handled); - RenderObject* handlePositionedChild(RenderObject* child, const MarginInfo&, bool& handled); - RenderObject* handleCompactChild(RenderObject* child, CompactInfo&, bool& handled); - RenderObject* handleRunInChild(RenderObject* child, bool& handled); - void collapseMargins(RenderObject* child, MarginInfo&, int yPosEstimate); - void clearFloatsIfNeeded(RenderObject* child, MarginInfo&, int oldTopPosMargin, int oldTopNegMargin); - void insertCompactIfNeeded(RenderObject* child, CompactInfo&); - int estimateVerticalPosition(RenderObject* child, const MarginInfo&); - void determineHorizontalPosition(RenderObject* child); + RenderBox* handleSpecialChild(RenderBox* child, const MarginInfo&, bool& handled); + RenderBox* handleFloatingChild(RenderBox* child, const MarginInfo&, bool& handled); + RenderBox* handlePositionedChild(RenderBox* child, const MarginInfo&, bool& handled); + RenderBox* handleRunInChild(RenderBox* child, bool& handled); + void collapseMargins(RenderBox* child, MarginInfo&, int yPosEstimate); + void clearFloatsIfNeeded(RenderBox* child, MarginInfo&, int oldTopPosMargin, int oldTopNegMargin); + int estimateVerticalPosition(RenderBox* child, const MarginInfo&); + void determineHorizontalPosition(RenderBox* child); void handleBottomOfBlock(int top, int bottom, MarginInfo&); void setCollapsedBottomMargin(const MarginInfo&); // End helper functions and structs used by layoutBlockChildren. private: - typedef ListHashSet<RenderObject*>::const_iterator Iterator; + typedef ListHashSet<RenderBox*>::const_iterator Iterator; DeprecatedPtrList<FloatingObject>* m_floatingObjects; - ListHashSet<RenderObject*>* m_positionedObjects; + ListHashSet<RenderBox*>* m_positionedObjects; // Allocated only when some of these fields have non-default values struct MaxMargin { diff --git a/WebCore/rendering/RenderBox.cpp b/WebCore/rendering/RenderBox.cpp index 40b0e93..7711f5e 100644 --- a/WebCore/rendering/RenderBox.cpp +++ b/WebCore/rendering/RenderBox.cpp @@ -33,10 +33,12 @@ #include "HTMLElement.h" #include "HTMLNames.h" #include "ImageBuffer.h" +#include "FloatQuad.h" #include "Frame.h" #include "Page.h" #include "RenderArena.h" #include "RenderFlexibleBox.h" +#include "RenderInline.h" #include "RenderLayer.h" #include "RenderReplica.h" #include "RenderTableCell.h" @@ -48,6 +50,10 @@ #include <algorithm> #include <math.h> +#if ENABLE(WML) +#include "WMLNames.h" +#endif + using namespace std; namespace WebCore { @@ -63,13 +69,9 @@ bool RenderBox::s_hadOverflowClip = false; RenderBox::RenderBox(Node* node) : RenderObject(node) - , m_width(0) - , m_height(0) #ifdef ANDROID_LAYOUT , m_visibleWidth(0) #endif - , m_x(0) - , m_y(0) , m_marginLeft(0) , m_marginRight(0) , m_marginTop(0) @@ -79,6 +81,7 @@ RenderBox::RenderBox(Node* node) , m_layer(0) , m_inlineBoxWrapper(0) { + setIsBox(); } RenderBox::~RenderBox() @@ -95,7 +98,7 @@ void RenderBox::destroy() // This must be done before we destroy the RenderObject. if (m_layer) - m_layer->clearClipRect(); + m_layer->clearClipRects(); if (style() && (style()->height().isPercent() || style()->minHeight().isPercent() || style()->maxHeight().isPercent())) RenderBlock::removePercentHeightDescendant(this); @@ -108,18 +111,85 @@ void RenderBox::styleWillChange(RenderStyle::Diff diff, const RenderStyle* newSt s_wasFloating = isFloating(); s_hadOverflowClip = hasOverflowClip(); + if (style()) { + // If our z-index changes value or our visibility changes, + // we need to dirty our stacking context's z-order list. + if (newStyle) { + if (hasLayer() && (style()->hasAutoZIndex() != newStyle->hasAutoZIndex() || + style()->zIndex() != newStyle->zIndex() || + style()->visibility() != newStyle->visibility())) { + layer()->dirtyStackingContextZOrderLists(); + if (style()->hasAutoZIndex() != newStyle->hasAutoZIndex() || style()->visibility() != newStyle->visibility()) + layer()->dirtyZOrderLists(); + } + } + + // The background of the root element or the body element could propagate up to + // the canvas. Just dirty the entire canvas when our style changes substantially. + if (diff >= RenderStyle::Repaint && element() && + (element()->hasTagName(htmlTag) || element()->hasTagName(bodyTag))) + view()->repaint(); + else if (parent() && !isText()) { + // Do a repaint with the old style first, e.g., for example if we go from + // having an outline to not having an outline. + if (diff == RenderStyle::RepaintLayer) { + layer()->repaintIncludingDescendants(); + if (!(style()->clip() == newStyle->clip())) + layer()->clearClipRectsIncludingDescendants(); + } else if (diff == RenderStyle::Repaint || newStyle->outlineSize() < style()->outlineSize()) + repaint(); + } + + if (diff == RenderStyle::Layout) { + // When a layout hint happens, we go ahead and do a repaint of the layer, since the layer could + // end up being destroyed. + if (hasLayer()) { + if (style()->position() != newStyle->position() || + style()->zIndex() != newStyle->zIndex() || + style()->hasAutoZIndex() != newStyle->hasAutoZIndex() || + !(style()->clip() == newStyle->clip()) || + style()->hasClip() != newStyle->hasClip() || + style()->opacity() != newStyle->opacity() || + style()->transform() != newStyle->transform()) + layer()->repaintIncludingDescendants(); + } else if (newStyle->hasTransform() || newStyle->opacity() < 1) { + // If we don't have a layer yet, but we are going to get one because of transform or opacity, + // then we need to repaint the old position of the object. + repaint(); + } + + // When a layout hint happens and an object's position style changes, we have to do a layout + // to dirty the render tree using the old position value now. + if (parent() && style()->position() != newStyle->position()) { + markContainingBlocksForLayout(); + if (style()->position() == StaticPosition) + repaint(); + if (isFloating() && !isPositioned() && (newStyle->position() == AbsolutePosition || newStyle->position() == FixedPosition)) + removeFromObjectLists(); + } + } + } + RenderObject::styleWillChange(diff, newStyle); } void RenderBox::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle) { + // We need to ensure that view->maximalOutlineSize() is valid for any repaints that happen + // during the style change (it's used by clippedOverflowRectForRepaint()). + if (style()->outlineWidth() > 0 && style()->outlineSize() > maximalOutlineSize(PaintPhaseOutline)) + static_cast<RenderView*>(document()->renderer())->setMaximalOutlineSize(style()->outlineSize()); + RenderObject::styleDidChange(diff, oldStyle); if (needsLayout() && oldStyle && (oldStyle->height().isPercent() || oldStyle->minHeight().isPercent() || oldStyle->maxHeight().isPercent())) RenderBlock::removePercentHeightDescendant(this); + bool isRootObject = isRoot(); + bool isViewObject = isRenderView(); + // The root and the RenderView always paint their backgrounds/borders. - if (isRoot() || isRenderView()) + if (isRootObject || isViewObject) setHasBoxDecorations(true); setInline(style()->isDisplayInlineType()); @@ -141,7 +211,7 @@ void RenderBox::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldSty } // We also handle <body> and <html>, whose overflow applies to the viewport. - if (!isRoot() && (isRenderBlock() || isTableRow() || isTableSection()) && style()->overflowX() != OVISIBLE) { + if (style()->overflowX() != OVISIBLE && !isRootObject && (isRenderBlock() || isTableRow() || isTableSection())) { bool boxHasOverflowClip = true; if (isBody()) { // Overflow on the body can propagate to the viewport under the following conditions. @@ -177,7 +247,7 @@ void RenderBox::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldSty if (parent() && !needsLayout() && containingBlock()) m_layer->updateLayerPositions(); } - } else if (m_layer && !isRoot() && !isRenderView()) { + } else if (m_layer && !isRootObject && !isViewObject) { ASSERT(m_layer->parent()); RenderLayer* layer = m_layer; m_layer = 0; @@ -210,9 +280,347 @@ void RenderBox::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldSty // Set the text color if we're the body. if (isBody()) document()->setTextColor(style()->color()); +} - if (style()->outlineWidth() > 0 && style()->outlineSize() > maximalOutlineSize(PaintPhaseOutline)) - static_cast<RenderView*>(document()->renderer())->setMaximalOutlineSize(style()->outlineSize()); + +int RenderBox::offsetLeft() const +{ + RenderBox* offsetPar = offsetParent(); + if (!offsetPar) + return 0; + int xPos = x() - offsetPar->borderLeft(); + if (!isPositioned()) { + if (isRelPositioned()) + xPos += relativePositionOffsetX(); + RenderObject* curr = parent(); + while (curr && curr != offsetPar) { + // FIXME: What are we supposed to do inside SVG content? + if (curr->isBox() && !curr->isTableRow()) + xPos += toRenderBox(curr)->x(); + curr = curr->parent(); + } + if (offsetPar->isBody() && !offsetPar->isRelPositioned() && !offsetPar->isPositioned()) + xPos += offsetPar->x(); + } + return xPos; +} + +int RenderBox::offsetTop() const +{ + RenderBox* offsetPar = offsetParent(); + if (!offsetPar) + return 0; + int yPos = y() - offsetPar->borderTop(); + if (!isPositioned()) { + if (isRelPositioned()) + yPos += relativePositionOffsetY(); + RenderObject* curr = parent(); + while (curr && curr != offsetPar) { + // FIXME: What are we supposed to do inside SVG content? + if (curr->isBox() && !curr->isTableRow()) + yPos += toRenderBox(curr)->y(); + curr = curr->parent(); + } + if (offsetPar->isBody() && !offsetPar->isRelPositioned() && !offsetPar->isPositioned()) + yPos += offsetPar->y(); + } + return yPos; +} + +RenderBox* RenderBox::offsetParent() const +{ + // FIXME: It feels like this function could almost be written using containing blocks. + if (isBody()) + return 0; + + bool skipTables = isPositioned() || isRelPositioned(); + float currZoom = style()->effectiveZoom(); + RenderObject* curr = parent(); + while (curr && (!curr->element() || + (!curr->isPositioned() && !curr->isRelPositioned() && !curr->isBody()))) { + Node* element = curr->element(); + if (!skipTables && element) { + bool isTableElement = element->hasTagName(tableTag) || + element->hasTagName(tdTag) || + element->hasTagName(thTag); + +#if ENABLE(WML) + if (!isTableElement && element->isWMLElement()) + isTableElement = element->hasTagName(WMLNames::tableTag) || + element->hasTagName(WMLNames::tdTag); +#endif + + if (isTableElement) + break; + } + + float newZoom = curr->style()->effectiveZoom(); + if (currZoom != newZoom) + break; + currZoom = newZoom; + curr = curr->parent(); + } + return curr && curr->isBox() ? toRenderBox(curr) : 0; +} + +// More IE extensions. clientWidth and clientHeight represent the interior of an object +// excluding border and scrollbar. +int RenderBox::clientWidth() const +{ + return width() - borderLeft() - borderRight() - verticalScrollbarWidth(); +} + +int RenderBox::clientHeight() const +{ + return height() - borderTop() - borderBottom() - horizontalScrollbarHeight(); +} + +// scrollWidth/scrollHeight will be the same as overflowWidth/overflowHeight unless the +// object has overflow:hidden/scroll/auto specified and also has overflow. +// FIXME: It's not completely clear how scrollWidth/Height should behave for +// objects with visible overflow. +int RenderBox::scrollWidth() const +{ + if (hasOverflowClip()) + return m_layer->scrollWidth(); + return overflowWidth(); +} + +int RenderBox::scrollHeight() const +{ + if (hasOverflowClip()) + return m_layer->scrollHeight(); + return overflowHeight(); +} + +int RenderBox::scrollLeft() const +{ + return hasOverflowClip() ? m_layer->scrollXOffset() : 0; +} + +int RenderBox::scrollTop() const +{ + return hasOverflowClip() ? m_layer->scrollYOffset() : 0; +} + +void RenderBox::setScrollLeft(int newLeft) +{ + if (hasOverflowClip()) + m_layer->scrollToXOffset(newLeft); +} + +void RenderBox::setScrollTop(int newTop) +{ + if (hasOverflowClip()) + m_layer->scrollToYOffset(newTop); +} + +int RenderBox::paddingTop(bool) const +{ + int w = 0; + Length padding = style()->paddingTop(); + if (padding.isPercent()) + w = containingBlock()->availableWidth(); + return padding.calcMinValue(w); +} + +int RenderBox::paddingBottom(bool) const +{ + int w = 0; + Length padding = style()->paddingBottom(); + if (padding.isPercent()) + w = containingBlock()->availableWidth(); + return padding.calcMinValue(w); +} + +int RenderBox::paddingLeft(bool) const +{ + int w = 0; + Length padding = style()->paddingLeft(); + if (padding.isPercent()) + w = containingBlock()->availableWidth(); + return padding.calcMinValue(w); +} + +int RenderBox::paddingRight(bool) const +{ + int w = 0; + Length padding = style()->paddingRight(); + if (padding.isPercent()) + w = containingBlock()->availableWidth(); + return padding.calcMinValue(w); +} + +void RenderBox::absoluteRects(Vector<IntRect>& rects, int tx, int ty, bool topLevel) +{ + // For blocks inside inlines, we go ahead and include margins so that we run right up to the + // inline boxes above and below us (thus getting merged with them to form a single irregular + // shape). + RenderFlow* continuation = virtualContinuation(); + if (topLevel && continuation) { + rects.append(IntRect(tx, ty - collapsedMarginTop(), + width(), height() + collapsedMarginTop() + collapsedMarginBottom())); + continuation->absoluteRects(rects, + tx - x() + continuation->containingBlock()->x(), + ty - y() + continuation->containingBlock()->y(), topLevel); + } else + rects.append(IntRect(tx, ty, width(), height())); +} + +void RenderBox::absoluteQuads(Vector<FloatQuad>& quads, bool topLevel) +{ + // For blocks inside inlines, we go ahead and include margins so that we run right up to the + // inline boxes above and below us (thus getting merged with them to form a single irregular + // shape). + RenderFlow* continuation = virtualContinuation(); + if (topLevel && continuation) { + FloatRect localRect(0, -collapsedMarginTop(), + width(), height() + collapsedMarginTop() + collapsedMarginBottom()); + quads.append(localToAbsoluteQuad(localRect)); + continuation->absoluteQuads(quads, topLevel); + } else + quads.append(localToAbsoluteQuad(FloatRect(0, 0, width(), height()))); +} + +IntRect RenderBox::absoluteContentBox() const +{ + IntRect rect = contentBoxRect(); + FloatPoint absPos = localToAbsolute(FloatPoint()); + rect.move(absPos.x(), absPos.y()); + return rect; +} + +FloatQuad RenderBox::absoluteContentQuad() const +{ + IntRect rect = contentBoxRect(); + return localToAbsoluteQuad(FloatRect(rect)); +} + + +IntRect RenderBox::outlineBoundsForRepaint(RenderBox* /*repaintContainer*/) const +{ + IntRect box = borderBoundingBox(); + adjustRectForOutlineAndShadow(box); + + FloatQuad absOutlineQuad = localToAbsoluteQuad(FloatRect(box)); + box = absOutlineQuad.enclosingBoundingBox(); + + // FIXME: layoutDelta needs to be applied in parts before/after transforms and + // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308 + box.move(view()->layoutDelta()); + + return box; +} + +void RenderBox::addFocusRingRects(GraphicsContext* graphicsContext, int tx, int ty) +{ + // For blocks inside inlines, we go ahead and include margins so that we run right up to the + // inline boxes above and below us (thus getting merged with them to form a single irregular + // shape). + RenderFlow* continuation = virtualContinuation(); + if (continuation) { + graphicsContext->addFocusRingRect(IntRect(tx, ty - collapsedMarginTop(), width(), height() + collapsedMarginTop() + collapsedMarginBottom())); + continuation->addFocusRingRects(graphicsContext, + tx - x() + continuation->containingBlock()->x(), + ty - y() + continuation->containingBlock()->y()); + } else + graphicsContext->addFocusRingRect(IntRect(tx, ty, width(), height())); +} + + +IntRect RenderBox::reflectionBox() const +{ + IntRect result; + if (!style()->boxReflect()) + return result; + IntRect box = borderBoxRect(); + result = box; + switch (style()->boxReflect()->direction()) { + case ReflectionBelow: + result.move(0, box.height() + reflectionOffset()); + break; + case ReflectionAbove: + result.move(0, -box.height() - reflectionOffset()); + break; + case ReflectionLeft: + result.move(-box.width() - reflectionOffset(), 0); + break; + case ReflectionRight: + result.move(box.width() + reflectionOffset(), 0); + break; + } + return result; +} + +int RenderBox::reflectionOffset() const +{ + if (!style()->boxReflect()) + return 0; + if (style()->boxReflect()->direction() == ReflectionLeft || style()->boxReflect()->direction() == ReflectionRight) + return style()->boxReflect()->offset().calcValue(borderBoxRect().width()); + return style()->boxReflect()->offset().calcValue(borderBoxRect().height()); +} + +IntRect RenderBox::reflectedRect(const IntRect& r) const +{ + if (!style()->boxReflect()) + return IntRect(); + + IntRect box = borderBoxRect(); + IntRect result = r; + switch (style()->boxReflect()->direction()) { + case ReflectionBelow: + result.setY(box.bottom() + reflectionOffset() + (box.bottom() - r.bottom())); + break; + case ReflectionAbove: + result.setY(box.y() - reflectionOffset() - box.height() + (box.bottom() - r.bottom())); + break; + case ReflectionLeft: + result.setX(box.x() - reflectionOffset() - box.width() + (box.right() - r.right())); + break; + case ReflectionRight: + result.setX(box.right() + reflectionOffset() + (box.right() - r.right())); + break; + } + return result; +} + +int RenderBox::verticalScrollbarWidth() const +{ + return includeVerticalScrollbarSize() ? layer()->verticalScrollbarWidth() : 0; +} + +int RenderBox::horizontalScrollbarHeight() const +{ + return includeHorizontalScrollbarSize() ? layer()->horizontalScrollbarHeight() : 0; +} + +bool RenderBox::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier) +{ + RenderLayer* l = layer(); + if (l && l->scroll(direction, granularity, multiplier)) + return true; + RenderBlock* b = containingBlock(); + if (b && !b->isRenderView()) + return b->scroll(direction, granularity, multiplier); + return false; +} + +bool RenderBox::canBeProgramaticallyScrolled(bool) const +{ + return (hasOverflowClip() && (scrollsOverflow() || (node() && node()->isContentEditable()))) || (node() && node()->isDocumentNode()); +} + +void RenderBox::autoscroll() +{ + if (layer()) + layer()->autoscroll(); +} + +void RenderBox::panScroll(const IntPoint& source) +{ + if (layer()) + layer()->panScrollFromPoint(source); } int RenderBox::minPrefWidth() const @@ -255,22 +663,12 @@ void RenderBox::setOverrideSize(int s) int RenderBox::overrideWidth() const { - return hasOverrideSize() ? overrideSize() : m_width; + return hasOverrideSize() ? overrideSize() : width(); } int RenderBox::overrideHeight() const { - return hasOverrideSize() ? overrideSize() : m_height; -} - -void RenderBox::setPos(int xPos, int yPos) -{ - // Optimize for the case where we don't move at all. - if (xPos == m_x && yPos == m_y) - return; - - m_x = xPos; - m_y = yPos; + return hasOverrideSize() ? overrideSize() : height(); } int RenderBox::calcBorderBoxWidth(int width) const @@ -304,10 +702,10 @@ int RenderBox::calcContentBoxHeight(int height) const } // Hit Testing -bool RenderBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction action) +bool RenderBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int xPos, int yPos, int tx, int ty, HitTestAction action) { - tx += m_x; - ty += m_y; + tx += x(); + ty += y(); // Check kids first. for (RenderObject* child = lastChild(); child; child = child->previousSibling()) { @@ -315,16 +713,16 @@ bool RenderBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result // at the moment (a demoted inline <form> for example). If we ever implement a // table-specific hit-test method (which we should do for performance reasons anyway), // then we can remove this check. - if (!child->hasLayer() && !child->isInlineFlow() && child->nodeAtPoint(request, result, x, y, tx, ty, action)) { - updateHitTestResult(result, IntPoint(x - tx, y - ty)); + if (!child->hasLayer() && !child->isRenderInline() && child->nodeAtPoint(request, result, xPos, yPos, tx, ty, action)) { + updateHitTestResult(result, IntPoint(xPos - tx, yPos - ty)); return true; } } // Check our bounds next. For this purpose always assume that we can only be hit in the // foreground phase (which is true for replaced elements like images). - if (style()->visibility() == VISIBLE && action == HitTestForeground && IntRect(tx, ty, m_width, m_height).contains(x, y)) { - updateHitTestResult(result, IntPoint(x - tx, y - ty)); + if (visibleToHitTesting() && action == HitTestForeground && IntRect(tx, ty, width(), height()).contains(xPos, yPos)) { + updateHitTestResult(result, IntPoint(xPos - tx, yPos - ty)); return true; } @@ -335,8 +733,8 @@ bool RenderBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result void RenderBox::paint(PaintInfo& paintInfo, int tx, int ty) { - tx += m_x; - ty += m_y; + tx += x(); + ty += y(); // default implementation. Just pass paint through to the children PaintInfo childInfo(paintInfo); @@ -402,8 +800,7 @@ void RenderBox::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty) } int w = width(); - int h = height() + borderTopExtra() + borderBottomExtra(); - ty -= borderTopExtra(); + int h = height(); // border-fit can adjust where we paint our border and background. If set, we snugly fit our line box descendants. (The iChat // balloon layout is an example of this). @@ -444,8 +841,7 @@ void RenderBox::paintMask(PaintInfo& paintInfo, int tx, int ty) return; int w = width(); - int h = height() + borderTopExtra() + borderBottomExtra(); - ty -= borderTopExtra(); + int h = height(); // border-fit can adjust where we paint our border and background. If set, we snugly fit our line box descendants. (The iChat // balloon layout is an example of this). @@ -490,7 +886,7 @@ void RenderBox::paintMaskImages(const PaintInfo& paintInfo, int my, int mh, int IntRect RenderBox::maskClipRect() { - IntRect bbox = borderBox(); + IntRect bbox = borderBoxRect(); if (style()->maskBoxImage().image()) return bbox; @@ -562,10 +958,12 @@ IntSize RenderBox::calculateBackgroundSize(const FillLayer* bgLayer, int scaledW return bg->imageSize(this, style()->effectiveZoom()); } -void RenderBox::imageChanged(WrappedImagePtr image) +void RenderBox::imageChanged(WrappedImagePtr image, const IntRect*) { - if (isInlineFlow() || - style()->borderImage().image() && style()->borderImage().image()->data() == image || + if (!parent()) + return; + + if (isRenderInline() || style()->borderImage().image() && style()->borderImage().image()->data() == image || style()->maskBoxImage().image() && style()->maskBoxImage().image()->data() == image) { repaint(); return; @@ -579,7 +977,7 @@ void RenderBox::imageChanged(WrappedImagePtr image) bool RenderBox::repaintLayerRectsForImage(WrappedImagePtr image, const FillLayer* layers, bool drawingBackground) { - IntRect absoluteRect; + IntRect rendererRect; RenderBox* layerRenderer = 0; for (const FillLayer* curLayer = layers; curLayer; curLayer = curLayer->next()) { @@ -601,24 +999,22 @@ bool RenderBox::repaintLayerRectsForImage(WrappedImagePtr image, const FillLayer rw = layerRenderer->width(); rh = layerRenderer->height(); } - absoluteRect = IntRect(-layerRenderer->marginLeft(), + rendererRect = IntRect(-layerRenderer->marginLeft(), -layerRenderer->marginTop(), max(layerRenderer->width() + layerRenderer->marginLeft() + layerRenderer->marginRight() + layerRenderer->borderLeft() + layerRenderer->borderRight(), rw), max(layerRenderer->height() + layerRenderer->marginTop() + layerRenderer->marginBottom() + layerRenderer->borderTop() + layerRenderer->borderBottom(), rh)); } else { layerRenderer = this; - absoluteRect = borderBox(); + rendererRect = borderBoxRect(); } - - layerRenderer->computeAbsoluteRepaintRect(absoluteRect); } IntRect repaintRect; IntPoint phase; IntSize tileSize; - layerRenderer->calculateBackgroundImageGeometry(curLayer, absoluteRect.x(), absoluteRect.y(), absoluteRect.width(), absoluteRect.height(), repaintRect, phase, tileSize); - view()->repaintViewRectangle(repaintRect); - if (repaintRect == absoluteRect) + layerRenderer->calculateBackgroundImageGeometry(curLayer, rendererRect.x(), rendererRect.y(), rendererRect.width(), rendererRect.height(), repaintRect, phase, tileSize); + layerRenderer->repaintRectangle(repaintRect); + if (repaintRect == rendererRect) return true; } } @@ -894,10 +1290,10 @@ void RenderBox::paintCustomHighlight(int tx, int ty, const AtomicString& type, b RootInlineBox* r = boxWrap ? boxWrap->root() : 0; if (r) { FloatRect rootRect(tx + r->xPos(), ty + r->selectionTop(), r->width(), r->selectionHeight()); - FloatRect imageRect(tx + m_x, rootRect.y(), width(), rootRect.height()); + FloatRect imageRect(tx + x(), rootRect.y(), width(), rootRect.height()); page->chrome()->client()->paintCustomHighlight(node(), type, imageRect, rootRect, behindText, false); } else { - FloatRect imageRect(tx + m_x, ty + m_y, width(), height()); + FloatRect imageRect(tx + x(), ty + y(), width(), height()); page->chrome()->client()->paintCustomHighlight(node(), type, imageRect, imageRect, behindText, false); } } @@ -914,8 +1310,8 @@ IntRect RenderBox::getOverflowClipRect(int tx, int ty) int clipX = tx + bLeft; int clipY = ty + bTop; - int clipWidth = m_width - bLeft - borderRight(); - int clipHeight = m_height - bTop - borderBottom() + borderTopExtra() + borderBottomExtra(); + int clipWidth = width() - bLeft - borderRight(); + int clipHeight = height() - bTop - borderBottom(); // Subtract out scrollbars if we have them. if (m_layer) { @@ -930,26 +1326,26 @@ IntRect RenderBox::getClipRect(int tx, int ty) { int clipX = tx; int clipY = ty; - int clipWidth = m_width; - int clipHeight = m_height; + int clipWidth = width(); + int clipHeight = height(); if (!style()->clipLeft().isAuto()) { - int c = style()->clipLeft().calcValue(m_width); + int c = style()->clipLeft().calcValue(width()); clipX += c; clipWidth -= c; } if (!style()->clipRight().isAuto()) - clipWidth -= m_width - style()->clipRight().calcValue(m_width); + clipWidth -= width() - style()->clipRight().calcValue(width()); if (!style()->clipTop().isAuto()) { - int c = style()->clipTop().calcValue(m_height); + int c = style()->clipTop().calcValue(height()); clipY += c; clipHeight -= c; } if (!style()->clipBottom().isAuto()) - clipHeight -= m_height - style()->clipBottom().calcValue(m_height); + clipHeight -= height() - style()->clipBottom().calcValue(height()); return IntRect(clipX, clipY, clipWidth, clipHeight); } @@ -960,13 +1356,13 @@ int RenderBox::containingBlockWidth() const if (!cb) return 0; if (shrinkToAvoidFloats()) - return cb->lineWidth(m_y); + return cb->lineWidth(y()); return cb->availableWidth(); } IntSize RenderBox::offsetForPositionedInContainer(RenderObject* container) const { - if (!container->isRelPositioned() || !container->isInlineFlow()) + if (!container->isRelPositioned() || !container->isRenderInline()) return IntSize(); // When we have an enclosing relpositioned inline, we need to add in the offset of the first line @@ -1001,15 +1397,17 @@ IntSize RenderBox::offsetForPositionedInContainer(RenderObject* container) const return offset; } -bool RenderBox::absolutePosition(int& xPos, int& yPos, bool fixed) const +FloatPoint RenderBox::localToAbsolute(FloatPoint localPoint, bool fixed, bool useTransforms) const { if (RenderView* v = view()) { - if (LayoutState* layoutState = v->layoutState()) { - xPos = layoutState->m_offset.width() + m_x; - yPos = layoutState->m_offset.height() + m_y; + if (v->layoutStateEnabled()) { + LayoutState* layoutState = v->layoutState(); + IntSize offset = layoutState->m_offset; + offset.expand(x(), y()); + localPoint += offset; if (style()->position() == RelativePosition && m_layer) - m_layer->relativePositionOffset(xPos, yPos); - return true; + localPoint += m_layer->relativePositionOffset(); + return localPoint; } } @@ -1017,41 +1415,91 @@ bool RenderBox::absolutePosition(int& xPos, int& yPos, bool fixed) const fixed = true; RenderObject* o = container(); - if (o && o->absolutePositionForContent(xPos, yPos, fixed)) { - if (style()->position() == AbsolutePosition) { - IntSize offset = offsetForPositionedInContainer(o); - xPos += offset.width(); - yPos += offset.height(); + if (o) { + if (useTransforms && m_layer && m_layer->transform()) { + fixed = false; // Elements with transforms act as a containing block for fixed position descendants + localPoint = m_layer->transform()->mapPoint(localPoint); } - if (o->hasOverflowClip()) - o->layer()->subtractScrollOffset(xPos, yPos); - - if (!isInline() || isReplaced()) { - RenderBlock* cb; - if (o->isBlockFlow() && style()->position() != AbsolutePosition && style()->position() != FixedPosition - && (cb = static_cast<RenderBlock*>(o))->hasColumns()) { - IntRect rect(m_x, m_y, 1, 1); - cb->adjustRectForColumns(rect); - xPos += rect.x(); - yPos += rect.y(); - } else { - xPos += m_x; - yPos += m_y; - } - } + localPoint += offsetFromContainer(o); - if (isRelPositioned()) { - xPos += relativePositionOffsetX(); - yPos += relativePositionOffsetY(); + return o->localToAbsolute(localPoint, fixed, useTransforms); + } + + return FloatPoint(); +} + +FloatPoint RenderBox::absoluteToLocal(FloatPoint containerPoint, bool fixed, bool useTransforms) const +{ + // We don't expect absoluteToLocal() to be called during layout (yet) + ASSERT(!view() || !view()->layoutStateEnabled()); + + if (style()->position() == FixedPosition) + fixed = true; + + if (useTransforms && m_layer && m_layer->transform()) + fixed = false; + + RenderObject* o = container(); + if (o) { + FloatPoint localPoint = o->absoluteToLocal(containerPoint, fixed, useTransforms); + localPoint -= offsetFromContainer(o); + if (useTransforms && m_layer && m_layer->transform()) + localPoint = m_layer->transform()->inverse().mapPoint(localPoint); + return localPoint; + } + + return FloatPoint(); +} + +FloatQuad RenderBox::localToContainerQuad(const FloatQuad& localQuad, RenderBox* repaintContainer, bool fixed) const +{ + if (repaintContainer == this) + return localQuad; + + if (style()->position() == FixedPosition) + fixed = true; + + RenderObject* o = container(); + if (o) { + FloatQuad quad = localQuad; + if (m_layer && m_layer->transform()) { + fixed = false; // Elements with transforms act as a containing block for fixed position descendants + quad = m_layer->transform()->mapQuad(quad); } + quad += offsetFromContainer(o); + return o->localToContainerQuad(quad, repaintContainer, fixed); + } + + return FloatQuad(); +} - return true; - } else { - xPos = 0; - yPos = 0; - return false; +IntSize RenderBox::offsetFromContainer(RenderObject* o) const +{ + ASSERT(o == container()); + + IntSize offset; + if (isRelPositioned()) + offset += relativePositionOffset(); + + if (!isInline() || isReplaced()) { + RenderBlock* cb; + if (o->isBlockFlow() && style()->position() != AbsolutePosition && style()->position() != FixedPosition + && (cb = static_cast<RenderBlock*>(o))->hasColumns()) { + IntRect rect(x(), y(), 1, 1); + cb->adjustRectForColumns(rect); + offset.expand(rect.x(), rect.y()); + } else + offset.expand(x(), y()); } + + if (o->hasOverflowClip()) + offset -= toRenderBox(o)->layer()->scrolledContentOffset(); + + if (style()->position() == AbsolutePosition) + offset += offsetForPositionedInContainer(o); + + return offset; } void RenderBox::dirtyLineBoxes(bool fullLayout, bool /*isRootLineBox*/) @@ -1089,8 +1537,7 @@ void RenderBox::position(InlineBox* box) box->remove(); box->destroy(renderArena()); } else if (isReplaced()) { - m_x = box->xPos(); - m_y = box->yPos(); + setLocation(box->xPos(), box->yPos()); m_inlineBoxWrapper = box; } } @@ -1105,42 +1552,46 @@ void RenderBox::deleteLineBoxWrapper() } } -IntRect RenderBox::absoluteClippedOverflowRect() +IntRect RenderBox::clippedOverflowRectForRepaint(RenderBox* repaintContainer) { if (style()->visibility() != VISIBLE && !enclosingLayer()->hasVisibleContent()) return IntRect(); IntRect r = overflowRect(false); - if (RenderView* v = view()) + RenderView* v = view(); + if (v) { + // FIXME: layoutDelta needs to be applied in parts before/after transforms and + // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308 r.move(v->layoutDelta()); - + } + if (style()) { if (style()->hasAppearance()) // The theme may wish to inflate the rect used when repainting. theme()->adjustRepaintRect(this, r); - // FIXME: Technically the outline inflation could fit within the theme inflation. - if (!isInline() && continuation()) - r.inflate(continuation()->style()->outlineSize()); - else - r.inflate(style()->outlineSize()); + // We have to use maximalOutlineSize() because a child might have an outline + // that projects outside of our overflowRect. + if (v) { + ASSERT(style()->outlineSize() <= v->maximalOutlineSize()); + r.inflate(v->maximalOutlineSize()); + } } - computeAbsoluteRepaintRect(r); + computeRectForRepaint(r, repaintContainer); return r; } -void RenderBox::computeAbsoluteRepaintRect(IntRect& rect, bool fixed) +void RenderBox::computeRectForRepaint(IntRect& rect, RenderBox* repaintContainer, bool fixed) { if (RenderView* v = view()) { - if (LayoutState* layoutState = v->layoutState()) { - if (style()->position() == RelativePosition && m_layer) { - int relX = 0; - int relY = 0; - m_layer->relativePositionOffset(relX, relY); - rect.move(relX, relY); - } - rect.move(m_x, m_y); + // LayoutState is only valid for root-relative repainting + if (v->layoutStateEnabled() && !repaintContainer) { + LayoutState* layoutState = v->layoutState(); + if (style()->position() == RelativePosition && m_layer) + rect.move(m_layer->relativePositionOffset()); + + rect.move(x(), y()); rect.move(layoutState->m_offset); if (layoutState->m_clipped) rect.intersect(layoutState->m_clipRect); @@ -1148,97 +1599,86 @@ void RenderBox::computeAbsoluteRepaintRect(IntRect& rect, bool fixed) } } - // FIXME: This is really a hack. If the reflection caused the repaint, we don't have to - // do this (and yet we do). If there are nested reflections, then the single static is insufficient. - static bool invalidatingReflection; - if (hasReflection() && !invalidatingReflection) { - invalidatingReflection = true; - layer()->reflection()->repaintRectangle(rect); - invalidatingReflection = false; - } + if (hasReflection()) + rect.unite(reflectedRect(rect)); + + if (repaintContainer == this) + return; - int x = rect.x() + m_x; - int y = rect.y() + m_y; + RenderObject* o = container(); + if (!o) + return; - // Apply the relative position offset when invalidating a rectangle. The layer - // is translated, but the render box isn't, so we need to do this to get the - // right dirty rect. Since this is called from RenderObject::setStyle, the relative position - // flag on the RenderObject has been cleared, so use the one on the style(). - if (style()->position() == RelativePosition && m_layer) - m_layer->relativePositionOffset(x, y); + IntPoint topLeft = rect.location(); + topLeft.move(x(), y()); if (style()->position() == FixedPosition) fixed = true; - - RenderObject* o = container(); - if (o) { - if (o->isBlockFlow() && style()->position() != AbsolutePosition && style()->position() != FixedPosition) { - RenderBlock* cb = static_cast<RenderBlock*>(o); - if (cb->hasColumns()) { - IntRect repaintRect(x, y, rect.width(), rect.height()); - cb->adjustRectForColumns(repaintRect); - x = repaintRect.x(); - y = repaintRect.y(); - rect = repaintRect; - } - } - if (style()->position() == AbsolutePosition) { - IntSize offset = offsetForPositionedInContainer(o); - x += offset.width(); - y += offset.height(); - } - - // We are now in our parent container's coordinate space. Apply our transform to obtain a bounding box - // in the parent's coordinate space that encloses us. - if (m_layer && m_layer->transform()) { - fixed = false; - rect = m_layer->transform()->mapRect(rect); - x = rect.x() + m_x; - y = rect.y() + m_y; + if (o->isBlockFlow() && style()->position() != AbsolutePosition && style()->position() != FixedPosition) { + RenderBlock* cb = static_cast<RenderBlock*>(o); + if (cb->hasColumns()) { + IntRect repaintRect(topLeft, rect.size()); + cb->adjustRectForColumns(repaintRect); + topLeft = repaintRect.location(); + rect = repaintRect; } + } - // FIXME: We ignore the lightweight clipping rect that controls use, since if |o| is in mid-layout, - // its controlClipRect will be wrong. For overflow clip we use the values cached by the layer. - if (o->hasOverflowClip()) { - // o->height() is inaccurate if we're in the middle of a layout of |o|, so use the - // layer's size instead. Even if the layer's size is wrong, the layer itself will repaint - // anyway if its size does change. - IntRect boxRect(0, 0, o->layer()->width(), o->layer()->height()); - o->layer()->subtractScrollOffset(x, y); // For overflow:auto/scroll/hidden. - IntRect repaintRect(x, y, rect.width(), rect.height()); - rect = intersection(repaintRect, boxRect); - if (rect.isEmpty()) - return; - } else { - rect.setX(x); - rect.setY(y); - } - - o->computeAbsoluteRepaintRect(rect, fixed); + // We are now in our parent container's coordinate space. Apply our transform to obtain a bounding box + // in the parent's coordinate space that encloses us. + if (m_layer && m_layer->transform()) { + fixed = false; + rect = m_layer->transform()->mapRect(rect); + // FIXME: this clobbers topLeft adjustment done for multicol above + topLeft = rect.location(); + topLeft.move(x(), y()); + } + + if (style()->position() == AbsolutePosition) + topLeft += offsetForPositionedInContainer(o); + else if (style()->position() == RelativePosition && m_layer) { + // Apply the relative position offset when invalidating a rectangle. The layer + // is translated, but the render box isn't, so we need to do this to get the + // right dirty rect. Since this is called from RenderObject::setStyle, the relative position + // flag on the RenderObject has been cleared, so use the one on the style(). + topLeft += m_layer->relativePositionOffset(); } + + // FIXME: We ignore the lightweight clipping rect that controls use, since if |o| is in mid-layout, + // its controlClipRect will be wrong. For overflow clip we use the values cached by the layer. + if (o->hasOverflowClip()) { + RenderBox* containerBox = toRenderBox(o); + + // o->height() is inaccurate if we're in the middle of a layout of |o|, so use the + // layer's size instead. Even if the layer's size is wrong, the layer itself will repaint + // anyway if its size does change. + topLeft -= containerBox->layer()->scrolledContentOffset(); // For overflow:auto/scroll/hidden. + + IntRect repaintRect(topLeft, rect.size()); + IntRect boxRect(0, 0, containerBox->layer()->width(), containerBox->layer()->height()); + rect = intersection(repaintRect, boxRect); + if (rect.isEmpty()) + return; + } else + rect.setLocation(topLeft); + + o->computeRectForRepaint(rect, repaintContainer, fixed); } void RenderBox::repaintDuringLayoutIfMoved(const IntRect& rect) { - int newX = m_x; - int newY = m_y; - int newWidth = m_width; - int newHeight = m_height; + int newX = x(); + int newY = y(); + int newWidth = width(); + int newHeight = height(); if (rect.x() != newX || rect.y() != newY) { // The child moved. Invalidate the object's old and new positions. We have to do this // since the object may not have gotten a layout. - m_x = rect.x(); - m_y = rect.y(); - m_width = rect.width(); - m_height = rect.height(); + m_frameRect = rect; repaint(); repaintOverhangingFloats(true); - - m_x = newX; - m_y = newY; - m_width = newWidth; - m_height = newHeight; + m_frameRect = IntRect(newX, newY, newWidth, newHeight); repaint(); repaintOverhangingFloats(true); } @@ -1293,7 +1733,7 @@ void RenderBox::calcWidth() // width. Use the width from the style context. if (hasOverrideSize() && parent()->style()->boxOrient() == HORIZONTAL && parent()->isFlexibleBox() && parent()->isFlexingChildren()) { - m_width = overrideSize(); + setWidth(overrideSize()); return; } @@ -1301,7 +1741,7 @@ void RenderBox::calcWidth() bool stretching = (parent()->style()->boxAlign() == BSTRETCH); bool treatAsReplaced = shouldCalculateSizeAsReplaced() && (!inVerticalBox || !stretching); - Length width = (treatAsReplaced) ? Length(calcReplacedWidth(), Fixed) : style()->width(); + Length w = (treatAsReplaced) ? Length(calcReplacedWidth(), Fixed) : style()->width(); RenderBlock* cb = containingBlock(); int containerWidth = max(0, containingBlockWidth()); @@ -1313,52 +1753,57 @@ void RenderBox::calcWidth() // just calculate margins m_marginLeft = marginLeft.calcMinValue(containerWidth); m_marginRight = marginRight.calcMinValue(containerWidth); +#ifdef ANDROID_LAYOUT + if (treatAsReplaced) { +#else if (treatAsReplaced) - m_width = max(width.value() + borderLeft() + borderRight() + paddingLeft() + paddingRight(), minPrefWidth()); +#endif + setWidth(max(w.value() + borderLeft() + borderRight() + paddingLeft() + paddingRight(), minPrefWidth())); #ifdef ANDROID_LAYOUT - // in SSR mode with replaced box, if the box width is wider than the container width, - // it will be shrinked to fit to the container. - if (containerWidth && (m_width+m_marginLeft+m_marginRight) > containerWidth && - document()->frame()->settings()->layoutAlgorithm() == Settings::kLayoutSSR) { - m_marginLeft = m_marginRight = 0; - m_width = m_minPrefWidth = m_maxPrefWidth = containerWidth; + // in SSR mode with replaced box, if the box width is wider than the container width, + // it will be shrinked to fit to the container. + if (containerWidth && (width() + m_marginLeft + m_marginRight) > containerWidth && + document()->frame()->settings()->layoutAlgorithm() == Settings::kLayoutSSR) { + m_marginLeft = m_marginRight = 0; + setWidth(containerWidth); + m_minPrefWidth = m_maxPrefWidth = containerWidth; + } } -#endif - +#endif return; } // Width calculations if (treatAsReplaced) - m_width = width.value() + borderLeft() + borderRight() + paddingLeft() + paddingRight(); + setWidth(w.value() + borderLeft() + borderRight() + paddingLeft() + paddingRight()); else { // Calculate Width - m_width = calcWidthUsing(Width, containerWidth); + setWidth(calcWidthUsing(Width, containerWidth)); // Calculate MaxWidth if (!style()->maxWidth().isUndefined()) { int maxW = calcWidthUsing(MaxWidth, containerWidth); - if (m_width > maxW) { - m_width = maxW; - width = style()->maxWidth(); + if (width() > maxW) { + setWidth(maxW); + w = style()->maxWidth(); } } // Calculate MinWidth int minW = calcWidthUsing(MinWidth, containerWidth); - if (m_width < minW) { - m_width = minW; - width = style()->minWidth(); + if (width() < minW) { + setWidth(minW); + w = style()->minWidth(); } } if (stretchesToMinIntrinsicWidth()) { - m_width = max(m_width, minPrefWidth()); - width = Length(m_width, Fixed); + setWidth(max(width(), minPrefWidth())); + w = Length(width(), Fixed); } // Margin calculations - if (width.isAuto()) { + if (w.isAuto()) { m_marginLeft = marginLeft.calcMinValue(containerWidth); m_marginRight = marginRight.calcMinValue(containerWidth); } else { @@ -1371,28 +1816,29 @@ void RenderBox::calcWidth() // If the box width is wider than the container width, it will be shrinked to fit to the container. if (containerWidth && !treatAsReplaced && document()->settings()->layoutAlgorithm() == Settings::kLayoutSSR) { - m_width += m_marginLeft + m_marginRight; + setWidth(width() + m_marginLeft + m_marginRight); m_marginLeft = m_marginLeft > ANDROID_SSR_MARGIN_PADDING ? ANDROID_SSR_MARGIN_PADDING : m_marginLeft; m_marginRight = m_marginRight > ANDROID_SSR_MARGIN_PADDING ? ANDROID_SSR_MARGIN_PADDING : m_marginRight; - if (m_width > containerWidth) - m_width = m_minPrefWidth = m_maxPrefWidth = containerWidth-(m_marginLeft + m_marginRight); - else - m_width -= (m_marginLeft + m_marginRight); + if (width() > containerWidth) { + m_minPrefWidth = m_maxPrefWidth = containerWidth-(m_marginLeft + m_marginRight); + setWidth(m_minPrefWidth); + } else + setWidth(width() -(m_marginLeft + m_marginRight)); } #endif - if (containerWidth && containerWidth != (m_width + m_marginLeft + m_marginRight) + if (containerWidth && containerWidth != (width() + m_marginLeft + m_marginRight) && !isFloating() && !isInline() && !cb->isFlexibleBox()) { if (cb->style()->direction() == LTR) - m_marginRight = containerWidth - m_width - m_marginLeft; + m_marginRight = containerWidth - width() - m_marginLeft; else - m_marginLeft = containerWidth - m_width - m_marginRight; + m_marginLeft = containerWidth - width() - m_marginRight; } } int RenderBox::calcWidthUsing(WidthType widthType, int cw) { - int width = m_width; + int widthResult = width(); Length w; if (widthType == Width) w = style()->width(); @@ -1405,24 +1851,23 @@ int RenderBox::calcWidthUsing(WidthType widthType, int cw) int marginLeft = style()->marginLeft().calcMinValue(cw); int marginRight = style()->marginRight().calcMinValue(cw); if (cw) - width = cw - marginLeft - marginRight; + widthResult = cw - marginLeft - marginRight; if (sizesToIntrinsicWidth(widthType)) { - width = max(width, minPrefWidth()); - width = min(width, maxPrefWidth()); + widthResult = max(widthResult, minPrefWidth()); + widthResult = min(widthResult, maxPrefWidth()); } } else - width = calcBorderBoxWidth(w.calcValue(cw)); + widthResult = calcBorderBoxWidth(w.calcValue(cw)); - return width; + return widthResult; } bool RenderBox::sizesToIntrinsicWidth(WidthType widthType) const { // Marquees in WinIE are like a mixture of blocks and inline-blocks. They size as though they're blocks, // but they allow text to sit on the same line as the marquee. - if (isFloating() || (isCompact() && isInline()) - || (isInlineBlockOrInlineTable() && !isHTMLMarquee())) + if (isFloating() || (isInlineBlockOrInlineTable() && !isHTMLMarquee())) return true; // This code may look a bit strange. Basically width:intrinsic should clamp the size when testing both @@ -1457,20 +1902,20 @@ void RenderBox::calcHorizontalMargins(const Length& marginLeft, const Length& ma return; } - if ((marginLeft.isAuto() && marginRight.isAuto() && m_width < containerWidth) + if ((marginLeft.isAuto() && marginRight.isAuto() && width() < containerWidth) || (!marginLeft.isAuto() && !marginRight.isAuto() && containingBlock()->style()->textAlign() == WEBKIT_CENTER)) { - m_marginLeft = max(0, (containerWidth - m_width) / 2); - m_marginRight = containerWidth - m_width - m_marginLeft; - } else if ((marginRight.isAuto() && m_width < containerWidth) + m_marginLeft = max(0, (containerWidth - width()) / 2); + m_marginRight = containerWidth - width() - m_marginLeft; + } else if ((marginRight.isAuto() && width() < containerWidth) || (!marginLeft.isAuto() && containingBlock()->style()->direction() == RTL && containingBlock()->style()->textAlign() == WEBKIT_LEFT)) { m_marginLeft = marginLeft.calcValue(containerWidth); - m_marginRight = containerWidth - m_width - m_marginLeft; - } else if ((marginLeft.isAuto() && m_width < containerWidth) + m_marginRight = containerWidth - width() - m_marginLeft; + } else if ((marginLeft.isAuto() && width() < containerWidth) || (!marginRight.isAuto() && containingBlock()->style()->direction() == LTR && containingBlock()->style()->textAlign() == WEBKIT_RIGHT)) { m_marginRight = marginRight.calcValue(containerWidth); - m_marginLeft = containerWidth - m_width - m_marginRight; + m_marginLeft = containerWidth - width() - m_marginRight; } else { - // This makes auto margins 0 if we failed a m_width < containerWidth test above (css2.1, 10.3.3). + // This makes auto margins 0 if we failed a width() < containerWidth test above (css2.1, 10.3.3). m_marginLeft = marginLeft.calcMinValue(containerWidth); m_marginRight = marginRight.calcMinValue(containerWidth); } @@ -1512,36 +1957,36 @@ void RenderBox::calcHeight() // Block children of horizontal flexible boxes fill the height of the box. if (h.isAuto() && parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL && parent()->isStretchingChildren()) { - h = Length(parent()->contentHeight() - marginTop() - marginBottom() - + h = Length(parentBox()->contentHeight() - marginTop() - marginBottom() - borderTop() - paddingTop() - borderBottom() - paddingBottom(), Fixed); checkMinMaxHeight = false; } - int height; + int heightResult; if (checkMinMaxHeight) { #ifdef ANDROID_LAYOUT // in SSR mode, ignore CSS height as layout is so different if (document()->settings()->layoutAlgorithm() == Settings::kLayoutSSR) - height = m_height; + heightResult = -1; else #endif - height = calcHeightUsing(style()->height()); - if (height == -1) - height = m_height; + heightResult = calcHeightUsing(style()->height()); + if (heightResult == -1) + heightResult = height(); int minH = calcHeightUsing(style()->minHeight()); // Leave as -1 if unset. - int maxH = style()->maxHeight().isUndefined() ? height : calcHeightUsing(style()->maxHeight()); + int maxH = style()->maxHeight().isUndefined() ? heightResult : calcHeightUsing(style()->maxHeight()); if (maxH == -1) - maxH = height; - height = min(maxH, height); - height = max(minH, height); + maxH = heightResult; + heightResult = min(maxH, heightResult); + heightResult = max(minH, heightResult); } else // The only times we don't check min/max height are when a fixed length has // been given as an override. Just use that. The value has already been adjusted // for box-sizing. - height = h.value() + borderTop() + borderBottom() + paddingTop() + paddingBottom(); + heightResult = h.value() + borderTop() + borderBottom() + paddingTop() + paddingBottom(); - m_height = height; - } + setHeight(heightResult); + } // WinIE quirk: The <html> block always fills the entire canvas in quirks mode. The <body> always fills the // <html> block in quirks mode. Only apply this quirk if the block is normal flow and no height @@ -1550,12 +1995,12 @@ void RenderBox::calcHeight() int margins = collapsedMarginTop() + collapsedMarginBottom(); int visHeight = view()->viewHeight(); if (isRoot()) - m_height = max(m_height, visHeight - margins); + setHeight(max(height(), visHeight - margins)); else { - int marginsBordersPadding = margins + parent()->marginTop() + parent()->marginBottom() - + parent()->borderTop() + parent()->borderBottom() - + parent()->paddingTop() + parent()->paddingBottom(); - m_height = max(m_height, visHeight - marginsBordersPadding); + int marginsBordersPadding = margins + parentBox()->marginTop() + parentBox()->marginBottom() + + parentBox()->borderTop() + parentBox()->borderBottom() + + parentBox()->paddingTop() + parentBox()->paddingBottom(); + setHeight(max(height(), visHeight - marginsBordersPadding)); } } } @@ -1626,7 +2071,7 @@ int RenderBox::calcPercentageHeight(const Length& height) if (result != -1) result = cb->calcContentBoxHeight(result); } else if (cb->isRenderView() || (cb->isBody() && style()->htmlHacks()) || isPositionedWithSpecifiedHeight) { - // Don't allow this to affect the block' m_height member variable, since this + // Don't allow this to affect the block' height() member variable, since this // can get called while the block is still laying out its kids. int oldHeight = cb->height(); cb->calcHeight(); @@ -1707,7 +2152,7 @@ int RenderBox::calcReplacedHeightUsing(Length height) const return calcContentBoxHeight(height.calcValue(newHeight)); } - int availableHeight = isPositioned() ? containingBlockHeightForPositioned(cb) : cb->availableHeight(); + int availableHeight = isPositioned() ? containingBlockHeightForPositioned(cb) : toRenderBox(cb)->availableHeight(); // It is necessary to use the border-box to match WinIE's broken // box model. This is essential for sizing inside @@ -1806,7 +2251,7 @@ void RenderBox::setStaticY(int staticY) int RenderBox::containingBlockWidthForPositioned(const RenderObject* containingBlock) const { - if (containingBlock->isInlineFlow()) { + if (containingBlock->isRenderInline()) { ASSERT(containingBlock->isRelPositioned()); const RenderFlow* flow = static_cast<const RenderFlow*>(containingBlock); @@ -1830,12 +2275,22 @@ int RenderBox::containingBlockWidthForPositioned(const RenderObject* containingB return max(0, (fromRight - fromLeft)); } - return containingBlock->width() - containingBlock->borderLeft() - containingBlock->borderRight() - containingBlock->verticalScrollbarWidth(); + const RenderBox* containingBlockBox = toRenderBox(containingBlock); + return containingBlockBox->width() - containingBlockBox->borderLeft() - containingBlockBox->borderRight() - containingBlockBox->verticalScrollbarWidth(); } int RenderBox::containingBlockHeightForPositioned(const RenderObject* containingBlock) const { - return containingBlock->height() - containingBlock->borderTop() - containingBlock->borderBottom(); + const RenderBox* containingBlockBox = toRenderBox(containingBlock); + + int heightResult; + if (containingBlock->isRenderInline()) { + ASSERT(containingBlock->isRelPositioned()); + heightResult = static_cast<const RenderInline*>(containingBlock)->linesBoundingBox().height(); + } else + heightResult = containingBlockBox->height(); + + return heightResult - containingBlockBox->borderTop() - containingBlockBox->borderBottom(); } void RenderBox::calcAbsoluteHorizontal() @@ -1860,7 +2315,7 @@ void RenderBox::calcAbsoluteHorizontal() // NOTE: 'static' is not a legal value for 'left' or 'right' as of CSS 2.1. // FIXME 3: Can perhaps optimize out cases when max-width/min-width are greater - // than or less than the computed m_width. Be careful of box-sizing and + // than or less than the computed width(). Be careful of box-sizing and // percentage issues. // The following is based off of the W3C Working Draft from April 11, 2006 of @@ -1872,8 +2327,8 @@ void RenderBox::calcAbsoluteHorizontal() // We don't use containingBlock(), since we may be positioned by an enclosing // relative positioned inline. - const RenderObject* containerBlock = container(); - + const RenderBox* containerBlock = toRenderBox(container()); + const int containerWidth = containingBlockWidthForPositioned(containerBlock); // To match WinIE, in quirks mode use the parent's 'direction' property @@ -1916,24 +2371,28 @@ void RenderBox::calcAbsoluteHorizontal() if (containerDirection == LTR) { // 'staticX' should already have been set through layout of the parent. int staticPosition = staticX() - containerBlock->borderLeft(); - for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent()) - staticPosition += po->xPos(); + for (RenderBox* po = parentBox(); po && po != containerBlock; po = po->parentBox()) + staticPosition += po->x(); left.setValue(Fixed, staticPosition); } else { - RenderObject* po = parent(); + RenderBox* po = parentBox(); // 'staticX' should already have been set through layout of the parent. int staticPosition = staticX() + containerWidth + containerBlock->borderRight() - po->width(); - for (; po && po != containerBlock; po = po->parent()) - staticPosition -= po->xPos(); + for (; po && po != containerBlock; po = po->parentBox()) + staticPosition -= po->x(); right.setValue(Fixed, staticPosition); } } // Calculate constraint equation values for 'width' case. + int widthResult; + int xResult; calcAbsoluteHorizontalValues(style()->width(), containerBlock, containerDirection, containerWidth, bordersPlusPadding, left, right, marginLeft, marginRight, - m_width, m_marginLeft, m_marginRight, m_x); + widthResult, m_marginLeft, m_marginRight, xResult); + setWidth(widthResult); + setX(xResult); // Calculate constraint equation values for 'max-width' case. if (!style()->maxWidth().isUndefined()) { @@ -1947,11 +2406,11 @@ void RenderBox::calcAbsoluteHorizontal() left, right, marginLeft, marginRight, maxWidth, maxMarginLeft, maxMarginRight, maxXPos); - if (m_width > maxWidth) { - m_width = maxWidth; + if (width() > maxWidth) { + setWidth(maxWidth); m_marginLeft = maxMarginLeft; m_marginRight = maxMarginRight; - m_x = maxXPos; + m_frameRect.setX(maxXPos); } } @@ -1967,25 +2426,28 @@ void RenderBox::calcAbsoluteHorizontal() left, right, marginLeft, marginRight, minWidth, minMarginLeft, minMarginRight, minXPos); - if (m_width < minWidth) { - m_width = minWidth; + if (width() < minWidth) { + setWidth(minWidth); m_marginLeft = minMarginLeft; m_marginRight = minMarginRight; - m_x = minXPos; + m_frameRect.setX(minXPos); } } - if (stretchesToMinIntrinsicWidth() && m_width < minPrefWidth() - bordersPlusPadding) + if (stretchesToMinIntrinsicWidth() && width() < minPrefWidth() - bordersPlusPadding) { calcAbsoluteHorizontalValues(Length(minPrefWidth() - bordersPlusPadding, Fixed), containerBlock, containerDirection, containerWidth, bordersPlusPadding, left, right, marginLeft, marginRight, - m_width, m_marginLeft, m_marginRight, m_x); + widthResult, m_marginLeft, m_marginRight, xResult); + setWidth(widthResult); + setX(xResult); + } - // Put m_width into correct form. - m_width += bordersPlusPadding; + // Put width() into correct form. + setWidth(width() + bordersPlusPadding); } -void RenderBox::calcAbsoluteHorizontalValues(Length width, const RenderObject* containerBlock, TextDirection containerDirection, +void RenderBox::calcAbsoluteHorizontalValues(Length width, const RenderBox* containerBlock, TextDirection containerDirection, const int containerWidth, const int bordersPlusPadding, const Length left, const Length right, const Length marginLeft, const Length marginRight, int& widthValue, int& marginLeftValue, int& marginRightValue, int& xPos) @@ -2172,7 +2634,7 @@ void RenderBox::calcAbsoluteVertical() // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline. - const RenderObject* containerBlock = container(); + const RenderBox* containerBlock = toRenderBox(container()); const int containerHeight = containingBlockHeightForPositioned(containerBlock); @@ -2204,20 +2666,22 @@ void RenderBox::calcAbsoluteVertical() if (top.isAuto() && bottom.isAuto()) { // staticY should already have been set through layout of the parent() int staticTop = staticY() - containerBlock->borderTop(); - for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent()) { + for (RenderBox* po = parentBox(); po && po != containerBlock; po = po->parentBox()) { if (!po->isTableRow()) - staticTop += po->yPos(); + staticTop += po->y(); } top.setValue(Fixed, staticTop); } - int height; // Needed to compute overflow. + int h; // Needed to compute overflow. + int y; // Calculate constraint equation values for 'height' case. calcAbsoluteVerticalValues(style()->height(), containerBlock, containerHeight, bordersPlusPadding, top, bottom, marginTop, marginBottom, - height, m_marginTop, m_marginBottom, m_y); + h, m_marginTop, m_marginBottom, y); + setY(y); // Avoid doing any work in the common case (where the values of min-height and max-height are their defaults). // see FIXME 3 @@ -2233,11 +2697,11 @@ void RenderBox::calcAbsoluteVertical() top, bottom, marginTop, marginBottom, maxHeight, maxMarginTop, maxMarginBottom, maxYPos); - if (height > maxHeight) { - height = maxHeight; + if (h > maxHeight) { + h = maxHeight; m_marginTop = maxMarginTop; m_marginBottom = maxMarginBottom; - m_y = maxYPos; + m_frameRect.setY(maxYPos); } } @@ -2252,19 +2716,19 @@ void RenderBox::calcAbsoluteVertical() top, bottom, marginTop, marginBottom, minHeight, minMarginTop, minMarginBottom, minYPos); - if (height < minHeight) { - height = minHeight; + if (h < minHeight) { + h = minHeight; m_marginTop = minMarginTop; m_marginBottom = minMarginBottom; - m_y = minYPos; + m_frameRect.setY(minYPos); } } // Set final height value. - m_height = height + bordersPlusPadding; + setHeight(h + bordersPlusPadding); } -void RenderBox::calcAbsoluteVerticalValues(Length height, const RenderObject* containerBlock, +void RenderBox::calcAbsoluteVerticalValues(Length h, const RenderBox* containerBlock, const int containerHeight, const int bordersPlusPadding, const Length top, const Length bottom, const Length marginTop, const Length marginBottom, int& heightValue, int& marginTopValue, int& marginBottomValue, int& yPos) @@ -2273,17 +2737,17 @@ void RenderBox::calcAbsoluteVerticalValues(Length height, const RenderObject* co // converted to the static position in calcAbsoluteVertical() ASSERT(!(top.isAuto() && bottom.isAuto())); - int contentHeight = m_height - bordersPlusPadding; + int contentHeight = height() - bordersPlusPadding; int topValue = 0; - bool heightIsAuto = height.isAuto(); + bool heightIsAuto = h.isAuto(); bool topIsAuto = top.isAuto(); bool bottomIsAuto = bottom.isAuto(); // Height is never unsolved for tables. if (isTable()) { - height.setValue(Fixed, contentHeight); + h.setValue(Fixed, contentHeight); heightIsAuto = false; } @@ -2299,7 +2763,7 @@ void RenderBox::calcAbsoluteVerticalValues(Length height, const RenderObject* co // NOTE: It is not necessary to solve for 'bottom' in the over constrained // case because the value is not used for any further calculations. - heightValue = calcContentBoxHeight(height.calcValue(containerHeight)); + heightValue = calcContentBoxHeight(h.calcValue(containerHeight)); topValue = top.calcValue(containerHeight); const int availableSpace = containerHeight - (topValue + heightValue + bottom.calcValue(containerHeight) + bordersPlusPadding); @@ -2366,7 +2830,7 @@ void RenderBox::calcAbsoluteVerticalValues(Length height, const RenderObject* co heightValue = contentHeight; } else if (topIsAuto && !heightIsAuto && !bottomIsAuto) { // RULE 4: (solve of top) - heightValue = calcContentBoxHeight(height.calcValue(containerHeight)); + heightValue = calcContentBoxHeight(h.calcValue(containerHeight)); topValue = availableSpace - (heightValue + bottom.calcValue(containerHeight)); } else if (!topIsAuto && heightIsAuto && !bottomIsAuto) { // RULE 5: (solve of height) @@ -2374,7 +2838,7 @@ void RenderBox::calcAbsoluteVerticalValues(Length height, const RenderObject* co heightValue = max(0, availableSpace - (topValue + bottom.calcValue(containerHeight))); } else if (!topIsAuto && !heightIsAuto && bottomIsAuto) { // RULE 6: (no need solve of bottom) - heightValue = calcContentBoxHeight(height.calcValue(containerHeight)); + heightValue = calcContentBoxHeight(h.calcValue(containerHeight)); topValue = top.calcValue(containerHeight); } } @@ -2393,7 +2857,7 @@ void RenderBox::calcAbsoluteHorizontalReplaced() // We don't use containingBlock(), since we may be positioned by an enclosing // relative positioned inline. - const RenderObject* containerBlock = container(); + const RenderBox* containerBlock = toRenderBox(container()); const int containerWidth = containingBlockWidthForPositioned(containerBlock); @@ -2415,8 +2879,8 @@ void RenderBox::calcAbsoluteHorizontalReplaced() // NOTE: This value of width is FINAL in that the min/max width calculations // are dealt with in calcReplacedWidth(). This means that the steps to produce // correct max/min in the non-replaced version, are not necessary. - m_width = calcReplacedWidth() + borderLeft() + borderRight() + paddingLeft() + paddingRight(); - const int availableSpace = containerWidth - m_width; + setWidth(calcReplacedWidth() + borderLeft() + borderRight() + paddingLeft() + paddingRight()); + const int availableSpace = containerWidth - width(); /*-----------------------------------------------------------------------*\ * 2. If both 'left' and 'right' have the value 'auto', then if 'direction' @@ -2429,15 +2893,15 @@ void RenderBox::calcAbsoluteHorizontalReplaced() if (containerDirection == LTR) { // 'staticX' should already have been set through layout of the parent. int staticPosition = staticX() - containerBlock->borderLeft(); - for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent()) - staticPosition += po->xPos(); + for (RenderBox* po = parentBox(); po && po != containerBlock; po = po->parentBox()) + staticPosition += po->x(); left.setValue(Fixed, staticPosition); } else { - RenderObject* po = parent(); + RenderBox* po = parentBox(); // 'staticX' should already have been set through layout of the parent. int staticPosition = staticX() + containerWidth + containerBlock->borderRight() - po->width(); - for (; po && po != containerBlock; po = po->parent()) - staticPosition -= po->xPos(); + for (; po && po != containerBlock; po = po->parentBox()) + staticPosition -= po->x(); right.setValue(Fixed, staticPosition); } } @@ -2534,7 +2998,7 @@ void RenderBox::calcAbsoluteHorizontalReplaced() \*-----------------------------------------------------------------------*/ // NOTE: It is not necessary to solve for 'right' when the direction is // LTR because the value is not used. - int totalWidth = m_width + leftValue + rightValue + m_marginLeft + m_marginRight; + int totalWidth = width() + leftValue + rightValue + m_marginLeft + m_marginRight; if (totalWidth > containerWidth && (containerDirection == RTL)) leftValue = containerWidth - (totalWidth - leftValue); @@ -2549,12 +3013,12 @@ void RenderBox::calcAbsoluteHorizontalReplaced() InlineFlowBox* firstLine = flow->firstLineBox(); InlineFlowBox* lastLine = flow->lastLineBox(); if (firstLine && lastLine && firstLine != lastLine) { - m_x = leftValue + m_marginLeft + lastLine->borderLeft() + (lastLine->xPos() - firstLine->xPos()); + m_frameRect.setX(leftValue + m_marginLeft + lastLine->borderLeft() + (lastLine->xPos() - firstLine->xPos())); return; } } - m_x = leftValue + m_marginLeft + containerBlock->borderLeft(); + m_frameRect.setX(leftValue + m_marginLeft + containerBlock->borderLeft()); } void RenderBox::calcAbsoluteVerticalReplaced() @@ -2566,7 +3030,7 @@ void RenderBox::calcAbsoluteVerticalReplaced() // the numbers correspond to numbers in spec) // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline. - const RenderObject* containerBlock = container(); + const RenderBox* containerBlock = toRenderBox(container()); const int containerHeight = containingBlockHeightForPositioned(containerBlock); @@ -2584,8 +3048,8 @@ void RenderBox::calcAbsoluteVerticalReplaced() // NOTE: This value of height is FINAL in that the min/max height calculations // are dealt with in calcReplacedHeight(). This means that the steps to produce // correct max/min in the non-replaced version, are not necessary. - m_height = calcReplacedHeight() + borderTop() + borderBottom() + paddingTop() + paddingBottom(); - const int availableSpace = containerHeight - m_height; + setHeight(calcReplacedHeight() + borderTop() + borderBottom() + paddingTop() + paddingBottom()); + const int availableSpace = containerHeight - height(); /*-----------------------------------------------------------------------*\ * 2. If both 'top' and 'bottom' have the value 'auto', replace 'top' @@ -2595,9 +3059,9 @@ void RenderBox::calcAbsoluteVerticalReplaced() if (top.isAuto() && bottom.isAuto()) { // staticY should already have been set through layout of the parent(). int staticTop = staticY() - containerBlock->borderTop(); - for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent()) { + for (RenderBox* po = parentBox(); po && po != containerBlock; po = po->parentBox()) { if (!po->isTableRow()) - staticTop += po->yPos(); + staticTop += po->y(); } top.setValue(Fixed, staticTop); } @@ -2686,10 +3150,10 @@ void RenderBox::calcAbsoluteVerticalReplaced() // or not. // Use computed values to calculate the vertical position. - m_y = topValue + m_marginTop + containerBlock->borderTop(); + m_frameRect.setY(topValue + m_marginTop + containerBlock->borderTop()); } -IntRect RenderBox::caretRect(InlineBox* box, int caretOffset, int* extraWidthToEndOfLine) +IntRect RenderBox::localCaretRect(InlineBox* box, int caretOffset, int* extraWidthToEndOfLine) { // VisiblePositions at offsets inside containers either a) refer to the positions before/after // those containers (tables and select elements) or b) refer to the position inside an empty block. @@ -2698,11 +3162,11 @@ IntRect RenderBox::caretRect(InlineBox* box, int caretOffset, int* extraWidthToE // FIXME: What about border and padding? const int caretWidth = 1; - IntRect rect(xPos(), yPos(), caretWidth, m_height); + IntRect rect(x(), y(), caretWidth, height()); TextDirection direction = box ? box->direction() : style()->direction(); if ((!caretOffset) ^ (direction == LTR)) - rect.move(IntSize(m_width - caretWidth, 0)); + rect.move(IntSize(width() - caretWidth, 0)); if (box) { RootInlineBox* rootBox = box->root(); @@ -2723,47 +3187,51 @@ IntRect RenderBox::caretRect(InlineBox* box, int caretOffset, int* extraWidthToE if (fontHeight > rect.height() || !isReplaced() && !isTable()) rect.setHeight(fontHeight); - RenderObject* cb = containingBlock(); - int cbx, cby; - if (!cb || !cb->absolutePosition(cbx, cby)) - // No point returning a relative position. - return IntRect(); - if (extraWidthToEndOfLine) - *extraWidthToEndOfLine = xPos() + m_width - rect.right(); + *extraWidthToEndOfLine = x() + width() - rect.right(); - rect.move(cbx, cby); + // Move to local coords + rect.move(-x(), -y()); return rect; } -int RenderBox::lowestPosition(bool includeOverflowInterior, bool includeSelf) const +int RenderBox::lowestPosition(bool /*includeOverflowInterior*/, bool includeSelf) const { - if (!includeSelf || !m_width) + if (!includeSelf || !width()) return 0; - int bottom = m_height; + int bottom = height(); if (isRelPositioned()) bottom += relativePositionOffsetY(); return bottom; } -int RenderBox::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const +int RenderBox::rightmostPosition(bool /*includeOverflowInterior*/, bool includeSelf) const { - if (!includeSelf || !m_height) + if (!includeSelf || !height()) return 0; - int right = m_width; + int right = width(); if (isRelPositioned()) right += relativePositionOffsetX(); return right; } -int RenderBox::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const +int RenderBox::leftmostPosition(bool /*includeOverflowInterior*/, bool includeSelf) const { - if (!includeSelf || !m_height) - return m_width; + if (!includeSelf || !height()) + return width(); int left = 0; if (isRelPositioned()) left += relativePositionOffsetX(); return left; } +#if ENABLE(SVG) + +TransformationMatrix RenderBox::localTransform() const +{ + return TransformationMatrix(1, 0, 0, 1, x(), y()); +} + +#endif + } // namespace WebCore diff --git a/WebCore/rendering/RenderBox.h b/WebCore/rendering/RenderBox.h index 133ae37..33e7411 100644 --- a/WebCore/rendering/RenderBox.h +++ b/WebCore/rendering/RenderBox.h @@ -24,10 +24,11 @@ #define RenderBox_h #include "RenderObject.h" +#include "ScrollTypes.h" namespace WebCore { - enum WidthType { Width, MinWidth, MaxWidth }; +enum WidthType { Width, MinWidth, MaxWidth }; class RenderBox : public RenderObject { public: @@ -36,6 +37,129 @@ public: virtual const char* renderName() const { return "RenderBox"; } + int x() const { return m_frameRect.x(); } + int y() const { return m_frameRect.y(); } + int width() const { ASSERT(!isRenderInline()); return m_frameRect.width(); } + int height() const { ASSERT(!isRenderInline()); return m_frameRect.height(); } + + void setX(int x) { m_frameRect.setX(x); } + void setY(int y) { m_frameRect.setY(y); } + void setWidth(int width) { m_frameRect.setWidth(width); } + void setHeight(int height) { m_frameRect.setHeight(height); } + + IntPoint location() const { return m_frameRect.location(); } + IntSize size() const { ASSERT(!isRenderInline()); return m_frameRect.size(); } + + void setLocation(const IntPoint& location) { m_frameRect.setLocation(location); } + void setLocation(int x, int y) { setLocation(IntPoint(x, y)); } + + void setSize(const IntSize& size) { m_frameRect.setSize(size); } + void move(int dx, int dy) { m_frameRect.move(dx, dy); } + + IntRect frameRect() const { ASSERT(!isRenderInline()); return m_frameRect; } + void setFrameRect(const IntRect& rect) { m_frameRect = rect; } + + IntRect borderBoxRect() const { return IntRect(0, 0, width(), height()); } + virtual IntRect borderBoundingBox() const { return borderBoxRect(); } // This will work on inlines to return the bounding box of all of the lines' border boxes. + + // The content area of the box (excludes padding and border). + IntRect contentBoxRect() const { return IntRect(borderLeft() + paddingLeft(), borderTop() + paddingTop(), contentWidth(), contentHeight()); } + // The content box in absolute coords. Ignores transforms. + IntRect absoluteContentBox() const; + // The content box converted to absolute coords (taking transforms into account). + FloatQuad absoluteContentQuad() const; + + // Bounds of the outline box in absolute coords. Respects transforms + virtual IntRect outlineBoundsForRepaint(RenderBox* /*repaintContainer*/) const; + virtual void addFocusRingRects(GraphicsContext*, int tx, int ty); + + // Use this with caution! No type checking is done! + RenderBox* previousSiblingBox() const; + RenderBox* nextSiblingBox() const; + RenderBox* parentBox() const; + + // The height of a block when you include normal flow overflow spillage out of the bottom + // of the block (e.g., a <div style="height:25px"> that has a 100px tall image inside + // it would have an overflow height of borderTop() + paddingTop() + 100px. + virtual int overflowHeight(bool /*includeInterior*/ = true) const { return height(); } + virtual int overflowWidth(bool /*includeInterior*/ = true) const { return width(); } + virtual void setOverflowHeight(int) { } + virtual void setOverflowWidth(int) { } + virtual int overflowLeft(bool /*includeInterior*/ = true) const { return 0; } + virtual int overflowTop(bool /*includeInterior*/ = true) const { return 0; } + virtual IntRect overflowRect(bool /*includeInterior*/ = true) const { return borderBoxRect(); } + + int contentWidth() const { return clientWidth() - paddingLeft() - paddingRight(); } + int contentHeight() const { return clientHeight() - paddingTop() - paddingBottom(); } + + // IE extensions. Used to calculate offsetWidth/Height. Overridden by inlines (RenderFlow) + // to return the remaining width on a given line (and the height of a single line). + virtual int offsetWidth() const { return width(); } + virtual int offsetHeight() const { return height(); } + virtual int offsetLeft() const; + virtual int offsetTop() const; + virtual RenderBox* offsetParent() const; + + // More IE extensions. clientWidth and clientHeight represent the interior of an object + // excluding border and scrollbar. clientLeft/Top are just the borderLeftWidth and borderTopWidth. + int clientLeft() const { return borderLeft(); } + int clientTop() const { return borderTop(); } + int clientWidth() const; + int clientHeight() const; + + // scrollWidth/scrollHeight will be the same as clientWidth/clientHeight unless the + // object has overflow:hidden/scroll/auto specified and also has overflow. + // scrollLeft/Top return the current scroll position. These methods are virtual so that objects like + // textareas can scroll shadow content (but pretend that they are the objects that are + // scrolling). + virtual int scrollLeft() const; + virtual int scrollTop() const; + virtual int scrollWidth() const; + virtual int scrollHeight() const; + virtual void setScrollLeft(int); + virtual void setScrollTop(int); + + bool hasHorizontalBordersPaddingOrMargin() const { return hasHorizontalBordersOrPadding() || marginLeft() != 0 || marginRight() != 0; } + bool hasHorizontalBordersOrPadding() const { return borderLeft() != 0 || borderRight() != 0 || paddingLeft() != 0 || paddingRight() != 0; } + + int marginTop() const { return m_marginTop; } + int marginBottom() const { return m_marginBottom; } + int marginLeft() const { return m_marginLeft; } + int marginRight() const { return m_marginRight; } + + // Virtual since table cells override + virtual int paddingTop(bool includeIntrinsicPadding = true) const; + virtual int paddingBottom(bool includeIntrinsicPadding = true) const; + virtual int paddingLeft(bool includeIntrinsicPadding = true) const; + virtual int paddingRight(bool includeIntrinsicPadding = true) const; + + virtual int borderTop() const { return style()->borderTopWidth(); } + virtual int borderBottom() const { return style()->borderBottomWidth(); } + virtual int borderLeft() const { return style()->borderLeftWidth(); } + virtual int borderRight() const { return style()->borderRightWidth(); } + + // The following seven functions are used to implement collapsing margins. + // All objects know their maximal positive and negative margins. The + // formula for computing a collapsed margin is |maxPosMargin| - |maxNegmargin|. + // For a non-collapsing box, such as a leaf element, this formula will simply return + // the margin of the element. Blocks override the maxTopMargin and maxBottomMargin + // methods. + virtual bool isSelfCollapsingBlock() const { return false; } + int collapsedMarginTop() const { return maxTopMargin(true) - maxTopMargin(false); } + int collapsedMarginBottom() const { return maxBottomMargin(true) - maxBottomMargin(false); } + virtual bool isTopMarginQuirk() const { return false; } + virtual bool isBottomMarginQuirk() const { return false; } + virtual int maxTopMargin(bool positive) const { return positive ? std::max(0, marginTop()) : -std::min(0, marginTop()); } + virtual int maxBottomMargin(bool positive) const { return positive ? std::max(0, marginBottom()) : -std::min(0, marginBottom()); } + + virtual void absoluteRects(Vector<IntRect>&, int tx, int ty, bool topLevel = true); + virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true); + + IntRect reflectionBox() const; + int reflectionOffset() const; + // Given a rect in the object's coordinate space, returns the corresponding rect in the reflection. + IntRect reflectedRect(const IntRect&) const; + virtual void paint(PaintInfo&, int tx, int ty); virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); @@ -49,30 +173,17 @@ public: virtual int overrideHeight() const; virtual void setOverrideSize(int); - virtual bool absolutePosition(int& x, int& y, bool fixed = false) const; - - virtual int xPos() const { return m_x; } - virtual int yPos() const { return m_y; } - virtual void setPos(int x, int y); - - virtual int width() const { return m_width; } - virtual int height() const { return m_height; } - virtual void setWidth(int width) { m_width = width; } - virtual void setHeight(int height) { m_height = height; } - - virtual int marginTop() const { return m_marginTop; } - virtual int marginBottom() const { return m_marginBottom; } - virtual int marginLeft() const { return m_marginLeft; } - virtual int marginRight() const { return m_marginRight; } - - virtual IntRect borderBox() const { return IntRect(0, -borderTopExtra(), width(), height() + borderTopExtra() + borderBottomExtra()); } + virtual FloatPoint localToAbsolute(FloatPoint localPoint = FloatPoint(), bool fixed = false, bool useTransforms = false) const; + virtual FloatPoint absoluteToLocal(FloatPoint containerPoint, bool fixed = false, bool useTransforms = false) const; + virtual IntSize offsetFromContainer(RenderObject*) const; + int calcBorderBoxWidth(int width) const; int calcBorderBoxHeight(int height) const; int calcContentBoxWidth(int width) const; int calcContentBoxHeight(int height) const; - virtual void borderFitAdjust(int& x, int& w) const {}; // Shrink the box in which the border paints if border-fit is set. + virtual void borderFitAdjust(int& /*x*/, int& /*w*/) const { } // Shrink the box in which the border paints if border-fit is set. // This method is now public so that centered objects like tables that are // shifted right by left-aligned floats can recompute their left and @@ -95,9 +206,10 @@ public: virtual int rightmostPosition(bool includeOverflowInterior = true, bool includeSelf = true) const; virtual int leftmostPosition(bool includeOverflowInterior = true, bool includeSelf = true) const; - virtual IntRect absoluteClippedOverflowRect(); - virtual void computeAbsoluteRepaintRect(IntRect&, bool fixed = false); + virtual IntRect clippedOverflowRectForRepaint(RenderBox* repaintContainer); + virtual void computeRectForRepaint(IntRect&, RenderBox* repaintContainer, bool fixed = false); IntSize offsetForPositionedInContainer(RenderObject*) const; + virtual FloatQuad localToContainerQuad(const FloatQuad&, RenderBox* repaintContainer, bool fixed = false) const; virtual void repaintDuringLayoutIfMoved(const IntRect&); @@ -128,6 +240,8 @@ public: int calcPercentageHeight(const Length& height); + // Block flows subclass availableWidth to handle multi column layout (shrinking the width available to children when laying out.) + virtual int availableWidth() const { return contentWidth(); } virtual int availableHeight() const; int availableHeightUsing(const Length&) const; @@ -135,10 +249,25 @@ public: int relativePositionOffsetX() const; int relativePositionOffsetY() const; - - virtual RenderLayer* layer() const { return m_layer; } - - virtual IntRect caretRect(InlineBox*, int caretOffset, int* extraWidthToEndOfLine = 0); + IntSize relativePositionOffset() const { return IntSize(relativePositionOffsetX(), relativePositionOffsetY()); } + + RenderLayer* layer() const { return m_layer; } + virtual bool requiresLayer() const { return isRoot() || isPositioned() || isRelPositioned() || isTransparent() || hasOverflowClip() || hasTransform() || hasMask() || hasReflection(); } + + virtual int verticalScrollbarWidth() const; + int horizontalScrollbarHeight() const; + virtual bool scroll(ScrollDirection, ScrollGranularity, float multiplier = 1.0f); + virtual bool canBeProgramaticallyScrolled(bool) const; + virtual void autoscroll(); + virtual void stopAutoscroll() { } + virtual void panScroll(const IntPoint&); + bool hasAutoVerticalScrollbar() const { return hasOverflowClip() && (style()->overflowY() == OAUTO || style()->overflowY() == OOVERLAY); } + bool hasAutoHorizontalScrollbar() const { return hasOverflowClip() && (style()->overflowX() == OAUTO || style()->overflowX() == OOVERLAY); } + bool scrollsOverflow() const { return scrollsOverflowX() || scrollsOverflowY(); } + bool scrollsOverflowX() const { return hasOverflowClip() && (style()->overflowX() == OSCROLL || hasAutoHorizontalScrollbar()); } + bool scrollsOverflowY() const { return hasOverflowClip() && (style()->overflowY() == OSCROLL || hasAutoVerticalScrollbar()); } + + virtual IntRect localCaretRect(InlineBox*, int caretOffset, int* extraWidthToEndOfLine = 0); virtual void paintFillLayerExtended(const PaintInfo&, const Color&, const FillLayer*, int clipY, int clipHeight, int tx, int ty, int width, int height, InlineFlowBox* = 0, CompositeOperator = CompositeSourceOver); @@ -154,23 +283,27 @@ public: virtual void paintBoxDecorations(PaintInfo&, int tx, int ty); virtual void paintMask(PaintInfo& paintInfo, int tx, int ty); - virtual void imageChanged(WrappedImagePtr); + virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); // Called when a positioned object moves but doesn't change size. A simplified layout is done // that just updates the object's position. virtual void tryLayoutDoingPositionedMovementOnly() { - int oldWidth = m_width; + int oldWidth = width(); calcWidth(); // If we shrink to fit our width may have changed, so we still need full layout. - if (oldWidth != m_width) + if (oldWidth != width()) return; calcHeight(); setNeedsLayout(false); } - virtual IntRect maskClipRect(); + IntRect maskClipRect(); +#if ENABLE(SVG) + virtual TransformationMatrix localTransform() const; +#endif + protected: virtual void styleWillChange(RenderStyle::Diff, const RenderStyle* newStyle); virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle); @@ -189,6 +322,9 @@ protected: virtual bool shouldCalculateSizeAsReplaced() const { return isReplaced() && !isInlineBlockOrInlineTable(); } private: + bool includeVerticalScrollbarSize() const { return hasOverflowClip() && (style()->overflowY() == OSCROLL || style()->overflowY() == OAUTO); } + bool includeHorizontalScrollbarSize() const { return hasOverflowClip() && (style()->overflowX() == OSCROLL || style()->overflowX() == OAUTO); } + void paintRootBoxDecorations(PaintInfo&, int tx, int ty); // Returns true if we did a full repaint bool repaintLayerRectsForImage(WrappedImagePtr image, const FillLayer* layers, bool drawingBackground); @@ -199,11 +335,11 @@ private: int containingBlockHeightForPositioned(const RenderObject* containingBlock) const; void calcAbsoluteVertical(); - void calcAbsoluteHorizontalValues(Length width, const RenderObject* cb, TextDirection containerDirection, + void calcAbsoluteHorizontalValues(Length width, const RenderBox* cb, TextDirection containerDirection, int containerWidth, int bordersPlusPadding, Length left, Length right, Length marginLeft, Length marginRight, int& widthValue, int& marginLeftValue, int& marginRightValue, int& xPos); - void calcAbsoluteVerticalValues(Length height, const RenderObject* cb, + void calcAbsoluteVerticalValues(Length height, const RenderBox* cb, int containerHeight, int bordersPlusPadding, Length top, Length bottom, Length marginTop, Length marginBottom, int& heightValue, int& marginTopValue, int& marginBottomValue, int& yPos); @@ -216,18 +352,16 @@ private: // These include tables, positioned objects, floats and flexible boxes. virtual void calcPrefWidths() = 0; +private: + // The width/height of the contents + borders + padding. The x/y location is relative to our container (which is not always our parent). + IntRect m_frameRect; + protected: - // The width/height of the contents + borders + padding. - int m_width; - int m_height; #ifdef ANDROID_LAYOUT int m_visibleWidth; #endif - int m_x; - int m_y; - int m_marginLeft; int m_marginRight; int m_marginTop; @@ -251,6 +385,33 @@ private: static bool s_hadOverflowClip; }; +inline RenderBox* toRenderBox(RenderObject* o) +{ + ASSERT(!o || o->isBox()); + return static_cast<RenderBox*>(o); +} + +inline const RenderBox* toRenderBox(const RenderObject* o) +{ + ASSERT(!o || o->isBox()); + return static_cast<const RenderBox*>(o); +} + +inline RenderBox* RenderBox::previousSiblingBox() const +{ + return toRenderBox(previousSibling()); +} + +inline RenderBox* RenderBox::nextSiblingBox() const +{ + return toRenderBox(nextSibling()); +} + +inline RenderBox* RenderBox::parentBox() const +{ + return toRenderBox(parent()); +} + } // namespace WebCore #endif // RenderBox_h diff --git a/WebCore/rendering/RenderButton.cpp b/WebCore/rendering/RenderButton.cpp index cbde565..f7ccd0c 100644 --- a/WebCore/rendering/RenderButton.cpp +++ b/WebCore/rendering/RenderButton.cpp @@ -30,6 +30,11 @@ #include "RenderTextFragment.h" #include "RenderTheme.h" +#if ENABLE(WML) +#include "WMLDoElement.h" +#include "WMLNames.h" +#endif + namespace WebCore { using namespace HTMLNames; @@ -48,7 +53,7 @@ void RenderButton::addChild(RenderObject* newChild, RenderObject* beforeChild) // Create an anonymous block. ASSERT(!firstChild()); m_inner = createAnonymousBlock(); - m_inner->style()->setBoxFlex(1.0f); + setupInnerStyle(m_inner->style()); RenderFlexibleBox::addChild(m_inner); } @@ -83,7 +88,7 @@ void RenderButton::styleDidChange(RenderStyle::Diff diff, const RenderStyle* old if (m_buttonText) m_buttonText->setStyle(style()); if (m_inner) // RenderBlock handled updating the anonymous block's style. - m_inner->style()->setBoxFlex(1.0f); + setupInnerStyle(m_inner->style()); setReplaced(isInline()); if (!m_default && theme()->isDefault(this)) { @@ -97,6 +102,16 @@ void RenderButton::styleDidChange(RenderStyle::Diff diff, const RenderStyle* old } } +void RenderButton::setupInnerStyle(RenderStyle* innerStyle) +{ + ASSERT(innerStyle->refCount() == 1); + // RenderBlock::createAnonymousBlock creates a new RenderStyle, so this is + // safe to modify. + innerStyle->setBoxFlex(1.0f); + if (style()->hasAppearance()) + theme()->adjustButtonInnerStyle(innerStyle); +} + void RenderButton::updateFromElement() { // If we're an input element, we may need to change our button text. @@ -105,6 +120,19 @@ void RenderButton::updateFromElement() String value = input->valueWithDefault(); setText(value); } + + +#if ENABLE(WML) + else if (element()->hasTagName(WMLNames::doTag)) { + WMLDoElement* doElement = static_cast<WMLDoElement*>(element()); + + String value = doElement->label(); + if (value.isEmpty()) + value = doElement->name(); + + setText(value); + } +#endif } bool RenderButton::canHaveChildren() const @@ -144,7 +172,7 @@ void RenderButton::updateBeforeAfterContent(RenderStyle::PseudoId type) IntRect RenderButton::controlClipRect(int tx, int ty) const { // Clip to the padding box to at least give content the extra padding space. - return IntRect(tx + borderLeft(), ty + borderTop(), m_width - borderLeft() - borderRight(), m_height - borderTop() - borderBottom()); + return IntRect(tx + borderLeft(), ty + borderTop(), width() - borderLeft() - borderRight(), height() - borderTop() - borderBottom()); } void RenderButton::timerFired(Timer<RenderButton>*) diff --git a/WebCore/rendering/RenderButton.h b/WebCore/rendering/RenderButton.h index a176c8d..24e4767 100644 --- a/WebCore/rendering/RenderButton.h +++ b/WebCore/rendering/RenderButton.h @@ -45,6 +45,7 @@ public: virtual void removeLeftoverAnonymousBlock(RenderBlock*) { } virtual bool createsAnonymousWrapper() const { return true; } + void setupInnerStyle(RenderStyle*); virtual void updateFromElement(); virtual void updateBeforeAfterContent(RenderStyle::PseudoId); diff --git a/WebCore/rendering/RenderContainer.cpp b/WebCore/rendering/RenderContainer.cpp index 947acac..dd39d9f 100644 --- a/WebCore/rendering/RenderContainer.cpp +++ b/WebCore/rendering/RenderContainer.cpp @@ -30,6 +30,7 @@ #include "Document.h" #include "RenderCounter.h" #include "RenderImageGeneratedContent.h" +#include "RenderInline.h" #include "RenderLayer.h" #include "RenderListItem.h" #include "RenderTable.h" @@ -126,9 +127,9 @@ void RenderContainer::addChild(RenderObject* newChild, RenderObject* beforeChild } if (newChild->isText() && newChild->style()->textTransform() == CAPITALIZE) { - RefPtr<StringImpl> textToTransform = static_cast<RenderText*>(newChild)->originalText(); + RefPtr<StringImpl> textToTransform = toRenderText(newChild)->originalText(); if (textToTransform) - static_cast<RenderText*>(newChild)->setText(textToTransform.release(), true); + toRenderText(newChild)->setText(textToTransform.release(), true); } } @@ -257,6 +258,9 @@ static RenderObject* findBeforeAfterParent(RenderObject* object) void RenderContainer::updateBeforeAfterContentForContainer(RenderStyle::PseudoId type, RenderContainer* styledObject) { + // Double check that the document did in fact use generated content rules. Otherwise we should not have been called. + ASSERT(document()->usesBeforeAfterRules()); + // In CSS2, before/after pseudo-content cannot nest. Check this first. if (style()->styleType() == RenderStyle::BEFORE || style()->styleType() == RenderStyle::AFTER) return; @@ -277,7 +281,7 @@ void RenderContainer::updateBeforeAfterContentForContainer(RenderStyle::PseudoId // Similarly, if we're the beginning of a <q>, and there's an inline continuation for our object, // then we don't generate the :after content. - if (newContentWanted && type == RenderStyle::AFTER && isRenderInline() && continuation()) + if (newContentWanted && type == RenderStyle::AFTER && isRenderInline() && static_cast<RenderInline*>(this)->continuation()) newContentWanted = false; // If we don't want generated content any longer, or if we have generated content, but it's no longer @@ -297,7 +301,7 @@ void RenderContainer::updateBeforeAfterContentForContainer(RenderStyle::PseudoId if (!newContentWanted) return; - if (isInlineFlow() && !pseudoElementStyle->isDisplayInlineType() && pseudoElementStyle->floating() == FNONE && + if (isRenderInline() && !pseudoElementStyle->isDisplayInlineType() && pseudoElementStyle->floating() == FNONE && !(pseudoElementStyle->position() == AbsolutePosition || pseudoElementStyle->position() == FixedPosition)) // According to the CSS2 spec (the end of section 12.1), the only allowed // display values for the pseudo style are NONE and INLINE for inline flows. @@ -520,7 +524,7 @@ void RenderContainer::layout() { ASSERT(needsLayout()); - view()->pushLayoutState(this, IntSize(m_x, m_y)); + LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y())); RenderObject* child = m_firstChild; while (child) { @@ -529,7 +533,7 @@ void RenderContainer::layout() child = child->nextSibling(); } - view()->popLayoutState(); + statePusher.pop(); setNeedsLayout(false); } @@ -576,7 +580,7 @@ void RenderContainer::removeLeftoverAnonymousBlock(RenderBlock* child) child->destroy(); } -VisiblePosition RenderContainer::positionForCoordinates(int x, int y) +VisiblePosition RenderContainer::positionForCoordinates(int xPos, int yPos) { // no children...return this render object's element, if there is one, and offset 0 if (!m_firstChild) @@ -586,8 +590,8 @@ VisiblePosition RenderContainer::positionForCoordinates(int x, int y) int right = contentWidth() + borderRight() + paddingRight() + borderLeft() + paddingLeft(); int bottom = contentHeight() + borderTop() + paddingTop() + borderBottom() + paddingBottom(); - if (x < 0 || x > right || y < 0 || y > bottom) { - if (x <= right / 2) + if (xPos < 0 || xPos > right || yPos < 0 || yPos > bottom) { + if (xPos <= right / 2) return VisiblePosition(Position(element(), 0)); else return VisiblePosition(Position(element(), maxDeepOffset(element()))); @@ -596,55 +600,60 @@ VisiblePosition RenderContainer::positionForCoordinates(int x, int y) // Pass off to the closest child. int minDist = INT_MAX; - RenderObject* closestRenderer = 0; - int newX = x; - int newY = y; + RenderBox* closestRenderer = 0; + int newX = xPos; + int newY = yPos; if (isTableRow()) { - newX += xPos(); - newY += yPos(); + newX += x(); + newY += y(); } - for (RenderObject* renderer = m_firstChild; renderer; renderer = renderer->nextSibling()) { - if (!renderer->firstChild() && !renderer->isInline() && !renderer->isBlockFlow() - || renderer->style()->visibility() != VISIBLE) + for (RenderObject* renderObject = m_firstChild; renderObject; renderObject = renderObject->nextSibling()) { + if (!renderObject->firstChild() && !renderObject->isInline() && !renderObject->isBlockFlow() + || renderObject->style()->visibility() != VISIBLE) + continue; + + if (!renderObject->isBox()) continue; - int top = borderTop() + paddingTop() + (isTableRow() ? 0 : renderer->yPos()); + RenderBox* renderer = toRenderBox(renderObject); + + int top = borderTop() + paddingTop() + (isTableRow() ? 0 : renderer->y()); int bottom = top + renderer->contentHeight(); - int left = borderLeft() + paddingLeft() + (isTableRow() ? 0 : renderer->xPos()); + int left = borderLeft() + paddingLeft() + (isTableRow() ? 0 : renderer->x()); int right = left + renderer->contentWidth(); - if (x <= right && x >= left && y <= top && y >= bottom) { + if (xPos <= right && xPos >= left && yPos <= top && yPos >= bottom) { if (renderer->isTableRow()) - return renderer->positionForCoordinates(x + newX - renderer->xPos(), y + newY - renderer->yPos()); - return renderer->positionForCoordinates(x - renderer->xPos(), y - renderer->yPos()); + return renderer->positionForCoordinates(xPos + newX - renderer->x(), yPos + newY - renderer->y()); + return renderer->positionForCoordinates(xPos - renderer->x(), yPos - renderer->y()); } // Find the distance from (x, y) to the box. Split the space around the box into 8 pieces // and use a different compare depending on which piece (x, y) is in. IntPoint cmp; - if (x > right) { - if (y < top) + if (xPos > right) { + if (yPos < top) cmp = IntPoint(right, top); - else if (y > bottom) + else if (yPos > bottom) cmp = IntPoint(right, bottom); else - cmp = IntPoint(right, y); - } else if (x < left) { - if (y < top) + cmp = IntPoint(right, yPos); + } else if (xPos < left) { + if (yPos < top) cmp = IntPoint(left, top); - else if (y > bottom) + else if (yPos > bottom) cmp = IntPoint(left, bottom); else - cmp = IntPoint(left, y); + cmp = IntPoint(left, yPos); } else { - if (y < top) - cmp = IntPoint(x, top); + if (yPos < top) + cmp = IntPoint(xPos, top); else - cmp = IntPoint(x, bottom); + cmp = IntPoint(xPos, bottom); } - int x1minusx2 = cmp.x() - x; - int y1minusy2 = cmp.y() - y; + int x1minusx2 = cmp.x() - xPos; + int y1minusy2 = cmp.y() - yPos; int dist = x1minusx2 * x1minusx2 + y1minusy2 * y1minusy2; if (dist < minDist) { @@ -654,7 +663,7 @@ VisiblePosition RenderContainer::positionForCoordinates(int x, int y) } if (closestRenderer) - return closestRenderer->positionForCoordinates(newX - closestRenderer->xPos(), newY - closestRenderer->yPos()); + return closestRenderer->positionForCoordinates(newX - closestRenderer->x(), newY - closestRenderer->y()); return VisiblePosition(element(), 0, DOWNSTREAM); } @@ -662,9 +671,8 @@ VisiblePosition RenderContainer::positionForCoordinates(int x, int y) void RenderContainer::addLineBoxRects(Vector<IntRect>& rects, unsigned start, unsigned end, bool) { if (!m_firstChild && (isInline() || isAnonymousBlock())) { - int x, y; - absolutePositionForContent(x, y); - absoluteRects(rects, x, y); + FloatPoint absPos = localToAbsolute(FloatPoint()); + absoluteRects(rects, absPos.x(), absPos.y()); return; } @@ -674,24 +682,39 @@ void RenderContainer::addLineBoxRects(Vector<IntRect>& rects, unsigned start, un unsigned offset = start; for (RenderObject* child = childAt(start); child && offset < end; child = child->nextSibling(), ++offset) { if (child->isText() || child->isInline() || child->isAnonymousBlock()) { - int x, y; - child->absolutePositionForContent(x, y); - child->absoluteRects(rects, x, y); + FloatPoint absPos = child->localToAbsolute(FloatPoint()); + child->absoluteRects(rects, absPos.x(), absPos.y()); } } } - +void RenderContainer::collectAbsoluteLineBoxQuads(Vector<FloatQuad>& quads, unsigned start, unsigned end, bool /*useSelectionHeight*/) +{ + if (!m_firstChild && (isInline() || isAnonymousBlock())) { + absoluteQuads(quads); + return; + } + + if (!m_firstChild) + return; + + unsigned offset = start; + for (RenderObject* child = childAt(start); child && offset < end; child = child->nextSibling(), ++offset) { + if (child->isText() || child->isInline() || child->isAnonymousBlock()) + child->absoluteQuads(quads); + } +} + #ifdef ANDROID_LAYOUT bool RenderContainer::hasChildTable() const { if (!firstChild()) return false; - for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { + for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { if (child->isTable()) { - return true; + return true; } else if (child->hasChildTable() == true) { - return true; + return true; } } return false; diff --git a/WebCore/rendering/RenderContainer.h b/WebCore/rendering/RenderContainer.h index 174aa17..8ae5296 100644 --- a/WebCore/rendering/RenderContainer.h +++ b/WebCore/rendering/RenderContainer.h @@ -34,6 +34,10 @@ public: virtual RenderObject* firstChild() const { return m_firstChild; } virtual RenderObject* lastChild() const { return m_lastChild; } + // Use this with caution! No type checking is done! + RenderBox* firstChildBox() const { ASSERT(!firstChild() || firstChild()->isBox()); return toRenderBox(m_firstChild); } + RenderBox* lastChildBox() const { ASSERT(!lastChild() || lastChild()->isBox()); return toRenderBox(m_lastChild); } + virtual bool canHaveChildren() const; virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0); virtual void removeChild(RenderObject*); @@ -66,8 +70,9 @@ public: #endif virtual void addLineBoxRects(Vector<IntRect>&, unsigned startOffset = 0, unsigned endOffset = UINT_MAX, bool useSelectionHeight = false); + virtual void collectAbsoluteLineBoxQuads(Vector<FloatQuad>&, unsigned startOffset = 0, unsigned endOffset = UINT_MAX, bool useSelectionHeight = false); -private: +protected: RenderObject* m_firstChild; RenderObject* m_lastChild; }; diff --git a/WebCore/rendering/RenderCounter.cpp b/WebCore/rendering/RenderCounter.cpp index 4b6deed..598f40d 100644 --- a/WebCore/rendering/RenderCounter.cpp +++ b/WebCore/rendering/RenderCounter.cpp @@ -29,6 +29,7 @@ #include "RenderListItem.h" #include "RenderListMarker.h" #include "RenderStyle.h" +#include <wtf/StdLibExtras.h> namespace WebCore { @@ -41,7 +42,7 @@ static CounterNode* counter(RenderObject*, const AtomicString& counterName, bool static CounterMaps& counterMaps() { - static CounterMaps staticCounterMaps; + DEFINE_STATIC_LOCAL(CounterMaps, staticCounterMaps, ()); return staticCounterMaps; } diff --git a/WebCore/rendering/RenderFieldset.cpp b/WebCore/rendering/RenderFieldset.cpp index d16495b..5baca3e 100644 --- a/WebCore/rendering/RenderFieldset.cpp +++ b/WebCore/rendering/RenderFieldset.cpp @@ -26,10 +26,13 @@ #include "config.h" #include "RenderFieldset.h" -#include "HTMLFormControlElement.h" #include "HTMLNames.h" #include "GraphicsContext.h" +#if ENABLE(WML) +#include "WMLNames.h" +#endif + using std::min; using std::max; @@ -37,7 +40,7 @@ namespace WebCore { using namespace HTMLNames; -RenderFieldset::RenderFieldset(HTMLFormControlElement* element) +RenderFieldset::RenderFieldset(Node* element) : RenderBlock(element) { } @@ -45,7 +48,7 @@ RenderFieldset::RenderFieldset(HTMLFormControlElement* element) void RenderFieldset::calcPrefWidths() { RenderBlock::calcPrefWidths(); - if (RenderObject* legend = findLegend()) { + if (RenderBox* legend = findLegend()) { int legendMinWidth = legend->minPrefWidth(); Length legendMarginLeft = legend->style()->marginLeft(); @@ -63,7 +66,7 @@ void RenderFieldset::calcPrefWidths() RenderObject* RenderFieldset::layoutLegend(bool relayoutChildren) { - RenderObject* legend = findLegend(); + RenderBox* legend = findLegend(); if (legend) { if (relayoutChildren) legend->setNeedsLayout(true); @@ -76,18 +79,18 @@ RenderObject* RenderFieldset::layoutLegend(bool relayoutChildren) xPos = borderLeft() + paddingLeft(); break; case CENTER: - xPos = (m_width - legend->width()) / 2; + xPos = (width() - legend->width()) / 2; break; default: - xPos = m_width - paddingRight() - borderRight() - legend->width() - legend->marginRight(); + xPos = width() - paddingRight() - borderRight() - legend->width() - legend->marginRight(); } } else { switch (legend->style()->textAlign()) { case RIGHT: - xPos = m_width - paddingRight() - borderRight() - legend->width(); + xPos = width() - paddingRight() - borderRight() - legend->width(); break; case CENTER: - xPos = (m_width - legend->width()) / 2; + xPos = (width() - legend->width()) / 2; break; default: xPos = borderLeft() + paddingLeft() + legend->marginLeft(); @@ -95,18 +98,22 @@ RenderObject* RenderFieldset::layoutLegend(bool relayoutChildren) } int b = borderTop(); int h = legend->height(); - legend->setPos(xPos, max((b-h)/2, 0)); - m_height = max(b,h) + paddingTop(); + legend->setLocation(xPos, max((b-h)/2, 0)); + setHeight(max(b,h) + paddingTop()); } return legend; } -RenderObject* RenderFieldset::findLegend() const +RenderBox* RenderFieldset::findLegend() const { for (RenderObject* legend = firstChild(); legend; legend = legend->nextSibling()) { if (!legend->isFloatingOrPositioned() && legend->element() && - legend->element()->hasTagName(legendTag)) - return legend; + legend->element()->hasTagName(legendTag) +#if ENABLE(WML) + || legend->element()->hasTagName(WMLNames::insertedLegendTag) +#endif + ) + return toRenderBox(legend); } return 0; } @@ -114,15 +121,15 @@ RenderObject* RenderFieldset::findLegend() const void RenderFieldset::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty) { int w = width(); - int h = height() + borderTopExtra() + borderBottomExtra(); - RenderObject* legend = findLegend(); + int h = height(); + RenderBox* legend = findLegend(); if (!legend) return RenderBlock::paintBoxDecorations(paintInfo, tx, ty); - int yOff = (legend->yPos() > 0) ? 0 : (legend->height() - borderTop()) / 2; - int legendBottom = ty + legend->yPos() + legend->height(); + int yOff = (legend->y() > 0) ? 0 : (legend->height() - borderTop()) / 2; + int legendBottom = ty + legend->y() + legend->height(); h -= yOff; - ty += yOff - borderTopExtra(); + ty += yOff; int my = max(ty, paintInfo.rect.y()); int end = min(paintInfo.rect.bottom(), ty + h); @@ -137,7 +144,7 @@ void RenderFieldset::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty) // Save time by not saving and restoring the GraphicsContext in the straight border case if (!style()->hasBorderRadius()) - return paintBorderMinusLegend(paintInfo.context, tx, ty, w, h, style(), legend->xPos(), legend->width(), legendBottom); + return paintBorderMinusLegend(paintInfo.context, tx, ty, w, h, style(), legend->x(), legend->width(), legendBottom); // We have rounded borders, create a clipping region // around the legend and paint the border as normal @@ -147,7 +154,7 @@ void RenderFieldset::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty) int clipTop = ty; int clipHeight = max(static_cast<int>(style()->borderTopWidth()), legend->height()); - graphicsContext->clipOut(IntRect(tx + legend->xPos(), clipTop, + graphicsContext->clipOut(IntRect(tx + legend->x(), clipTop, legend->width(), clipHeight)); paintBorder(paintInfo.context, tx, ty, w, h, style(), true, true); @@ -160,14 +167,14 @@ void RenderFieldset::paintMask(PaintInfo& paintInfo, int tx, int ty) return; int w = width(); - int h = height() + borderTopExtra() + borderBottomExtra(); - RenderObject* legend = findLegend(); + int h = height(); + RenderBox* legend = findLegend(); if (!legend) return RenderBlock::paintMask(paintInfo, tx, ty); - int yOff = (legend->yPos() > 0) ? 0 : (legend->height() - borderTop()) / 2; + int yOff = (legend->y() > 0) ? 0 : (legend->height() - borderTop()) / 2; h -= yOff; - ty += yOff - borderTopExtra(); + ty += yOff; int my = max(ty, paintInfo.rect.y()); int end = min(paintInfo.rect.bottom(), ty + h); diff --git a/WebCore/rendering/RenderFieldset.h b/WebCore/rendering/RenderFieldset.h index 87652fd..38f3236 100644 --- a/WebCore/rendering/RenderFieldset.h +++ b/WebCore/rendering/RenderFieldset.h @@ -30,11 +30,9 @@ namespace WebCore { -class HTMLFormControlElement; - class RenderFieldset : public RenderBlock { public: - RenderFieldset(HTMLFormControlElement*); + RenderFieldset(Node*); virtual const char* renderName() const { return "RenderFieldSet"; } virtual bool isFieldset() const { return true; } @@ -43,10 +41,9 @@ public: virtual void calcPrefWidths(); virtual bool avoidsFloats() const { return true; } - virtual bool expandsToEncloseOverhangingFloats() const { return style()->height().isAuto(); } virtual bool stretchesToMinIntrinsicWidth() const { return true; } - RenderObject* findLegend() const; + RenderBox* findLegend() const; protected: virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle); diff --git a/WebCore/rendering/RenderFileUploadControl.cpp b/WebCore/rendering/RenderFileUploadControl.cpp index fe9772e..cbf1409 100644 --- a/WebCore/rendering/RenderFileUploadControl.cpp +++ b/WebCore/rendering/RenderFileUploadControl.cpp @@ -151,7 +151,7 @@ void RenderFileUploadControl::updateFromElement() int RenderFileUploadControl::maxFilenameWidth() const { - return max(0, contentWidth() - m_button->renderer()->width() - afterButtonSpacing + return max(0, contentWidth() - m_button->renderBox()->width() - afterButtonSpacing - (m_fileChooser->icon() ? iconWidth + iconFilenameSpacing : 0)); } @@ -194,7 +194,7 @@ void RenderFileUploadControl::paintObject(PaintInfo& paintInfo, int tx, int ty) // Determine where the filename should be placed int contentLeft = tx + borderLeft() + paddingLeft(); - int buttonAndIconWidth = m_button->renderer()->width() + afterButtonSpacing + int buttonAndIconWidth = m_button->renderBox()->width() + afterButtonSpacing + (m_fileChooser->icon() ? iconWidth + iconFilenameSpacing : 0); int textX; if (style()->direction() == LTR) @@ -207,20 +207,19 @@ void RenderFileUploadControl::paintObject(PaintInfo& paintInfo, int tx, int ty) + buttonRenderer->marginTop() + buttonRenderer->borderTop() + buttonRenderer->paddingTop() + buttonRenderer->baselinePosition(true, false); - paintInfo.context->setFont(style()->font()); paintInfo.context->setFillColor(style()->color()); // Draw the filename - paintInfo.context->drawBidiText(textRun, IntPoint(textX, textY)); + paintInfo.context->drawBidiText(style()->font(), textRun, IntPoint(textX, textY)); if (m_fileChooser->icon()) { // Determine where the icon should be placed int iconY = ty + borderTop() + paddingTop() + (contentHeight() - iconHeight) / 2; int iconX; if (style()->direction() == LTR) - iconX = contentLeft + m_button->renderer()->width() + afterButtonSpacing; + iconX = contentLeft + m_button->renderBox()->width() + afterButtonSpacing; else - iconX = contentLeft + contentWidth() - m_button->renderer()->width() - afterButtonSpacing - iconWidth; + iconX = contentLeft + contentWidth() - m_button->renderBox()->width() - afterButtonSpacing - iconWidth; // Draw the file icon m_fileChooser->icon()->paint(paintInfo.context, IntRect(iconX, iconY, iconWidth, iconHeight)); @@ -294,7 +293,7 @@ String RenderFileUploadControl::fileTextValue() } HTMLFileUploadInnerButtonElement::HTMLFileUploadInnerButtonElement(Document* doc, Node* shadowParent) - : HTMLInputElement(doc) + : HTMLInputElement(inputTag, doc) , m_shadowParent(shadowParent) { } diff --git a/WebCore/rendering/RenderFlexibleBox.cpp b/WebCore/rendering/RenderFlexibleBox.cpp index f39bf74..e6dd91a 100644 --- a/WebCore/rendering/RenderFlexibleBox.cpp +++ b/WebCore/rendering/RenderFlexibleBox.cpp @@ -28,6 +28,7 @@ #include "CharacterNames.h" #include "RenderLayer.h" #include "RenderView.h" +#include <wtf/StdLibExtras.h> #ifdef ANDROID_LAYOUT #include "Document.h" @@ -49,11 +50,11 @@ public: lastOrdinal = 1; if (!forward) { // No choice, since we're going backwards, we have to find out the highest ordinal up front. - RenderObject* child = box->firstChild(); + RenderBox* child = box->firstChildBox(); while (child) { if (child->style()->boxOrdinalGroup() > lastOrdinal) lastOrdinal = child->style()->boxOrdinalGroup(); - child = child->nextSibling(); + child = child->nextSiblingBox(); } } @@ -65,29 +66,28 @@ public: currentOrdinal = forward ? 0 : lastOrdinal+1; } - RenderObject* first() { + RenderBox* first() { reset(); return next(); } - RenderObject* next() { - + RenderBox* next() { do { if (!current) { if (forward) { currentOrdinal++; if (currentOrdinal > lastOrdinal) return 0; - current = box->firstChild(); + current = box->firstChildBox(); } else { currentOrdinal--; if (currentOrdinal == 0) return 0; - current = box->lastChild(); + current = box->lastChildBox(); } } else - current = forward ? current->nextSibling() : current->previousSibling(); + current = forward ? current->nextSiblingBox() : current->previousSiblingBox(); if (current && current->style()->boxOrdinalGroup() > lastOrdinal) lastOrdinal = current->style()->boxOrdinalGroup(); } while (!current || current->style()->boxOrdinalGroup() != currentOrdinal || @@ -97,7 +97,7 @@ public: private: RenderFlexibleBox* box; - RenderObject* current; + RenderBox* current; bool forward; unsigned int currentOrdinal; unsigned int lastOrdinal; @@ -116,13 +116,10 @@ RenderFlexibleBox::~RenderFlexibleBox() void RenderFlexibleBox::calcHorizontalPrefWidths() { - RenderObject *child = firstChild(); - while (child) { + for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { // positioned children don't affect the minmaxwidth - if (child->isPositioned() || child->style()->visibility() == COLLAPSE) { - child = child->nextSibling(); + if (child->isPositioned() || child->style()->visibility() == COLLAPSE) continue; - } // A margin basically has three types: fixed, percentage, and auto (variable). // Auto and percentage margins simply become 0 when computing min/max width. @@ -138,21 +135,15 @@ void RenderFlexibleBox::calcHorizontalPrefWidths() m_minPrefWidth += child->minPrefWidth() + margin; m_maxPrefWidth += child->maxPrefWidth() + margin; - - child = child->nextSibling(); } } void RenderFlexibleBox::calcVerticalPrefWidths() { - RenderObject *child = firstChild(); - while(child != 0) - { + for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { // Positioned children and collapsed children don't affect the min/max width - if (child->isPositioned() || child->style()->visibility() == COLLAPSE) { - child = child->nextSibling(); + if (child->isPositioned() || child->style()->visibility() == COLLAPSE) continue; - } // A margin basically has three types: fixed, percentage, and auto (variable). // Auto/percentage margins simply become 0 when computing min/max width. @@ -170,8 +161,6 @@ void RenderFlexibleBox::calcVerticalPrefWidths() w = child->maxPrefWidth() + margin; m_maxPrefWidth = max(w, m_maxPrefWidth); - - child = child->nextSibling(); } } @@ -221,26 +210,23 @@ void RenderFlexibleBox::layoutBlock(bool relayoutChildren) bool checkForRepaint = checkForRepaintDuringLayout(); if (checkForRepaint) { oldBounds = absoluteClippedOverflowRect(); - oldOutlineBox = absoluteOutlineBox(); + oldOutlineBox = absoluteOutlineBounds(); } - if (!hasReflection()) - view()->pushLayoutState(this, IntSize(m_x, m_y)); - else - view()->disableLayoutState(); + LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasTransform() || hasReflection()); - int previousWidth = m_width; - int previousHeight = m_height; + int previousWidth = width(); + int previousHeight = height(); -#ifdef ANDROID_LAYOUT + #ifdef ANDROID_LAYOUT int previousVisibleWidth = m_visibleWidth; #endif - + calcWidth(); calcHeight(); - m_overflowWidth = m_width; + m_overflowWidth = width(); - if (previousWidth != m_width || previousHeight != m_height || + if (previousWidth != width() || previousHeight != height() || (parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL && parent()->style()->boxAlign() == BSTRETCH)) relayoutChildren = true; @@ -252,8 +238,8 @@ void RenderFlexibleBox::layoutBlock(bool relayoutChildren) && settings->layoutAlgorithm() == Settings::kLayoutFitColumnToScreen) relayoutChildren = true; #endif + setHeight(0); - m_height = 0; m_overflowHeight = 0; m_flexingChildren = m_stretchingChildren = false; @@ -272,21 +258,21 @@ void RenderFlexibleBox::layoutBlock(bool relayoutChildren) else layoutVerticalBox(relayoutChildren); - int oldHeight = m_height; + int oldHeight = height(); calcHeight(); - if (oldHeight != m_height) { + if (oldHeight != height()) { // If the block got expanded in size, then increase our overflowheight to match. - if (m_overflowHeight > m_height) + if (m_overflowHeight > height()) m_overflowHeight -= (borderBottom() + paddingBottom() + horizontalScrollbarHeight()); - if (m_overflowHeight < m_height) - m_overflowHeight = m_height; + if (m_overflowHeight < height()) + m_overflowHeight = height(); } - if (previousHeight != m_height) + if (previousHeight != height()) relayoutChildren = true; layoutPositionedObjects(relayoutChildren || isRoot()); - if (!isFloatingOrPositioned() && m_height == 0) { + if (!isFloatingOrPositioned() && height() == 0) { // We are a block with no border and padding and a computed height // of 0. The CSS spec states that zero-height blocks collapse their margins // together. @@ -305,15 +291,15 @@ void RenderFlexibleBox::layoutBlock(bool relayoutChildren) } // Always ensure our overflow width is at least as large as our width. - if (m_overflowWidth < m_width) - m_overflowWidth = m_width; + if (m_overflowWidth < width()) + m_overflowWidth = width(); if (!hasOverflowClip()) { for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next) { m_overflowLeft = min(m_overflowLeft, boxShadow->x - boxShadow->blur); - m_overflowWidth = max(m_overflowWidth, m_width + boxShadow->x + boxShadow->blur); + m_overflowWidth = max(m_overflowWidth, width() + boxShadow->x + boxShadow->blur); m_overflowTop = min(m_overflowTop, boxShadow->y - boxShadow->blur); - m_overflowHeight = max(m_overflowHeight, m_height + boxShadow->y + boxShadow->blur); + m_overflowHeight = max(m_overflowHeight, height() + boxShadow->y + boxShadow->blur); } if (hasReflection()) { @@ -325,10 +311,7 @@ void RenderFlexibleBox::layoutBlock(bool relayoutChildren) } } - if (!hasReflection()) - view()->popLayoutState(); - else - view()->enableLayoutState(); + statePusher.pop(); // Update our scrollbars if we're overflow:auto/scroll/hidden now that we know if // we overflow or not. @@ -354,11 +337,11 @@ void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren) unsigned int lowestFlexGroup = 0; bool haveFlex = false; int remainingSpace = 0; - m_overflowHeight = m_height; + m_overflowHeight = height(); // The first walk over our kids is to find out if we have any flexible children. FlexBoxIterator iterator(this); - RenderObject* child = iterator.next(); + RenderBox* child = iterator.next(); while (child) { // Check to see if this child flexes. if (!child->isPositioned() && child->style()->boxFlex() > 0.0f) { @@ -383,8 +366,8 @@ void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren) // their preferred widths. The second pass handles flexing the children. do { // Reset our height. - m_height = yPos; - m_overflowHeight = m_height; + setHeight(yPos); + m_overflowHeight = height(); xPos = borderLeft() + paddingLeft(); // Our first pass is done without flexing. We simply lay the children @@ -422,28 +405,28 @@ void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren) maxDescent = max(maxDescent, descent); // Now update our height. - m_height = max(yPos + maxAscent + maxDescent, m_height); + setHeight(max(yPos + maxAscent + maxDescent, height())); } else - m_height = max(m_height, yPos + child->marginTop() + child->height() + child->marginBottom()); + setHeight(max(height(), yPos + child->marginTop() + child->height() + child->marginBottom())); child = iterator.next(); } if (!iterator.first() && hasLineIfEmpty()) - m_height += lineHeight(true, true); + setHeight(height() + lineHeight(true, true)); - m_height += toAdd; + setHeight(height() + toAdd); // Always make sure our overflowheight is at least our height. - if (m_overflowHeight < m_height) - m_overflowHeight = m_height; + if (m_overflowHeight < height()) + m_overflowHeight = height(); - oldHeight = m_height; + oldHeight = height(); calcHeight(); relayoutChildren = false; - if (oldHeight != m_height) + if (oldHeight != height()) heightSpecified = true; // Now that our height is actually known, we can place our boxes. @@ -467,7 +450,7 @@ void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren) // fill the height of a containing box by default. // Now do a layout. int oldChildHeight = child->height(); - static_cast<RenderBox*>(child)->calcHeight(); + toRenderBox(child)->calcHeight(); if (oldChildHeight != child->height()) child->setChildNeedsLayout(true, false); child->layoutIfNeeded(); @@ -500,7 +483,7 @@ void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren) static_cast<RenderBlock*>(child)->addVisualOverflow(static_cast<RenderBlock*>(child)->floatRect()); m_overflowHeight = max(m_overflowHeight, childY + child->overflowHeight(false)); - m_overflowTop = min(m_overflowTop, child->yPos() + child->overflowTop(false)); + m_overflowTop = min(m_overflowTop, child->y() + child->overflowTop(false)); xPos += child->width() + child->marginRight(); @@ -641,7 +624,7 @@ void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren) remainingSpace -= (remainingSpace/totalChildren); totalChildren--; - placeChild(child, child->xPos()+offset, child->yPos()); + placeChild(child, child->x()+offset, child->y()); child = iterator.next(); } } @@ -656,7 +639,7 @@ void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren) child = iterator.next(); continue; } - placeChild(child, child->xPos()+offset, child->yPos()); + placeChild(child, child->x()+offset, child->y()); child = iterator.next(); } } @@ -668,20 +651,20 @@ void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren) } if (child) { - m_overflowLeft = min(child->xPos() + child->overflowLeft(false), m_overflowLeft); + m_overflowLeft = min(child->x() + child->overflowLeft(false), m_overflowLeft); - RenderObject* lastChild = child; + RenderBox* lastChild = child; while ((child = iterator.next())) { if (!child->isPositioned()) lastChild = child; } - m_overflowWidth = max(lastChild->xPos() + lastChild->overflowWidth(false), m_overflowWidth); + m_overflowWidth = max(lastChild->x() + lastChild->overflowWidth(false), m_overflowWidth); } // So that the calcHeight in layoutBlock() knows to relayout positioned objects because of // a height change, we revert our height back to the intrinsic height before returning. if (heightSpecified) - m_height = oldHeight; + setHeight(oldHeight); } void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren) @@ -689,7 +672,7 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren) int xPos = borderLeft() + paddingLeft(); int yPos = borderTop() + paddingTop(); if( style()->direction() == RTL ) - xPos = m_width - paddingRight() - borderRight(); + xPos = width() - paddingRight() - borderRight(); int toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight(); bool heightSpecified = false; int oldHeight = 0; @@ -701,7 +684,7 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren) // The first walk over our kids is to find out if we have any flexible children. FlexBoxIterator iterator(this); - RenderObject *child = iterator.next(); + RenderBox* child = iterator.next(); while (child) { // Check to see if this child flexes. if (!child->isPositioned() && child->style()->boxFlex() > 0.0f) { @@ -794,7 +777,7 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren) continue; const UChar ellipsisAndSpace[2] = { horizontalEllipsis, ' ' }; - static AtomicString ellipsisAndSpaceStr(ellipsisAndSpace, 2); + DEFINE_STATIC_LOCAL(AtomicString, ellipsisAndSpaceStr, (ellipsisAndSpace, 2)); const Font& font = style(numVisibleLines == 1)->font(); int ellipsisAndSpaceWidth = font.width(TextRun(ellipsisAndSpace, 2)); @@ -830,9 +813,9 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren) // Our first pass is done without flexing. We simply lay the children // out within the box. do { - m_height = borderTop() + paddingTop(); - int minHeight = m_height + toAdd; - m_overflowHeight = m_height; + setHeight(borderTop() + paddingTop()); + int minHeight = height() + toAdd; + m_overflowHeight = height(); child = iterator.first(); while (child) { @@ -850,7 +833,7 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren) child->setStaticX(borderRight()+paddingRight()); } if (child->hasStaticY()) - child->setStaticY(m_height); + child->setStaticY(height()); child = iterator.next(); continue; } @@ -859,7 +842,7 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren) child->calcVerticalMargins(); // Add in the child's marginTop to our height. - m_height += child->marginTop(); + setHeight(height() + child->marginTop()); // Now do a layout. child->layoutIfNeeded(); @@ -886,39 +869,39 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren) } // Place the child. - placeChild(child, childX, m_height); - m_height += child->height() + child->marginBottom(); + placeChild(child, childX, height()); + setHeight(height() + child->height() + child->marginBottom()); if (child->isRenderBlock()) static_cast<RenderBlock*>(child)->addVisualOverflow(static_cast<RenderBlock*>(child)->floatRect()); // See if this child has made our overflow need to grow. - m_overflowWidth = max(child->xPos() + child->overflowWidth(false), m_overflowWidth); - m_overflowLeft = min(child->xPos() + child->overflowLeft(false), m_overflowLeft); + m_overflowWidth = max(child->x() + child->overflowWidth(false), m_overflowWidth); + m_overflowLeft = min(child->x() + child->overflowLeft(false), m_overflowLeft); child = iterator.next(); } - yPos = m_height; + yPos = height(); if (!iterator.first() && hasLineIfEmpty()) - m_height += lineHeight(true, true); + setHeight(height() + lineHeight(true, true)); - m_height += toAdd; + setHeight(height() + toAdd); // Negative margins can cause our height to shrink below our minimal height (border/padding). // If this happens, ensure that the computed height is increased to the minimal height. - if (m_height < minHeight) - m_height = minHeight; + if (height() < minHeight) + setHeight(minHeight); // Always make sure our overflowheight is at least our height. - if (m_overflowHeight < m_height) - m_overflowHeight = m_height; + if (m_overflowHeight < height()) + m_overflowHeight = height(); // Now we have to calc our height, so we know how much space we have remaining. - oldHeight = m_height; + oldHeight = height(); calcHeight(); - if (oldHeight != m_height) + if (oldHeight != height()) heightSpecified = true; remainingSpace = borderTop() + paddingTop() + contentHeight() - yPos; @@ -1050,7 +1033,7 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren) offset += remainingSpace/totalChildren; remainingSpace -= (remainingSpace/totalChildren); totalChildren--; - placeChild(child, child->xPos(), child->yPos()+offset); + placeChild(child, child->x(), child->y()+offset); child = iterator.next(); } } @@ -1065,7 +1048,7 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren) child = iterator.next(); continue; } - placeChild(child, child->xPos(), child->yPos()+offset); + placeChild(child, child->x(), child->y()+offset); child = iterator.next(); } } @@ -1077,28 +1060,28 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren) } if (child) { - m_overflowTop = min(child->yPos() + child->overflowTop(false), m_overflowTop); + m_overflowTop = min(child->y() + child->overflowTop(false), m_overflowTop); - RenderObject* lastChild = child; + RenderBox* lastChild = child; while ((child = iterator.next())) { if (!child->isPositioned()) lastChild = child; } - m_overflowHeight = max(lastChild->yPos() + lastChild->overflowHeight(false), m_overflowHeight); + m_overflowHeight = max(lastChild->y() + lastChild->overflowHeight(false), m_overflowHeight); } // So that the calcHeight in layoutBlock() knows to relayout positioned objects because of // a height change, we revert our height back to the intrinsic height before returning. if (heightSpecified) - m_height = oldHeight; + setHeight(oldHeight); } -void RenderFlexibleBox::placeChild(RenderObject* child, int x, int y) +void RenderFlexibleBox::placeChild(RenderBox* child, int x, int y) { - IntRect oldRect(child->xPos(), child->yPos() , child->width(), child->height()); + IntRect oldRect(child->x(), child->y() , child->width(), child->height()); // Place the child. - child->setPos(x, y); + child->setLocation(x, y); // If the child moved, we have to repaint it as well as any floating/positioned // descendants. An exception is if we need a layout. In this case, we know we're going to @@ -1107,7 +1090,7 @@ void RenderFlexibleBox::placeChild(RenderObject* child, int x, int y) child->repaintDuringLayoutIfMoved(oldRect); } -int RenderFlexibleBox::allowedChildFlex(RenderObject* child, bool expanding, unsigned int group) +int RenderFlexibleBox::allowedChildFlex(RenderBox* child, bool expanding, unsigned int group) { if (child->isPositioned() || child->style()->boxFlex() == 0.0f || child->style()->boxFlexGroup() != group) return 0; diff --git a/WebCore/rendering/RenderFlexibleBox.h b/WebCore/rendering/RenderFlexibleBox.h index f48caf5..a0f84ce 100644 --- a/WebCore/rendering/RenderFlexibleBox.h +++ b/WebCore/rendering/RenderFlexibleBox.h @@ -48,10 +48,10 @@ public: virtual bool isFlexingChildren() const { return m_flexingChildren; } virtual bool isStretchingChildren() const { return m_stretchingChildren; } - void placeChild(RenderObject* child, int x, int y); + void placeChild(RenderBox* child, int x, int y); protected: - int allowedChildFlex(RenderObject* child, bool expanding, unsigned group); + int allowedChildFlex(RenderBox* child, bool expanding, unsigned group); bool hasMultipleLines() const { return style()->boxLines() == MULTIPLE; } bool isVertical() const { return style()->boxOrient() == VERTICAL; } diff --git a/WebCore/rendering/RenderFlow.cpp b/WebCore/rendering/RenderFlow.cpp index eb689cf..94ec124 100644 --- a/WebCore/rendering/RenderFlow.cpp +++ b/WebCore/rendering/RenderFlow.cpp @@ -246,7 +246,7 @@ void RenderFlow::destroy() void RenderFlow::dirtyLinesFromChangedChild(RenderObject* child) { - if (!parent() || (selfNeedsLayout() && !isInlineFlow()) || isTable()) + if (!parent() || (selfNeedsLayout() && !isRenderInline()) || isTable()) return; // If we have no first line box, then just bail early. @@ -272,10 +272,10 @@ void RenderFlow::dirtyLinesFromChangedChild(RenderObject* child) if (wrapper) box = wrapper->root(); } else if (curr->isText()) { - InlineTextBox* textBox = static_cast<RenderText*>(curr)->lastTextBox(); + InlineTextBox* textBox = toRenderText(curr)->lastTextBox(); if (textBox) box = textBox->root(); - } else if (curr->isInlineFlow()) { + } else if (curr->isRenderInline()) { InlineRunBox* runBox = static_cast<RenderFlow*>(curr)->lastLineBox(); if (runBox) box = runBox->root(); @@ -310,9 +310,9 @@ void RenderFlow::dirtyLinesFromChangedChild(RenderObject* child) } } -int RenderFlow::lineHeight(bool firstLine, bool isRootLineBox) const +int RenderFlow::lineHeight(bool firstLine, bool /*isRootLineBox*/) const { - if (firstLine) { + if (firstLine && document()->usesFirstLineRules()) { RenderStyle* s = style(firstLine); Length lh = s->lineHeight(); if (lh.isNegative()) { @@ -346,7 +346,7 @@ void RenderFlow::dirtyLineBoxes(bool fullLayout, bool isRootLineBox) } } -InlineBox* RenderFlow::createInlineBox(bool makePlaceHolderBox, bool isRootLineBox, bool isOnlyRun) +InlineBox* RenderFlow::createInlineBox(bool makePlaceHolderBox, bool isRootLineBox, bool /*isOnlyRun*/) { checkConsistency(); @@ -355,7 +355,7 @@ InlineBox* RenderFlow::createInlineBox(bool makePlaceHolderBox, bool isRootLineB return RenderContainer::createInlineBox(false, isRootLineBox); // (or positioned element placeholders). InlineFlowBox* flowBox = 0; - if (isInlineFlow()) + if (isRenderInline()) flowBox = new (renderArena()) InlineFlowBox(this); else flowBox = new (renderArena()) RootInlineBox(this); @@ -381,9 +381,9 @@ void RenderFlow::paintLines(PaintInfo& paintInfo, int tx, int ty) && paintInfo.phase != PaintPhaseMask) return; - bool inlineFlow = isInlineFlow(); + bool inlineFlow = isRenderInline(); if (inlineFlow) - ASSERT(m_layer); // The only way a compact/run-in/inline could paint like this is if it has a layer. + ASSERT(m_layer); // The only way an inline could paint like this is if it has a layer. // If we have no lines then we have no work to do. if (!firstLineBox()) @@ -400,7 +400,7 @@ void RenderFlow::paintLines(PaintInfo& paintInfo, int tx, int ty) return; PaintInfo info(paintInfo); - RenderFlowSequencedSet outlineObjects; + ListHashSet<RenderFlow*> outlineObjects; info.outlineObjects = &outlineObjects; // See if our root lines intersect with the dirty rect. If so, then we paint @@ -435,8 +435,8 @@ void RenderFlow::paintLines(PaintInfo& paintInfo, int tx, int ty) } if (info.phase == PaintPhaseOutline || info.phase == PaintPhaseSelfOutline || info.phase == PaintPhaseChildOutlines) { - RenderFlowSequencedSet::iterator end = info.outlineObjects->end(); - for (RenderFlowSequencedSet::iterator it = info.outlineObjects->begin(); it != end; ++it) { + ListHashSet<RenderFlow*>::iterator end = info.outlineObjects->end(); + for (ListHashSet<RenderFlow*>::iterator it = info.outlineObjects->begin(); it != end; ++it) { RenderFlow* flow = *it; flow->paintOutline(info.context, tx, ty); } @@ -449,9 +449,9 @@ bool RenderFlow::hitTestLines(const HitTestRequest& request, HitTestResult& resu if (hitTestAction != HitTestForeground) return false; - bool inlineFlow = isInlineFlow(); + bool inlineFlow = isRenderInline(); if (inlineFlow) - ASSERT(m_layer); // The only way a compact/run-in/inline could paint like this is if it has a layer. + ASSERT(m_layer); // The only way an inline can hit test like this is if it has a layer. // If we have no lines then we have no work to do. if (!firstLineBox()) @@ -480,151 +480,11 @@ bool RenderFlow::hitTestLines(const HitTestRequest& request, HitTestResult& resu return false; } -IntRect RenderFlow::absoluteClippedOverflowRect() -{ - if (isInlineFlow()) { - // Only compacts and run-ins are allowed in here during layout. - ASSERT(!view() || !view()->layoutState() || isCompact() || isRunIn()); - - if (!firstLineBox() && !continuation()) - return IntRect(); - - // Find our leftmost position. - int left = 0; - int top = firstLineBox() ? firstLineBox()->yPos() : 0; - for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) { - if (curr == firstLineBox() || curr->xPos() < left) - left = curr->xPos(); - } - - // Now invalidate a rectangle. - int ow = style() ? style()->outlineSize() : 0; - if (isCompact()) - left -= m_x; - - // We need to add in the relative position offsets of any inlines (including us) up to our - // containing block. - RenderBlock* cb = containingBlock(); - for (RenderObject* inlineFlow = this; inlineFlow && inlineFlow->isInlineFlow() && inlineFlow != cb; - inlineFlow = inlineFlow->parent()) { - if (inlineFlow->style()->position() == RelativePosition && inlineFlow->hasLayer()) - inlineFlow->layer()->relativePositionOffset(left, top); - } - - IntRect r(-ow + left, -ow + top, width() + ow * 2, height() + ow * 2); - if (cb->hasColumns()) - cb->adjustRectForColumns(r); - - if (cb->hasOverflowClip()) { - // cb->height() is inaccurate if we're in the middle of a layout of |cb|, so use the - // layer's size instead. Even if the layer's size is wrong, the layer itself will repaint - // anyway if its size does change. - int x = r.x(); - int y = r.y(); - IntRect boxRect(0, 0, cb->layer()->width(), cb->layer()->height()); - cb->layer()->subtractScrollOffset(x, y); // For overflow:auto/scroll/hidden. - IntRect repaintRect(x, y, r.width(), r.height()); - r = intersection(repaintRect, boxRect); - } - cb->computeAbsoluteRepaintRect(r); - - if (ow) { - for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { - if (!curr->isText()) { - IntRect childRect = curr->getAbsoluteRepaintRectWithOutline(ow); - r.unite(childRect); - } - } - - if (continuation() && !continuation()->isInline()) { - IntRect contRect = continuation()->getAbsoluteRepaintRectWithOutline(ow); - r.unite(contRect); - } - } - - return r; - } - - return RenderContainer::absoluteClippedOverflowRect(); -} - -int RenderFlow::lowestPosition(bool includeOverflowInterior, bool includeSelf) const -{ - ASSERT(!isInlineFlow()); - if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip())) - return includeSelf && m_width > 0 ? overflowHeight(false) : 0; - - int bottom = includeSelf && m_width > 0 ? m_height : 0; - if (!hasColumns()) { - // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids. - // For now, we have to descend into all the children, since we may have a huge abs div inside - // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to - // the abs div. - for (RenderObject* c = firstChild(); c; c = c->nextSibling()) { - if (!c->isFloatingOrPositioned() && !c->isText() && !c->isInlineFlow()) - bottom = max(bottom, c->yPos() + c->lowestPosition(false)); - } - } - - if (includeSelf && isRelPositioned()) - bottom += relativePositionOffsetY(); - - return bottom; -} - -int RenderFlow::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const -{ - ASSERT(!isInlineFlow()); - if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip())) - return includeSelf && m_height > 0 ? overflowWidth(false) : 0; - - int right = includeSelf && m_height > 0 ? m_width : 0; - if (!hasColumns()) { - // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids. - // For now, we have to descend into all the children, since we may have a huge abs div inside - // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to - // the abs div. - for (RenderObject* c = firstChild(); c; c = c->nextSibling()) { - if (!c->isFloatingOrPositioned() && !c->isText() && !c->isInlineFlow()) - right = max(right, c->xPos() + c->rightmostPosition(false)); - } - } - - if (includeSelf && isRelPositioned()) - right += relativePositionOffsetX(); - - return right; -} - -int RenderFlow::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const -{ - ASSERT(!isInlineFlow()); - if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip())) - return includeSelf && m_height > 0 ? overflowLeft(false) : m_width; - - int left = includeSelf && m_height > 0 ? 0 : m_width; - if (!hasColumns()) { - // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids. - // For now, we have to descend into all the children, since we may have a huge abs div inside - // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to - // the abs div. - for (RenderObject* c = firstChild(); c; c = c->nextSibling()) { - if (!c->isFloatingOrPositioned() && !c->isText() && !c->isInlineFlow()) - left = min(left, c->xPos() + c->leftmostPosition(false)); - } - } - - if (includeSelf && isRelPositioned()) - left += relativePositionOffsetX(); - - return left; -} - -IntRect RenderFlow::caretRect(InlineBox* inlineBox, int caretOffset, int* extraWidthToEndOfLine) +IntRect RenderFlow::localCaretRect(InlineBox* inlineBox, int caretOffset, int* extraWidthToEndOfLine) { // Do the normal calculation in most cases. if (firstChild() || style()->display() == INLINE) - return RenderContainer::caretRect(inlineBox, caretOffset, extraWidthToEndOfLine); + return RenderContainer::localCaretRect(inlineBox, caretOffset, extraWidthToEndOfLine); // This is a special case: // The element is not an inline element, and it's empty. So we have to @@ -684,20 +544,17 @@ IntRect RenderFlow::caretRect(InlineBox* inlineBox, int caretOffset, int* extraW // So *extraWidthToEndOfLine will always be 0 here. int myRight = x + caretWidth; - int ignore; - absolutePositionForContent(myRight, ignore); + // FIXME: why call localToAbsoluteForContent() twice here, too? + FloatPoint absRightPoint = localToAbsolute(FloatPoint(myRight, 0)); - int containerRight = containingBlock()->xPos() + containingBlockWidth(); - absolutePositionForContent(containerRight, ignore); + int containerRight = containingBlock()->x() + containingBlockWidth(); + FloatPoint absContainerPoint = localToAbsolute(FloatPoint(containerRight, 0)); - *extraWidthToEndOfLine = containerRight - myRight; + *extraWidthToEndOfLine = absContainerPoint.x() - absRightPoint.x(); } } - int absx, absy; - absolutePositionForContent(absx, absy); - x += absx; - int y = absy + paddingTop() + borderTop(); + int y = paddingTop() + borderTop(); return IntRect(x, y, caretWidth, height); } @@ -722,28 +579,27 @@ void RenderFlow::addFocusRingRects(GraphicsContext* graphicsContext, int tx, int graphicsContext->addFocusRingRect(IntRect(tx + curr->xPos(), ty + curr->yPos(), curr->width(), curr->height())); for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) - if (!curr->isText() && !curr->isListMarker()) { - int x = 0; - int y = 0; - if (curr->layer()) - curr->absolutePosition(x, y); - else { - x = tx + curr->xPos(); - y = ty + curr->yPos(); - } - curr->addFocusRingRects(graphicsContext, x, y); + if (!curr->isText() && !curr->isListMarker() && curr->isBox()) { + RenderBox* box = toRenderBox(curr); + FloatPoint pos; + // FIXME: This doesn't work correctly with transforms. + if (box->layer()) + pos = curr->localToAbsolute(); + else + pos = FloatPoint(tx + box->x(), ty + box->y()); + box->addFocusRingRects(graphicsContext, pos.x(), pos.y()); } } if (continuation()) { if (isInline()) continuation()->addFocusRingRects(graphicsContext, - tx - containingBlock()->xPos() + continuation()->xPos(), - ty - containingBlock()->yPos() + continuation()->yPos()); + tx - containingBlock()->x() + continuation()->x(), + ty - containingBlock()->y() + continuation()->y()); else continuation()->addFocusRingRects(graphicsContext, - tx - xPos() + continuation()->containingBlock()->xPos(), - ty - yPos() + continuation()->containingBlock()->yPos()); + tx - x() + continuation()->containingBlock()->x(), + ty - y() + continuation()->containingBlock()->y()); } } diff --git a/WebCore/rendering/RenderFlow.h b/WebCore/rendering/RenderFlow.h index c284ed8..897e40a 100644 --- a/WebCore/rendering/RenderFlow.h +++ b/WebCore/rendering/RenderFlow.h @@ -52,13 +52,15 @@ public: , m_selectionState(SelectionNone) , m_hasColumns(false) , m_isContinuation(false) + , m_cellWidthChanged(false) { } #ifndef NDEBUG virtual ~RenderFlow(); #endif - virtual RenderFlow* continuation() const { return m_continuation; } + virtual RenderFlow* virtualContinuation() const { return continuation(); } + RenderFlow* continuation() const { return m_continuation; } void setContinuation(RenderFlow* c) { m_continuation = c; } RenderFlow* continuationBefore(RenderObject* beforeChild); @@ -87,13 +89,7 @@ public: void paintLines(PaintInfo&, int tx, int ty); bool hitTestLines(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); - virtual IntRect absoluteClippedOverflowRect(); - - virtual int lowestPosition(bool includeOverflowInterior = true, bool includeSelf = true) const; - virtual int rightmostPosition(bool includeOverflowInterior = true, bool includeSelf = true) const; - virtual int leftmostPosition(bool includeOverflowInterior = true, bool includeSelf = true) const; - - virtual IntRect caretRect(InlineBox*, int caretOffset, int* extraWidthToEndOfLine = 0); + virtual IntRect localCaretRect(InlineBox*, int caretOffset, int* extraWidthToEndOfLine = 0); virtual void addFocusRingRects(GraphicsContext*, int tx, int ty); void paintOutlineForLine(GraphicsContext*, int tx, int ty, const IntRect& prevLine, const IntRect& thisLine, const IntRect& nextLine); @@ -133,6 +129,9 @@ protected: // from RenderInline bool m_isContinuation : 1; // Whether or not we're a continuation of an inline. + + // from RenderTableCell + bool m_cellWidthChanged : 1; }; #ifdef NDEBUG diff --git a/WebCore/rendering/RenderForeignObject.cpp b/WebCore/rendering/RenderForeignObject.cpp index 5070b97..523601c 100644 --- a/WebCore/rendering/RenderForeignObject.cpp +++ b/WebCore/rendering/RenderForeignObject.cpp @@ -38,10 +38,10 @@ RenderForeignObject::RenderForeignObject(SVGForeignObjectElement* node) { } -AffineTransform RenderForeignObject::translationForAttributes() +TransformationMatrix RenderForeignObject::translationForAttributes() { SVGForeignObjectElement* foreign = static_cast<SVGForeignObjectElement*>(element()); - return AffineTransform().translate(foreign->x().value(foreign), foreign->y().value(foreign)); + return TransformationMatrix().translate(foreign->x().value(foreign), foreign->y().value(foreign)); } void RenderForeignObject::paint(PaintInfo& paintInfo, int parentX, int parentY) @@ -50,7 +50,7 @@ void RenderForeignObject::paint(PaintInfo& paintInfo, int parentX, int parentY) return; paintInfo.context->save(); - paintInfo.context->concatCTM(AffineTransform().translate(parentX, parentY)); + paintInfo.context->concatCTM(TransformationMatrix().translate(parentX, parentY)); paintInfo.context->concatCTM(localTransform()); paintInfo.context->concatCTM(translationForAttributes()); paintInfo.context->clip(getClipRect(parentX, parentY)); @@ -70,22 +70,17 @@ void RenderForeignObject::paint(PaintInfo& paintInfo, int parentX, int parentY) paintInfo.context->restore(); } -void RenderForeignObject::computeAbsoluteRepaintRect(IntRect& r, bool f) +void RenderForeignObject::computeRectForRepaint(IntRect& rect, RenderBox* repaintContainer, bool fixed) { - AffineTransform transform = translationForAttributes() * localTransform(); - r = transform.mapRect(r); + TransformationMatrix transform = translationForAttributes() * localTransform(); + rect = transform.mapRect(rect); - RenderBlock::computeAbsoluteRepaintRect(r, f); -} - -bool RenderForeignObject::requiresLayer() -{ - return false; + RenderBlock::computeRectForRepaint(rect, repaintContainer, fixed); } bool RenderForeignObject::calculateLocalTransform() { - AffineTransform oldTransform = m_localTransform; + TransformationMatrix oldTransform = m_localTransform; m_localTransform = static_cast<SVGForeignObjectElement*>(element())->animatedLocalTransform(); return (oldTransform != m_localTransform); } @@ -102,7 +97,7 @@ void RenderForeignObject::layout() bool checkForRepaint = checkForRepaintDuringLayout(); if (checkForRepaint) { oldBounds = m_absoluteBounds; - oldOutlineBox = absoluteOutlineBox(); + oldOutlineBox = absoluteOutlineBounds(); } calculateLocalTransform(); @@ -120,7 +115,7 @@ void RenderForeignObject::layout() bool RenderForeignObject::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction) { - AffineTransform totalTransform = absoluteTransform(); + TransformationMatrix totalTransform = absoluteTransform(); totalTransform *= translationForAttributes(); double localX, localY; totalTransform.inverse().map(x, y, &localX, &localY); diff --git a/WebCore/rendering/RenderForeignObject.h b/WebCore/rendering/RenderForeignObject.h index b624683..28f4ddb 100644 --- a/WebCore/rendering/RenderForeignObject.h +++ b/WebCore/rendering/RenderForeignObject.h @@ -24,7 +24,7 @@ #define RenderForeignObject_h #if ENABLE(SVG) && ENABLE(SVG_FOREIGN_OBJECT) -#include "AffineTransform.h" +#include "TransformationMatrix.h" #include "RenderSVGBlock.h" namespace WebCore { @@ -39,19 +39,19 @@ public: virtual void paint(PaintInfo&, int parentX, int parentY); - virtual AffineTransform localTransform() const { return m_localTransform; } + virtual TransformationMatrix localTransform() const { return m_localTransform; } virtual bool calculateLocalTransform(); - virtual void computeAbsoluteRepaintRect(IntRect&, bool fixed); - virtual bool requiresLayer(); + virtual void computeRectForRepaint(IntRect&, RenderBox* repaintContainer, bool fixed = false); + virtual bool requiresLayer() const { return false; } virtual void layout(); virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); private: - AffineTransform translationForAttributes(); + TransformationMatrix translationForAttributes(); - AffineTransform m_localTransform; + TransformationMatrix m_localTransform; IntRect m_absoluteBounds; }; diff --git a/WebCore/rendering/RenderFrame.cpp b/WebCore/rendering/RenderFrame.cpp index c996138..9e1d92b 100644 --- a/WebCore/rendering/RenderFrame.cpp +++ b/WebCore/rendering/RenderFrame.cpp @@ -76,17 +76,17 @@ void RenderFrame::layout() root = static_cast<RenderView*>(view->frame()->document()->renderer()); if (root) { // Resize the widget so that the RenderView will layout according to those dimensions. - view->resize(m_width, m_height); + view->resize(width(), height()); view->layout(); // We can only grow in width and height because if positionFrames gives us a width and we become smaller, // then the fixup process of forcing the frame to fill extra space will fail. - if (m_width > root->docWidth()) { + if (width() > root->docWidth()) { view->resize(root->docWidth(), 0); view->layout(); } // Honor the height set by RenderFrameSet::positionFrames unless our document height is larger. - m_height = max(root->docHeight(), m_height); - m_width = max(root->docWidth(), m_width); + setHeight(max(root->docHeight(), height())); + setWidth(max(root->docWidth(), width())); } } setNeedsLayout(false); diff --git a/WebCore/rendering/RenderFrameSet.cpp b/WebCore/rendering/RenderFrameSet.cpp index 2b74d8a..f6cd4df 100644 --- a/WebCore/rendering/RenderFrameSet.cpp +++ b/WebCore/rendering/RenderFrameSet.cpp @@ -129,8 +129,8 @@ void RenderFrameSet::paint(PaintInfo& paintInfo, int tx, int ty) return; // Add in our offsets. - tx += m_x; - ty += m_y; + tx += x(); + ty += y(); int rows = frameSet()->totalRows(); int cols = frameSet()->totalCols(); @@ -464,8 +464,8 @@ void RenderFrameSet::layout() // Force a grid recalc. m_gridCalculated = false; #endif - m_width = view()->viewWidth(); - m_height = view()->viewHeight(); + setWidth(view()->viewWidth()); + setHeight(view()->viewHeight()); } size_t cols = frameSet()->totalCols(); @@ -490,8 +490,8 @@ void RenderFrameSet::layout() } #endif int borderThickness = frameSet()->border(); - layOutAxis(m_rows, frameSet()->rowLengths(), m_height - (rows - 1) * borderThickness); - layOutAxis(m_cols, frameSet()->colLengths(), m_width - (cols - 1) * borderThickness); + layOutAxis(m_rows, frameSet()->rowLengths(), height() - (rows - 1) * borderThickness); + layOutAxis(m_cols, frameSet()->colLengths(), width() - (cols - 1) * borderThickness); #ifdef FLATTEN_FRAMESET } #endif @@ -514,7 +514,7 @@ void RenderFrameSet::layout() void RenderFrameSet::positionFrames() { - RenderObject* child = firstChild(); + RenderBox* child = firstChildBox(); if (!child) return; @@ -539,7 +539,8 @@ void RenderFrameSet::positionFrames() rowHeight = l.value(); } for (int c = 0; c < cols && child; c++) { - child->setPos(xPos, yPos); + child->setX(xPos); + child->setY(yPos); child->setWidth(m_cols.m_sizes[c]); child->setHeight(height); int colWidth = -1; @@ -560,7 +561,7 @@ void RenderFrameSet::positionFrames() height = max(child->height(), height); xPos += child->width() + borderThickness; - child = child->nextSibling(); + child = (RenderBox*)child->nextSibling(); } ASSERT(height >= m_rows.m_sizes[r]); m_rows.m_sizes[r] = height; @@ -574,10 +575,10 @@ void RenderFrameSet::positionFrames() int newHeight = yPos - borderThickness; // Distribute the extra width and height evenly across the grid. - int dWidth = (m_width - newWidth) / cols; - int dHeight = (m_height - newHeight) / rows; + int dWidth = (width() - newWidth) / cols; + int dHeight = (height() - newHeight) / rows; if (dWidth > 0) { - int availableWidth = m_width - (cols - 1) * borderThickness; + int availableWidth = width() - (cols - 1) * borderThickness; for (int c = 0; c < cols; c++) availableWidth -= m_cols.m_sizes[c] += dWidth; // If the extra width did not distribute evenly, add the remainder to @@ -586,7 +587,7 @@ void RenderFrameSet::positionFrames() m_cols.m_sizes[cols - 1] += availableWidth; } if (dHeight > 0) { - int availableHeight = m_height - (rows - 1) * borderThickness; + int availableHeight = height() - (rows - 1) * borderThickness; for (int r = 0; r < rows; r++) availableHeight -= m_rows.m_sizes[r] += dHeight; // If the extra height did not distribute evenly, add the remainder to @@ -596,9 +597,9 @@ void RenderFrameSet::positionFrames() } // Ensure the rows and columns are filled by falling through to the normal // layout - m_height = max(m_height, newHeight); - m_width = max(m_width, newWidth); - child = firstChild(); + setHeight(max(height(), newHeight)); + setWidth(max(width(), newWidth)); + child = (RenderBox*)firstChild(); yPos = 0; #endif // FLATTEN_FRAMESET @@ -606,7 +607,7 @@ void RenderFrameSet::positionFrames() int xPos = 0; int height = m_rows.m_sizes[r]; for (int c = 0; c < cols; c++) { - child->setPos(xPos, yPos); + child->setLocation(xPos, yPos); int width = m_cols.m_sizes[c]; // has to be resized and itself resize its contents @@ -619,7 +620,7 @@ void RenderFrameSet::positionFrames() xPos += width + borderThickness; - child = child->nextSibling(); + child = child->nextSiblingBox(); if (!child) return; } @@ -627,7 +628,7 @@ void RenderFrameSet::positionFrames() } // all the remaining frames are hidden to avoid ugly spurious unflowed frames - for (; child; child = child->nextSibling()) { + for (; child; child = child->nextSiblingBox()) { child->setWidth(0); child->setHeight(0); child->setNeedsLayout(false); @@ -666,8 +667,9 @@ bool RenderFrameSet::userResize(MouseEvent* evt) if (needsLayout()) return false; if (evt->type() == eventNames().mousedownEvent && evt->button() == LeftButton) { - startResizing(m_cols, evt->pageX() - xPos()); - startResizing(m_rows, evt->pageY() - yPos()); + FloatPoint pos = localToAbsolute(); + startResizing(m_cols, evt->pageX() - pos.x()); + startResizing(m_rows, evt->pageY() - pos.y()); if (m_cols.m_splitBeingResized != noSplit || m_rows.m_splitBeingResized != noSplit) { setIsResizing(true); return true; @@ -675,8 +677,9 @@ bool RenderFrameSet::userResize(MouseEvent* evt) } } else { if (evt->type() == eventNames().mousemoveEvent || (evt->type() == eventNames().mouseupEvent && evt->button() == LeftButton)) { - continueResizing(m_cols, evt->pageX() - xPos()); - continueResizing(m_rows, evt->pageY() - yPos()); + FloatPoint pos = localToAbsolute(); + continueResizing(m_cols, evt->pageX() - pos.x()); + continueResizing(m_rows, evt->pageY() - pos.y()); if (evt->type() == eventNames().mouseupEvent && evt->button() == LeftButton) { setIsResizing(false); return true; @@ -763,7 +766,7 @@ int RenderFrameSet::hitTestSplit(const GridAxis& axis, int position) const return noSplit; } -bool RenderFrameSet::isChildAllowed(RenderObject* child, RenderStyle* style) const +bool RenderFrameSet::isChildAllowed(RenderObject* child, RenderStyle*) const { return child->isFrame() || child->isFrameSet(); } diff --git a/WebCore/rendering/RenderHTMLCanvas.cpp b/WebCore/rendering/RenderHTMLCanvas.cpp index cc8c2c1..f4d88d8 100644 --- a/WebCore/rendering/RenderHTMLCanvas.cpp +++ b/WebCore/rendering/RenderHTMLCanvas.cpp @@ -39,32 +39,33 @@ using namespace HTMLNames; RenderHTMLCanvas::RenderHTMLCanvas(HTMLCanvasElement* element) : RenderReplaced(element, element->size()) { + view()->frameView()->setIsVisuallyNonEmpty(); } void RenderHTMLCanvas::paintReplaced(PaintInfo& paintInfo, int tx, int ty) { - IntRect rect = contentBox(); + IntRect rect = contentBoxRect(); rect.move(tx, ty); static_cast<HTMLCanvasElement*>(node())->paint(paintInfo.context, rect); } void RenderHTMLCanvas::canvasSizeChanged() { - IntSize size = static_cast<HTMLCanvasElement*>(node())->size(); - IntSize zoomedSize(size.width() * style()->effectiveZoom(), size.height() * style()->effectiveZoom()); + IntSize canvasSize = static_cast<HTMLCanvasElement*>(node())->size(); + IntSize zoomedSize(canvasSize.width() * style()->effectiveZoom(), canvasSize.height() * style()->effectiveZoom()); - if (size == intrinsicSize()) + if (canvasSize == intrinsicSize()) return; - setIntrinsicSize(size); + setIntrinsicSize(canvasSize); if (!prefWidthsDirty()) setPrefWidthsDirty(true); - IntSize oldSize = IntSize(m_width, m_height); + IntSize oldSize = size(); calcWidth(); calcHeight(); - if (oldSize == IntSize(m_width, m_height)) + if (oldSize == size()) return; if (!selfNeedsLayout()) diff --git a/WebCore/rendering/RenderImage.cpp b/WebCore/rendering/RenderImage.cpp index 604c407..e67a4ca 100644 --- a/WebCore/rendering/RenderImage.cpp +++ b/WebCore/rendering/RenderImage.cpp @@ -28,6 +28,7 @@ #include "BitmapImage.h" #include "Document.h" +#include "FrameView.h" #include "GraphicsContext.h" #include "HTMLImageElement.h" #include "HTMLInputElement.h" @@ -36,11 +37,16 @@ #include "HitTestResult.h" #include "Page.h" #include "RenderView.h" +#include <wtf/CurrentTime.h> + #ifdef ANDROID_LAYOUT #include "Settings.h" #endif -#include "SystemTime.h" +#if ENABLE(WML) +#include "WMLImageElement.h" +#include "WMLNames.h" +#endif using namespace std; @@ -169,7 +175,7 @@ bool RenderImageScaleObserver::shouldImagePaintAtLowQuality(RenderImage* image, HashMap<RenderImage*, RenderImageScaleData*>* RenderImageScaleObserver::gImages = 0; -void RenderImage::highQualityRepaintTimerFired(Timer<RenderImage>* timer) +void RenderImage::highQualityRepaintTimerFired(Timer<RenderImage>*) { RenderImageScaleObserver::highQualityRepaintTimerFired(this); } @@ -181,6 +187,8 @@ RenderImage::RenderImage(Node* node) , m_cachedImage(0) { updateAltText(); + + view()->frameView()->setIsVisuallyNonEmpty(); } RenderImage::~RenderImage() @@ -248,13 +256,13 @@ bool RenderImage::setImageSizeForAltText(CachedImage* newImage /* = 0 */) return true; } -void RenderImage::imageChanged(WrappedImagePtr newImage) +void RenderImage::imageChanged(WrappedImagePtr newImage, const IntRect* rect) { if (documentBeingDestroyed()) return; if (hasBoxDecorations() || hasMask()) - RenderReplaced::imageChanged(newImage); + RenderReplaced::imageChanged(newImage, rect); if (newImage != imagePtr() || !newImage) return; @@ -277,28 +285,36 @@ void RenderImage::imageChanged(WrappedImagePtr newImage) // layout when we get added in to the render tree hierarchy later. if (containingBlock()) { // lets see if we need to relayout at all.. - int oldwidth = m_width; - int oldheight = m_height; + int oldwidth = width(); + int oldheight = height(); if (!prefWidthsDirty()) setPrefWidthsDirty(true); calcWidth(); calcHeight(); - if (imageSizeChanged || m_width != oldwidth || m_height != oldheight) { + if (imageSizeChanged || width() != oldwidth || height() != oldheight) { shouldRepaint = false; if (!selfNeedsLayout()) setNeedsLayout(true); } - m_width = oldwidth; - m_height = oldheight; + setWidth(oldwidth); + setHeight(oldheight); } } if (shouldRepaint) { - // FIXME: We always just do a complete repaint, since we always pass in the full image - // rect at the moment anyway. - repaintRectangle(contentBox()); + IntRect repaintRect; + if (rect) { + // The image changed rect is in source image coordinates (pre-zooming), + // so map from the bounds of the image to the contentsBox. + repaintRect = enclosingIntRect(mapRect(*rect, FloatRect(FloatPoint(), imageSize(1.0f)), contentBoxRect())); + // Guard against too-large changed rects. + repaintRect.intersect(contentBoxRect()); + } else + repaintRect = contentBoxRect(); + + repaintRectangle(repaintRect); } } @@ -359,9 +375,7 @@ void RenderImage::paintReplaced(PaintInfo& paintInfo, int tx, int ty) } if (!m_altText.isEmpty()) { - String text = m_altText; - text.replace('\\', backslashAsCurrencySymbol()); - context->setFont(style()->font()); + String text = document()->displayStringModifiedByEncoding(m_altText); context->setFillColor(style()->color()); int ax = tx + leftBorder + leftPad; int ay = ty + topBorder + topPad; @@ -374,9 +388,9 @@ void RenderImage::paintReplaced(PaintInfo& paintInfo, int tx, int ty) int textWidth = font.width(textRun); if (errorPictureDrawn) { if (usableWidth >= textWidth && font.height() <= imageY) - context->drawText(textRun, IntPoint(ax, ay + ascent)); + context->drawText(style()->font(), textRun, IntPoint(ax, ay + ascent)); } else if (usableWidth >= textWidth && cHeight >= font.height()) - context->drawText(textRun, IntPoint(ax, ay + ascent)); + context->drawText(style()->font(), textRun, IntPoint(ax, ay + ascent)); } } } else if (hasImage() && cWidth > 0 && cHeight > 0) { @@ -386,7 +400,7 @@ void RenderImage::paintReplaced(PaintInfo& paintInfo, int tx, int ty) #if PLATFORM(MAC) if (style()->highlight() != nullAtom && !paintInfo.context->paintingDisabled()) - paintCustomHighlight(tx - m_x, ty - m_y, style()->highlight(), true); + paintCustomHighlight(tx - x(), ty - y(), style()->highlight(), true); #endif IntSize contentSize(cWidth, cHeight); @@ -414,8 +428,8 @@ bool RenderImage::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu bool inside = RenderReplaced::nodeAtPoint(request, result, _x, _y, _tx, _ty, hitTestAction); if (inside && element()) { - int tx = _tx + m_x; - int ty = _ty + m_y; + int tx = _tx + x(); + int ty = _ty + y(); HTMLMapElement* map = imageMap(); if (map) { @@ -437,6 +451,10 @@ void RenderImage::updateAltText() m_altText = static_cast<HTMLInputElement*>(element())->altText(); else if (element()->hasTagName(imgTag)) m_altText = static_cast<HTMLImageElement*>(element())->altText(); +#if ENABLE(WML) + else if (element()->hasTagName(WMLNames::imgTag)) + m_altText = static_cast<WMLImageElement*>(element())->altText(); +#endif } bool RenderImage::isWidthSpecified() const @@ -476,8 +494,10 @@ bool RenderImage::isHeightSpecified() const int RenderImage::calcReplacedWidth(bool includeMaxWidth) const { if (imageHasRelativeWidth()) - if (RenderObject* cb = isPositioned() ? container() : containingBlock()) - setImageContainerSize(IntSize(cb->availableWidth(), cb->availableHeight())); + if (RenderObject* cb = isPositioned() ? container() : containingBlock()) { + if (cb->isBox()) + setImageContainerSize(IntSize(toRenderBox(cb)->availableWidth(), toRenderBox(cb)->availableHeight())); + } int width; if (isWidthSpecified()) diff --git a/WebCore/rendering/RenderImage.h b/WebCore/rendering/RenderImage.h index 477fdeb..71896d6 100644 --- a/WebCore/rendering/RenderImage.h +++ b/WebCore/rendering/RenderImage.h @@ -47,7 +47,7 @@ public: virtual int minimumReplacedHeight() const; - virtual void imageChanged(WrappedImagePtr); + virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); bool setImageSizeForAltText(CachedImage* newImage = 0); @@ -72,7 +72,7 @@ public: void highQualityRepaintTimerFired(Timer<RenderImage>*); protected: - virtual Image* image(int w = 0, int h = 0) { return m_cachedImage ? m_cachedImage->image() : nullImage(); } + virtual Image* image(int /*w*/ = 0, int /*h*/ = 0) { return m_cachedImage ? m_cachedImage->image() : nullImage(); } virtual bool errorOccurred() const { return m_cachedImage && m_cachedImage->errorOccurred(); } virtual bool usesImageContainerSize() const { return m_cachedImage ? m_cachedImage->usesImageContainerSize() : false; } virtual void setImageContainerSize(const IntSize& size) const { if (m_cachedImage) m_cachedImage->setImageContainerSize(size); } diff --git a/WebCore/rendering/RenderInline.cpp b/WebCore/rendering/RenderInline.cpp index 79d914f..4f4412d 100644 --- a/WebCore/rendering/RenderInline.cpp +++ b/WebCore/rendering/RenderInline.cpp @@ -25,9 +25,10 @@ #include "config.h" #include "RenderInline.h" -#include "Document.h" +#include "FloatQuad.h" #include "RenderArena.h" #include "RenderBlock.h" +#include "RenderView.h" #include "VisiblePosition.h" namespace WebCore { @@ -68,7 +69,7 @@ void RenderInline::styleDidChange(RenderStyle::Diff diff, const RenderStyle* old m_lineHeight = -1; // Update pseudos for :before and :after now. - if (!isAnonymous()) { + if (!isAnonymous() && document()->usesBeforeAfterRules()) { updateBeforeAfterContent(RenderStyle::BEFORE); updateBeforeAfterContent(RenderStyle::AFTER); } @@ -115,7 +116,8 @@ void RenderInline::addChildToFlow(RenderObject* newChild, RenderObject* beforeCh // has to move into the inline continuation. Call updateBeforeAfterContent to ensure that our :after // content gets properly destroyed. bool isLastChild = (beforeChild == lastChild()); - updateBeforeAfterContent(RenderStyle::AFTER); + if (document()->usesBeforeAfterRules()) + updateBeforeAfterContent(RenderStyle::AFTER); if (isLastChild && beforeChild != lastChild()) beforeChild = 0; // We destroyed the last child, so now we need to update our insertion // point to be 0. It's just a straight append now. @@ -187,7 +189,8 @@ void RenderInline::splitInlines(RenderBlock* fromBlock, RenderBlock* toBlock, // Someone may have indirectly caused a <q> to split. When this happens, the :after content // has to move into the inline continuation. Call updateBeforeAfterContent to ensure that the inline's :after // content gets properly destroyed. - curr->updateBeforeAfterContent(RenderStyle::AFTER); + if (document()->usesBeforeAfterRules()) + curr->updateBeforeAfterContent(RenderStyle::AFTER); // Now we need to take all of the children starting from the first child // *after* currChild and append them all to the clone. @@ -290,46 +293,33 @@ void RenderInline::absoluteRects(Vector<IntRect>& rects, int tx, int ty, bool to rects.append(IntRect(tx + curr->xPos(), ty + curr->yPos(), curr->width(), curr->height())); for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { - if (!curr->isText()) - curr->absoluteRects(rects, tx + curr->xPos(), ty + curr->yPos(), false); + if (curr->isBox()) { + RenderBox* box = toRenderBox(curr); + curr->absoluteRects(rects, tx + box->x(), ty + box->y(), false); + } } if (continuation() && topLevel) continuation()->absoluteRects(rects, - tx - containingBlock()->xPos() + continuation()->xPos(), - ty - containingBlock()->yPos() + continuation()->yPos(), + tx - containingBlock()->x() + continuation()->x(), + ty - containingBlock()->y() + continuation()->y(), topLevel); } -bool RenderInline::requiresLayer() -{ - return isRelPositioned() || isTransparent() || hasMask(); -} - -int RenderInline::width() const +void RenderInline::absoluteQuads(Vector<FloatQuad>& quads, bool topLevel) { - // Return the width of the minimal left side and the maximal right side. - int leftSide = 0; - int rightSide = 0; for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) { - if (curr == firstLineBox() || curr->xPos() < leftSide) - leftSide = curr->xPos(); - if (curr == firstLineBox() || curr->xPos() + curr->width() > rightSide) - rightSide = curr->xPos() + curr->width(); + FloatRect localRect(curr->xPos(), curr->yPos(), curr->width(), curr->height()); + quads.append(localToAbsoluteQuad(localRect)); + } + + for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { + if (!curr->isText()) + curr->absoluteQuads(quads, false); } - return rightSide - leftSide; -} - -int RenderInline::height() const -{ - // 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 - // unable to reproduce this at all (and consequently unable to figure ot why this is happening). The assert will hopefully catch the problem in debug - // builds and help us someday figure out why. We also put in a redundant check of lastLineBox() to avoid the crash for now. - ASSERT(!firstLineBox() == !lastLineBox()); // Either both are null or both exist. - if (firstLineBox() && lastLineBox()) - return lastLineBox()->yPos() + lastLineBox()->height() - firstLineBox()->yPos(); - return 0; + if (continuation() && topLevel) + continuation()->absoluteQuads(quads, topLevel); } int RenderInline::offsetLeft() const @@ -354,6 +344,8 @@ const char* RenderInline::renderName() const return "RenderInline (relative positioned)"; if (isAnonymous()) return "RenderInline (generated)"; + if (isRunIn()) + return "RenderInline (run-in)"; return "RenderInline"; } @@ -367,17 +359,104 @@ VisiblePosition RenderInline::positionForCoordinates(int x, int y) { // Translate the coords from the pre-anonymous block to the post-anonymous block. RenderBlock* cb = containingBlock(); - int parentBlockX = cb->xPos() + x; - int parentBlockY = cb->yPos() + y; - for (RenderObject* c = continuation(); c; c = c->continuation()) { - RenderObject* contBlock = c; + int parentBlockX = cb->x() + x; + int parentBlockY = cb->y() + y; + for (RenderFlow* c = continuation(); c; c = c->continuation()) { + RenderFlow* contBlock = c; if (c->isInline()) contBlock = c->containingBlock(); if (c->isInline() || c->firstChild()) - return c->positionForCoordinates(parentBlockX - contBlock->xPos(), parentBlockY - contBlock->yPos()); + return c->positionForCoordinates(parentBlockX - contBlock->x(), parentBlockY - contBlock->y()); } return RenderFlow::positionForCoordinates(x, y); } +IntRect RenderInline::linesBoundingBox() const +{ + 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 + // unable to reproduce this at all (and consequently unable to figure ot why this is happening). The assert will hopefully catch the problem in debug + // builds and help us someday figure out why. We also put in a redundant check of lastLineBox() to avoid the crash for now. + ASSERT(!firstLineBox() == !lastLineBox()); // Either both are null or both exist. + if (firstLineBox() && lastLineBox()) { + // Return the width of the minimal left side and the maximal right side. + int leftSide = 0; + int rightSide = 0; + for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) { + if (curr == firstLineBox() || curr->xPos() < leftSide) + leftSide = curr->xPos(); + if (curr == firstLineBox() || curr->xPos() + curr->width() > rightSide) + rightSide = curr->xPos() + curr->width(); + } + result.setWidth(rightSide - leftSide); + result.setX(leftSide); + result.setHeight(lastLineBox()->yPos() + lastLineBox()->height() - firstLineBox()->yPos()); + result.setY(firstLineBox()->yPos()); + } + + return result; +} + +IntRect RenderInline::clippedOverflowRectForRepaint(RenderBox* repaintContainer) +{ + // Only run-ins are allowed in here during layout. + ASSERT(!view() || !view()->layoutStateEnabled() || isRunIn()); + + if (!firstLineBox() && !continuation()) + return IntRect(); + + // Find our leftmost position. + IntRect boundingBox(linesBoundingBox()); + int left = boundingBox.x(); + int top = boundingBox.y(); + + // Now invalidate a rectangle. + int ow = style() ? style()->outlineSize() : 0; + + // We need to add in the relative position offsets of any inlines (including us) up to our + // containing block. + RenderBlock* cb = containingBlock(); + for (RenderObject* inlineFlow = this; inlineFlow && inlineFlow->isRenderInline() && inlineFlow != cb; + inlineFlow = inlineFlow->parent()) { + if (inlineFlow->style()->position() == RelativePosition && inlineFlow->hasLayer()) + toRenderBox(inlineFlow)->layer()->relativePositionOffset(left, top); + } + + IntRect r(-ow + left, -ow + top, boundingBox.width() + ow * 2, boundingBox.height() + ow * 2); + if (cb->hasColumns()) + cb->adjustRectForColumns(r); + + if (cb->hasOverflowClip()) { + // cb->height() is inaccurate if we're in the middle of a layout of |cb|, so use the + // layer's size instead. Even if the layer's size is wrong, the layer itself will repaint + // anyway if its size does change. + int x = r.x(); + int y = r.y(); + IntRect boxRect(0, 0, cb->layer()->width(), cb->layer()->height()); + cb->layer()->subtractScrolledContentOffset(x, y); // For overflow:auto/scroll/hidden. + IntRect repaintRect(x, y, r.width(), r.height()); + r = intersection(repaintRect, boxRect); + } + ASSERT(repaintContainer != this); + cb->computeRectForRepaint(r, repaintContainer); + + if (ow) { + for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { + if (!curr->isText()) { + IntRect childRect = curr->rectWithOutlineForRepaint(repaintContainer, ow); + r.unite(childRect); + } + } + + if (continuation() && !continuation()->isInline()) { + IntRect contRect = continuation()->rectWithOutlineForRepaint(repaintContainer, ow); + r.unite(contRect); + } + } + + return r; +} + } // namespace WebCore diff --git a/WebCore/rendering/RenderInline.h b/WebCore/rendering/RenderInline.h index 36cb864..83b8506 100644 --- a/WebCore/rendering/RenderInline.h +++ b/WebCore/rendering/RenderInline.h @@ -39,7 +39,6 @@ public: virtual const char* renderName() const; virtual bool isRenderInline() const { return true; } - virtual bool isInlineFlow() const { return true; } virtual bool childrenInline() const { return true; } virtual bool isInlineContinuation() const; @@ -56,21 +55,28 @@ public: virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); - // overrides RenderObject - virtual bool requiresLayer(); + virtual bool requiresLayer() const { return isRelPositioned() || isTransparent() || hasMask(); } - virtual int width() const; - virtual int height() const; - - // used to calculate offsetWidth/Height. Overridden by inlines (RenderFlow) to return - // the remaining width on a given line (and the height of a single line). virtual int offsetLeft() const; virtual int offsetTop() const; + virtual int offsetWidth() const { return linesBoundingBox().width(); } + virtual int offsetHeight() const { return linesBoundingBox().height(); } void absoluteRects(Vector<IntRect>&, int tx, int ty, bool topLevel = true); + virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true); + + virtual IntRect clippedOverflowRectForRepaint(RenderBox* repaintContainer); virtual VisiblePosition positionForCoordinates(int x, int y); + IntRect linesBoundingBox() const; + + virtual IntRect borderBoundingBox() const + { + IntRect boundingBox = linesBoundingBox(); + return IntRect(0, 0, boundingBox.width(), boundingBox.height()); + } + protected: virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle); diff --git a/WebCore/rendering/RenderLayer.cpp b/WebCore/rendering/RenderLayer.cpp index 93efde1..1a538c6 100644 --- a/WebCore/rendering/RenderLayer.cpp +++ b/WebCore/rendering/RenderLayer.cpp @@ -74,6 +74,7 @@ #include "ScrollbarTheme.h" #include "SelectionController.h" #include "TranslateTransformOperation.h" +#include <wtf/StdLibExtras.h> #if ENABLE(SVG) #include "SVGNames.h" @@ -115,8 +116,8 @@ void ClipRects::destroy(RenderArena* renderArena) renderArena->free(*(size_t *)this, this); } -RenderLayer::RenderLayer(RenderObject* object) - : m_object(object) +RenderLayer::RenderLayer(RenderBox* renderer) + : m_renderer(renderer) , m_parent(0) , m_previous(0) , m_next(0) @@ -139,6 +140,9 @@ RenderLayer::RenderLayer(RenderObject* object) , m_negZOrderList(0) , m_overflowList(0) , m_clipRects(0) +#ifndef NDEBUG + , m_clipRectsRoot(0) +#endif , m_scrollDimensionsDirty(true) , m_zOrderListsDirty(true) , m_overflowListDirty(true) @@ -160,9 +164,9 @@ RenderLayer::RenderLayer(RenderObject* object) , m_scrollCorner(0) , m_resizer(0) { - if (!object->firstChild() && object->style()) { + if (!renderer->firstChild() && renderer->style()) { m_visibleContentStatusDirty = false; - m_hasVisibleContent = object->style()->visibility() == VISIBLE; + m_hasVisibleContent = renderer->style()->visibility() == VISIBLE; } } @@ -203,7 +207,7 @@ RenderLayer::~RenderLayer() void RenderLayer::updateLayerPositions(bool doFullRepaint, bool checkForRepaint) { if (doFullRepaint) { - m_object->repaint(); + renderer()->repaint(); checkForRepaint = doFullRepaint = false; } @@ -221,14 +225,14 @@ void RenderLayer::updateLayerPositions(bool doFullRepaint, bool checkForRepaint) updateTransform(); if (m_hasVisibleContent) { - RenderView* view = m_object->view(); + RenderView* view = renderer()->view(); ASSERT(view); // FIXME: Optimize using LayoutState and remove the disableLayoutState() call // from updateScrollInfoAfterLayout(). - ASSERT(!view->layoutState()); + ASSERT(!view->layoutStateEnabled()); - IntRect newRect = m_object->absoluteClippedOverflowRect(); - IntRect newOutlineBox = m_object->absoluteOutlineBox(); + IntRect newRect = renderer()->absoluteClippedOverflowRect(); + IntRect newOutlineBox = renderer()->absoluteOutlineBounds(); if (checkForRepaint) { if (view && !view->printing()) { if (m_needsFullRepaint) { @@ -236,7 +240,7 @@ void RenderLayer::updateLayerPositions(bool doFullRepaint, bool checkForRepaint) if (newRect != m_repaintRect) view->repaintViewRectangle(newRect); } else - m_object->repaintAfterLayoutIfNeeded(m_repaintRect, m_outlineBox); + renderer()->repaintAfterLayoutIfNeeded(m_repaintRect, m_outlineBox); } } m_repaintRect = newRect; @@ -266,14 +270,14 @@ void RenderLayer::updateTransform() bool hadTransform = m_transform; if (hasTransform != hadTransform) { if (hasTransform) - m_transform.set(new AffineTransform); + m_transform.set(new TransformationMatrix); else m_transform.clear(); } if (hasTransform) { m_transform->reset(); - renderer()->style()->applyTransform(*m_transform, renderer()->borderBox().size()); + renderer()->style()->applyTransform(*m_transform, renderer()->borderBoxRect().size()); } } @@ -285,7 +289,7 @@ void RenderLayer::setHasVisibleContent(bool b) m_hasVisibleContent = b; if (m_hasVisibleContent) { m_repaintRect = renderer()->absoluteClippedOverflowRect(); - m_outlineBox = renderer()->absoluteOutlineBox(); + m_outlineBox = renderer()->absoluteOutlineBounds(); if (!isOverflowOnly()) dirtyStackingContextZOrderLists(); } @@ -338,12 +342,12 @@ void RenderLayer::updateVisibilityStatus() } if (m_visibleContentStatusDirty) { - if (m_object->style()->visibility() == VISIBLE) + if (renderer()->style()->visibility() == VISIBLE) m_hasVisibleContent = true; else { // layer may be hidden but still have some visible content, check for this m_hasVisibleContent = false; - RenderObject* r = m_object->firstChild(); + RenderObject* r = renderer()->firstChild(); while (r) { if (r->style()->visibility() == VISIBLE && !r->hasLayer()) { m_hasVisibleContent = true; @@ -356,7 +360,7 @@ void RenderLayer::updateVisibilityStatus() else { do { r = r->parent(); - if (r==m_object) + if (r==renderer()) r = 0; } while (r && !r->nextSibling()); if (r) @@ -371,72 +375,80 @@ void RenderLayer::updateVisibilityStatus() void RenderLayer::updateLayerPosition() { // Clear our cached clip rect information. - clearClipRect(); + clearClipRects(); - int x = m_object->xPos(); - int y = m_object->yPos() - m_object->borderTopExtra(); + int x = renderer()->x(); + int y = renderer()->y(); - if (!m_object->isPositioned() && m_object->parent()) { + if (!renderer()->isPositioned() && renderer()->parent()) { // We must adjust our position by walking up the render tree looking for the // nearest enclosing object with a layer. - RenderObject* curr = m_object->parent(); + RenderBox* curr = renderer()->parentBox(); while (curr && !curr->hasLayer()) { if (!curr->isTableRow()) { // Rows and cells share the same coordinate space (that of the section). // Omit them when computing our xpos/ypos. - x += curr->xPos(); - y += curr->yPos(); + x += curr->x(); + y += curr->y(); } - curr = curr->parent(); + curr = curr->parentBox(); } - y += curr->borderTopExtra(); if (curr->isTableRow()) { // Put ourselves into the row coordinate space. - x -= curr->xPos(); - y -= curr->yPos(); + x -= curr->x(); + y -= curr->y(); } } m_relX = m_relY = 0; - if (m_object->isRelPositioned()) { - m_relX = static_cast<RenderBox*>(m_object)->relativePositionOffsetX(); - m_relY = static_cast<RenderBox*>(m_object)->relativePositionOffsetY(); + if (renderer()->isRelPositioned()) { + m_relX = toRenderBox(renderer())->relativePositionOffsetX(); + m_relY = toRenderBox(renderer())->relativePositionOffsetY(); x += m_relX; y += m_relY; } // Subtract our parent's scroll offset. - if (m_object->isPositioned() && enclosingPositionedAncestor()) { + if (renderer()->isPositioned() && enclosingPositionedAncestor()) { RenderLayer* positionedParent = enclosingPositionedAncestor(); // For positioned layers, we subtract out the enclosing positioned layer's scroll offset. - positionedParent->subtractScrollOffset(x, y); + positionedParent->subtractScrolledContentOffset(x, y); - if (m_object->isPositioned()) { - IntSize offset = static_cast<RenderBox*>(m_object)->offsetForPositionedInContainer(positionedParent->renderer()); + if (renderer()->isPositioned()) { + IntSize offset = toRenderBox(renderer())->offsetForPositionedInContainer(positionedParent->renderer()); x += offset.width(); y += offset.height(); } } else if (parent()) - parent()->subtractScrollOffset(x, y); + parent()->subtractScrolledContentOffset(x, y); - setPos(x,y); + // FIXME: We'd really like to just get rid of the concept of a layer rectangle and rely on the renderers. - setWidth(m_object->width()); - setHeight(m_object->height() + m_object->borderTopExtra() + m_object->borderBottomExtra()); + setPos(x, y); - if (!m_object->hasOverflowClip()) { - if (m_object->overflowWidth() > m_object->width()) - setWidth(m_object->overflowWidth()); - if (m_object->overflowHeight() > m_object->height()) - setHeight(m_object->overflowHeight()); + if (renderer()->isRenderInline()) { + RenderInline* inlineFlow = static_cast<RenderInline*>(renderer()); + IntRect lineBox = inlineFlow->linesBoundingBox(); + setWidth(lineBox.width()); + setHeight(lineBox.height()); + } else { + setWidth(renderer()->width()); + setHeight(renderer()->height()); + + if (!renderer()->hasOverflowClip()) { + if (renderer()->overflowWidth() > renderer()->width()) + setWidth(renderer()->overflowWidth()); + if (renderer()->overflowHeight() > renderer()->height()) + setHeight(renderer()->overflowHeight()); + } } } RenderLayer *RenderLayer::stackingContext() const { RenderLayer* curr = parent(); - for ( ; curr && !curr->m_object->isRenderView() && !curr->m_object->isRoot() && - curr->m_object->style()->hasAutoZIndex(); + for ( ; curr && !curr->renderer()->isRenderView() && !curr->renderer()->isRoot() && + curr->renderer()->style()->hasAutoZIndex(); curr = curr->parent()) { } return curr; } @@ -444,7 +456,7 @@ RenderLayer *RenderLayer::stackingContext() const RenderLayer* RenderLayer::enclosingPositionedAncestor() const { RenderLayer* curr = parent(); - for ( ; curr && !curr->m_object->isRenderView() && !curr->m_object->isPositioned() && !curr->m_object->isRelPositioned() && !curr->hasTransform(); + for ( ; curr && !curr->renderer()->isRenderView() && !curr->renderer()->isPositioned() && !curr->renderer()->isRelPositioned() && !curr->hasTransform(); curr = curr->parent()) { } return curr; } @@ -452,11 +464,17 @@ RenderLayer* RenderLayer::enclosingPositionedAncestor() const RenderLayer* RenderLayer::enclosingTransformedAncestor() const { RenderLayer* curr = parent(); - for ( ; curr && !curr->m_object->isRenderView() && !curr->transform(); curr = curr->parent()) + for ( ; curr && !curr->renderer()->isRenderView() && !curr->transform(); curr = curr->parent()) { } return curr; } +IntPoint RenderLayer::absoluteToContents(const IntPoint& absolutePoint) const +{ + // We don't use convertToLayerCoords because it doesn't know about transforms + return roundedIntPoint(renderer()->absoluteToLocal(absolutePoint, false, true)); +} + bool RenderLayer::requiresSlowRepaints() const { if (isTransparent() || hasReflection() || hasTransform()) @@ -469,10 +487,10 @@ bool RenderLayer::requiresSlowRepaints() const bool RenderLayer::isTransparent() const { #if ENABLE(SVG) - if (m_object->node()->namespaceURI() == SVGNames::svgNamespaceURI) + if (renderer()->node()->namespaceURI() == SVGNames::svgNamespaceURI) return false; #endif - return m_object->isTransparent() || m_object->hasMask(); + return renderer()->isTransparent() || renderer()->hasMask(); } RenderLayer* @@ -483,20 +501,20 @@ RenderLayer::transparentAncestor() return curr; } -static IntRect transparencyClipBox(const AffineTransform& enclosingTransform, const RenderLayer* l, const RenderLayer* rootLayer) +static IntRect transparencyClipBox(const TransformationMatrix& enclosingTransform, const RenderLayer* l, const RenderLayer* rootLayer) { // FIXME: Although this function completely ignores CSS-imposed clipping, we did already intersect with the // paintDirtyRect, and that should cut down on the amount we have to paint. Still it // would be better to respect clips. - AffineTransform* t = l->transform(); + TransformationMatrix* t = l->transform(); if (t && rootLayer != l) { // The best we can do here is to use enclosed bounding boxes to establish a "fuzzy" enough clip to encompass // the transformed layer and all of its children. int x = 0; int y = 0; l->convertToLayerCoords(rootLayer, x, y); - AffineTransform transform; + TransformationMatrix transform; transform.translate(x, y); transform = *t * transform; transform = transform * enclosingTransform; @@ -542,7 +560,7 @@ void RenderLayer::beginTransparencyLayers(GraphicsContext* p, const RenderLayer* if (isTransparent()) { m_usedTransparency = true; p->save(); - p->clip(transparencyClipBox(AffineTransform(), this, rootLayer)); + p->clip(transparencyClipBox(TransformationMatrix(), this, rootLayer)); p->beginTransparencyLayer(renderer()->opacity()); } } @@ -637,7 +655,7 @@ void RenderLayer::removeOnlyThisLayer() return; // Dirty the clip rects. - clearClipRects(); + clearClipRectsIncludingDescendants(); // Remove us from the parent. RenderLayer* parent = m_parent; @@ -676,7 +694,7 @@ void RenderLayer::insertOnlyThisLayer() curr->moveLayers(m_parent, this); // Clear out all the clip rects. - clearClipRects(); + clearClipRectsIncludingDescendants(); } void @@ -685,18 +703,17 @@ RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, int& x, int& if (ancestorLayer == this) return; - if (m_object->style()->position() == FixedPosition) { + if (renderer()->style()->position() == FixedPosition) { // Add in the offset of the view. We can obtain this by calling - // absolutePosition() on the RenderView. - int xOff, yOff; - m_object->absolutePosition(xOff, yOff, true); - x += xOff; - y += yOff; + // localToAbsolute() on the RenderView. + FloatPoint absPos = renderer()->localToAbsolute(FloatPoint(), true); + x += absPos.x(); + y += absPos.y(); return; } RenderLayer* parentLayer; - if (m_object->style()->position() == AbsolutePosition) + if (renderer()->style()->position() == AbsolutePosition) parentLayer = enclosingPositionedAncestor(); else parentLayer = parent(); @@ -749,10 +766,10 @@ void RenderLayer::panScrollFromPoint(const IntPoint& sourcePoint) void RenderLayer::scrollByRecursively(int xDelta, int yDelta) { bool restrictedByLineClamp = false; - if (m_object->parent()) - restrictedByLineClamp = m_object->parent()->style()->lineClamp() >= 0; + if (renderer()->parent()) + restrictedByLineClamp = renderer()->parent()->style()->lineClamp() >= 0; - if (m_object->hasOverflowClip() && !restrictedByLineClamp) { + if (renderer()->hasOverflowClip() && !restrictedByLineClamp) { int newOffsetX = scrollXOffset() + xDelta; int newOffsetY = scrollYOffset() + yDelta; scrollToOffset(newOffsetX, newOffsetY); @@ -760,26 +777,26 @@ void RenderLayer::scrollByRecursively(int xDelta, int yDelta) // If this layer can't do the scroll we ask its parent int leftToScrollX = newOffsetX - scrollXOffset(); int leftToScrollY = newOffsetY - scrollYOffset(); - if ((leftToScrollX || leftToScrollY) && m_object->parent()) { - m_object->parent()->enclosingLayer()->scrollByRecursively(leftToScrollX, leftToScrollY); + if ((leftToScrollX || leftToScrollY) && renderer()->parent()) { + renderer()->parent()->enclosingLayer()->scrollByRecursively(leftToScrollX, leftToScrollY); Frame* frame = renderer()->document()->frame(); if (frame) frame->eventHandler()->updateAutoscrollRenderer(); } - } else if (m_object->view()->frameView()) - m_object->view()->frameView()->scrollBy(IntSize(xDelta, yDelta)); + } else if (renderer()->view()->frameView()) + renderer()->view()->frameView()->scrollBy(IntSize(xDelta, yDelta)); } void -RenderLayer::scrollOffset(int& x, int& y) +RenderLayer::addScrolledContentOffset(int& x, int& y) const { x += scrollXOffset() + m_scrollLeftOverflow; y += scrollYOffset(); } void -RenderLayer::subtractScrollOffset(int& x, int& y) +RenderLayer::subtractScrolledContentOffset(int& x, int& y) const { x -= scrollXOffset() + m_scrollLeftOverflow; y -= scrollYOffset(); @@ -793,8 +810,8 @@ void RenderLayer::scrollToOffset(int x, int y, bool updateScrollbars, bool repai // Call the scrollWidth/Height functions so that the dimensions will be computed if they need // to be (for overflow:hidden blocks). - int maxX = scrollWidth() - m_object->clientWidth(); - int maxY = scrollHeight() - m_object->clientHeight(); + int maxX = scrollWidth() - renderer()->clientWidth(); + int maxY = scrollHeight() - renderer()->clientHeight(); if (x > maxX) x = maxX; if (y > maxY) y = maxY; @@ -805,7 +822,10 @@ void RenderLayer::scrollToOffset(int x, int y, bool updateScrollbars, bool repai // complicated (since it will involve testing whether our layer // is either occluded by another layer or clipped by an enclosing // layer or contains fixed backgrounds, etc.). - m_scrollX = x - m_scrollOriginX; + int newScrollX = x - m_scrollOriginX; + if (m_scrollY == y && m_scrollX == newScrollX) + return; + m_scrollX = newScrollX; m_scrollY = y; // Update the positions of our child layers. @@ -826,9 +846,14 @@ void RenderLayer::scrollToOffset(int x, int y, bool updateScrollbars, bool repai view->updateWidgetPositions(); } + // The caret rect needs to be invalidated after scrolling + Frame* frame = renderer()->document()->frame(); + if (frame) + frame->invalidateSelection(); + // Just schedule a full repaint of our object. if (repaint) - m_object->repaint(); + renderer()->repaint(); if (updateScrollbars) { if (m_hBar) @@ -851,31 +876,29 @@ void RenderLayer::scrollRectToVisible(const IntRect &rect, bool scrollToAnchor, int xOffset = 0, yOffset = 0; // We may end up propagating a scroll event. It is important that we suspend events until - // the end of the function since they could delete the layer or the layer's m_object. - FrameView* frameView = m_object->document()->view(); + // the end of the function since they could delete the layer or the layer's renderer(). + FrameView* frameView = renderer()->document()->view(); if (frameView) frameView->pauseScheduledEvents(); bool restrictedByLineClamp = false; - if (m_object->parent()) { - parentLayer = m_object->parent()->enclosingLayer(); - restrictedByLineClamp = m_object->parent()->style()->lineClamp() >= 0; + if (renderer()->parent()) { + parentLayer = renderer()->parent()->enclosingLayer(); + restrictedByLineClamp = renderer()->parent()->style()->lineClamp() >= 0; } - if (m_object->hasOverflowClip() && !restrictedByLineClamp) { + if (renderer()->hasOverflowClip() && !restrictedByLineClamp) { // Don't scroll to reveal an overflow layer that is restricted by the -webkit-line-clamp property. // This will prevent us from revealing text hidden by the slider in Safari RSS. - int x, y; - m_object->absolutePosition(x, y); - x += m_object->borderLeft(); - y += m_object->borderTop(); + FloatPoint absPos = renderer()->localToAbsolute(); + absPos.move(renderer()->borderLeft(), renderer()->borderTop()); - IntRect layerBounds = IntRect(x + scrollXOffset(), y + scrollYOffset(), m_object->clientWidth(), m_object->clientHeight()); + IntRect layerBounds = IntRect(absPos.x() + scrollXOffset(), absPos.y() + scrollYOffset(), renderer()->clientWidth(), renderer()->clientHeight()); IntRect exposeRect = IntRect(rect.x() + scrollXOffset(), rect.y() + scrollYOffset(), rect.width(), rect.height()); IntRect r = getRectToExpose(layerBounds, exposeRect, alignX, alignY); - xOffset = r.x() - x; - yOffset = r.y() - y; + xOffset = r.x() - absPos.x(); + yOffset = r.y() - absPos.y(); // Adjust offsets if they're outside of the allowable range. xOffset = max(0, min(scrollWidth() - layerBounds.width(), xOffset)); yOffset = max(0, min(scrollHeight() - layerBounds.height(), yOffset)); @@ -891,7 +914,7 @@ void RenderLayer::scrollRectToVisible(const IntRect &rect, bool scrollToAnchor, } } else if (!parentLayer && renderer()->canBeProgramaticallyScrolled(scrollToAnchor)) { if (frameView) { - if (m_object->document() && m_object->document()->ownerElement() && m_object->document()->ownerElement()->renderer()) { + if (renderer()->document() && renderer()->document()->ownerElement() && renderer()->document()->ownerElement()->renderer()) { IntRect viewRect = frameView->visibleContentRect(); IntRect r = getRectToExpose(viewRect, rect, alignX, alignY); @@ -902,7 +925,7 @@ void RenderLayer::scrollRectToVisible(const IntRect &rect, bool scrollToAnchor, yOffset = max(0, min(frameView->contentsHeight(), yOffset)); frameView->setScrollPosition(IntPoint(xOffset, yOffset)); - parentLayer = m_object->document()->ownerElement()->renderer()->enclosingLayer(); + parentLayer = renderer()->document()->ownerElement()->renderer()->enclosingLayer(); newRect.setX(rect.x() - frameView->scrollX() + frameView->x()); newRect.setY(rect.y() - frameView->scrollY() + frameView->y()); } else { @@ -1014,13 +1037,13 @@ void RenderLayer::autoscroll() void RenderLayer::resize(const PlatformMouseEvent& evt, const IntSize& oldOffset) { - if (!inResizeMode() || !m_object->hasOverflowClip()) + if (!inResizeMode() || !renderer()->hasOverflowClip()) return; // Set the width and height of the shadow ancestor node if there is one. // This is necessary for textarea elements since the resizable layer is in the shadow content. - Element* element = static_cast<Element*>(m_object->node()->shadowAncestorNode()); - RenderBox* renderer = static_cast<RenderBox*>(element->renderer()); + Element* element = static_cast<Element*>(renderer()->node()->shadowAncestorNode()); + RenderBox* renderer = toRenderBox(element->renderer()); EResize resize = renderer->style()->resize(); if (resize == RESIZE_NONE) @@ -1156,7 +1179,7 @@ static IntRect resizerCornerRect(const RenderLayer* layer, const IntRect& bounds bool RenderLayer::scrollbarCornerPresent() const { - return !scrollCornerRect(this, m_object->borderBox()).isEmpty(); + return !scrollCornerRect(this, renderer()->borderBoxRect()).isEmpty(); } void RenderLayer::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect) @@ -1172,12 +1195,12 @@ void RenderLayer::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& r PassRefPtr<Scrollbar> RenderLayer::createScrollbar(ScrollbarOrientation orientation) { RefPtr<Scrollbar> widget; - bool hasCustomScrollbarStyle = m_object->node()->shadowAncestorNode()->renderer()->style()->hasPseudoStyle(RenderStyle::SCROLLBAR); + bool hasCustomScrollbarStyle = renderer()->node()->shadowAncestorNode()->renderer()->style()->hasPseudoStyle(RenderStyle::SCROLLBAR); if (hasCustomScrollbarStyle) - widget = RenderScrollbar::createCustomScrollbar(this, orientation, m_object->node()->shadowAncestorNode()->renderer()); + widget = RenderScrollbar::createCustomScrollbar(this, orientation, renderer()->node()->shadowAncestorNode()->renderBox()); else widget = Scrollbar::createNativeScrollbar(this, orientation, RegularScrollbar); - m_object->document()->view()->addChild(widget.get()); + renderer()->document()->view()->addChild(widget.get()); return widget.release(); } @@ -1209,8 +1232,8 @@ void RenderLayer::setHasHorizontalScrollbar(bool hasScrollbar) #if ENABLE(DASHBOARD_SUPPORT) // Force an update since we know the scrollbars have changed things. - if (m_object->document()->hasDashboardRegions()) - m_object->document()->setDashboardRegionsDirty(true); + if (renderer()->document()->hasDashboardRegions()) + renderer()->document()->setDashboardRegionsDirty(true); #endif } @@ -1232,8 +1255,8 @@ void RenderLayer::setHasVerticalScrollbar(bool hasScrollbar) #if ENABLE(DASHBOARD_SUPPORT) // Force an update since we know the scrollbars have changed things. - if (m_object->document()->hasDashboardRegions()) - m_object->document()->setDashboardRegionsDirty(true); + if (renderer()->document()->hasDashboardRegions()) + renderer()->document()->setDashboardRegionsDirty(true); #endif } @@ -1251,39 +1274,38 @@ int RenderLayer::horizontalScrollbarHeight() const return m_hBar->height(); } -IntSize RenderLayer::offsetFromResizeCorner(const IntPoint& p) const +IntSize RenderLayer::offsetFromResizeCorner(const IntPoint& absolutePoint) const { // Currently the resize corner is always the bottom right corner - int x = width(); - int y = height(); - convertToLayerCoords(root(), x, y); - return p - IntPoint(x, y); + IntPoint bottomRight(width(), height()); + IntPoint localPoint = absoluteToContents(absolutePoint); + return localPoint - bottomRight; } void RenderLayer::positionOverflowControls(int tx, int ty) { - if (!m_hBar && !m_vBar && (!m_object->hasOverflowClip() || m_object->style()->resize() == RESIZE_NONE)) + if (!m_hBar && !m_vBar && (!renderer()->hasOverflowClip() || renderer()->style()->resize() == RESIZE_NONE)) return; - IntRect borderBox = m_object->borderBox(); + IntRect borderBox = renderer()->borderBoxRect(); IntRect scrollCorner(scrollCornerRect(this, borderBox)); IntRect absBounds(borderBox.x() + tx, borderBox.y() + ty, borderBox.width(), borderBox.height()); if (m_vBar) - m_vBar->setFrameRect(IntRect(absBounds.right() - m_object->borderRight() - m_vBar->width(), - absBounds.y() + m_object->borderTop(), + m_vBar->setFrameRect(IntRect(absBounds.right() - renderer()->borderRight() - m_vBar->width(), + absBounds.y() + renderer()->borderTop(), m_vBar->width(), - absBounds.height() - (m_object->borderTop() + m_object->borderBottom()) - scrollCorner.height())); + absBounds.height() - (renderer()->borderTop() + renderer()->borderBottom()) - scrollCorner.height())); if (m_hBar) - m_hBar->setFrameRect(IntRect(absBounds.x() + m_object->borderLeft(), - absBounds.bottom() - m_object->borderBottom() - m_hBar->height(), - absBounds.width() - (m_object->borderLeft() + m_object->borderRight()) - scrollCorner.width(), + m_hBar->setFrameRect(IntRect(absBounds.x() + renderer()->borderLeft(), + absBounds.bottom() - renderer()->borderBottom() - m_hBar->height(), + absBounds.width() - (renderer()->borderLeft() + renderer()->borderRight()) - scrollCorner.width(), m_hBar->height())); if (m_scrollCorner) - m_scrollCorner->setRect(scrollCorner); + m_scrollCorner->setFrameRect(scrollCorner); if (m_resizer) - m_resizer->setRect(resizerCornerRect(this, borderBox)); + m_resizer->setFrameRect(resizerCornerRect(this, borderBox)); } int RenderLayer::scrollWidth() @@ -1304,17 +1326,17 @@ void RenderLayer::computeScrollDimensions(bool* needHBar, bool* needVBar) { m_scrollDimensionsDirty = false; - bool ltr = m_object->style()->direction() == LTR; + bool ltr = renderer()->style()->direction() == LTR; - int clientWidth = m_object->clientWidth(); - int clientHeight = m_object->clientHeight(); + int clientWidth = renderer()->clientWidth(); + int clientHeight = renderer()->clientHeight(); - m_scrollLeftOverflow = ltr ? 0 : min(0, m_object->leftmostPosition(true, false) - m_object->borderLeft()); + m_scrollLeftOverflow = ltr ? 0 : min(0, renderer()->leftmostPosition(true, false) - renderer()->borderLeft()); int rightPos = ltr ? - m_object->rightmostPosition(true, false) - m_object->borderLeft() : + renderer()->rightmostPosition(true, false) - renderer()->borderLeft() : clientWidth - m_scrollLeftOverflow; - int bottomPos = m_object->lowestPosition(true, false) - m_object->borderTop(); + int bottomPos = renderer()->lowestPosition(true, false) - renderer()->borderTop(); m_scrollWidth = max(rightPos, clientWidth); m_scrollHeight = max(bottomPos, clientHeight); @@ -1344,9 +1366,9 @@ void RenderLayer::updateOverflowStatus(bool horizontalOverflow, bool verticalOve m_horizontalOverflow = horizontalOverflow; m_verticalOverflow = verticalOverflow; - if (FrameView* frameView = m_object->document()->view()) { + if (FrameView* frameView = renderer()->document()->view()) { frameView->scheduleEvent(OverflowEvent::create(horizontalOverflowChanged, horizontalOverflow, verticalOverflowChanged, verticalOverflow), - EventTargetNodeCast(m_object->element())); + EventTargetNodeCast(renderer()->element())); } } } @@ -1359,13 +1381,13 @@ RenderLayer::updateScrollInfoAfterLayout() bool horizontalOverflow, verticalOverflow; computeScrollDimensions(&horizontalOverflow, &verticalOverflow); - if (m_object->style()->overflowX() != OMARQUEE) { + if (renderer()->style()->overflowX() != OMARQUEE) { // Layout may cause us to be in an invalid scroll position. In this case we need // to pull our scroll offsets back to the max (or push them up to the min). - int newX = max(0, min(scrollXOffset(), scrollWidth() - m_object->clientWidth())); - int newY = max(0, min(m_scrollY, scrollHeight() - m_object->clientHeight())); + int newX = max(0, min(scrollXOffset(), scrollWidth() - renderer()->clientWidth())); + int newY = max(0, min(m_scrollY, scrollHeight() - renderer()->clientHeight())); if (newX != scrollXOffset() || newY != m_scrollY) { - RenderView* view = m_object->view(); + RenderView* view = renderer()->view(); ASSERT(view); // scrollToOffset() may call updateLayerPositions(), which doesn't work // with LayoutState. @@ -1382,58 +1404,58 @@ RenderLayer::updateScrollInfoAfterLayout() bool haveVerticalBar = m_vBar; // overflow:scroll should just enable/disable. - if (m_object->style()->overflowX() == OSCROLL) + if (renderer()->style()->overflowX() == OSCROLL) m_hBar->setEnabled(horizontalOverflow); - if (m_object->style()->overflowY() == OSCROLL) + if (renderer()->style()->overflowY() == OSCROLL) m_vBar->setEnabled(verticalOverflow); // A dynamic change from a scrolling overflow to overflow:hidden means we need to get rid of any // scrollbars that may be present. - if (m_object->style()->overflowX() == OHIDDEN && haveHorizontalBar) + if (renderer()->style()->overflowX() == OHIDDEN && haveHorizontalBar) setHasHorizontalScrollbar(false); - if (m_object->style()->overflowY() == OHIDDEN && haveVerticalBar) + if (renderer()->style()->overflowY() == OHIDDEN && haveVerticalBar) setHasVerticalScrollbar(false); // overflow:auto may need to lay out again if scrollbars got added/removed. - bool scrollbarsChanged = (m_object->hasAutoHorizontalScrollbar() && haveHorizontalBar != horizontalOverflow) || - (m_object->hasAutoVerticalScrollbar() && haveVerticalBar != verticalOverflow); + bool scrollbarsChanged = (renderer()->hasAutoHorizontalScrollbar() && haveHorizontalBar != horizontalOverflow) || + (renderer()->hasAutoVerticalScrollbar() && haveVerticalBar != verticalOverflow); if (scrollbarsChanged) { - if (m_object->hasAutoHorizontalScrollbar()) + if (renderer()->hasAutoHorizontalScrollbar()) setHasHorizontalScrollbar(horizontalOverflow); - if (m_object->hasAutoVerticalScrollbar()) + if (renderer()->hasAutoVerticalScrollbar()) setHasVerticalScrollbar(verticalOverflow); #if ENABLE(DASHBOARD_SUPPORT) // Force an update since we know the scrollbars have changed things. - if (m_object->document()->hasDashboardRegions()) - m_object->document()->setDashboardRegionsDirty(true); + if (renderer()->document()->hasDashboardRegions()) + renderer()->document()->setDashboardRegionsDirty(true); #endif - m_object->repaint(); + renderer()->repaint(); - if (m_object->style()->overflowX() == OAUTO || m_object->style()->overflowY() == OAUTO) { + if (renderer()->style()->overflowX() == OAUTO || renderer()->style()->overflowY() == OAUTO) { if (!m_inOverflowRelayout) { // Our proprietary overflow: overlay value doesn't trigger a layout. m_inOverflowRelayout = true; - m_object->setNeedsLayout(true); - if (m_object->isRenderBlock()) - static_cast<RenderBlock*>(m_object)->layoutBlock(true); + renderer()->setNeedsLayout(true, false); + if (renderer()->isRenderBlock()) + static_cast<RenderBlock*>(renderer())->layoutBlock(true); else - m_object->layout(); + renderer()->layout(); m_inOverflowRelayout = false; } } } // If overflow:scroll is turned into overflow:auto a bar might still be disabled (Bug 11985). - if (m_hBar && m_object->hasAutoHorizontalScrollbar()) + if (m_hBar && renderer()->hasAutoHorizontalScrollbar()) m_hBar->setEnabled(true); - if (m_vBar && m_object->hasAutoVerticalScrollbar()) + if (m_vBar && renderer()->hasAutoVerticalScrollbar()) m_vBar->setEnabled(true); // Set up the range (and page step/line step). if (m_hBar) { - int clientWidth = m_object->clientWidth(); + int clientWidth = renderer()->clientWidth(); int pageStep = (clientWidth - cAmountToKeepWhenPaging); if (pageStep < 0) pageStep = clientWidth; m_hBar->setSteps(cScrollbarPixelsPerLineStep, pageStep); @@ -1441,21 +1463,21 @@ RenderLayer::updateScrollInfoAfterLayout() m_hBar->setValue(scrollXOffset()); } if (m_vBar) { - int clientHeight = m_object->clientHeight(); + int clientHeight = renderer()->clientHeight(); int pageStep = (clientHeight - cAmountToKeepWhenPaging); if (pageStep < 0) pageStep = clientHeight; m_vBar->setSteps(cScrollbarPixelsPerLineStep, pageStep); m_vBar->setProportion(clientHeight, m_scrollHeight); } - if (m_object->element() && m_object->document()->hasListenerType(Document::OVERFLOWCHANGED_LISTENER)) + if (renderer()->element() && renderer()->document()->hasListenerType(Document::OVERFLOWCHANGED_LISTENER)) updateOverflowStatus(horizontalOverflow, verticalOverflow); } void RenderLayer::paintOverflowControls(GraphicsContext* context, int tx, int ty, const IntRect& damageRect) { // Don't do anything if we have no overflow. - if (!m_object->hasOverflowClip()) + if (!renderer()->hasOverflowClip()) return; // Move the scrollbar widgets if necessary. We normally move and resize widgets during layout, but sometimes @@ -1479,7 +1501,7 @@ void RenderLayer::paintOverflowControls(GraphicsContext* context, int tx, int ty void RenderLayer::paintScrollCorner(GraphicsContext* context, int tx, int ty, const IntRect& damageRect) { - IntRect cornerRect = scrollCornerRect(this, m_object->borderBox()); + IntRect cornerRect = scrollCornerRect(this, renderer()->borderBoxRect()); IntRect absRect = IntRect(cornerRect.x() + tx, cornerRect.y() + ty, cornerRect.width(), cornerRect.height()); if (!absRect.intersects(damageRect)) return; @@ -1499,10 +1521,10 @@ void RenderLayer::paintScrollCorner(GraphicsContext* context, int tx, int ty, co void RenderLayer::paintResizer(GraphicsContext* context, int tx, int ty, const IntRect& damageRect) { - if (m_object->style()->resize() == RESIZE_NONE) + if (renderer()->style()->resize() == RESIZE_NONE) return; - IntRect cornerRect = resizerCornerRect(this, m_object->borderBox()); + IntRect cornerRect = resizerCornerRect(this, renderer()->borderBoxRect()); IntRect absRect = IntRect(cornerRect.x() + tx, cornerRect.y() + ty, cornerRect.width(), cornerRect.height()); if (!absRect.intersects(damageRect)) return; @@ -1518,9 +1540,7 @@ void RenderLayer::paintResizer(GraphicsContext* context, int tx, int ty, const I } // Paint the resizer control. - static RefPtr<Image> resizeCornerImage; - if (!resizeCornerImage) - resizeCornerImage = Image::loadPlatformResource("textAreaResizeCorner"); + DEFINE_STATIC_LOCAL(RefPtr<Image>, resizeCornerImage, (Image::loadPlatformResource("textAreaResizeCorner"))); IntPoint imagePoint(absRect.right() - resizeCornerImage->width(), absRect.bottom() - resizeCornerImage->height()); context->drawImage(resizeCornerImage.get(), imagePoint); @@ -1538,16 +1558,15 @@ void RenderLayer::paintResizer(GraphicsContext* context, int tx, int ty, const I } } -bool RenderLayer::isPointInResizeControl(const IntPoint& point) +bool RenderLayer::isPointInResizeControl(const IntPoint& absolutePoint) const { - if (!m_object->hasOverflowClip() || m_object->style()->resize() == RESIZE_NONE) + if (!renderer()->hasOverflowClip() || renderer()->style()->resize() == RESIZE_NONE) return false; - int x = 0; - int y = 0; - convertToLayerCoords(root(), x, y); - IntRect absBounds(x, y, m_object->width(), m_object->height()); - return resizerCornerRect(this, absBounds).contains(point); + IntPoint localPoint = absoluteToContents(absolutePoint); + + IntRect localBounds(0, 0, renderer()->width(), renderer()->height()); + return resizerCornerRect(this, localBounds).contains(localPoint); } bool RenderLayer::hitTestOverflowControls(HitTestResult& result) @@ -1633,7 +1652,7 @@ static void restoreClip(GraphicsContext* p, const IntRect& paintDirtyRect, const void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p, const IntRect& paintDirtyRect, bool haveTransparency, PaintRestriction paintRestriction, - RenderObject* paintingRoot, bool appliedTransform) + RenderObject* paintingRoot, bool appliedTransform, bool temporaryClipRects) { // 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 @@ -1642,7 +1661,7 @@ RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p, return; // If this layer is totally invisible then there is nothing to paint. - if (!m_object->opacity()) + if (!renderer()->opacity()) return; if (isTransparent()) @@ -1662,8 +1681,14 @@ RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p, // Make sure the parent's clip rects have been calculated. IntRect clipRect = paintDirtyRect; if (parent()) { - parent()->calculateClipRects(rootLayer); - clipRect = parent()->clipRects()->overflowClipRect(); + if (temporaryClipRects) { + ClipRects parentClipRects; + parent()->calculateClipRects(rootLayer, parentClipRects); + clipRect = parentClipRects.overflowClipRect(); + } else { + parent()->updateClipRects(rootLayer); + clipRect = parent()->clipRects()->overflowClipRect(); + } clipRect.intersect(paintDirtyRect); } @@ -1675,7 +1700,7 @@ RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p, int x = 0; int y = 0; convertToLayerCoords(rootLayer, x, y); - AffineTransform transform; + TransformationMatrix transform; transform.translate(x, y); transform = *m_transform * transform; @@ -1684,7 +1709,7 @@ RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p, p->concatCTM(transform); // Now do a paint with the root layer shifted to be us. - paintLayer(this, p, transform.inverse().mapRect(paintDirtyRect), haveTransparency, paintRestriction, paintingRoot, true); + paintLayer(this, p, transform.inverse().mapRect(paintDirtyRect), haveTransparency, paintRestriction, paintingRoot, true, temporaryClipRects); p->restore(); @@ -1698,17 +1723,17 @@ RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p, if (m_reflection && !m_paintingInsideReflection && (!m_transform || appliedTransform)) { // Mark that we are now inside replica painting. m_paintingInsideReflection = true; - reflectionLayer()->paintLayer(rootLayer, p, paintDirtyRect, haveTransparency, paintRestriction, paintingRoot); + reflectionLayer()->paintLayer(rootLayer, p, paintDirtyRect, haveTransparency, paintRestriction, paintingRoot, false, temporaryClipRects); m_paintingInsideReflection = false; } // Calculate the clip rects we should use. IntRect layerBounds, damageRect, clipRectToApply, outlineRect; - calculateRects(rootLayer, paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect); + calculateRects(rootLayer, paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect, temporaryClipRects); int x = layerBounds.x(); int y = layerBounds.y(); - int tx = x - renderer()->xPos(); - int ty = y - renderer()->yPos() + renderer()->borderTopExtra(); + int tx = x - renderer()->x(); + int ty = y - renderer()->y(); // Ensure our lists are up-to-date. updateZOrderLists(); @@ -1722,7 +1747,7 @@ RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p, // Else, our renderer tree may or may not contain the painting root, so we pass that root along // so it will be tested against as we decend through the renderers. RenderObject* paintingRootForRenderer = 0; - if (paintingRoot && !m_object->isDescendantOf(paintingRoot)) + if (paintingRoot && !renderer()->isDescendantOf(paintingRoot)) paintingRootForRenderer = paintingRoot; // We want to paint our layer, but only if we intersect the damage rect. @@ -1752,7 +1777,7 @@ RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p, // Now walk the sorted list of children with negative z-indices. if (m_negZOrderList) for (Vector<RenderLayer*>::iterator it = m_negZOrderList->begin(); it != m_negZOrderList->end(); ++it) - it[0]->paintLayer(rootLayer, p, paintDirtyRect, haveTransparency, paintRestriction, paintingRoot); + it[0]->paintLayer(rootLayer, p, paintDirtyRect, haveTransparency, paintRestriction, paintingRoot, false, temporaryClipRects); // Now establish the appropriate clip and paint our child RenderObjects. if (shouldPaint && !clipRectToApply.isEmpty()) { @@ -1790,12 +1815,12 @@ RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p, // Paint any child layers that have overflow. if (m_overflowList) for (Vector<RenderLayer*>::iterator it = m_overflowList->begin(); it != m_overflowList->end(); ++it) - it[0]->paintLayer(rootLayer, p, paintDirtyRect, haveTransparency, paintRestriction, paintingRoot); + it[0]->paintLayer(rootLayer, p, paintDirtyRect, haveTransparency, paintRestriction, paintingRoot, false, temporaryClipRects); // Now walk the sorted list of children with positive z-indices. if (m_posZOrderList) for (Vector<RenderLayer*>::iterator it = m_posZOrderList->begin(); it != m_posZOrderList->end(); ++it) - it[0]->paintLayer(rootLayer, p, paintDirtyRect, haveTransparency, paintRestriction, paintingRoot); + it[0]->paintLayer(rootLayer, p, paintDirtyRect, haveTransparency, paintRestriction, paintingRoot, false, temporaryClipRects); if (renderer()->hasMask() && shouldPaint && !selectionOnly && !damageRect.isEmpty()) { setClip(p, paintDirtyRect, damageRect); @@ -1873,7 +1898,7 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, const HitTestRequ // Make sure the parent's clip rects have been calculated. if (parent()) { - parent()->calculateClipRects(rootLayer); + parent()->updateClipRects(rootLayer); // Go ahead and test the enclosing clip now. IntRect clipRect = parent()->clipRects()->overflowClipRect(); @@ -1886,7 +1911,7 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, const HitTestRequ int x = 0; int y = 0; convertToLayerCoords(rootLayer, x, y); - AffineTransform transform; + TransformationMatrix transform; transform.translate(x, y); transform = *m_transform * transform; @@ -1931,8 +1956,8 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, const HitTestRequ // Next we want to see if the mouse pos is inside the child RenderObjects of the layer. if (fgRect.contains(hitTestPoint) && renderer()->hitTest(request, result, hitTestPoint, - layerBounds.x() - renderer()->xPos(), - layerBounds.y() - renderer()->yPos() + m_object->borderTopExtra(), + layerBounds.x() - renderer()->x(), + layerBounds.y() - renderer()->y(), HitTestDescendants)) { // For positioned generated content, we might still not have a // node by the time we get to the layer level, since none of @@ -1961,8 +1986,8 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, const HitTestRequ // Next we want to see if the mouse is inside this layer but not any of its children. if (bgRect.contains(hitTestPoint) && renderer()->hitTest(request, result, hitTestPoint, - layerBounds.x() - renderer()->xPos(), - layerBounds.y() - renderer()->yPos() + m_object->borderTopExtra(), + layerBounds.x() - renderer()->x(), + layerBounds.y() - renderer()->y(), HitTestSelf)) { if (!result.innerNode() || !result.innerNonSharedNode()) { Node* e = enclosingElement(); @@ -1986,16 +2011,38 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, const HitTestRequ return 0; } -void RenderLayer::calculateClipRects(const RenderLayer* rootLayer) +void RenderLayer::updateClipRects(const RenderLayer* rootLayer) { - if (m_clipRects) + if (m_clipRects) { + ASSERT(rootLayer == m_clipRectsRoot); return; // We have the correct cached value. + } + + // For transformed layers, the root layer was shifted to be us, so there is no need to + // 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); + ClipRects clipRects; + calculateClipRects(rootLayer, clipRects, true); + + if (parentLayer && parentLayer->clipRects() && clipRects == *parentLayer->clipRects()) + m_clipRects = parentLayer->clipRects(); + else + m_clipRects = new (renderer()->renderArena()) ClipRects(clipRects); + m_clipRects->ref(); +#ifndef NDEBUG + m_clipRectsRoot = rootLayer; +#endif +} + +void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, ClipRects& clipRects, bool useCached) const +{ IntRect infiniteRect(INT_MIN/2, INT_MIN/2, INT_MAX, INT_MAX); if (!parent()) { // The root layer's clip rect is always infinite. - m_clipRects = new (m_object->renderArena()) ClipRects(infiniteRect); - m_clipRects->ref(); + clipRects.reset(infiniteRect); return; } @@ -2004,100 +2051,95 @@ void RenderLayer::calculateClipRects(const RenderLayer* rootLayer) RenderLayer* parentLayer = rootLayer != this ? parent() : 0; // Ensure that our parent's clip has been calculated so that we can examine the values. - if (parentLayer) - parentLayer->calculateClipRects(rootLayer); - - // Set up our three rects to initially match the parent rects. - IntRect posClipRect(parentLayer ? parentLayer->clipRects()->posClipRect() : infiniteRect); - IntRect overflowClipRect(parentLayer ? parentLayer->clipRects()->overflowClipRect() : infiniteRect); - IntRect fixedClipRect(parentLayer ? parentLayer->clipRects()->fixedClipRect() : infiniteRect); - bool fixed = parentLayer ? parentLayer->clipRects()->fixed() : false; + if (parentLayer) { + if (useCached && parentLayer->clipRects()) + clipRects = *parentLayer->clipRects(); + else + parentLayer->calculateClipRects(rootLayer, clipRects); + } + else + clipRects.reset(infiniteRect); // A fixed object is essentially the root of its containing block hierarchy, so when // we encounter such an object, we reset our clip rects to the fixedClipRect. - if (m_object->style()->position() == FixedPosition) { - posClipRect = fixedClipRect; - overflowClipRect = fixedClipRect; - fixed = true; + if (renderer()->style()->position() == FixedPosition) { + clipRects.setPosClipRect(clipRects.fixedClipRect()); + clipRects.setOverflowClipRect(clipRects.fixedClipRect()); + clipRects.setFixed(true); } - else if (m_object->style()->position() == RelativePosition) - posClipRect = overflowClipRect; - else if (m_object->style()->position() == AbsolutePosition) - overflowClipRect = posClipRect; + else if (renderer()->style()->position() == RelativePosition) + clipRects.setPosClipRect(clipRects.overflowClipRect()); + else if (renderer()->style()->position() == AbsolutePosition) + clipRects.setOverflowClipRect(clipRects.posClipRect()); // Update the clip rects that will be passed to child layers. - if (m_object->hasOverflowClip() || m_object->hasClip()) { + if (renderer()->hasOverflowClip() || renderer()->hasClip()) { // This layer establishes a clip of some kind. int x = 0; int y = 0; convertToLayerCoords(rootLayer, x, y); RenderView* view = renderer()->view(); ASSERT(view); - if (view && fixed && rootLayer->renderer() == view) { + if (view && clipRects.fixed() && rootLayer->renderer() == view) { x -= view->frameView()->scrollX(); y -= view->frameView()->scrollY(); } - if (m_object->hasOverflowClip()) { - IntRect newOverflowClip = m_object->getOverflowClipRect(x,y); - overflowClipRect.intersect(newOverflowClip); - if (m_object->isPositioned() || m_object->isRelPositioned()) - posClipRect.intersect(newOverflowClip); + if (renderer()->hasOverflowClip()) { + IntRect newOverflowClip = renderer()->getOverflowClipRect(x,y); + clipRects.setOverflowClipRect(intersection(newOverflowClip, clipRects.overflowClipRect())); + if (renderer()->isPositioned() || renderer()->isRelPositioned()) + clipRects.setPosClipRect(intersection(newOverflowClip, clipRects.posClipRect())); } - if (m_object->hasClip()) { - IntRect newPosClip = m_object->getClipRect(x,y); - posClipRect.intersect(newPosClip); - overflowClipRect.intersect(newPosClip); - fixedClipRect.intersect(newPosClip); + if (renderer()->hasClip()) { + IntRect newPosClip = renderer()->getClipRect(x,y); + clipRects.setPosClipRect(intersection(newPosClip, clipRects.posClipRect())); + clipRects.setOverflowClipRect(intersection(newPosClip, clipRects.overflowClipRect())); + clipRects.setFixedClipRect(intersection(newPosClip, clipRects.fixedClipRect())); } } - - // If our clip rects match our parent's clip, then we can just share its data structure and - // ref count. - if (parent()->clipRects() && - fixed == parent()->clipRects()->fixed() && - posClipRect == parent()->clipRects()->posClipRect() && - overflowClipRect == parent()->clipRects()->overflowClipRect() && - fixedClipRect == parent()->clipRects()->fixedClipRect()) - m_clipRects = parent()->clipRects(); - else - m_clipRects = new (m_object->renderArena()) ClipRects(overflowClipRect, fixedClipRect, posClipRect, fixed); - m_clipRects->ref(); } void RenderLayer::calculateRects(const RenderLayer* rootLayer, const IntRect& paintDirtyRect, IntRect& layerBounds, - IntRect& backgroundRect, IntRect& foregroundRect, IntRect& outlineRect) const + IntRect& backgroundRect, IntRect& foregroundRect, IntRect& outlineRect, bool temporaryClipRects) const { if (rootLayer != this && parent()) { - parent()->calculateClipRects(rootLayer); + ClipRects parentClipRects; + if (temporaryClipRects) + parent()->calculateClipRects(rootLayer, parentClipRects); + else { + parent()->updateClipRects(rootLayer); + parentClipRects = *parent()->clipRects(); + } - backgroundRect = m_object->style()->position() == FixedPosition ? parent()->clipRects()->fixedClipRect() : - (m_object->isPositioned() ? parent()->clipRects()->posClipRect() : - parent()->clipRects()->overflowClipRect()); + backgroundRect = renderer()->style()->position() == FixedPosition ? parentClipRects.fixedClipRect() : + (renderer()->isPositioned() ? parentClipRects.posClipRect() : + parentClipRects.overflowClipRect()); RenderView* view = renderer()->view(); ASSERT(view); - if (view && parent()->clipRects()->fixed() && rootLayer->renderer() == view) + if (view && parentClipRects.fixed() && rootLayer->renderer() == view) backgroundRect.move(view->frameView()->scrollX(), view->frameView()->scrollY()); backgroundRect.intersect(paintDirtyRect); } else backgroundRect = paintDirtyRect; + foregroundRect = backgroundRect; outlineRect = backgroundRect; int x = 0; int y = 0; convertToLayerCoords(rootLayer, x, y); - layerBounds = IntRect(x,y,width(),height()); + layerBounds = IntRect(x, y, width(), height()); // Update the clip rects that will be passed to child layers. - if (m_object->hasOverflowClip() || m_object->hasClip()) { + if (renderer()->hasOverflowClip() || renderer()->hasClip()) { // This layer establishes a clip of some kind. - if (m_object->hasOverflowClip()) - foregroundRect.intersect(m_object->getOverflowClipRect(x,y)); - if (m_object->hasClip()) { + if (renderer()->hasOverflowClip()) + foregroundRect.intersect(renderer()->getOverflowClipRect(x,y)); + if (renderer()->hasClip()) { // Clip applies to *us* as well, so go ahead and update the damageRect. - IntRect newPosClip = m_object->getClipRect(x,y); + IntRect newPosClip = renderer()->getClipRect(x,y); backgroundRect.intersect(newPosClip); foregroundRect.intersect(newPosClip); outlineRect.intersect(newPosClip); @@ -2122,7 +2164,7 @@ void RenderLayer::calculateRects(const RenderLayer* rootLayer, const IntRect& pa IntRect RenderLayer::childrenClipRect() const { - RenderLayer* rootLayer = renderer()->document()->renderer()->layer(); + RenderLayer* rootLayer = renderer()->view()->layer(); IntRect layerBounds, backgroundRect, foregroundRect, outlineRect; calculateRects(rootLayer, rootLayer->boundingBox(rootLayer), layerBounds, backgroundRect, foregroundRect, outlineRect); return foregroundRect; @@ -2130,7 +2172,7 @@ IntRect RenderLayer::childrenClipRect() const IntRect RenderLayer::selfClipRect() const { - RenderLayer* rootLayer = renderer()->document()->renderer()->layer(); + RenderLayer* rootLayer = renderer()->view()->layer(); IntRect layerBounds, backgroundRect, foregroundRect, outlineRect; calculateRects(rootLayer, rootLayer->boundingBox(rootLayer), layerBounds, backgroundRect, foregroundRect, outlineRect); return backgroundRect; @@ -2148,7 +2190,7 @@ bool RenderLayer::intersectsDamageRect(const IntRect& layerBounds, const IntRect // can go ahead and return true. RenderView* view = renderer()->view(); ASSERT(view); - if (view && !renderer()->isInlineFlow()) { + if (view && !renderer()->isRenderInline()) { IntRect b = layerBounds; b.inflate(view->maximalOutlineSize()); if (b.intersects(damageRect)) @@ -2172,7 +2214,7 @@ IntRect RenderLayer::boundingBox(const RenderLayer* rootLayer) const // as part of our bounding box. We do this because we are the responsible layer for both hit testing and painting those // floats. IntRect result; - if (renderer()->isInlineFlow()) { + if (renderer()->isRenderInline()) { // Go from our first line box to our last line box. RenderInline* inlineFlow = static_cast<RenderInline*>(renderer()); InlineFlowBox* firstBox = inlineFlow->firstLineBox(); @@ -2183,16 +2225,14 @@ IntRect RenderLayer::boundingBox(const RenderLayer* rootLayer) const int left = firstBox->xPos(); for (InlineRunBox* curr = firstBox->nextLineBox(); curr; curr = curr->nextLineBox()) left = min(left, curr->xPos()); - result = IntRect(m_x + left, m_y + (top - renderer()->yPos()), width(), bottom - top); + result = IntRect(m_x + left, m_y + (top - renderer()->y()), width(), bottom - top); } else if (renderer()->isTableRow()) { // Our bounding box is just the union of all of our cells' border/overflow rects. for (RenderObject* child = renderer()->firstChild(); child; child = child->nextSibling()) { if (child->isTableCell()) { - IntRect bbox = child->borderBox(); - bbox.move(0, child->borderTopExtra()); + IntRect bbox = toRenderBox(child)->borderBoxRect(); result.unite(bbox); IntRect overflowRect = renderer()->overflowRect(false); - overflowRect.move(0, child->borderTopExtra()); if (bbox != overflowRect) result.unite(overflowRect); } @@ -2202,7 +2242,7 @@ IntRect RenderLayer::boundingBox(const RenderLayer* rootLayer) const if (renderer()->hasMask()) result = renderer()->maskClipRect(); else { - IntRect bbox = renderer()->borderBox(); + IntRect bbox = renderer()->borderBoxRect(); result = bbox; IntRect overflowRect = renderer()->overflowRect(false); if (bbox != overflowRect) @@ -2210,11 +2250,7 @@ IntRect RenderLayer::boundingBox(const RenderLayer* rootLayer) const } // We have to adjust the x/y of this result so that it is in the coordinate space of the layer. - // We also have to add in borderTopExtra here, since borderBox(), in order to play well with methods like - // floatRect that deal with child content, uses an origin of (0,0) that is at the child content box (so - // border box returns a y coord of -borderTopExtra(). The layer, however, uses the outer box. This is all - // really confusing. - result.move(m_x, m_y + renderer()->borderTopExtra()); + result.move(m_x, m_y); } // Convert the bounding box to an absolute position. We can do this easily by looking at the delta @@ -2230,22 +2266,25 @@ IntRect RenderLayer::boundingBox(const RenderLayer* rootLayer) const return result; } -void RenderLayer::clearClipRects() +void RenderLayer::clearClipRectsIncludingDescendants() { if (!m_clipRects) return; - clearClipRect(); + clearClipRects(); for (RenderLayer* l = firstChild(); l; l = l->nextSibling()) - l->clearClipRects(); + l->clearClipRectsIncludingDescendants(); } -void RenderLayer::clearClipRect() +void RenderLayer::clearClipRects() { if (m_clipRects) { - m_clipRects->deref(m_object->renderArena()); + m_clipRects->deref(renderer()->renderArena()); m_clipRects = 0; +#ifndef NDEBUG + m_clipRectsRoot = 0; +#endif } } @@ -2425,7 +2464,7 @@ void RenderLayer::collectLayers(Vector<RenderLayer*>*& posBuffer, Vector<RenderL void RenderLayer::repaintIncludingDescendants() { - m_object->repaint(); + renderer()->repaint(); for (RenderLayer* curr = firstChild(); curr; curr = curr->nextSibling()) curr->repaintIncludingDescendants(); } @@ -2439,7 +2478,7 @@ bool RenderLayer::shouldBeOverflowOnly() const !isTransparent(); } -void RenderLayer::styleChanged(RenderStyle::Diff, const RenderStyle* oldStyle) +void RenderLayer::styleChanged(RenderStyle::Diff, const RenderStyle*) { bool isOverflowOnly = shouldBeOverflowOnly(); if (isOverflowOnly != m_isOverflowOnly) { @@ -2450,7 +2489,7 @@ void RenderLayer::styleChanged(RenderStyle::Diff, const RenderStyle* oldStyle) dirtyStackingContextZOrderLists(); } - if (m_object->style()->overflowX() == OMARQUEE && m_object->style()->marqueeBehavior() != MNONE) { + if (renderer()->style()->overflowX() == OMARQUEE && renderer()->style()->marqueeBehavior() != MNONE) { if (!m_marquee) m_marquee = new RenderMarquee(this); m_marquee->updateMarqueeStyle(); @@ -2481,12 +2520,12 @@ void RenderLayer::styleChanged(RenderStyle::Diff, const RenderStyle* oldStyle) void RenderLayer::updateScrollCornerStyle() { - RenderObject* actualRenderer = m_object->node()->isElementNode() ? m_object->node()->shadowAncestorNode()->renderer() : m_object; - RefPtr<RenderStyle> corner = m_object->hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(RenderStyle::SCROLLBAR_CORNER, actualRenderer->style()) : 0; + RenderObject* actualRenderer = renderer()->node()->isElementNode() ? renderer()->node()->shadowAncestorNode()->renderer() : renderer(); + RefPtr<RenderStyle> corner = renderer()->hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(RenderStyle::SCROLLBAR_CORNER, actualRenderer->style()) : 0; if (corner) { if (!m_scrollCorner) { - m_scrollCorner = new (m_object->renderArena()) RenderScrollbarPart(m_object->document()); - m_scrollCorner->setParent(m_object); + m_scrollCorner = new (renderer()->renderArena()) RenderScrollbarPart(renderer()->document()); + m_scrollCorner->setParent(renderer()); } m_scrollCorner->setStyle(corner.release()); } else if (m_scrollCorner) { @@ -2497,12 +2536,12 @@ void RenderLayer::updateScrollCornerStyle() void RenderLayer::updateResizerStyle() { - RenderObject* actualRenderer = m_object->node()->isElementNode() ? m_object->node()->shadowAncestorNode()->renderer() : m_object; - RefPtr<RenderStyle> resizer = m_object->hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(RenderStyle::RESIZER, actualRenderer->style()) : 0; + RenderObject* actualRenderer = renderer()->node()->isElementNode() ? renderer()->node()->shadowAncestorNode()->renderer() : renderer(); + RefPtr<RenderStyle> resizer = renderer()->hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(RenderStyle::RESIZER, actualRenderer->style()) : 0; if (resizer) { if (!m_resizer) { - m_resizer = new (m_object->renderArena()) RenderScrollbarPart(m_object->document()); - m_resizer->setParent(m_object); + m_resizer = new (renderer()->renderArena()) RenderScrollbarPart(renderer()->document()); + m_resizer->setParent(renderer()); } m_resizer->setStyle(resizer.release()); } else if (m_resizer) { diff --git a/WebCore/rendering/RenderLayer.h b/WebCore/rendering/RenderLayer.h index f946b5f..54c15e9 100644 --- a/WebCore/rendering/RenderLayer.h +++ b/WebCore/rendering/RenderLayer.h @@ -45,18 +45,17 @@ #define RenderLayer_h #include "ScrollbarClient.h" -#include "RenderObject.h" +#include "RenderBox.h" #include "Timer.h" #include <wtf/OwnPtr.h> namespace WebCore { -class AffineTransform; +class TransformationMatrix; class CachedResource; class HitTestResult; class RenderFrameSet; class RenderMarquee; -class RenderObject; class RenderReplica; class RenderScrollbarPart; class RenderStyle; @@ -69,6 +68,12 @@ struct HitTestRequest; class ClipRects { public: + ClipRects() + : m_refCnt(0) + , m_fixed(false) + { + } + ClipRects(const IntRect& r) : m_overflowClipRect(r) , m_fixedClipRect(r) @@ -78,19 +83,34 @@ public: { } - ClipRects(const IntRect& overflowRect, const IntRect& fixedRect, const IntRect& posRect, bool fixed) - : m_overflowClipRect(overflowRect) - , m_fixedClipRect(fixedRect) - , m_posClipRect(posRect) + ClipRects(const ClipRects& other) + : m_overflowClipRect(other.overflowClipRect()) + , m_fixedClipRect(other.fixedClipRect()) + , m_posClipRect(other.posClipRect()) , m_refCnt(0) - , m_fixed(fixed) + , m_fixed(other.fixed()) { } - const IntRect& overflowClipRect() { return m_overflowClipRect; } - const IntRect& fixedClipRect() { return m_fixedClipRect; } - const IntRect& posClipRect() { return m_posClipRect; } + void reset(const IntRect& r) + { + m_overflowClipRect = r; + m_fixedClipRect = r; + m_posClipRect = r; + m_fixed = false; + } + + const IntRect& overflowClipRect() const { return m_overflowClipRect; } + void setOverflowClipRect(const IntRect& r) { m_overflowClipRect = r; } + + const IntRect& fixedClipRect() const { return m_fixedClipRect; } + void setFixedClipRect(const IntRect&r) { m_fixedClipRect = r; } + + const IntRect& posClipRect() const { return m_posClipRect; } + void setPosClipRect(const IntRect& r) { m_posClipRect = r; } + bool fixed() const { return m_fixed; } + void setFixed(bool fixed) { m_fixed = fixed; } void ref() { m_refCnt++; } void deref(RenderArena* renderArena) { if (--m_refCnt == 0) destroy(renderArena); } @@ -102,6 +122,23 @@ public: // Overridden to prevent the normal delete from being called. void operator delete(void*, size_t); + + bool operator==(const ClipRects& other) const + { + return m_overflowClipRect == other.overflowClipRect() && + m_fixedClipRect == other.fixedClipRect() && + m_posClipRect == other.posClipRect() && + m_fixed == other.fixed(); + } + + ClipRects& operator=(const ClipRects& other) + { + m_overflowClipRect = other.overflowClipRect(); + m_fixedClipRect = other.fixedClipRect(); + m_posClipRect = other.posClipRect(); + m_fixed = other.fixed(); + return *this; + } private: // The normal operator new is disallowed on all render objects. @@ -145,10 +182,10 @@ public: static ScrollBehavior getPartialBehavior(const ScrollAlignment& s) { return s.m_rectPartial; } static ScrollBehavior getHiddenBehavior(const ScrollAlignment& s) { return s.m_rectHidden; } - RenderLayer(RenderObject*); + RenderLayer(RenderBox*); ~RenderLayer(); - RenderObject* renderer() const { return m_object; } + RenderBox* renderer() const { return m_renderer; } RenderLayer* parent() const { return m_parent; } RenderLayer* previousSibling() const { return m_previous; } RenderLayer* nextSibling() const { return m_next; } @@ -176,7 +213,7 @@ public: RenderLayer* transparentAncestor(); void beginTransparencyLayers(GraphicsContext*, const RenderLayer* rootLayer); - bool hasReflection() const { return m_object->hasReflection(); } + bool hasReflection() const { return renderer()->hasReflection(); } RenderReplica* reflection() const { return m_reflection; } RenderLayer* reflectionLayer() const; @@ -208,10 +245,13 @@ public: // Scrolling methods for layers that can scroll their overflow. void scrollByRecursively(int xDelta, int yDelta); - void scrollOffset(int& x, int& y); - void subtractScrollOffset(int& x, int& y); + void addScrolledContentOffset(int& x, int& y) const; + void subtractScrolledContentOffset(int& x, int& y) const; + IntSize scrolledContentOffset() const { return IntSize(scrollXOffset() + m_scrollLeftOverflow, scrollYOffset()); } + int scrollXOffset() const { return m_scrollX + m_scrollOriginX; } int scrollYOffset() const { return m_scrollY; } + void scrollToOffset(int x, int y, bool updateScrollbars = true, bool repaint = true); void scrollToXOffset(int x) { scrollToOffset(x, m_scrollY); } void scrollToYOffset(int y) { scrollToOffset(m_scrollX + m_scrollOriginX, y); } @@ -232,9 +272,9 @@ public: int horizontalScrollbarHeight() const; void positionOverflowControls(int tx, int ty); - bool isPointInResizeControl(const IntPoint&); + bool isPointInResizeControl(const IntPoint& absolutePoint) const; bool hitTestOverflowControls(HitTestResult&); - IntSize offsetFromResizeCorner(const IntPoint&) const; + IntSize offsetFromResizeCorner(const IntPoint& absolutePoint) const; void paintOverflowControls(GraphicsContext*, int tx, int ty, const IntRect& damageRect); void paintScrollCorner(GraphicsContext*, int tx, int ty, const IntRect& damageRect); @@ -254,10 +294,11 @@ public: void updateTransform(); - void relativePositionOffset(int& relX, int& relY) { relX += m_relX; relY += m_relY; } + void relativePositionOffset(int& relX, int& relY) const { relX += m_relX; relY += m_relY; } + IntSize relativePositionOffset() const { return IntSize(m_relX, m_relY); } + void clearClipRectsIncludingDescendants(); void clearClipRects(); - void clearClipRect(); // Get the enclosing stacking context for this layer. A stacking context is a layer // that has a non-auto z-index. @@ -298,9 +339,15 @@ 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) const; - void calculateClipRects(const RenderLayer* rootLayer); + IntRect& backgroundRect, IntRect& foregroundRect, IntRect& outlineRect, bool temporaryClipRects = false) const; + + // Compute and cache clip rects computed with the given layer as the root + void updateClipRects(const RenderLayer* rootLayer); + // 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; ClipRects* clipRects() const { return m_clipRects; } + IntRect childrenClipRect() const; // Returns the foreground clip rect of the layer in the document's coordinate space. IntRect selfClipRect() const; // Returns the background clip rect of the layer in the document's coordinate space. @@ -319,8 +366,8 @@ public: void setStaticX(int staticX) { m_staticX = staticX; } void setStaticY(int staticY) { m_staticY = staticY; } - bool hasTransform() const { return m_object->hasTransform(); } - AffineTransform* transform() const { return m_transform.get(); } + bool hasTransform() const { return renderer()->hasTransform(); } + TransformationMatrix* transform() const { return m_transform.get(); } void destroy(RenderArena*); @@ -345,7 +392,8 @@ private: void collectLayers(Vector<RenderLayer*>*&, Vector<RenderLayer*>*&); void paintLayer(RenderLayer* rootLayer, GraphicsContext*, const IntRect& paintDirtyRect, - bool haveTransparency, PaintRestriction, RenderObject* paintingRoot, bool appliedTransform = false); + bool haveTransparency, PaintRestriction, RenderObject* paintingRoot, + bool appliedTransform = false, bool temporaryClipRects = false); RenderLayer* hitTestLayer(RenderLayer* rootLayer, const HitTestRequest&, HitTestResult&, const IntRect& hitTestRect, const IntPoint& hitTestPoint, bool appliedTransform = false); void computeScrollDimensions(bool* needHBar = 0, bool* needVBar = 0); @@ -370,11 +418,14 @@ private: RenderLayer* enclosingTransformedAncestor() const; + // Convert a point in absolute coords into layer coords, taking transforms into account + IntPoint absoluteToContents(const IntPoint&) const; + void updateScrollCornerStyle(); void updateResizerStyle(); protected: - RenderObject* m_object; + RenderBox* m_renderer; RenderLayer* m_parent; RenderLayer* m_previous; @@ -400,8 +451,8 @@ protected: // Our scroll offsets if the view is scrolled. int m_scrollX; int m_scrollY; - int m_scrollOriginX; - int m_scrollLeftOverflow; + int m_scrollOriginX; // only non-zero for rtl content + int m_scrollLeftOverflow; // only non-zero for rtl content // The width/height of our scrolled area. int m_scrollWidth; @@ -426,6 +477,9 @@ protected: Vector<RenderLayer*>* m_overflowList; ClipRects* m_clipRects; // Cached clip rects used when painting and hit testing. +#ifndef NDEBUG + const RenderLayer* m_clipRectsRoot; // Root layer used to compute clip rects. +#endif bool m_scrollDimensionsDirty : 1; bool m_zOrderListsDirty : 1; @@ -453,7 +507,7 @@ protected: int m_staticX; int m_staticY; - OwnPtr<AffineTransform> m_transform; + OwnPtr<TransformationMatrix> m_transform; // May ultimately be extended to many replicas (with their own paint order). RenderReplica* m_reflection; diff --git a/WebCore/rendering/RenderLegend.cpp b/WebCore/rendering/RenderLegend.cpp index b4cf291..1fac53f 100644 --- a/WebCore/rendering/RenderLegend.cpp +++ b/WebCore/rendering/RenderLegend.cpp @@ -26,11 +26,9 @@ #include "config.h" #include "RenderLegend.h" -#include "HTMLFormControlElement.h" - namespace WebCore { -RenderLegend::RenderLegend(HTMLFormControlElement* element) +RenderLegend::RenderLegend(Node* element) : RenderBlock(element) { } diff --git a/WebCore/rendering/RenderLegend.h b/WebCore/rendering/RenderLegend.h index fa8b249..649f132 100644 --- a/WebCore/rendering/RenderLegend.h +++ b/WebCore/rendering/RenderLegend.h @@ -30,11 +30,9 @@ namespace WebCore { - class HTMLFormControlElement; - class RenderLegend : public RenderBlock { public: - RenderLegend(HTMLFormControlElement*); + RenderLegend(Node*); virtual const char* renderName() const { return "RenderLegend"; } }; diff --git a/WebCore/rendering/RenderListBox.cpp b/WebCore/rendering/RenderListBox.cpp index c435ff4..3dddc13 100644 --- a/WebCore/rendering/RenderListBox.cpp +++ b/WebCore/rendering/RenderListBox.cpp @@ -2,6 +2,7 @@ * This file is part of the select element renderer in WebCore. * * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -41,10 +42,10 @@ #include "FrameView.h" #include "GraphicsContext.h" #include "HTMLNames.h" -#include "HTMLOptGroupElement.h" -#include "HTMLOptionElement.h" #include "HTMLSelectElement.h" #include "HitTestResult.h" +#include "OptionGroupElement.h" +#include "OptionElement.h" #include "Page.h" #include "RenderScrollbar.h" #include "RenderTheme.h" @@ -103,10 +104,10 @@ void RenderListBox::updateFromElement() HTMLElement* element = listItems[i]; String text; Font itemFont = style()->font(); - if (element->hasTagName(optionTag)) - text = static_cast<HTMLOptionElement*>(element)->optionText(); - else if (element->hasTagName(optgroupTag)) { - text = static_cast<HTMLOptGroupElement*>(element)->groupLabelText(); + if (OptionElement* optionElement = toOptionElement(element)) + text = optionElement->textIndentedToRespectGroupLabel(); + else if (OptionGroupElement* optionGroupElement = toOptionGroupElement(element)) { + text = optionGroupElement->groupLabelText(); FontDescription d = itemFont.fontDescription(); d.setWeight(d.bolderWeight()); itemFont = Font(d, itemFont.letterSpacing(), itemFont.wordSpacing()); @@ -223,7 +224,7 @@ void RenderListBox::calcHeight() int toAdd = paddingTop() + paddingBottom() + borderTop() + borderBottom(); int itemHeight = RenderListBox::itemHeight(); - m_height = itemHeight * size() - rowSpacing + toAdd; + setHeight(itemHeight * size() - rowSpacing + toAdd); RenderBlock::calcHeight(); @@ -237,7 +238,7 @@ void RenderListBox::calcHeight() } } -int RenderListBox::baselinePosition(bool b, bool isRootLineBox) const +int RenderListBox::baselinePosition(bool, bool) const { return height() + marginTop() + marginBottom() - baselineAdjustment; } @@ -295,13 +296,14 @@ void RenderListBox::paintItemForeground(PaintInfo& paintInfo, int tx, int ty, in HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node()); const Vector<HTMLElement*>& listItems = select->listItems(); HTMLElement* element = listItems[listIndex]; + OptionElement* optionElement = toOptionElement(element); String itemText; - if (element->hasTagName(optionTag)) - itemText = static_cast<HTMLOptionElement*>(element)->optionText(); - else if (element->hasTagName(optgroupTag)) - itemText = static_cast<HTMLOptGroupElement*>(element)->groupLabelText(); - + if (optionElement) + itemText = optionElement->textIndentedToRespectGroupLabel(); + else if (OptionGroupElement* optionGroupElement = toOptionGroupElement(element)) + itemText = optionGroupElement->groupLabelText(); + // Determine where the item text should be placed IntRect r = itemBoundingBoxRect(tx, ty, listIndex); r.move(optionsSpacingHorizontal, style()->font().ascent()); @@ -311,7 +313,7 @@ void RenderListBox::paintItemForeground(PaintInfo& paintInfo, int tx, int ty, in itemStyle = style(); Color textColor = element->renderStyle() ? element->renderStyle()->color() : style()->color(); - if (element->hasTagName(optionTag) && static_cast<HTMLOptionElement*>(element)->selected()) { + if (optionElement && optionElement->selected()) { if (document()->frame()->selection()->isFocusedAndActive() && document()->focusedNode() == node()) textColor = theme()->activeListBoxSelectionForegroundColor(); // Honor the foreground color for disabled items @@ -328,15 +330,14 @@ void RenderListBox::paintItemForeground(PaintInfo& paintInfo, int tx, int ty, in itemFont = Font(d, itemFont.letterSpacing(), itemFont.wordSpacing()); itemFont.update(document()->styleSelector()->fontSelector()); } - paintInfo.context->setFont(itemFont); - + unsigned length = itemText.length(); const UChar* string = itemText.characters(); TextRun textRun(string, length, 0, 0, 0, itemStyle->direction() == RTL, itemStyle->unicodeBidi() == Override, false, false); // Draw the item text if (itemStyle->visibility() != HIDDEN) - paintInfo.context->drawBidiText(textRun, r.location()); + paintInfo.context->drawBidiText(itemFont, textRun, r.location()); } void RenderListBox::paintItemBackground(PaintInfo& paintInfo, int tx, int ty, int listIndex) @@ -344,9 +345,10 @@ void RenderListBox::paintItemBackground(PaintInfo& paintInfo, int tx, int ty, in HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node()); const Vector<HTMLElement*>& listItems = select->listItems(); HTMLElement* element = listItems[listIndex]; + OptionElement* optionElement = toOptionElement(element); Color backColor; - if (element->hasTagName(optionTag) && static_cast<HTMLOptionElement*>(element)->selected()) { + if (optionElement && optionElement->selected()) { if (document()->frame()->selection()->isFocusedAndActive() && document()->focusedNode() == node()) backColor = theme()->activeListBoxSelectionBackgroundColor(); else @@ -368,9 +370,9 @@ bool RenderListBox::isPointInOverflowControl(HitTestResult& result, int _x, int return false; IntRect vertRect(_tx + width() - borderRight() - m_vBar->width(), - _ty + borderTop() - borderTopExtra(), - m_vBar->width(), - height() + borderTopExtra() + borderBottomExtra() - borderTop() - borderBottom()); + _ty, + m_vBar->width(), + height() - borderTop() - borderBottom()); if (vertRect.contains(_x, _y)) { result.setScrollbar(m_vBar.get()); @@ -401,9 +403,8 @@ void RenderListBox::panScroll(const IntPoint& panStartMousePosition) const int iconRadius = 7; const int speedReducer = 4; - int offsetX; - int offsetY; - absolutePosition(offsetX, offsetY); + // FIXME: This doesn't work correctly with transforms. + FloatPoint absOffset = localToAbsolute(); IntPoint currentMousePosition = document()->frame()->eventHandler()->currentMousePosition(); // We need to check if the current mouse position is out of the window. When the mouse is out of the window, the position is incoherent @@ -423,7 +424,7 @@ void RenderListBox::panScroll(const IntPoint& panStartMousePosition) if (yDelta > 0) //offsetY = view()->viewHeight(); - offsetY += listHeight(); + absOffset.move(0, listHeight()); else if (yDelta < 0) yDelta--; @@ -431,7 +432,7 @@ void RenderListBox::panScroll(const IntPoint& panStartMousePosition) yDelta /= speedReducer; IntPoint scrollPoint(0,0); - scrollPoint.setY(offsetY + yDelta); + scrollPoint.setY(absOffset.y() + yDelta); int newOffset = scrollToward(scrollPoint); if (newOffset < 0) return; @@ -444,11 +445,10 @@ void RenderListBox::panScroll(const IntPoint& panStartMousePosition) int RenderListBox::scrollToward(const IntPoint& destination) { - int rx = 0; - int ry = 0; - absolutePosition(rx, ry); - int offsetX = destination.x() - rx; - int offsetY = destination.y() - ry; + // FIXME: This doesn't work correctly with transforms. + FloatPoint absPos = localToAbsolute(); + int offsetX = destination.x() - absPos.x(); + int offsetY = destination.y() - absPos.y(); int rows = numVisibleItems(); int offset = m_indexOffset; @@ -581,7 +581,7 @@ void RenderListBox::setScrollTop(int newTop) IntRect RenderListBox::controlClipRect(int tx, int ty) const { - IntRect clipRect = contentBox(); + IntRect clipRect = contentBoxRect(); clipRect.move(tx, ty); return clipRect; } @@ -599,13 +599,6 @@ void RenderListBox::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& repaintRectangle(scrollRect); } -bool RenderListBox::isScrollable() const -{ - if (numVisibleItems() < numItems()) - return true; - return RenderObject::isScrollable(); -} - PassRefPtr<Scrollbar> RenderListBox::createScrollbar() { RefPtr<Scrollbar> widget; diff --git a/WebCore/rendering/RenderListBox.h b/WebCore/rendering/RenderListBox.h index ccc6847..b9cfcb1 100644 --- a/WebCore/rendering/RenderListBox.h +++ b/WebCore/rendering/RenderListBox.h @@ -58,7 +58,6 @@ public: virtual bool isPointInOverflowControl(HitTestResult&, int x, int y, int tx, int ty); virtual bool scroll(ScrollDirection, ScrollGranularity, float multiplier = 1.0f); - virtual bool isScrollable() const; virtual void calcPrefWidths(); virtual int baselinePosition(bool firstLine, bool isRootLineBox) const; diff --git a/WebCore/rendering/RenderListItem.cpp b/WebCore/rendering/RenderListItem.cpp index b69612e..47158b6 100644 --- a/WebCore/rendering/RenderListItem.cpp +++ b/WebCore/rendering/RenderListItem.cpp @@ -31,6 +31,7 @@ #include "HTMLOListElement.h" #include "RenderListMarker.h" #include "RenderView.h" +#include <wtf/StdLibExtras.h> using namespace std; @@ -143,7 +144,7 @@ static RenderObject* getParentOfFirstLineBox(RenderBlock* curr, RenderObject* ma if (currChild == marker) continue; - if (currChild->isInline() && (!currChild->isInlineFlow() || curr->generatesLineBoxesForInlineChild(currChild))) + if (currChild->isInline() && (!currChild->isRenderInline() || curr->generatesLineBoxesForInlineChild(currChild))) return curr; if (currChild->isFloating() || currChild->isPositioned()) @@ -234,12 +235,12 @@ void RenderListItem::layout() void RenderListItem::positionListMarker() { if (m_marker && !m_marker->isInside() && m_marker->inlineBoxWrapper()) { - int markerOldX = m_marker->xPos(); + int markerOldX = m_marker->x(); int yOffset = 0; int xOffset = 0; - for (RenderObject* o = m_marker->parent(); o != this; o = o->parent()) { - yOffset += o->yPos(); - xOffset += o->xPos(); + for (RenderBox* o = m_marker->parentBox(); o != this; o = o->parentBox()) { + yOffset += o->y(); + xOffset += o->x(); } bool adjustOverflow = false; @@ -266,12 +267,12 @@ void RenderListItem::positionListMarker() if (adjustOverflow) { IntRect markerRect(markerXPos + xOffset, yOffset, m_marker->width(), m_marker->height()); - RenderObject* o = m_marker; + RenderBox* o = m_marker; do { - o = o->parent(); + o = o->parentBox(); if (o->isRenderBlock()) static_cast<RenderBlock*>(o)->addVisualOverflow(markerRect); - markerRect.move(-o->xPos(), -o->yPos()); + markerRect.move(-o->x(), -o->y()); } while (o != this); } } @@ -279,7 +280,7 @@ void RenderListItem::positionListMarker() void RenderListItem::paint(PaintInfo& paintInfo, int tx, int ty) { - if (!m_height) + if (!height()) return; RenderBlock::paint(paintInfo, tx, ty); @@ -289,7 +290,7 @@ const String& RenderListItem::markerText() const { if (m_marker) return m_marker->text(); - static String staticNullString; + DEFINE_STATIC_LOCAL(String, staticNullString, ()); return staticNullString; } diff --git a/WebCore/rendering/RenderListMarker.cpp b/WebCore/rendering/RenderListMarker.cpp index b2937b9..340db50 100644 --- a/WebCore/rendering/RenderListMarker.cpp +++ b/WebCore/rendering/RenderListMarker.cpp @@ -506,9 +506,9 @@ void RenderListMarker::styleDidChange(RenderStyle::Diff diff, const RenderStyle* } } -InlineBox* RenderListMarker::createInlineBox(bool, bool isRootLineBox, bool) +InlineBox* RenderListMarker::createInlineBox(bool, bool unusedIsRootLineBox, bool) { - ASSERT(!isRootLineBox); + ASSERT_UNUSED(unusedIsRootLineBox, !unusedIsRootLineBox); ListMarkerBox* box = new (renderArena()) ListMarkerBox(this); m_inlineBoxWrapper = box; return box; @@ -530,7 +530,7 @@ void RenderListMarker::paint(PaintInfo& paintInfo, int tx, int ty) IntRect marker = getRelativeMarkerRect(); marker.move(tx, ty); - IntRect box(tx + m_x, ty + m_y, m_width, m_height); + IntRect box(tx + x(), ty + y(), width(), height()); if (box.y() > paintInfo.rect.bottom() || box.y() + box.height() < paintInfo.rect.y()) return; @@ -539,7 +539,6 @@ void RenderListMarker::paint(PaintInfo& paintInfo, int tx, int ty) paintBoxDecorations(paintInfo, box.x(), box.y()); GraphicsContext* context = paintInfo.context; - context->setFont(style()->font()); if (isImage()) { #if PLATFORM(MAC) @@ -619,15 +618,15 @@ void RenderListMarker::paint(PaintInfo& paintInfo, int tx, int ty) const Font& font = style()->font(); if (style()->direction() == LTR) { int width = font.width(textRun); - context->drawText(textRun, marker.location()); + context->drawText(style()->font(), textRun, marker.location()); const UChar periodSpace[2] = { '.', ' ' }; - context->drawText(TextRun(periodSpace, 2), marker.location() + IntSize(width, 0)); + context->drawText(style()->font(), TextRun(periodSpace, 2), marker.location() + IntSize(width, 0)); } else { const UChar spacePeriod[2] = { ' ', '.' }; TextRun spacePeriodRun(spacePeriod, 2); int width = font.width(spacePeriodRun); - context->drawText(spacePeriodRun, marker.location()); - context->drawText(textRun, marker.location() + IntSize(width, 0)); + context->drawText(style()->font(), spacePeriodRun, marker.location()); + context->drawText(style()->font(), textRun, marker.location() + IntSize(width, 0)); } } @@ -637,11 +636,11 @@ void RenderListMarker::layout() ASSERT(!prefWidthsDirty()); if (isImage()) { - m_width = m_image->imageSize(this, style()->effectiveZoom()).width(); - m_height = m_image->imageSize(this, style()->effectiveZoom()).height(); + setWidth(m_image->imageSize(this, style()->effectiveZoom()).width()); + setHeight(m_image->imageSize(this, style()->effectiveZoom()).height()); } else { - m_width = minPrefWidth(); - m_height = style()->font().height(); + setWidth(minPrefWidth()); + setHeight(style()->font().height()); } m_marginLeft = m_marginRight = 0; @@ -656,13 +655,13 @@ void RenderListMarker::layout() setNeedsLayout(false); } -void RenderListMarker::imageChanged(WrappedImagePtr o) +void RenderListMarker::imageChanged(WrappedImagePtr o, const IntRect*) { // A list marker can't have a background or border image, so no need to call the base class method. if (o != m_image->data()) return; - if (m_width != m_image->imageSize(this, style()->effectiveZoom()).width() || m_height != m_image->imageSize(this, style()->effectiveZoom()).height() || m_image->errorOccurred()) + if (width() != m_image->imageSize(this, style()->effectiveZoom()).width() || height() != m_image->imageSize(this, style()->effectiveZoom()).height() || m_image->errorOccurred()) setNeedsLayoutAndPrefWidthsRecalc(); else repaint(); @@ -830,7 +829,7 @@ bool RenderListMarker::isInside() const IntRect RenderListMarker::getRelativeMarkerRect() { if (isImage()) - return IntRect(m_x, m_y, m_image->imageSize(this, style()->effectiveZoom()).width(), m_image->imageSize(this, style()->effectiveZoom()).height()); + return IntRect(x(), y(), m_image->imageSize(this, style()->effectiveZoom()).width(), m_image->imageSize(this, style()->effectiveZoom()).height()); switch (style()->listStyleType()) { case DISC: @@ -840,7 +839,7 @@ IntRect RenderListMarker::getRelativeMarkerRect() const Font& font = style()->font(); int ascent = font.ascent(); int bulletWidth = (ascent * 2 / 3 + 1) / 2; - return IntRect(m_x + 1, m_y + 3 * (ascent - ascent * 2 / 3) / 2, bulletWidth, bulletWidth); + return IntRect(x() + 1, y() + 3 * (ascent - ascent * 2 / 3) / 2, bulletWidth, bulletWidth); } case LNONE: return IntRect(); @@ -867,7 +866,7 @@ IntRect RenderListMarker::getRelativeMarkerRect() int itemWidth = font.width(m_text); const UChar periodSpace[2] = { '.', ' ' }; int periodSpaceWidth = font.width(TextRun(periodSpace, 2)); - return IntRect(m_x, m_y + font.ascent(), itemWidth + periodSpaceWidth, font.height()); + return IntRect(x(), y() + font.ascent(), itemWidth + periodSpaceWidth, font.height()); } return IntRect(); @@ -890,14 +889,13 @@ IntRect RenderListMarker::selectionRect(bool clipToVisibleContent) return IntRect(); RootInlineBox* root = inlineBoxWrapper()->root(); - IntRect rect(0, root->selectionTop() - yPos(), width(), root->selectionHeight()); + IntRect rect(0, root->selectionTop() - y(), width(), root->selectionHeight()); if (clipToVisibleContent) computeAbsoluteRepaintRect(rect); else { - int absx, absy; - absolutePosition(absx, absy); - rect.move(absx, absy); + FloatPoint absPos = localToAbsolute(); + rect.move(absPos.x(), absPos.y()); } return rect; diff --git a/WebCore/rendering/RenderListMarker.h b/WebCore/rendering/RenderListMarker.h index 3c5224c..738427c 100644 --- a/WebCore/rendering/RenderListMarker.h +++ b/WebCore/rendering/RenderListMarker.h @@ -47,7 +47,7 @@ public: virtual void layout(); virtual void calcPrefWidths(); - virtual void imageChanged(WrappedImagePtr); + virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); virtual InlineBox* createInlineBox(bool, bool, bool); diff --git a/WebCore/rendering/RenderMarquee.cpp b/WebCore/rendering/RenderMarquee.cpp index 96d26ea..2b4dcfd 100644 --- a/WebCore/rendering/RenderMarquee.cpp +++ b/WebCore/rendering/RenderMarquee.cpp @@ -105,7 +105,7 @@ bool RenderMarquee::isHorizontal() const int RenderMarquee::computePosition(EMarqueeDirection dir, bool stopAtContentEdge) { - RenderObject* o = m_layer->renderer(); + RenderBox* o = m_layer->renderer(); RenderStyle* s = o->style(); if (isHorizontal()) { bool ltr = s->direction() == LTR; diff --git a/WebCore/rendering/RenderMedia.cpp b/WebCore/rendering/RenderMedia.cpp index 4953a35..80bf586 100644 --- a/WebCore/rendering/RenderMedia.cpp +++ b/WebCore/rendering/RenderMedia.cpp @@ -35,11 +35,12 @@ #include "FrameView.h" #include "GraphicsContext.h" #include "HTMLMediaElement.h" +#include "HTMLNames.h" #include "MediaControlElements.h" #include "MouseEvent.h" #include "MediaPlayer.h" #include "RenderSlider.h" -#include "SystemTime.h" +#include <wtf/CurrentTime.h> #include <wtf/MathExtras.h> using namespace std; @@ -81,6 +82,11 @@ RenderMedia::~RenderMedia() void RenderMedia::destroy() { if (m_controlsShadowRoot && m_controlsShadowRoot->renderer()) { + + // detach the panel before removing the shadow renderer to prevent a crash in m_controlsShadowRoot->detach() + // when display: style changes + m_panel->detach(); + removeChild(m_controlsShadowRoot->renderer()); m_controlsShadowRoot->detach(); } @@ -99,16 +105,16 @@ MediaPlayer* RenderMedia::player() const void RenderMedia::layout() { - IntSize oldSize = contentBox().size(); + IntSize oldSize = contentBoxRect().size(); RenderReplaced::layout(); - RenderObject* controlsRenderer = m_controlsShadowRoot ? m_controlsShadowRoot->renderer() : 0; + RenderBox* controlsRenderer = m_controlsShadowRoot ? m_controlsShadowRoot->renderBox() : 0; if (!controlsRenderer) return; - IntSize newSize = contentBox().size(); + IntSize newSize = contentBoxRect().size(); if (newSize != oldSize || controlsRenderer->needsLayout()) { - controlsRenderer->setPos(borderLeft() + paddingLeft(), borderTop() + paddingTop()); + controlsRenderer->setLocation(borderLeft() + paddingLeft(), borderTop() + paddingTop()); controlsRenderer->style()->setHeight(Length(newSize.height(), Fixed)); controlsRenderer->style()->setWidth(Length(newSize.width(), Fixed)); controlsRenderer->setNeedsLayout(true, false); @@ -145,7 +151,7 @@ void RenderMedia::createPanel() { ASSERT(!m_panel); RenderStyle* style = getCachedPseudoStyle(RenderStyle::MEDIA_CONTROLS_PANEL); - m_panel = new HTMLDivElement(document()); + m_panel = new HTMLDivElement(HTMLNames::divTag, document()); RenderObject* renderer = m_panel->createRenderer(renderArena(), style); if (renderer) { m_panel->setRenderer(renderer); @@ -185,27 +191,41 @@ void RenderMedia::createSeekForwardButton() m_seekForwardButton->attachToParent(m_panel.get()); } +void RenderMedia::createTimelineContainer() +{ + ASSERT(!m_timelineContainer); + RenderStyle* style = getCachedPseudoStyle(RenderStyle::MEDIA_CONTROLS_TIMELINE_CONTAINER); + m_timelineContainer = new HTMLDivElement(HTMLNames::divTag, document()); + RenderObject* renderer = m_timelineContainer->createRenderer(renderArena(), style); + if (renderer) { + m_timelineContainer->setRenderer(renderer); + renderer->setStyle(style); + m_timelineContainer->setAttached(); + m_timelineContainer->setInDocument(true); + m_panel->addChild(m_timelineContainer); + m_panel->renderer()->addChild(renderer); + } +} + void RenderMedia::createTimeline() { ASSERT(!m_timeline); m_timeline = new MediaControlTimelineElement(document(), mediaElement()); - m_timeline->attachToParent(m_panel.get()); + m_timeline->attachToParent(m_timelineContainer.get()); } -void RenderMedia::createTimeDisplay() +void RenderMedia::createCurrentTimeDisplay() { - ASSERT(!m_timeDisplay); - RenderStyle* style = getCachedPseudoStyle(RenderStyle::MEDIA_CONTROLS_TIME_DISPLAY); - m_timeDisplay = new HTMLDivElement(document()); - RenderObject* renderer = m_timeDisplay->createRenderer(renderArena(), style); - if (renderer) { - m_timeDisplay->setRenderer(renderer); - renderer->setStyle(style); - m_timeDisplay->setAttached(); - m_timeDisplay->setInDocument(true); - m_panel->addChild(m_timeDisplay); - m_panel->renderer()->addChild(renderer); - } + ASSERT(!m_currentTimeDisplay); + m_currentTimeDisplay = new MediaTimeDisplayElement(document(), mediaElement(), true); + m_currentTimeDisplay->attachToParent(m_timelineContainer.get()); +} + +void RenderMedia::createTimeRemainingDisplay() +{ + ASSERT(!m_timeRemainingDisplay); + m_timeRemainingDisplay = new MediaTimeDisplayElement(document(), mediaElement(), false); + m_timeRemainingDisplay->attachToParent(m_timelineContainer.get()); } void RenderMedia::createFullscreenButton() @@ -229,10 +249,12 @@ void RenderMedia::updateControls() m_panel = 0; m_muteButton = 0; m_playButton = 0; + m_timelineContainer = 0; m_timeline = 0; m_seekBackButton = 0; m_seekForwardButton = 0; - m_timeDisplay = 0; + m_currentTimeDisplay = 0; + m_timeRemainingDisplay = 0; m_fullscreenButton = 0; m_controlsShadowRoot = 0; } @@ -247,17 +269,23 @@ void RenderMedia::updateControls() createPanel(); createMuteButton(); createPlayButton(); + createTimelineContainer(); createTimeline(); createSeekBackButton(); createSeekForwardButton(); - createTimeDisplay(); + createCurrentTimeDisplay(); + createTimeRemainingDisplay(); createFullscreenButton(); } - - if (media->paused() || media->ended() || media->networkState() < HTMLMediaElement::LOADED_METADATA) - m_timeUpdateTimer.stop(); - else + + if (media->paused() || media->ended() || media->networkState() < HTMLMediaElement::LOADED_METADATA) { + if (m_timeUpdateTimer.isActive()) + m_timeUpdateTimer.stop(); + } else if (style()->visibility() == VISIBLE && m_timeline && m_timeline->renderer() && m_timeline->renderer()->style()->display() != NONE ) { m_timeUpdateTimer.startRepeating(cTimeUpdateRepeatDelay); + } + + m_previousVisible = style()->visibility(); if (m_muteButton) m_muteButton->update(); @@ -286,30 +314,45 @@ String RenderMedia::formatTime(float time) { if (!isfinite(time)) time = 0; - int seconds = (int)time; + int seconds = (int)fabsf(time); int hours = seconds / (60 * 60); int minutes = (seconds / 60) % 60; seconds %= 60; - return String::format("%02d:%02d:%02d", hours, minutes, seconds); + if (hours) { + if (hours > 9) + return String::format("%s%02d:%02d:%02d", (time < 0 ? "-" : ""), hours, minutes, seconds); + else + return String::format("%s%01d:%02d:%02d", (time < 0 ? "-" : ""), hours, minutes, seconds); + } + else + return String::format("%s%02d:%02d", (time < 0 ? "-" : ""), minutes, seconds); } void RenderMedia::updateTimeDisplay() { - if (!m_timeDisplay) + if (!m_currentTimeDisplay || !m_currentTimeDisplay->renderer() || m_currentTimeDisplay->renderer()->style()->display() == NONE || style()->visibility() != VISIBLE) return; - String timeString = formatTime(mediaElement()->currentTime()); + float now = mediaElement()->currentTime(); + float duration = mediaElement()->duration(); + + String timeString = formatTime(now); ExceptionCode ec; - m_timeDisplay->setInnerText(timeString, ec); -} + m_currentTimeDisplay->setInnerText(timeString, ec); + timeString = formatTime(now - duration); + m_timeRemainingDisplay->setInnerText(timeString, ec); +} + void RenderMedia::updateControlVisibility() { if (!m_panel || !m_panel->renderer()) return; + // Don't fade for audio controls. HTMLMediaElement* media = mediaElement(); if (player() && !player()->hasVideo() || !media->isVideo()) return; + // do fading manually, css animations don't work well with shadow trees bool visible = style()->visibility() == VISIBLE && (m_mouseOver || media->paused() || media->ended() || media->networkState() < HTMLMediaElement::LOADED_METADATA); if (visible == (m_opacityAnimationTo > 0)) @@ -319,7 +362,7 @@ void RenderMedia::updateControlVisibility() // don't fade gradually if it the element has just changed visibility m_previousVisible = style()->visibility(); m_opacityAnimationTo = m_previousVisible == VISIBLE ? 1.0f : 0; - changeOpacity(m_panel.get(), 0); + changeOpacity(m_panel.get(), m_opacityAnimationTo); return; } @@ -355,23 +398,28 @@ void RenderMedia::opacityAnimationTimerFired(Timer<RenderMedia>*) float opacity = narrowPrecisionToFloat(m_opacityAnimationFrom + (m_opacityAnimationTo - m_opacityAnimationFrom) * time / cOpacityAnimationDuration); changeOpacity(m_panel.get(), opacity); } - + void RenderMedia::forwardEvent(Event* event) { if (event->isMouseEvent() && m_controlsShadowRoot) { MouseEvent* mouseEvent = static_cast<MouseEvent*>(event); IntPoint point(mouseEvent->pageX(), mouseEvent->pageY()); - if (m_muteButton && m_muteButton->renderer() && m_muteButton->renderer()->absoluteBoundingBoxRect().contains(point)) + if (m_muteButton && m_muteButton->hitTest(point)) m_muteButton->defaultEventHandler(event); - if (m_playButton && m_playButton->renderer() && m_playButton->renderer()->absoluteBoundingBoxRect().contains(point)) + + if (m_playButton && m_playButton->hitTest(point)) m_playButton->defaultEventHandler(event); - if (m_seekBackButton && m_seekBackButton->renderer() && m_seekBackButton->renderer()->absoluteBoundingBoxRect().contains(point)) + + if (m_seekBackButton && m_seekBackButton->hitTest(point)) m_seekBackButton->defaultEventHandler(event); - if (m_seekForwardButton && m_seekForwardButton->renderer() && m_seekForwardButton->renderer()->absoluteBoundingBoxRect().contains(point)) + + if (m_seekForwardButton && m_seekForwardButton->hitTest(point)) m_seekForwardButton->defaultEventHandler(event); - if (m_timeline && m_timeline->renderer() && m_timeline->renderer()->absoluteBoundingBoxRect().contains(point)) + + if (m_timeline && m_timeline->hitTest(point)) m_timeline->defaultEventHandler(event); - if (m_fullscreenButton && m_fullscreenButton->renderer() && m_fullscreenButton->renderer()->absoluteBoundingBoxRect().contains(point)) + + if (m_fullscreenButton && m_fullscreenButton->hitTest(point)) m_fullscreenButton->defaultEventHandler(event); if (event->type() == eventNames().mouseoverEvent) { @@ -392,7 +440,7 @@ int RenderMedia::lowestPosition(bool includeOverflowInterior, bool includeSelf) if (!m_controlsShadowRoot || !m_controlsShadowRoot->renderer()) return bottom; - return max(bottom, m_controlsShadowRoot->renderer()->yPos() + m_controlsShadowRoot->renderer()->lowestPosition(includeOverflowInterior, includeSelf)); + return max(bottom, m_controlsShadowRoot->renderBox()->y() + m_controlsShadowRoot->renderer()->lowestPosition(includeOverflowInterior, includeSelf)); } int RenderMedia::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const @@ -401,7 +449,7 @@ int RenderMedia::rightmostPosition(bool includeOverflowInterior, bool includeSel if (!m_controlsShadowRoot || !m_controlsShadowRoot->renderer()) return right; - return max(right, m_controlsShadowRoot->renderer()->xPos() + m_controlsShadowRoot->renderer()->rightmostPosition(includeOverflowInterior, includeSelf)); + return max(right, m_controlsShadowRoot->renderBox()->x() + m_controlsShadowRoot->renderer()->rightmostPosition(includeOverflowInterior, includeSelf)); } int RenderMedia::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const @@ -410,7 +458,7 @@ int RenderMedia::leftmostPosition(bool includeOverflowInterior, bool includeSelf if (!m_controlsShadowRoot || !m_controlsShadowRoot->renderer()) return left; - return min(left, m_controlsShadowRoot->renderer()->xPos() + m_controlsShadowRoot->renderer()->leftmostPosition(includeOverflowInterior, includeSelf)); + return min(left, m_controlsShadowRoot->renderBox()->x() + m_controlsShadowRoot->renderer()->leftmostPosition(includeOverflowInterior, includeSelf)); } } // namespace WebCore diff --git a/WebCore/rendering/RenderMedia.h b/WebCore/rendering/RenderMedia.h index 8f48caf..a4670e9 100644 --- a/WebCore/rendering/RenderMedia.h +++ b/WebCore/rendering/RenderMedia.h @@ -40,6 +40,7 @@ class MediaControlPlayButtonElement; class MediaControlSeekButtonElement; class MediaControlTimelineElement; class MediaControlFullscreenButtonElement; +class MediaTimeDisplayElement; class MediaPlayer; class RenderMedia : public RenderReplaced { @@ -66,6 +67,7 @@ public: void updateFromElement(); void updatePlayer(); void updateControls(); + void updateTimeDisplay(); void forwardEvent(Event*); @@ -75,17 +77,19 @@ public: private: void createControlsShadowRoot(); + void destroyControlsShadowRoot(); void createPanel(); void createMuteButton(); void createPlayButton(); void createSeekBackButton(); void createSeekForwardButton(); + void createTimelineContainer(); void createTimeline(); - void createTimeDisplay(); + void createCurrentTimeDisplay(); + void createTimeRemainingDisplay(); void createFullscreenButton(); void timeUpdateTimerFired(Timer<RenderMedia>*); - void updateTimeDisplay(); void updateControlVisibility(); void changeOpacity(HTMLElement*, float opacity); @@ -99,7 +103,9 @@ private: RefPtr<MediaControlSeekButtonElement> m_seekForwardButton; RefPtr<MediaControlTimelineElement> m_timeline; RefPtr<MediaControlFullscreenButtonElement> m_fullscreenButton; - RefPtr<HTMLElement> m_timeDisplay; + RefPtr<HTMLElement> m_timelineContainer; + RefPtr<MediaTimeDisplayElement> m_currentTimeDisplay; + RefPtr<MediaTimeDisplayElement> m_timeRemainingDisplay; EventTargetNode* m_lastUnderNode; EventTargetNode* m_nodeUnderMouse; diff --git a/WebCore/rendering/RenderMenuList.cpp b/WebCore/rendering/RenderMenuList.cpp index 469a73d..71e9e15 100644 --- a/WebCore/rendering/RenderMenuList.cpp +++ b/WebCore/rendering/RenderMenuList.cpp @@ -1,7 +1,8 @@ -/** +/* * This file is part of the select element renderer in WebCore. * * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -24,20 +25,16 @@ #include "RenderMenuList.h" #include "CSSStyleSelector.h" -#include "Document.h" -#include "FontSelector.h" #include "FrameView.h" -#include "GraphicsContext.h" #include "HTMLNames.h" -#include "HTMLOptionElement.h" -#include "HTMLOptGroupElement.h" #include "HTMLSelectElement.h" +#include "NodeRenderStyle.h" +#include "OptionElement.h" +#include "OptionGroupElement.h" #include "PopupMenu.h" #include "RenderBR.h" #include "RenderScrollbar.h" -#include "RenderText.h" #include "RenderTheme.h" -#include "NodeRenderStyle.h" #include <math.h> using namespace std; @@ -141,11 +138,13 @@ void RenderMenuList::updateOptionsWidth() int size = listItems.size(); for (int i = 0; i < size; ++i) { HTMLElement* element = listItems[i]; - if (element->hasTagName(optionTag)) { - String text = static_cast<HTMLOptionElement*>(element)->optionText(); - if (!text.isEmpty()) - maxOptionWidth = max(maxOptionWidth, style()->font().floatWidth(text)); - } + OptionElement* optionElement = toOptionElement(element); + if (!optionElement) + continue; + + String text = optionElement->textIndentedToRespectGroupLabel(); + if (!text.isEmpty()) + maxOptionWidth = max(maxOptionWidth, style()->font().floatWidth(text)); } int width = static_cast<int>(ceilf(maxOptionWidth)); @@ -178,10 +177,10 @@ void RenderMenuList::setTextFromOption(int optionIndex) int i = select->optionToListIndex(optionIndex); String text = ""; if (i >= 0 && i < size) { - HTMLElement* element = listItems[i]; - if (element->hasTagName(optionTag)) - text = static_cast<HTMLOptionElement*>(listItems[i])->optionText(); + if (OptionElement* optionElement = toOptionElement(listItems[i])) + text = optionElement->textIndentedToRespectGroupLabel(); } + setText(text.stripWhiteSpace()); } @@ -224,8 +223,8 @@ IntRect RenderMenuList::controlClipRect(int tx, int ty) const contentWidth(), contentHeight()); - IntRect innerBox(tx + m_innerBlock->xPos() + m_innerBlock->paddingLeft(), - ty + m_innerBlock->yPos() + m_innerBlock->paddingTop(), + IntRect innerBox(tx + m_innerBlock->x() + m_innerBlock->paddingLeft(), + ty + m_innerBlock->y() + m_innerBlock->paddingTop(), m_innerBlock->contentWidth(), m_innerBlock->contentHeight()); @@ -275,7 +274,13 @@ void RenderMenuList::showPopup() m_popup = PopupMenu::create(this); HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node()); m_popupIsVisible = true; - m_popup->show(absoluteBoundingBoxRect(), document()->view(), + + // Compute the top left taking transforms into account, but use + // the actual width of the element to size the popup. + FloatPoint absTopLeft = localToAbsolute(FloatPoint(), false, true); + IntRect absBounds = absoluteBoundingBoxRect(); + absBounds.setLocation(roundedIntPoint(absTopLeft)); + m_popup->show(absBounds, document()->view(), select->optionToListIndex(select->selectedIndex())); } @@ -296,10 +301,10 @@ String RenderMenuList::itemText(unsigned listIndex) const { HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node()); HTMLElement* element = select->listItems()[listIndex]; - if (element->hasTagName(optgroupTag)) - return static_cast<HTMLOptGroupElement*>(element)->groupLabelText(); - else if (element->hasTagName(optionTag)) - return static_cast<HTMLOptionElement*>(element)->optionText(); + if (OptionGroupElement* optionGroupElement = toOptionGroupElement(element)) + return optionGroupElement->groupLabelText(); + else if (OptionElement* optionElement = toOptionElement(element)) + return optionElement->textIndentedToRespectGroupLabel(); return String(); } @@ -418,7 +423,9 @@ bool RenderMenuList::itemIsSelected(unsigned listIndex) const { HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node()); HTMLElement* element = select->listItems()[listIndex]; - return element->hasTagName(optionTag)&& static_cast<HTMLOptionElement*>(element)->selected(); + if (OptionElement* optionElement = toOptionElement(element)) + return optionElement->selected(); + return false; } void RenderMenuList::setTextFromItem(unsigned listIndex) diff --git a/WebCore/rendering/RenderMenuList.h b/WebCore/rendering/RenderMenuList.h index f31ef32..a7530fa 100644 --- a/WebCore/rendering/RenderMenuList.h +++ b/WebCore/rendering/RenderMenuList.h @@ -23,8 +23,8 @@ #ifndef RenderMenuList_h #define RenderMenuList_h -#include "RenderFlexibleBox.h" #include "PopupMenuClient.h" +#include "RenderFlexibleBox.h" #if PLATFORM(MAC) #define POPUP_MENU_PULLS_DOWN 0 @@ -36,6 +36,7 @@ namespace WebCore { class HTMLSelectElement; class PopupMenu; +class RenderText; class RenderMenuList : public RenderFlexibleBox, private PopupMenuClient { public: @@ -44,6 +45,7 @@ public: HTMLSelectElement* selectElement(); +private: virtual bool isMenuList() const { return true; } virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0); @@ -60,6 +62,7 @@ public: virtual void calcPrefWidths(); +public: bool popupIsVisible() const { return m_popupIsVisible; } void showPopup(); void hidePopup(); @@ -68,10 +71,9 @@ public: String text() const; -protected: +private: virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle); -private: // PopupMenuClient methods virtual String itemText(unsigned listIndex) const; virtual bool itemIsEnabled(unsigned listIndex) const; diff --git a/WebCore/rendering/RenderObject.cpp b/WebCore/rendering/RenderObject.cpp index 56fb7df..ea84f33 100644 --- a/WebCore/rendering/RenderObject.cpp +++ b/WebCore/rendering/RenderObject.cpp @@ -26,26 +26,13 @@ #include "RenderObject.h" #include "AXObjectCache.h" -#include "AffineTransform.h" -#include "AnimationController.h" #include "CSSStyleSelector.h" -#include "CachedImage.h" -#include "Chrome.h" -#include "Document.h" -#include "Element.h" -#include "EventHandler.h" -#include "FloatRect.h" -#include "Frame.h" +#include "FloatQuad.h" #include "FrameView.h" #include "GraphicsContext.h" #include "HTMLNames.h" -#include "HTMLOListElement.h" -#include "HitTestRequest.h" #include "HitTestResult.h" -#include "KURL.h" #include "Page.h" -#include "PlatformScreen.h" -#include "Position.h" #include "RenderArena.h" #include "RenderCounter.h" #include "RenderFlexibleBox.h" @@ -55,11 +42,8 @@ #include "RenderTableCell.h" #include "RenderTableCol.h" #include "RenderTableRow.h" -#include "RenderText.h" #include "RenderTheme.h" #include "RenderView.h" -#include "SelectionController.h" -#include "TextResourceDecoder.h" #include <algorithm> #ifdef ANDROID_LAYOUT #include "Settings.h" @@ -67,6 +51,10 @@ #include <stdio.h> #include <wtf/RefCountedLeakCounter.h> +#if ENABLE(WML) +#include "WMLNames.h" +#endif + using namespace std; namespace WebCore { @@ -174,6 +162,7 @@ RenderObject::RenderObject(Node* node) , m_next(0) #ifndef NDEBUG , m_hasAXObject(false) + , m_setNeedsLayoutForbidden(false) #endif , m_verticalPosition(PositionUndefined) , m_needsLayout(false) @@ -187,6 +176,7 @@ RenderObject::RenderObject(Node* node) , m_paintBackground(false) , m_isAnonymous(node == node->document()) , m_isText(false) + , m_isBox(false) , m_inline(true) , m_replaced(false) , m_isDragging(false) @@ -241,11 +231,6 @@ bool RenderObject::canHaveChildren() const return false; } -RenderFlow* RenderObject::continuation() const -{ - return 0; -} - bool RenderObject::isInlineContinuation() const { return false; @@ -321,9 +306,9 @@ RenderObject* RenderObject::nextInPreOrderAfterChildren(RenderObject* stayWithin if (!(o = nextSibling())) { o = parent(); while (o && !o->nextSibling()) { - o = o->parent(); if (o == stayWithin) return 0; + o = o->parent(); } if (o) o = o->nextSibling(); @@ -355,7 +340,7 @@ bool RenderObject::isEditable() const { RenderText* textRenderer = 0; if (isText()) - textRenderer = static_cast<RenderText*>(const_cast<RenderObject*>(this)); + textRenderer = toRenderText(const_cast<RenderObject*>(this)); return style()->visibility() == VISIBLE && element() && element()->isContentEditable() && @@ -402,7 +387,7 @@ static void addLayers(RenderObject* obj, RenderLayer* parentLayer, RenderObject* beforeChild = newObject->parent()->findNextLayer(parentLayer, newObject); newObject = 0; } - parentLayer->addChild(obj->layer(), beforeChild); + parentLayer->addChild(toRenderBox(obj)->layer(), beforeChild); return; } @@ -426,7 +411,7 @@ void RenderObject::removeLayers(RenderLayer* parentLayer) return; if (hasLayer()) { - parentLayer->removeChild(layer()); + parentLayer->removeChild(toRenderBox(this)->layer()); return; } @@ -440,9 +425,10 @@ void RenderObject::moveLayers(RenderLayer* oldParent, RenderLayer* newParent) return; if (hasLayer()) { + RenderLayer* layer = toRenderBox(this)->layer(); if (oldParent) - oldParent->removeChild(layer()); - newParent->addChild(layer()); + oldParent->removeChild(layer); + newParent->addChild(layer); return; } @@ -458,7 +444,7 @@ RenderLayer* RenderObject::findNextLayer(RenderLayer* parentLayer, RenderObject* return 0; // Step 1: If our layer is a child of the desired parent, then return our layer. - RenderLayer* ourLayer = layer(); + RenderLayer* ourLayer = hasLayer() ? toRenderBox(this)->layer() : 0; if (ourLayer && ourLayer->parent() == parentLayer) return ourLayer; @@ -490,7 +476,7 @@ RenderLayer* RenderObject::enclosingLayer() const { const RenderObject* curr = this; while (curr) { - RenderLayer* layer = curr->layer(); + RenderLayer* layer = curr->hasLayer() ? toRenderBox(curr)->layer() : 0; if (layer) return layer; curr = curr->parent(); @@ -498,168 +484,22 @@ RenderLayer* RenderObject::enclosingLayer() const return 0; } -bool RenderObject::requiresLayer() +RenderBox* RenderObject::enclosingBox() const { - return isRoot() || isPositioned() || isRelPositioned() || isTransparent() || hasOverflowClip() || hasTransform() || hasMask() || hasReflection(); -} - -RenderBlock* RenderObject::firstLineBlock() const -{ - return 0; -} - -int RenderObject::offsetLeft() const -{ - RenderObject* offsetPar = offsetParent(); - if (!offsetPar) - return 0; - int x = xPos() - offsetPar->borderLeft(); - if (!isPositioned()) { - if (isRelPositioned()) - x += static_cast<const RenderBox*>(this)->relativePositionOffsetX(); - RenderObject* curr = parent(); - while (curr && curr != offsetPar) { - x += curr->xPos(); - curr = curr->parent(); - } - if (offsetPar->isBody() && !offsetPar->isRelPositioned() && !offsetPar->isPositioned()) - x += offsetPar->xPos(); - } - return x; -} - -int RenderObject::offsetTop() const -{ - RenderObject* offsetPar = offsetParent(); - if (!offsetPar) - return 0; -#ifdef ANDROID_FIX - // This is to fix https://bugs.webkit.org/show_bug.cgi?id=23178. - int y = yPos() - borderTopExtra() + offsetPar->borderTopExtra() - offsetPar->borderTop(); -#else - int y = yPos() - borderTopExtra() - offsetPar->borderTop(); -#endif - if (!isPositioned()) { - if (isRelPositioned()) - y += static_cast<const RenderBox*>(this)->relativePositionOffsetY(); - RenderObject* curr = parent(); - while (curr && curr != offsetPar) { - if (!curr->isTableRow()) - y += curr->yPos(); - curr = curr->parent(); - } - if (offsetPar->isBody() && !offsetPar->isRelPositioned() && !offsetPar->isPositioned()) - y += offsetPar->yPos(); - } - return y; -} - -RenderObject* RenderObject::offsetParent() const -{ - // FIXME: It feels like this function could almost be written using containing blocks. - if (isBody()) - return 0; - - bool skipTables = isPositioned() || isRelPositioned(); - float currZoom = style()->effectiveZoom(); - RenderObject* curr = parent(); - while (curr && (!curr->element() || - (!curr->isPositioned() && !curr->isRelPositioned() && !curr->isBody()))) { - if (!skipTables && curr->element() && (curr->element()->hasTagName(tableTag) || - curr->element()->hasTagName(tdTag) || curr->element()->hasTagName(thTag))) - break; - float newZoom = curr->style()->effectiveZoom(); - if (currZoom != newZoom) - break; - currZoom = newZoom; + RenderObject* curr = const_cast<RenderObject*>(this); + while (curr) { + if (curr->isBox()) + return toRenderBox(curr); curr = curr->parent(); } - return curr; -} - -int RenderObject::verticalScrollbarWidth() const -{ - return includeVerticalScrollbarSize() ? layer()->verticalScrollbarWidth() : 0; -} - -int RenderObject::horizontalScrollbarHeight() const -{ - return includeHorizontalScrollbarSize() ? layer()->horizontalScrollbarHeight() : 0; -} - -// More IE extensions. clientWidth and clientHeight represent the interior of an object -// excluding border and scrollbar. -int RenderObject::clientWidth() const -{ - return width() - borderLeft() - borderRight() - verticalScrollbarWidth(); -} - -int RenderObject::clientHeight() const -{ - return height() - borderTop() - borderBottom() - horizontalScrollbarHeight(); -} - -// scrollWidth/scrollHeight will be the same as clientWidth/clientHeight unless the -// object has overflow:hidden/scroll/auto specified and also has overflow. -int RenderObject::scrollWidth() const -{ - return hasOverflowClip() ? layer()->scrollWidth() : overflowWidth(); -} - -int RenderObject::scrollHeight() const -{ - return hasOverflowClip() ? layer()->scrollHeight() : overflowHeight(); -} - -int RenderObject::scrollLeft() const -{ - return hasOverflowClip() ? layer()->scrollXOffset() : 0; -} - -int RenderObject::scrollTop() const -{ - return hasOverflowClip() ? layer()->scrollYOffset() : 0; -} - -void RenderObject::setScrollLeft(int newLeft) -{ - if (hasOverflowClip()) - layer()->scrollToXOffset(newLeft); -} - -void RenderObject::setScrollTop(int newTop) -{ - if (hasOverflowClip()) - layer()->scrollToYOffset(newTop); -} - -bool RenderObject::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier) -{ - RenderLayer* l = layer(); - if (l && l->scroll(direction, granularity, multiplier)) - return true; - RenderBlock* b = containingBlock(); - if (b && !b->isRenderView()) - return b->scroll(direction, granularity, multiplier); - return false; -} -bool RenderObject::canBeProgramaticallyScrolled(bool scrollToAnchor) const -{ - if (!layer()) - return false; - - return (hasOverflowClip() && (scrollsOverflow() || (node() && node()->isContentEditable()))) || (node() && node()->isDocumentNode()); -} - -void RenderObject::autoscroll() -{ - layer()->autoscroll(); + ASSERT_NOT_REACHED(); + return 0; } -void RenderObject::panScroll(const IntPoint& source) +RenderBlock* RenderObject::firstLineBlock() const { - layer()->panScrollFromPoint(source); + return 0; } bool RenderObject::hasStaticX() const @@ -672,10 +512,6 @@ bool RenderObject::hasStaticY() const return (style()->top().isAuto() && style()->bottom().isAuto()) || style()->top().isStatic(); } -void RenderObject::markAllDescendantsWithFloatsForLayout(RenderObject*) -{ -} - void RenderObject::setPrefWidthsDirty(bool b, bool markParents) { bool alreadyDirty = m_prefWidthsDirty; @@ -704,11 +540,12 @@ void RenderObject::setNeedsLayout(bool b, bool markParents) bool alreadyNeededLayout = m_needsLayout; m_needsLayout = b; if (b) { + ASSERT(!isSetNeedsLayoutForbidden()); if (!alreadyNeededLayout) { if (markParents) markContainingBlocksForLayout(); if (hasLayer()) - layer()->setNeedsFullRepaint(); + toRenderBox(this)->layer()->setNeedsFullRepaint(); } } else { m_everHadLayout = true; @@ -723,6 +560,7 @@ void RenderObject::setChildNeedsLayout(bool b, bool markParents) bool alreadyNeededLayout = m_normalChildNeedsLayout; m_normalChildNeedsLayout = b; if (b) { + ASSERT(!isSetNeedsLayoutForbidden()); if (!alreadyNeededLayout && markParents) markContainingBlocksForLayout(); } else { @@ -739,7 +577,7 @@ void RenderObject::setNeedsPositionedMovementLayout() if (!alreadyNeededLayout) { markContainingBlocksForLayout(); if (hasLayer()) - layer()->setNeedsFullRepaint(); + toRenderBox(this)->layer()->setNeedsFullRepaint(); } } @@ -776,10 +614,12 @@ void RenderObject::markContainingBlocksForLayout(bool scheduleRelayout, RenderOb if (o->m_posChildNeedsLayout) return; o->m_posChildNeedsLayout = true; + ASSERT(!o->isSetNeedsLayoutForbidden()); } else { if (o->m_normalChildNeedsLayout) return; o->m_normalChildNeedsLayout = true; + ASSERT(!o->isSetNeedsLayoutForbidden()); } if (o == newRoot) @@ -1693,59 +1533,6 @@ void RenderObject::paintBoxShadow(GraphicsContext* context, int tx, int ty, int } } -void RenderObject::addLineBoxRects(Vector<IntRect>&, unsigned startOffset, unsigned endOffset, bool useSelectionHeight) -{ -} - -void RenderObject::absoluteRects(Vector<IntRect>& rects, int tx, int ty, bool topLevel) -{ - // For blocks inside inlines, we go ahead and include margins so that we run right up to the - // inline boxes above and below us (thus getting merged with them to form a single irregular - // shape). - if (topLevel && continuation()) { - rects.append(IntRect(tx, ty - collapsedMarginTop(), - width(), height() + collapsedMarginTop() + collapsedMarginBottom())); - continuation()->absoluteRects(rects, - tx - xPos() + continuation()->containingBlock()->xPos(), - ty - yPos() + continuation()->containingBlock()->yPos(), topLevel); - } else - rects.append(IntRect(tx, ty, width(), height() + borderTopExtra() + borderBottomExtra())); -} - -IntRect RenderObject::absoluteBoundingBoxRect() -{ - int x, y; - absolutePosition(x, y); - Vector<IntRect> rects; - absoluteRects(rects, x, y); - - size_t n = rects.size(); - if (!n) - return IntRect(); - - IntRect result = rects[0]; - for (size_t i = 1; i < n; ++i) - result.unite(rects[i]); - return result; -} - -void RenderObject::addAbsoluteRectForLayer(IntRect& result) -{ - if (hasLayer()) - result.unite(absoluteBoundingBoxRect()); - for (RenderObject* current = firstChild(); current; current = current->nextSibling()) - current->addAbsoluteRectForLayer(result); -} - -IntRect RenderObject::paintingRootRect(IntRect& topLevelRect) -{ - IntRect result = absoluteBoundingBoxRect(); - topLevelRect = result; - for (RenderObject* current = firstChild(); current; current = current->nextSibling()) - current->addAbsoluteRectForLayer(result); - return result; -} - void RenderObject::addPDFURLRect(GraphicsContext* context, const IntRect& rect) { if (rect.isEmpty()) @@ -1759,28 +1546,12 @@ void RenderObject::addPDFURLRect(GraphicsContext* context, const IntRect& rect) context->setURLForRect(node->document()->completeURL(href), rect); } - -void RenderObject::addFocusRingRects(GraphicsContext* graphicsContext, int tx, int ty) -{ - // For blocks inside inlines, we go ahead and include margins so that we run right up to the - // inline boxes above and below us (thus getting merged with them to form a single irregular - // shape). - if (continuation()) { - graphicsContext->addFocusRingRect(IntRect(tx, ty - collapsedMarginTop(), width(), height() + collapsedMarginTop() + collapsedMarginBottom())); - continuation()->addFocusRingRects(graphicsContext, - tx - xPos() + continuation()->containingBlock()->xPos(), - ty - yPos() + continuation()->containingBlock()->yPos()); - } else - graphicsContext->addFocusRingRect(IntRect(tx, ty, width(), height())); -} - void RenderObject::paintOutline(GraphicsContext* graphicsContext, int tx, int ty, int w, int h, const RenderStyle* style) { if (!hasOutline()) return; int ow = style->outlineWidth(); - EBorderStyle os = style->outlineStyle(); Color oc = style->outlineColor(); @@ -1826,10 +1597,67 @@ void RenderObject::paintOutline(GraphicsContext* graphicsContext, int tx, int ty BSBottom, Color(oc), style->color(), os, ow, ow); } +void RenderObject::addLineBoxRects(Vector<IntRect>&, unsigned, unsigned, bool) +{ +} + +IntRect RenderObject::absoluteBoundingBoxRect(bool useTransforms) +{ + if (useTransforms) { + Vector<FloatQuad> quads; + absoluteQuads(quads); + + size_t n = quads.size(); + if (!n) + return IntRect(); + + IntRect result = quads[0].enclosingBoundingBox(); + for (size_t i = 1; i < n; ++i) + result.unite(quads[i].enclosingBoundingBox()); + return result; + } + + FloatPoint absPos = localToAbsolute(); + Vector<IntRect> rects; + absoluteRects(rects, absPos.x(), absPos.y()); + + size_t n = rects.size(); + if (!n) + return IntRect(); + + IntRect result = rects[0]; + for (size_t i = 1; i < n; ++i) + result.unite(rects[i]); + return result; +} + +void RenderObject::addAbsoluteRectForLayer(IntRect& result) +{ + if (hasLayer()) + result.unite(absoluteBoundingBoxRect()); + for (RenderObject* current = firstChild(); current; current = current->nextSibling()) + current->addAbsoluteRectForLayer(result); +} + +IntRect RenderObject::paintingRootRect(IntRect& topLevelRect) +{ + IntRect result = absoluteBoundingBoxRect(); + topLevelRect = result; + for (RenderObject* current = firstChild(); current; current = current->nextSibling()) + current->addAbsoluteRectForLayer(result); + return result; +} + void RenderObject::paint(PaintInfo& /*paintInfo*/, int /*tx*/, int /*ty*/) { } +RenderBox* RenderObject::containerForRepaint() const +{ + // For now, all repaints are root-relative. + return 0; +} + void RenderObject::repaint(bool immediate) { // Can't use view(), since we might be unrooted. @@ -1838,9 +1666,11 @@ void RenderObject::repaint(bool immediate) o = o->parent(); if (!o->isRenderView()) return; + RenderView* view = static_cast<RenderView*>(o); if (view->printing()) return; // Don't repaint if we're printing. + view->repaintViewRectangle(absoluteClippedOverflowRect(), immediate); } @@ -1852,11 +1682,17 @@ void RenderObject::repaintRectangle(const IntRect& r, bool immediate) o = o->parent(); if (!o->isRenderView()) return; + RenderView* view = static_cast<RenderView*>(o); if (view->printing()) return; // Don't repaint if we're printing. + IntRect absRect(r); + + // FIXME: layoutDelta needs to be applied in parts before/after transforms and + // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308 absRect.move(view->layoutDelta()); + computeAbsoluteRepaintRect(absRect); view->repaintViewRectangle(absRect, immediate); } @@ -1875,7 +1711,7 @@ bool RenderObject::repaintAfterLayoutIfNeeded(const IntRect& oldBounds, const In if (!fullRepaint && style()->borderFit() == BorderFitLines) fullRepaint = true; if (!fullRepaint) { - newOutlineBox = absoluteOutlineBox(); + newOutlineBox = absoluteOutlineBounds(); if (newOutlineBox.location() != oldOutlineBox.location() || (mustRepaintBackgroundOrBorder() && (newBounds != oldBounds || newOutlineBox != oldOutlineBox))) fullRepaint = true; } @@ -1918,7 +1754,8 @@ bool RenderObject::repaintAfterLayoutIfNeeded(const IntRect& oldBounds, const In // We didn't move, but we did change size. Invalidate the delta, which will consist of possibly // two rectangles (but typically only one). - RenderStyle* outlineStyle = !isInline() && continuation() ? continuation()->style() : style(); + RenderFlow* continuation = virtualContinuation(); + RenderStyle* outlineStyle = !isInline() && continuation ? continuation->style() : style(); int ow = outlineStyle->outlineSize(); ShadowData* boxShadow = style()->boxShadow(); int width = abs(newOutlineBox.width() - oldOutlineBox.width()); @@ -1927,7 +1764,8 @@ bool RenderObject::repaintAfterLayoutIfNeeded(const IntRect& oldBounds, const In for (ShadowData* shadow = boxShadow; shadow; shadow = shadow->next) shadowRight = max(shadow->x + shadow->blur, shadowRight); - int borderWidth = max(-outlineStyle->outlineOffset(), max(borderRight(), max(style()->borderTopRightRadius().width(), style()->borderBottomRightRadius().width()))) + max(ow, shadowRight); + int borderRight = isBox() ? toRenderBox(this)->borderRight() : 0; + int borderWidth = max(-outlineStyle->outlineOffset(), max(borderRight, max(style()->borderTopRightRadius().width(), style()->borderBottomRightRadius().width()))) + max(ow, shadowRight); IntRect rightRect(newOutlineBox.x() + min(newOutlineBox.width(), oldOutlineBox.width()) - borderWidth, newOutlineBox.y(), width + borderWidth, @@ -1944,7 +1782,8 @@ bool RenderObject::repaintAfterLayoutIfNeeded(const IntRect& oldBounds, const In for (ShadowData* shadow = boxShadow; shadow; shadow = shadow->next) shadowBottom = max(shadow->y + shadow->blur, shadowBottom); - int borderHeight = max(-outlineStyle->outlineOffset(), max(borderBottom(), max(style()->borderBottomLeftRadius().height(), style()->borderBottomRightRadius().height()))) + max(ow, shadowBottom); + int borderBottom = isBox() ? toRenderBox(this)->borderBottom() : 0; + int borderHeight = max(-outlineStyle->outlineOffset(), max(borderBottom, max(style()->borderBottomLeftRadius().height(), style()->borderBottomRightRadius().height()))) + max(ow, shadowBottom); IntRect bottomRect(newOutlineBox.x(), min(newOutlineBox.bottom(), oldOutlineBox.bottom()) - borderHeight, max(newOutlineBox.width(), oldOutlineBox.width()), @@ -1958,11 +1797,11 @@ bool RenderObject::repaintAfterLayoutIfNeeded(const IntRect& oldBounds, const In return false; } -void RenderObject::repaintDuringLayoutIfMoved(const IntRect& rect) +void RenderObject::repaintDuringLayoutIfMoved(const IntRect&) { } -void RenderObject::repaintOverhangingFloats(bool paintAllDescendants) +void RenderObject::repaintOverhangingFloats(bool) { } @@ -1974,33 +1813,36 @@ bool RenderObject::checkForRepaintDuringLayout() const return !document()->view()->needsFullRepaint() && !hasLayer(); } -IntRect RenderObject::getAbsoluteRepaintRectWithOutline(int ow) +IntRect RenderObject::rectWithOutlineForRepaint(RenderBox* repaintContainer, int outlineWidth) { - IntRect r(absoluteClippedOverflowRect()); - r.inflate(ow); + IntRect r(clippedOverflowRectForRepaint(repaintContainer)); + r.inflate(outlineWidth); - if (continuation() && !isInline()) - r.inflateY(collapsedMarginTop()); + if (virtualContinuation() && !isInline()) + r.inflateY(toRenderBox(this)->collapsedMarginTop()); - if (isInlineFlow()) { + if (isRenderInline()) { for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { if (!curr->isText()) - r.unite(curr->getAbsoluteRepaintRectWithOutline(ow)); + r.unite(curr->rectWithOutlineForRepaint(repaintContainer, outlineWidth)); } } return r; } -IntRect RenderObject::absoluteClippedOverflowRect() +IntRect RenderObject::clippedOverflowRectForRepaint(RenderBox* repaintContainer) { if (parent()) - return parent()->absoluteClippedOverflowRect(); + return parent()->clippedOverflowRectForRepaint(repaintContainer); return IntRect(); } -void RenderObject::computeAbsoluteRepaintRect(IntRect& rect, bool fixed) +void RenderObject::computeRectForRepaint(IntRect& rect, RenderBox* repaintContainer, bool fixed) { + if (repaintContainer == this) + return; + if (RenderObject* o = parent()) { if (o->isBlockFlow()) { RenderBlock* cb = static_cast<RenderBlock*>(o); @@ -2012,21 +1854,23 @@ void RenderObject::computeAbsoluteRepaintRect(IntRect& rect, bool fixed) // o->height() is inaccurate if we're in the middle of a layout of |o|, so use the // layer's size instead. Even if the layer's size is wrong, the layer itself will repaint // anyway if its size does change. - IntRect boxRect(0, 0, o->layer()->width(), o->layer()->height()); + RenderBox* boxParent = toRenderBox(o); + + IntRect boxRect(0, 0, boxParent->layer()->width(), boxParent->layer()->height()); int x = rect.x(); int y = rect.y(); - o->layer()->subtractScrollOffset(x, y); // For overflow:auto/scroll/hidden. + boxParent->layer()->subtractScrolledContentOffset(x, y); // For overflow:auto/scroll/hidden. IntRect repaintRect(x, y, rect.width(), rect.height()); rect = intersection(repaintRect, boxRect); if (rect.isEmpty()) return; } - o->computeAbsoluteRepaintRect(rect, fixed); + o->computeRectForRepaint(rect, repaintContainer, fixed); } } -void RenderObject::dirtyLinesFromChangedChild(RenderObject* child) +void RenderObject::dirtyLinesFromChangedChild(RenderObject*) { } @@ -2068,8 +1912,8 @@ Color RenderObject::selectionForegroundColor() const color = pseudoStyle->color(); } else color = document()->frame()->selection()->isFocusedAndActive() ? - theme()->platformActiveSelectionForegroundColor() : - theme()->platformInactiveSelectionForegroundColor(); + theme()->activeSelectionForegroundColor() : + theme()->inactiveSelectionForegroundColor(); return color; } @@ -2138,7 +1982,7 @@ void RenderObject::handleDynamicFloatPositionChange() RenderInline* parentInline = static_cast<RenderInline*>(parent()); RenderBlock* newBox = parentInline->createAnonymousBlock(); - RenderFlow* oldContinuation = parent()->continuation(); + RenderFlow* oldContinuation = parentInline->continuation(); parentInline->setContinuation(newBox); RenderObject* beforeChild = nextSibling(); @@ -2213,15 +2057,7 @@ void RenderObject::styleWillChange(RenderStyle::Diff diff, const RenderStyle* ne document()->setDashboardRegionsDirty(true); #endif - if ((m_style->hasAutoZIndex() != newStyle->hasAutoZIndex() || - m_style->zIndex() != newStyle->zIndex() || - m_style->visibility() != newStyle->visibility()) && hasLayer()) { - layer()->dirtyStackingContextZOrderLists(); - if (m_style->hasAutoZIndex() != newStyle->hasAutoZIndex() || - m_style->visibility() != newStyle->visibility()) - layer()->dirtyZOrderLists(); - } - // keep layer hierarchy visibility bits up to date if visibility changes + // Keep layer hierarchy visibility bits up to date if visibility changes. if (m_style->visibility() != newStyle->visibility()) { if (RenderLayer* l = enclosingLayer()) { if (newStyle->visibility() == VISIBLE) @@ -2235,62 +2071,8 @@ void RenderObject::styleWillChange(RenderStyle::Diff diff, const RenderStyle* ne } } - // The background of the root element or the body element could propagate up to - // the canvas. Just dirty the entire canvas when our style changes substantially. - if (diff >= RenderStyle::Repaint && element() && - (element()->hasTagName(htmlTag) || element()->hasTagName(bodyTag))) - view()->repaint(); - else if (m_parent && !isText()) { - // Do a repaint with the old style first, e.g., for example if we go from - // having an outline to not having an outline. - if (diff == RenderStyle::RepaintLayer) { - layer()->repaintIncludingDescendants(); - if (!(m_style->clip() == newStyle->clip())) - layer()->clearClipRects(); - } else if (diff == RenderStyle::Repaint || newStyle->outlineSize() < m_style->outlineSize()) - repaint(); - } - - // When a layout hint happens, we go ahead and do a repaint of the layer, since the layer could - // end up being destroyed. - if (diff == RenderStyle::Layout && hasLayer() && - (m_style->position() != newStyle->position() || - m_style->zIndex() != newStyle->zIndex() || - m_style->hasAutoZIndex() != newStyle->hasAutoZIndex() || - !(m_style->clip() == newStyle->clip()) || - m_style->hasClip() != newStyle->hasClip() || - m_style->opacity() != newStyle->opacity())) - layer()->repaintIncludingDescendants(); - - // When a layout hint happens and an object's position style changes, we have to do a layout - // to dirty the render tree using the old position value now. - if (diff == RenderStyle::Layout && m_parent && m_style->position() != newStyle->position()) { - markContainingBlocksForLayout(); - if (m_style->position() == StaticPosition) - repaint(); - if (isFloating() && !isPositioned() && (newStyle->position() == AbsolutePosition || newStyle->position() == FixedPosition)) - removeFromObjectLists(); - if (isRenderBlock()) { - if (newStyle->position() == StaticPosition) - // Clear our positioned objects list. Our absolutely positioned descendants will be - // inserted into our containing block's positioned objects list during layout. - removePositionedObjects(0); - else if (m_style->position() == StaticPosition) { - // Remove our absolutely positioned descendants from their current containing block. - // They will be inserted into our positioned objects list during layout. - RenderObject* cb = parent(); - while (cb && (cb->style()->position() == StaticPosition || (cb->isInline() && !cb->isReplaced())) && !cb->isRenderView()) { - if (cb->style()->position() == RelativePosition && cb->isInline() && !cb->isReplaced()) { - cb = cb->containingBlock(); - break; - } - cb = cb->parent(); - } - cb->removePositionedObjects(static_cast<RenderBlock*>(this)); - } - } - } - + if (m_parent && (diff == RenderStyle::Repaint || newStyle->outlineSize() < m_style->outlineSize())) + repaint(); if (isFloating() && (m_style->floating() != newStyle->floating())) // For changes in float styles, we need to conceivably remove ourselves // from the floating objects list. @@ -2302,7 +2084,7 @@ void RenderObject::styleWillChange(RenderStyle::Diff diff, const RenderStyle* ne s_affectsParentBlock = isFloatingOrPositioned() && (!newStyle->isFloating() && newStyle->position() != AbsolutePosition && newStyle->position() != FixedPosition) - && parent() && (parent()->isBlockFlow() || parent()->isInlineFlow()); + && parent() && (parent()->isBlockFlow() || parent()->isRenderInline()); // reset style flags if (diff == RenderStyle::Layout || diff == RenderStyle::LayoutPositionedMovementOnly) { @@ -2331,22 +2113,21 @@ void RenderObject::styleWillChange(RenderStyle::Diff diff, const RenderStyle* ne } } -void RenderObject::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle) +void RenderObject::styleDidChange(RenderStyle::Diff diff, const RenderStyle*) { setHasBoxDecorations(m_style->hasBorder() || m_style->hasBackground() || m_style->hasAppearance() || m_style->boxShadow()); if (s_affectsParentBlock) handleDynamicFloatPositionChange(); - // No need to ever schedule repaints from a style change of a text run, since - // we already did this for the parent of the text run. - // We do have to schedule layouts, though, since a style change can force us to - // need to relayout. - if (diff == RenderStyle::Layout && m_parent) + if (!m_parent) + return; + + if (diff == RenderStyle::Layout) setNeedsLayoutAndPrefWidthsRecalc(); - else if (diff == RenderStyle::LayoutPositionedMovementOnly && m_parent && !isText()) + else if (diff == RenderStyle::LayoutPositionedMovementOnly) setNeedsPositionedMovementLayout(); - else if (m_parent && !isText() && (diff == RenderStyle::RepaintLayer || diff == RenderStyle::Repaint)) + else if (diff == RenderStyle::RepaintLayer || diff == RenderStyle::Repaint) // Do a repaint with the new style now, e.g., for example if we go from // not having an outline to having an outline. repaint(); @@ -2380,87 +2161,63 @@ IntRect RenderObject::viewRect() const return view()->viewRect(); } -bool RenderObject::absolutePosition(int& xPos, int& yPos, bool f) const +FloatPoint RenderObject::localToAbsolute(FloatPoint localPoint, bool fixed, bool useTransforms) const { RenderObject* o = parent(); if (o) { - o->absolutePosition(xPos, yPos, f); - yPos += o->borderTopExtra(); if (o->hasOverflowClip()) - o->layer()->subtractScrollOffset(xPos, yPos); - return true; - } else { - xPos = yPos = 0; - return false; + localPoint -= toRenderBox(o)->layer()->scrolledContentOffset(); + return o->localToAbsolute(localPoint, fixed, useTransforms); } -} - -IntRect RenderObject::caretRect(InlineBox* inlineBox, int caretOffset, int* extraWidthToEndOfLine) -{ - if (extraWidthToEndOfLine) - *extraWidthToEndOfLine = 0; - return IntRect(); + return FloatPoint(); } -int RenderObject::paddingTop() const +FloatPoint RenderObject::absoluteToLocal(FloatPoint containerPoint, bool fixed, bool useTransforms) const { - int w = 0; - Length padding = m_style->paddingTop(); - if (padding.isPercent()) - w = containingBlock()->availableWidth(); -#ifdef ANDROID_LAYOUT - // in SSR mode, we use ANDROID_SSR_MARGIN_PADDING for padding. - if (document()->settings()->layoutAlgorithm() == Settings::kLayoutSSR && - padding.calcMinValue(w) > ANDROID_SSR_MARGIN_PADDING) - return ANDROID_SSR_MARGIN_PADDING; -#endif - return padding.calcMinValue(w); + RenderObject* o = parent(); + if (o) { + FloatPoint localPoint = o->absoluteToLocal(containerPoint, fixed, useTransforms); + if (o->hasOverflowClip()) + localPoint += toRenderBox(o)->layer()->scrolledContentOffset(); + return localPoint; + } + return FloatPoint(); } -int RenderObject::paddingBottom() const +FloatQuad RenderObject::localToContainerQuad(const FloatQuad& localQuad, RenderBox* repaintContainer, bool fixed) const { - int w = 0; - Length padding = style()->paddingBottom(); - if (padding.isPercent()) - w = containingBlock()->availableWidth(); -#ifdef ANDROID_LAYOUT - // in SSR mode, we use ANDROID_SSR_MARGIN_PADDING for padding. - if (document()->settings()->layoutAlgorithm() == Settings::kLayoutSSR && - padding.calcMinValue(w) > ANDROID_SSR_MARGIN_PADDING) - return ANDROID_SSR_MARGIN_PADDING; -#endif - return padding.calcMinValue(w); + if (repaintContainer == this) + return localQuad; + + RenderObject* o = parent(); + if (o) { + FloatQuad quad = localQuad; + if (o->hasOverflowClip()) + quad -= toRenderBox(o)->layer()->scrolledContentOffset(); + return o->localToContainerQuad(quad, repaintContainer, fixed); + } + + return FloatQuad(); } -int RenderObject::paddingLeft() const +IntSize RenderObject::offsetFromContainer(RenderObject* o) const { - int w = 0; - Length padding = style()->paddingLeft(); - if (padding.isPercent()) - w = containingBlock()->availableWidth(); -#ifdef ANDROID_LAYOUT - // in SSR mode, we use ANDROID_SSR_MARGIN_PADDING for padding. - if (document()->settings()->layoutAlgorithm() == Settings::kLayoutSSR && - padding.calcMinValue(w) > ANDROID_SSR_MARGIN_PADDING) - return ANDROID_SSR_MARGIN_PADDING; -#endif - return padding.calcMinValue(w); + ASSERT(o == container()); + + IntSize offset; + if (o->hasOverflowClip()) + offset -= toRenderBox(o)->layer()->scrolledContentOffset(); + + return offset; } -int RenderObject::paddingRight() const +IntRect RenderObject::localCaretRect(InlineBox*, int, int* extraWidthToEndOfLine) { - int w = 0; - Length padding = style()->paddingRight(); - if (padding.isPercent()) - w = containingBlock()->availableWidth(); -#ifdef ANDROID_LAYOUT - // in SSR mode, we use ANDROID_SSR_MARGIN_PADDING for padding. - if (document()->settings()->layoutAlgorithm() == Settings::kLayoutSSR && - padding.calcMinValue(w) > ANDROID_SSR_MARGIN_PADDING) - return ANDROID_SSR_MARGIN_PADDING; -#endif - return padding.calcMinValue(w); + if (extraWidthToEndOfLine) + *extraWidthToEndOfLine = 0; + + return IntRect(); } RenderView* RenderObject::view() const @@ -2497,6 +2254,8 @@ RenderObject* RenderObject::container() const // as we can. If we're in the tree, we'll get the root. If we // aren't we'll get the root of our little subtree (most likely // we'll just return 0). + // FIXME: The definition of view() has changed to not crawl up the render tree. It might + // be safe now to use it. while (o && o->parent() && !(o->hasTransform() && o->isRenderBlock())) o = o->parent(); } else if (pos == AbsolutePosition) { @@ -2514,7 +2273,7 @@ RenderObject* RenderObject::container() const // content (and perhaps XBL). That's why it uses the render tree and not the DOM tree. RenderObject* RenderObject::hoverAncestor() const { - return (!isInline() && continuation()) ? continuation() : parent(); + return (!isInline() && virtualContinuation()) ? virtualContinuation() : parent(); } bool RenderObject::isSelectionBorder() const @@ -2536,14 +2295,14 @@ void RenderObject::removeFromObjectLists() } if (outermostBlock) - outermostBlock->markAllDescendantsWithFloatsForLayout(this); + outermostBlock->markAllDescendantsWithFloatsForLayout(toRenderBox(this), false); } if (isPositioned()) { RenderObject* p; for (p = parent(); p; p = p->parent()) { if (p->isRenderBlock()) - static_cast<RenderBlock*>(p)->removePositionedObject(this); + static_cast<RenderBlock*>(p)->removePositionedObject(toRenderBox(this)); } } } @@ -2562,9 +2321,10 @@ void RenderObject::destroy() if (m_hasCounterNodeMap) RenderCounter::destroyCounterNodes(this); - if (AXObjectCache::accessibilityEnabled()) + if (AXObjectCache::accessibilityEnabled()) { + document()->axObjectCache()->childrenChanged(this->parent()); document()->axObjectCache()->remove(this); - + } animation()->cancelAnimations(this); // By default no ref-counting. RenderWidget::destroy() doesn't call @@ -2573,11 +2333,11 @@ void RenderObject::destroy() remove(); + // FIXME: Would like to do this in RenderBox, but the timing is so complicated that this can't easily + // be moved into RenderBox::destroy. RenderArena* arena = renderArena(); - if (hasLayer()) - layer()->destroy(arena); - + toRenderBox(this)->layer()->destroy(arena); arenaDelete(arena, this); } @@ -2614,11 +2374,16 @@ void RenderObject::arenaDelete(RenderArena* arena, void* base) arena->free(*(size_t*)base, base); } -VisiblePosition RenderObject::positionForCoordinates(int x, int y) +VisiblePosition RenderObject::positionForCoordinates(int, int) { return VisiblePosition(element(), caretMinOffset(), DOWNSTREAM); } +VisiblePosition RenderObject::positionForPoint(const IntPoint& point) +{ + return positionForCoordinates(point.x(), point.y()); +} + void RenderObject::updateDragState(bool dragOn) { bool valueChanged = (dragOn != m_isDragging); @@ -2627,8 +2392,9 @@ void RenderObject::updateDragState(bool dragOn) element()->setChanged(); for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) curr->updateDragState(dragOn); - if (continuation()) - continuation()->updateDragState(dragOn); + RenderFlow* continuation = virtualContinuation(); + if (continuation) + continuation->updateDragState(dragOn); } bool RenderObject::hitTest(const HitTestRequest& request, HitTestResult& result, const IntPoint& point, int tx, int ty, HitTestFilter hitTestFilter) @@ -2663,24 +2429,24 @@ void RenderObject::updateHitTestResult(HitTestResult& result, const IntPoint& po IntPoint localPoint(point); if (isRenderView()) node = document()->documentElement(); - else if (!isInline() && continuation()) + else if (!isInline() && virtualContinuation()) // We are in the margins of block elements that are part of a continuation. In // this case we're actually still inside the enclosing inline element that was // split. Go ahead and set our inner node accordingly. - node = continuation()->element(); + node = virtualContinuation()->element(); if (node) { - if (node->renderer() && node->renderer()->continuation() && node->renderer() != this) { + if (node->renderer() && node->renderer()->virtualContinuation() && node->renderer() != this) { // We're in the continuation of a split inline. Adjust our local point to be in the coordinate space // of the principal renderer's containing block. This will end up being the innerNonSharedNode. - RenderObject* firstBlock = node->renderer()->containingBlock(); + RenderBlock* firstBlock = node->renderer()->containingBlock(); // Get our containing block. - RenderObject* block = this; + RenderBox* block = toRenderBox(this); if (isInline()) block = containingBlock(); - localPoint.move(block->xPos() - firstBlock->xPos(), block->yPos() - firstBlock->yPos()); + localPoint.move(block->x() - firstBlock->x(), block->y() - firstBlock->y()); } result.setInnerNode(node); @@ -2792,9 +2558,9 @@ void RenderObject::removeLeftoverAnonymousBlock(RenderBlock*) { } -InlineBox* RenderObject::createInlineBox(bool, bool isRootLineBox, bool) +InlineBox* RenderObject::createInlineBox(bool, bool unusedIsRootLineBox, bool) { - ASSERT(!isRootLineBox); + ASSERT_UNUSED(unusedIsRootLineBox, !unusedIsRootLineBox); return new (renderArena()) InlineBox(this); } @@ -2826,7 +2592,7 @@ RenderStyle* RenderObject::firstLineStyle() const RenderBlock* firstLineBlock = obj->firstLineBlock(); if (firstLineBlock) s = firstLineBlock->getCachedPseudoStyle(RenderStyle::FIRST_LINE, style()); - } else if (!obj->isAnonymous() && obj->isInlineFlow()) { + } else if (!obj->isAnonymous() && obj->isRenderInline()) { RenderStyle* parentStyle = obj->parent()->firstLineStyle(); if (parentStyle != obj->parent()->style()) { // A first-line style is in effect. We need to cache a first-line style @@ -2915,8 +2681,8 @@ void RenderObject::getTextDecorationColors(int decorations, Color& underline, Co } } curr = curr->parent(); - if (curr && curr->isRenderBlock() && curr->continuation()) - curr = curr->continuation(); + if (curr && curr->isRenderBlock() && curr->virtualContinuation()) + curr = curr->virtualContinuation(); } while (curr && decorations && (!quirksMode || !curr->element() || (!curr->element()->hasTagName(aTag) && !curr->element()->hasTagName(fontTag)))); @@ -2939,16 +2705,18 @@ void RenderObject::updateWidgetPosition() void RenderObject::addDashboardRegions(Vector<DashboardRegionValue>& regions) { // Convert the style regions to absolute coordinates. - if (style()->visibility() != VISIBLE) + if (style()->visibility() != VISIBLE || !isBox()) return; + + RenderBox* box = toRenderBox(this); const Vector<StyleDashboardRegion>& styleRegions = style()->dashboardRegions(); unsigned i, count = styleRegions.size(); for (i = 0; i < count; i++) { StyleDashboardRegion styleRegion = styleRegions[i]; - int w = width(); - int h = height(); + int w = box->width(); + int h = box->height(); DashboardRegionValue region; region.label = styleRegion.label; @@ -2965,10 +2733,9 @@ void RenderObject::addDashboardRegions(Vector<DashboardRegionValue>& regions) region.clip.setWidth(0); } - int x, y; - absolutePosition(x, y); - region.bounds.setX(x + styleRegion.offset.left().value()); - region.bounds.setY(y + styleRegion.offset.top().value()); + FloatPoint absPos = localToAbsolute(); + region.bounds.setX(absPos.x() + styleRegion.offset.left().value()); + region.bounds.setY(absPos.y() + styleRegion.offset.top().value()); if (document()->frame()) { float pageScaleFactor = document()->frame()->page()->chrome()->scaleFactor(); @@ -3012,15 +2779,6 @@ bool RenderObject::shrinkToAvoidFloats() const return style()->width().isAuto(); } -UChar RenderObject::backslashAsCurrencySymbol() const -{ - if (Node *node = element()) { - if (TextResourceDecoder* decoder = node->document()->decoder()) - return decoder->encoding().backslashAsCurrencySymbol(); - } - return '\\'; -} - bool RenderObject::willRenderImage(CachedImage*) { // Without visibility we won't render (and therefore don't care about animation). @@ -3068,34 +2826,9 @@ int RenderObject::nextOffset(int current) const return current + 1; } -int RenderObject::maxTopMargin(bool positive) const -{ - return positive ? max(0, marginTop()) : -min(0, marginTop()); -} - -int RenderObject::maxBottomMargin(bool positive) const -{ - return positive ? max(0, marginBottom()) : -min(0, marginBottom()); -} - -IntRect RenderObject::contentBox() const -{ - return IntRect(borderLeft() + paddingLeft(), borderTop() + paddingTop(), - contentWidth(), contentHeight()); -} - -IntRect RenderObject::absoluteContentBox() const -{ - IntRect rect = contentBox(); - int x, y; - absolutePositionForContent(x, y); - rect.move(x, y); - return rect; -} - void RenderObject::adjustRectForOutlineAndShadow(IntRect& rect) const { - int outlineSize = !isInline() && continuation() ? continuation()->style()->outlineSize() : style()->outlineSize(); + int outlineSize = !isInline() && virtualContinuation() ? virtualContinuation()->style()->outlineSize() : style()->outlineSize(); if (ShadowData* boxShadow = style()->boxShadow()) { int shadowLeft = 0; int shadowRight = 0; @@ -3118,64 +2851,14 @@ void RenderObject::adjustRectForOutlineAndShadow(IntRect& rect) const rect.inflate(outlineSize); } -IntRect RenderObject::absoluteOutlineBox() const -{ - IntRect box = borderBox(); - int x, y; - absolutePosition(x, y); - box.move(x, y); - box.move(view()->layoutDelta()); - adjustRectForOutlineAndShadow(box); - return box; -} - -bool RenderObject::isScrollable() const -{ - RenderLayer* l = enclosingLayer(); - return l && (l->verticalScrollbar() || l->horizontalScrollbar()); -} - AnimationController* RenderObject::animation() const { return document()->frame()->animation(); } -void RenderObject::imageChanged(CachedImage* image) -{ - imageChanged(static_cast<WrappedImagePtr>(image)); -} - -IntRect RenderObject::reflectionBox() const -{ - IntRect result; - if (!m_style->boxReflect()) - return result; - IntRect box = borderBox(); - result = box; - switch (m_style->boxReflect()->direction()) { - case ReflectionBelow: - result.move(0, box.height() + reflectionOffset()); - break; - case ReflectionAbove: - result.move(0, -box.height() - reflectionOffset()); - break; - case ReflectionLeft: - result.move(-box.width() - reflectionOffset(), 0); - break; - case ReflectionRight: - result.move(box.width() + reflectionOffset(), 0); - break; - } - return result; -} - -int RenderObject::reflectionOffset() const +void RenderObject::imageChanged(CachedImage* image, const IntRect* rect) { - if (!m_style->boxReflect()) - return 0; - if (m_style->boxReflect()->direction() == ReflectionLeft || m_style->boxReflect()->direction() == ReflectionRight) - return m_style->boxReflect()->offset().calcValue(borderBox().width()); - return m_style->boxReflect()->offset().calcValue(borderBox().height()); + imageChanged(static_cast<WrappedImagePtr>(image), rect); } #if ENABLE(SVG) @@ -3185,12 +2868,12 @@ FloatRect RenderObject::relativeBBox(bool) const return FloatRect(); } -AffineTransform RenderObject::localTransform() const +TransformationMatrix RenderObject::localTransform() const { - return AffineTransform(1, 0, 0, 1, xPos(), yPos()); + return TransformationMatrix(); } -AffineTransform RenderObject::absoluteTransform() const +TransformationMatrix RenderObject::absoluteTransform() const { if (parent()) return localTransform() * parent()->absoluteTransform(); diff --git a/WebCore/rendering/RenderObject.h b/WebCore/rendering/RenderObject.h index b904c41..889ce9b 100644 --- a/WebCore/rendering/RenderObject.h +++ b/WebCore/rendering/RenderObject.h @@ -3,7 +3,7 @@ * (C) 2000 Antti Koivisto (koivisto@kde.org) * (C) 2000 Dirk Mueller (mueller@kde.org) * (C) 2004 Allan Sandfeld Jensen (kde@carewolf.com) - * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -26,38 +26,20 @@ #define RenderObject_h #include "CachedResourceClient.h" +#include "FloatQuad.h" #include "Document.h" #include "RenderStyle.h" -#include "ScrollTypes.h" -#include "VisiblePosition.h" -#include <wtf/HashMap.h> namespace WebCore { -class AffineTransform; class AnimationController; -class Color; -class Document; -class Element; -class Event; -class FloatRect; -class FrameView; -class HTMLAreaElement; class HitTestResult; class InlineBox; class InlineFlowBox; -class Position; -class RenderArena; class RenderBlock; class RenderFlow; -class RenderFrameSet; class RenderLayer; -class RenderTable; -class RenderText; -class RenderView; -class String; - -struct HitTestRequest; +class VisiblePosition; /* * The painting of a layer occurs in three distinct phases. Each phase involves @@ -103,11 +85,10 @@ enum HitTestAction { HitTestForeground }; -enum VerticalPositionHint { - PositionTop = -0x7fffffff, - PositionBottom = 0x7fffffff, - PositionUndefined = static_cast<int>(0x80000000) -}; +// Values for verticalPosition. +const int PositionTop = -0x7fffffff; +const int PositionBottom = 0x7fffffff; +const int PositionUndefined = 0x80000000; #if ENABLE(DASHBOARD_SUPPORT) struct DashboardRegionValue { @@ -127,15 +108,11 @@ struct DashboardRegionValue { }; #endif -// FIXME: This should be a HashSequencedSet, but we don't have that data structure yet. -// This means the paint order of outlines will be wrong, although this is a minor issue. -typedef HashSet<RenderFlow*> RenderFlowSequencedSet; - // Base class for all rendering tree objects. class RenderObject : public CachedResourceClient { friend class RenderContainer; - friend class RenderSVGContainer; friend class RenderLayer; + friend class RenderSVGContainer; public: // Anonymous objects should pass the document as their node, and they will then automatically be // marked as anonymous in the constructor. @@ -163,15 +140,18 @@ public: RenderObject* firstLeafChild() const; RenderObject* lastLeafChild() const; - virtual RenderLayer* layer() const { return 0; } + // The following five functions are used when the render tree hierarchy changes to make sure layers get + // properly added and removed. Since containership can be implemented by any subclass, and since a hierarchy + // can contain a mixture of boxes and other object types, these functions need to be in the base class. RenderLayer* enclosingLayer() const; void addLayers(RenderLayer* parentLayer, RenderObject* newObject); void removeLayers(RenderLayer* parentLayer); void moveLayers(RenderLayer* oldParent, RenderLayer* newParent); RenderLayer* findNextLayer(RenderLayer* parentLayer, RenderObject* startPoint, bool checkParent = true); - virtual void positionChildLayers() { } - virtual bool requiresLayer(); + // Convenience function for getting to the nearest enclosing box of a RenderObject. + RenderBox* enclosingBox() const; + virtual IntRect getOverflowClipRect(int /*tx*/, int /*ty*/) { return IntRect(0, 0, 0, 0); } virtual IntRect getClipRect(int /*tx*/, int /*ty*/) { return IntRect(0, 0, 0, 0); } bool hasClip() { return isPositioned() && style()->hasClip(); } @@ -187,6 +167,8 @@ public: #ifndef NDEBUG void setHasAXObject(bool flag) { m_hasAXObject = flag; } bool hasAXObject() const { return m_hasAXObject; } + bool isSetNeedsLayoutForbidden() const { return m_setNeedsLayoutForbidden; } + void setNeedsLayoutIsForbidden(bool flag) { m_setNeedsLayoutForbidden = flag; } #endif // Obtains the nearest enclosing block (including this block) that contributes a first-line style to our inline @@ -269,7 +251,6 @@ public: virtual bool isImage() const { return false; } virtual bool isInlineBlockOrInlineTable() const { return false; } virtual bool isInlineContinuation() const; - virtual bool isInlineFlow() const { return false; } virtual bool isListBox() const { return false; } virtual bool isListItem() const { return false; } virtual bool isListMarker() const { return false; } @@ -290,7 +271,6 @@ public: virtual bool isTextField() const { return false; } virtual bool isWidget() const { return false; } - bool isRoot() const { return document()->documentElement() == node(); } bool isBody() const; bool isHR() const; @@ -300,7 +280,7 @@ public: virtual bool childrenInline() const { return false; } virtual void setChildrenInline(bool) { } - virtual RenderFlow* continuation() const; + virtual RenderFlow* virtualContinuation() const { return 0; } #if ENABLE(SVG) virtual bool isSVGRoot() const { return false; } @@ -311,8 +291,8 @@ public: virtual FloatRect relativeBBox(bool includeStroke = true) const; - virtual AffineTransform localTransform() const; - virtual AffineTransform absoluteTransform() const; + virtual TransformationMatrix localTransform() const; + virtual TransformationMatrix absoluteTransform() const; #endif virtual bool isEditable() const; @@ -328,8 +308,8 @@ public: bool isPositioned() const { return m_positioned; } // absolute or fixed positioning bool isRelPositioned() const { return m_relPositioned; } // relative positioning bool isText() const { return m_isText; } + bool isBox() const { return m_isBox; } bool isInline() const { return m_inline; } // inline object - bool isCompact() const { return style()->display() == COMPACT; } // compact object bool isRunIn() const { return style()->display() == RUN_IN; } // run-in object bool isDragging() const { return m_isDragging; } bool isReplaced() const { return m_replaced; } // a "replaced" element (see CSS) @@ -338,9 +318,6 @@ public: bool hasBoxDecorations() const { return m_paintBackground; } bool mustRepaintBackgroundOrBorder() const; - - bool hasHorizontalBordersPaddingOrMargin() const { return hasHorizontalBordersOrPadding() || marginLeft() != 0 || marginRight() != 0; } - bool hasHorizontalBordersOrPadding() const { return borderLeft() != 0 || borderRight() != 0 || paddingLeft() != 0 || paddingRight() != 0; } bool needsLayout() const { return m_needsLayout || m_normalChildNeedsLayout || m_posChildNeedsLayout || m_needsPositionedMovementLayout; } bool selfNeedsLayout() const { return m_needsLayout; } @@ -357,23 +334,8 @@ public: virtual bool hasControlClip() const { return false; } virtual IntRect controlClipRect(int /*tx*/, int /*ty*/) const { return IntRect(); } - bool hasAutoVerticalScrollbar() const { return hasOverflowClip() && (style()->overflowY() == OAUTO || style()->overflowY() == OOVERLAY); } - bool hasAutoHorizontalScrollbar() const { return hasOverflowClip() && (style()->overflowX() == OAUTO || style()->overflowX() == OOVERLAY); } - - bool scrollsOverflow() const { return scrollsOverflowX() || scrollsOverflowY(); } - bool scrollsOverflowX() const { return hasOverflowClip() && (style()->overflowX() == OSCROLL || hasAutoHorizontalScrollbar()); } - bool scrollsOverflowY() const { return hasOverflowClip() && (style()->overflowY() == OSCROLL || hasAutoVerticalScrollbar()); } - - virtual int verticalScrollbarWidth() const; - virtual int horizontalScrollbarHeight() const; - bool hasTransform() const { return m_hasTransform; } bool hasMask() const { return style() && style()->hasMask(); } - virtual IntRect maskClipRect() { return borderBox(); } - -private: - bool includeVerticalScrollbarSize() const { return hasOverflowClip() && (style()->overflowY() == OSCROLL || style()->overflowY() == OAUTO); } - bool includeHorizontalScrollbarSize() const { return hasOverflowClip() && (style()->overflowX() == OSCROLL || style()->overflowX() == OAUTO); } public: // The pseudo element style can be cached or uncached. Use the cached method if the pseudo element doesn't respect @@ -401,7 +363,6 @@ public: RenderObject* container() const; RenderObject* hoverAncestor() const; - virtual void markAllDescendantsWithFloatsForLayout(RenderObject* floatToRemove = 0); void markContainingBlocksForLayout(bool scheduleRelayout = true, RenderObject* newRoot = 0); void setNeedsLayout(bool b, bool markParents = true); void setChildNeedsLayout(bool b, bool markParents = true); @@ -421,7 +382,8 @@ public: void setFloating(bool b = true) { m_floating = b; } void setInline(bool b = true) { m_inline = b; } void setHasBoxDecorations(bool b = true) { m_paintBackground = b; } - void setRenderText() { m_isText = true; } + void setIsText() { m_isText = true; } + void setIsBox() { m_isBox = true; } void setReplaced(bool b = true) { m_replaced = b; } void setHasOverflowClip(bool b = true) { m_hasOverflowClip = b; } void setHasLayer(bool b = true) { m_hasLayer = b; } @@ -457,7 +419,7 @@ public: */ struct PaintInfo { PaintInfo(GraphicsContext* newContext, const IntRect& newRect, PaintPhase newPhase, bool newForceBlackText, - RenderObject* newPaintingRoot, RenderFlowSequencedSet* newOutlineObjects) + RenderObject* newPaintingRoot, ListHashSet<RenderFlow*>* newOutlineObjects) : context(newContext) , rect(newRect) , phase(newPhase) @@ -472,23 +434,21 @@ public: PaintPhase phase; bool forceBlackText; RenderObject* paintingRoot; // used to draw just one element and its visual kids - RenderFlowSequencedSet* outlineObjects; // used to list outlines that should be painted by a block with inline children + ListHashSet<RenderFlow*>* outlineObjects; // used to list outlines that should be painted by a block with inline children }; virtual void paint(PaintInfo&, int tx, int ty); void paintBorder(GraphicsContext*, int tx, int ty, int w, int h, const RenderStyle*, bool begin = true, bool end = true); bool paintNinePieceImage(GraphicsContext*, int tx, int ty, int w, int h, const RenderStyle*, const NinePieceImage&, CompositeOperator = CompositeSourceOver); - void paintOutline(GraphicsContext*, int tx, int ty, int w, int h, const RenderStyle*); void paintBoxShadow(GraphicsContext*, int tx, int ty, int w, int h, const RenderStyle*, bool begin = true, bool end = true); // RenderBox implements this. - virtual void paintBoxDecorations(PaintInfo&, int tx, int ty) { } - virtual void paintMask(PaintInfo&, int tx, int ty) { } + virtual void paintBoxDecorations(PaintInfo&, int /*tx*/, int /*ty*/) { } + virtual void paintMask(PaintInfo&, int /*tx*/, int /*ty*/) { } virtual void paintFillLayerExtended(const PaintInfo&, const Color&, const FillLayer*, - int clipy, int cliph, int tx, int ty, int width, int height, - InlineFlowBox* box = 0, CompositeOperator = CompositeSourceOver) { } + int /*clipY*/, int /*clipH*/, int /*tx*/, int /*ty*/, int /*width*/, int /*height*/, + InlineFlowBox* = 0, CompositeOperator = CompositeSourceOver) { } - /* * Calculates the actual width of the object (only for non inline * objects) @@ -518,11 +478,6 @@ public: // repaint and do not need a relayout virtual void updateFromElement() { } - // Block flows subclass availableWidth to handle multi column layout (shrinking the width available to children when laying out.) - virtual int availableWidth() const { return contentWidth(); } - - virtual int availableHeight() const { return 0; } - virtual void updateWidgetPosition(); #if ENABLE(DASHBOARD_SUPPORT) @@ -535,7 +490,7 @@ public: void updateHitTestResult(HitTestResult&, const IntPoint&); virtual VisiblePosition positionForCoordinates(int x, int y); - VisiblePosition positionForPoint(const IntPoint& point) { return positionForCoordinates(point.x(), point.y()); } + VisiblePosition positionForPoint(const IntPoint&); virtual void dirtyLinesFromChangedChild(RenderObject*); @@ -559,142 +514,41 @@ public: // return just the height of the containing block virtual int containingBlockHeight() const; - // content area (box minus padding/border) - IntRect contentBox() const; - IntRect absoluteContentBox() const; - int contentWidth() const { return clientWidth() - paddingLeft() - paddingRight(); } - int contentHeight() const { return clientHeight() - paddingTop() - paddingBottom(); } - // used by flexible boxes to impose a flexed width/height override virtual int overrideSize() const { return 0; } virtual int overrideWidth() const { return 0; } virtual int overrideHeight() const { return 0; } virtual void setOverrideSize(int /*overrideSize*/) { } - // relative to parent node - virtual void setPos(int /*xPos*/, int /*yPos*/) { } - virtual void setWidth(int /*width*/) { } - virtual void setHeight(int /*height*/) { } - virtual void setRect(const IntRect& rect) { setPos(rect.x(), rect.y()); setWidth(rect.width()); setHeight(rect.height()); } - - virtual int xPos() const { return 0; } - virtual int yPos() const { return 0; } - - // calculate client position of box - virtual bool absolutePosition(int& x, int& y, bool fixed = false) const; + // Convert the given local point to absolute coordinates + // FIXME: Temporary. If useTransforms is true, take transforms into account. Eventually localToAbsolute() will always be transform-aware. + virtual FloatPoint localToAbsolute(FloatPoint localPoint = FloatPoint(), bool fixed = false, bool useTransforms = false) const; + virtual FloatPoint absoluteToLocal(FloatPoint, bool fixed = false, bool useTransforms = false) const; - // This function is used to deal with the extra top space that can occur in table cells (called borderTopExtra). - // The children of the cell do not factor this space in, so we have to add it in. Any code that wants to - // accurately deal with the contents of a cell must call this function instad of absolutePosition. - bool absolutePositionForContent(int& xPos, int& yPos, bool fixed = false) const + // Convert a local quad to absolute coordinates, taking transforms into account. + FloatQuad localToAbsoluteQuad(const FloatQuad& quad, bool fixed = false) const { - bool result = absolutePosition(xPos, yPos, fixed); - yPos += borderTopExtra(); - return result; + return localToContainerQuad(quad, 0, fixed); } + // Convert a local quad into the coordinate system of container, taking transforms into account. + virtual FloatQuad localToContainerQuad(const FloatQuad&, RenderBox* repaintContainer, bool fixed = false) const; - // width and height are without margins but include paddings and borders - virtual int width() const { return 0; } - virtual int height() const { return 0; } - - virtual IntRect borderBox() const { return IntRect(0, 0, width(), height()); } - IntRect absoluteOutlineBox() const; - - // The height of a block when you include normal flow overflow spillage out of the bottom - // of the block (e.g., a <div style="height:25px"> that has a 100px tall image inside - // it would have an overflow height of borderTop() + paddingTop() + 100px. - virtual int overflowHeight(bool /*includeInterior*/ = true) const { return height(); } - virtual int overflowWidth(bool /*includeInterior*/ = true) const { return width(); } - virtual void setOverflowHeight(int) { } - virtual void setOverflowWidth(int) { } - virtual int overflowLeft(bool /*includeInterior*/ = true) const { return 0; } - virtual int overflowTop(bool /*includeInterior*/ = true) const { return 0; } - virtual IntRect overflowRect(bool /*includeInterior*/ = true) const { return borderBox(); } - - // IE extensions. Used to calculate offsetWidth/Height. Overridden by inlines (RenderFlow) - // to return the remaining width on a given line (and the height of a single line). - virtual int offsetWidth() const { return width(); } - virtual int offsetHeight() const { return height() + borderTopExtra() + borderBottomExtra(); } - - // IE extensions. Also supported by Gecko. We override in render flow to get the - // left and top correct. -dwh - virtual int offsetLeft() const; - virtual int offsetTop() const; - virtual RenderObject* offsetParent() const; - - // More IE extensions. clientWidth and clientHeight represent the interior of an object - // excluding border and scrollbar. clientLeft/Top are just the borderLeftWidth and borderTopWidth. - int clientLeft() const { return borderLeft(); } - int clientTop() const { return borderTop(); } - int clientWidth() const; - int clientHeight() const; - - // scrollWidth/scrollHeight will be the same as clientWidth/clientHeight unless the - // object has overflow:hidden/scroll/auto specified and also has overflow. - // scrollLeft/Top return the current scroll position. These methods are virtual so that objects like - // textareas can scroll shadow content (but pretend that they are the objects that are - // scrolling). - virtual int scrollLeft() const; - virtual int scrollTop() const; - virtual int scrollWidth() const; - virtual int scrollHeight() const; - virtual void setScrollLeft(int); - virtual void setScrollTop(int); - - virtual bool scroll(ScrollDirection, ScrollGranularity, float multiplier = 1.0f); - virtual bool canBeProgramaticallyScrolled(bool) const; - virtual void autoscroll(); - virtual void stopAutoscroll() { } - - virtual void panScroll(const IntPoint&); - - virtual bool isScrollable() const; - - // The following seven functions are used to implement collapsing margins. - // All objects know their maximal positive and negative margins. The - // formula for computing a collapsed margin is |maxPosMargin|-|maxNegmargin|. - // For a non-collapsing, e.g., a leaf element, this formula will simply return - // the margin of the element. Blocks override the maxTopMargin and maxBottomMargin - // methods. - virtual bool isSelfCollapsingBlock() const { return false; } - virtual int collapsedMarginTop() const { return maxTopMargin(true) - maxTopMargin(false); } - virtual int collapsedMarginBottom() const { return maxBottomMargin(true) - maxBottomMargin(false); } - virtual bool isTopMarginQuirk() const { return false; } - virtual bool isBottomMarginQuirk() const { return false; } - - virtual int maxTopMargin(bool positive) const; - virtual int maxBottomMargin(bool positive) const; - - virtual int marginTop() const { return 0; } - virtual int marginBottom() const { return 0; } - virtual int marginLeft() const { return 0; } - virtual int marginRight() const { return 0; } - - // Virtual since table cells override - virtual int paddingTop() const; - virtual int paddingBottom() const; - virtual int paddingLeft() const; - virtual int paddingRight() const; - - virtual int borderTop() const { return style()->borderTopWidth(); } - virtual int borderBottom() const { return style()->borderBottomWidth(); } - virtual int borderTopExtra() const { return 0; } - virtual int borderBottomExtra() const { return 0; } - virtual int borderLeft() const { return style()->borderLeftWidth(); } - virtual int borderRight() const { return style()->borderRightWidth(); } + // Return the offset from the container() renderer (excluding transforms) + virtual IntSize offsetFromContainer(RenderObject*) const; virtual void addLineBoxRects(Vector<IntRect>&, unsigned startOffset = 0, unsigned endOffset = UINT_MAX, bool useSelectionHeight = false); + + virtual void absoluteRects(Vector<IntRect>&, int, int, bool = true) { } + // FIXME: useTransforms should go away eventually + IntRect absoluteBoundingBoxRect(bool useTransforms = false); - virtual void absoluteRects(Vector<IntRect>&, int tx, int ty, bool topLevel = true); - IntRect absoluteBoundingBoxRect(); + // Build an array of quads in absolute coords for line boxes + virtual void collectAbsoluteLineBoxQuads(Vector<FloatQuad>&, unsigned /*startOffset*/ = 0, unsigned /*endOffset*/ = UINT_MAX, bool /*useSelectionHeight*/ = false) { } + virtual void absoluteQuads(Vector<FloatQuad>&, bool /*topLevel*/ = true) { } // the rect that will be painted if this object is passed as the paintingRoot IntRect paintingRootRect(IntRect& topLevelRect); - void addPDFURLRect(GraphicsContext*, const IntRect&); - - virtual void addFocusRingRects(GraphicsContext*, int tx, int ty); - virtual int minPrefWidth() const { return 0; } virtual int maxPrefWidth() const { return 0; } @@ -717,6 +571,11 @@ public: void drawBorder(GraphicsContext*, int x1, int y1, int x2, int y2, BorderSide, Color, const Color& textcolor, EBorderStyle, int adjbw1, int adjbw2); + // Return the RenderBox in the container chain which is responsible for painting this object, or 0 + // if painting is root-relative. This is the container that should be passed to the 'forRepaint' + // methods. + RenderBox* containerForRepaint() const; + // Repaint the entire object. Called when, e.g., the color of a border changes, or when a border // style changes. void repaint(bool immediate = false); @@ -737,13 +596,23 @@ public: // Returns the rect that should be repainted whenever this object changes. The rect is in the view's // coordinate space. This method deals with outlines and overflow. - virtual IntRect absoluteClippedOverflowRect(); - - IntRect getAbsoluteRepaintRectWithOutline(int ow); + IntRect absoluteClippedOverflowRect() + { + return clippedOverflowRectForRepaint(0); + } + virtual IntRect clippedOverflowRectForRepaint(RenderBox* repaintContainer); + + IntRect rectWithOutlineForRepaint(RenderBox* repaintContainer, int outlineWidth); - // Given a rect in the object's coordinate space, this method converts the rectangle to the view's - // coordinate space. - virtual void computeAbsoluteRepaintRect(IntRect&, bool fixed = false); + // Given a rect in the object's coordinate space, compute a rect suitable for repainting + // that rect in view coordinates. + void computeAbsoluteRepaintRect(IntRect& r, bool fixed = false) + { + return computeRectForRepaint(r, 0, fixed); + } + // Given a rect in the object's coordinate space, compute a rect suitable for repainting + // that rect in the coordinate space of repaintContainer. + virtual void computeRectForRepaint(IntRect&, RenderBox* repaintContainer, bool fixed = false); virtual unsigned int length() const { return 1; } @@ -751,9 +620,6 @@ public: virtual bool containsFloats() { return false; } virtual bool containsFloat(RenderObject*) { return false; } virtual bool hasOverhangingFloats() { return false; } - virtual bool expandsToEncloseOverhangingFloats() const { return isFloating() && style()->height().isAuto(); } - - virtual void removePositionedObjects(RenderBlock*) { } virtual bool avoidsFloats() const; bool shrinkToAvoidFloats() const; @@ -765,8 +631,6 @@ public: float opacity() const { return style()->opacity(); } bool hasReflection() const { return m_hasReflection; } - IntRect reflectionBox() const; - int reflectionOffset() const; // Applied as a "slop" to dirty rect checks during the outline painting phase's dirty-rect checks. int maximalOutlineSize(PaintPhase) const; @@ -830,14 +694,12 @@ public: Node* draggableNode(bool dhtmlOK, bool uaOK, int x, int y, bool& dhtmlWillDrag) const; /** - * Returns the content coordinates of the caret within this render object. - * @param offset zero-based offset determining position within the render object. - * @param override @p true if input overrides existing characters, - * @p false if it inserts them. The width of the caret depends on this one. + * Returns the local coordinates of the caret within this render object. + * @param caretOffset zero-based offset determining position within the render object. * @param extraWidthToEndOfLine optional out arg to give extra width to end of line - * useful for character range rect computations */ - virtual IntRect caretRect(InlineBox*, int caretOffset, int* extraWidthToEndOfLine = 0); + virtual IntRect localCaretRect(InlineBox*, int caretOffset, int* extraWidthToEndOfLine = 0); virtual int lowestPosition(bool /*includeOverflowInterior*/ = true, bool /*includeSelf*/ = true) const { return 0; } virtual int rightmostPosition(bool /*includeOverflowInterior*/ = true, bool /*includeSelf*/ = true) const { return 0; } @@ -857,9 +719,6 @@ public: virtual bool isFlexingChildren() const { return false; } virtual bool isStretchingChildren() const { return false; } - // Convenience, to avoid repeating the code to dig down to get this. - UChar backslashAsCurrencySymbol() const; - virtual int caretMinOffset() const; virtual int caretMaxOffset() const; virtual unsigned caretMaxRenderedOffset() const; @@ -867,8 +726,8 @@ public: virtual int previousOffset(int current) const; virtual int nextOffset(int current) const; - virtual void imageChanged(CachedImage* image); - virtual void imageChanged(WrappedImagePtr data) { }; + virtual void imageChanged(CachedImage*, const IntRect* = 0); + virtual void imageChanged(WrappedImagePtr, const IntRect* = 0) { } virtual bool willRenderImage(CachedImage*); virtual void selectionStartEnd(int& spos, int& epos) const; @@ -900,6 +759,15 @@ public: AnimationController* animation() const; + bool visibleToHitTesting() const { return style()->visibility() == VISIBLE && style()->pointerEvents() != PE_NONE; } + + virtual void addFocusRingRects(GraphicsContext*, int /*tx*/, int /*ty*/) { }; + + IntRect absoluteOutlineBounds() const + { + return outlineBoundsForRepaint(0); + } + protected: // Overrides should call the superclass at the end virtual void styleWillChange(RenderStyle::Diff, const RenderStyle* newStyle); @@ -908,6 +776,9 @@ protected: virtual void printBoxDecorations(GraphicsContext*, int /*x*/, int /*y*/, int /*w*/, int /*h*/, int /*tx*/, int /*ty*/) { } + void paintOutline(GraphicsContext*, int tx, int ty, int w, int h, const RenderStyle*); + void addPDFURLRect(GraphicsContext*, const IntRect&); + virtual IntRect viewRect() const; int getVerticalPosition(bool firstLine) const; @@ -916,6 +787,8 @@ protected: void arenaDelete(RenderArena*, void* objectBase); + virtual IntRect outlineBoundsForRepaint(RenderBox* /*repaintContainer*/) const { return IntRect(); } + private: RefPtr<RenderStyle> m_style; @@ -927,6 +800,7 @@ private: #ifndef NDEBUG bool m_hasAXObject; + bool m_setNeedsLayoutForbidden : 1; #endif mutable int m_verticalPosition; @@ -944,6 +818,7 @@ private: bool m_isAnonymous : 1; bool m_isText : 1; + bool m_isBox : 1; bool m_inline : 1; bool m_replaced : 1; bool m_isDragging : 1; diff --git a/WebCore/rendering/RenderPart.cpp b/WebCore/rendering/RenderPart.cpp index a9a821e..6f79a00 100644 --- a/WebCore/rendering/RenderPart.cpp +++ b/WebCore/rendering/RenderPart.cpp @@ -88,13 +88,11 @@ void RenderPart::updateWidgetPosition() if (!m_widget) return; - int x, y, width, height; - absolutePosition(x, y); - x += borderLeft() + paddingLeft(); - y += borderTop() + paddingTop(); - width = m_width - borderLeft() - borderRight() - paddingLeft() - paddingRight(); - height = m_height - borderTop() - borderBottom() - paddingTop() - paddingBottom(); - IntRect newBounds(x,y,width,height); + FloatPoint absPos = localToAbsolute(); + absPos.move(borderLeft() + paddingLeft(), borderTop() + paddingTop()); + int w = width() - borderLeft() - borderRight() - paddingLeft() - paddingRight(); + int h = height() - borderTop() - borderBottom() - paddingTop() - paddingBottom(); + IntRect newBounds(absPos.x(), absPos.y(), w, h); bool boundsChanged = newBounds != m_widget->frameRect(); if (boundsChanged) { // The widget changed positions. Update the frame geometry. diff --git a/WebCore/rendering/RenderPartObject.cpp b/WebCore/rendering/RenderPartObject.cpp index 75ecdec..86cb2ad 100644 --- a/WebCore/rendering/RenderPartObject.cpp +++ b/WebCore/rendering/RenderPartObject.cpp @@ -36,6 +36,8 @@ #include "HTMLParamElement.h" #include "MIMETypeRegistry.h" #include "Page.h" +#include "PluginData.h" +#include "RenderView.h" #include "Text.h" #ifdef FLATTEN_IFRAME @@ -52,6 +54,9 @@ RenderPartObject::RenderPartObject(HTMLFrameOwnerElement* element) // init RenderObject attributes setInline(true); m_hasFallbackContent = false; + + if (element->hasTagName(embedTag) || element->hasTagName(objectTag)) + view()->frameView()->setIsVisuallyNonEmpty(); } RenderPartObject::~RenderPartObject() @@ -79,183 +84,216 @@ static bool isURLAllowed(Document* doc, const String& url) return true; } -static inline void mapClassIdToServiceType(const String& classId, String& serviceType) +typedef HashMap<String, String, CaseFoldingHash> ClassIdToTypeMap; + +static ClassIdToTypeMap* createClassIdToTypeMap() { - // It is ActiveX, but the nsplugin system handling - // should also work, that's why we don't override the - // serviceType with application/x-activex-handler - // but let the KTrader in khtmlpart::createPart() detect - // the user's preference: launch with activex viewer or - // with nspluginviewer (Niko) - if (classId.contains("D27CDB6E-AE6D-11cf-96B8-444553540000")) - serviceType = "application/x-shockwave-flash"; - else if (classId.contains("CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA")) - serviceType = "audio/x-pn-realaudio-plugin"; - else if (classId.contains("02BF25D5-8C17-4B23-BC80-D3488ABDDC6B")) - serviceType = "video/quicktime"; - else if (classId.contains("166B1BCA-3F9C-11CF-8075-444553540000")) - serviceType = "application/x-director"; - else if (classId.contains("6BF52A52-394A-11d3-B153-00C04F79FAA6")) - serviceType = "application/x-mplayer2"; - else if (!classId.isEmpty()) { - // We have a clsid, means this is Active X (Niko) - serviceType = "application/x-activex-handler"; - } + ClassIdToTypeMap* map = new ClassIdToTypeMap; + map->add("clsid:D27CDB6E-AE6D-11CF-96B8-444553540000", "application/x-shockwave-flash"); + map->add("clsid:CFCDAA03-8BE4-11CF-B84B-0020AFBBCCFA", "audio/x-pn-realaudio-plugin"); + map->add("clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B", "video/quicktime"); + map->add("clsid:166B1BCA-3F9C-11CF-8075-444553540000", "application/x-director"); +#if ENABLE(ACTIVEX_TYPE_CONVERSION_WMPLAYER) + map->add("clsid:6BF52A52-394A-11D3-B153-00C04F79FAA6", "application/x-mplayer2"); + map->add("clsid:22D6F312-B0F6-11D0-94AB-0080C74C7E95", "application/x-mplayer2"); +#endif + return map; +} + +static const String& activeXType() +{ + DEFINE_STATIC_LOCAL(String, activeXType, ("application/x-oleobject")); + return activeXType; +} + +static inline bool havePlugin(const PluginData* pluginData, const String& type) +{ + return pluginData && !type.isEmpty() && pluginData->supportsMimeType(type); +} + +static String serviceTypeForClassId(const String& classId, const PluginData* pluginData) +{ + // Return early if classId is empty (since we won't do anything below). + // Furthermore, if classId is null, calling get() below will crash. + if (classId.isEmpty()) + return String(); + + static ClassIdToTypeMap* map = createClassIdToTypeMap(); + String type = map->get(classId); + + // If we do have a plug-in that supports generic ActiveX content and don't have a plug-in + // for the MIME type we came up with, ignore the MIME type we came up with and just use + // the ActiveX type. + if (havePlugin(pluginData, activeXType()) && !havePlugin(pluginData, type)) + return activeXType(); + + return type; +} + +static inline bool shouldUseEmbedDescendant(HTMLObjectElement* objectElement, const PluginData* pluginData) +{ + // If we have both an <object> and <embed>, we always want to use the <embed> except when we have + // an ActiveX plug-in and plan to use it. + return !(havePlugin(pluginData, activeXType()) + && serviceTypeForClassId(objectElement->classId(), pluginData) == activeXType()); } void RenderPartObject::updateWidget(bool onlyCreateNonNetscapePlugins) { - String url; - String serviceType; - Vector<String> paramNames; - Vector<String> paramValues; - Frame* frame = m_view->frame(); - - if (element()->hasTagName(objectTag)) { - - HTMLObjectElement* o = static_cast<HTMLObjectElement*>(element()); - - o->setNeedWidgetUpdate(false); - if (!o->isFinishedParsingChildren()) - return; - // Check for a child EMBED tag. - HTMLEmbedElement* embed = 0; - for (Node* child = o->firstChild(); child;) { - if (child->hasTagName(embedTag)) { - embed = static_cast<HTMLEmbedElement*>(child); - break; - } else if (child->hasTagName(objectTag)) - child = child->nextSibling(); // Don't descend into nested OBJECT tags - else - child = child->traverseNextNode(o); // Otherwise descend (EMBEDs may be inside COMMENT tags) - } - - // Use the attributes from the EMBED tag instead of the OBJECT tag including WIDTH and HEIGHT. - HTMLElement *embedOrObject; - if (embed) { - embedOrObject = (HTMLElement *)embed; - url = embed->url(); - serviceType = embed->serviceType(); - } else - embedOrObject = (HTMLElement *)o; - - // If there was no URL or type defined in EMBED, try the OBJECT tag. - if (url.isEmpty()) - url = o->url(); - if (serviceType.isEmpty()) - serviceType = o->serviceType(); - - HashSet<StringImpl*, CaseFoldingHash> uniqueParamNames; - - // Scan the PARAM children. - // Get the URL and type from the params if we don't already have them. - // Get the attributes from the params if there is no EMBED tag. - Node *child = o->firstChild(); - while (child && (url.isEmpty() || serviceType.isEmpty() || !embed)) { - if (child->hasTagName(paramTag)) { - HTMLParamElement* p = static_cast<HTMLParamElement*>(child); - String name = p->name(); - if (url.isEmpty() && (equalIgnoringCase(name, "src") || equalIgnoringCase(name, "movie") || equalIgnoringCase(name, "code") || equalIgnoringCase(name, "url"))) - url = p->value(); - if (serviceType.isEmpty() && equalIgnoringCase(name, "type")) { - serviceType = p->value(); - int pos = serviceType.find(";"); - if (pos != -1) - serviceType = serviceType.left(pos); - } - if (!embed && !name.isEmpty()) { - uniqueParamNames.add(name.impl()); - paramNames.append(p->name()); - paramValues.append(p->value()); - } - } - child = child->nextSibling(); - } - - // When OBJECT is used for an applet via Sun's Java plugin, the CODEBASE attribute in the tag - // points to the Java plugin itself (an ActiveX component) while the actual applet CODEBASE is - // in a PARAM tag. See <http://java.sun.com/products/plugin/1.2/docs/tags.html>. This means - // we have to explicitly suppress the tag's CODEBASE attribute if there is none in a PARAM, - // else our Java plugin will misinterpret it. [4004531] - String codebase; - if (!embed && MIMETypeRegistry::isJavaAppletMIMEType(serviceType)) { - codebase = "codebase"; - uniqueParamNames.add(codebase.impl()); // pretend we found it in a PARAM already - } - - // Turn the attributes of either the EMBED tag or OBJECT tag into arrays, but don't override PARAM values. - NamedAttrMap* attributes = embedOrObject->attributes(); - if (attributes) { - for (unsigned i = 0; i < attributes->length(); ++i) { - Attribute* it = attributes->attributeItem(i); - const AtomicString& name = it->name().localName(); - if (embed || !uniqueParamNames.contains(name.impl())) { - paramNames.append(name.string()); - paramValues.append(it->value().string()); - } - } - } - - // If we still don't have a type, try to map from a specific CLASSID to a type. - if (serviceType.isEmpty() && !o->classId().isEmpty()) - mapClassIdToServiceType(o->classId(), serviceType); - - if (!isURLAllowed(document(), url)) + String url; + String serviceType; + Vector<String> paramNames; + Vector<String> paramValues; + Frame* frame = m_view->frame(); + + if (element()->hasTagName(objectTag)) { + HTMLObjectElement* o = static_cast<HTMLObjectElement*>(element()); + + o->setNeedWidgetUpdate(false); + if (!o->isFinishedParsingChildren()) return; - // Find out if we support fallback content. - m_hasFallbackContent = false; - for (Node *child = o->firstChild(); child && !m_hasFallbackContent; child = child->nextSibling()) { - if ((!child->isTextNode() && !child->hasTagName(embedTag) && !child->hasTagName(paramTag)) || // Discount <embed> and <param> - (child->isTextNode() && !static_cast<Text*>(child)->containsOnlyWhitespace())) - m_hasFallbackContent = true; - } - - if (onlyCreateNonNetscapePlugins) { - KURL completedURL; - if (!url.isEmpty()) - completedURL = frame->loader()->completeURL(url); + // Check for a child EMBED tag. + HTMLEmbedElement* embed = 0; + const PluginData* pluginData = frame->page()->pluginData(); + if (shouldUseEmbedDescendant(o, pluginData)) { + for (Node* child = o->firstChild(); child; ) { + if (child->hasTagName(embedTag)) { + embed = static_cast<HTMLEmbedElement*>(child); + break; + } else if (child->hasTagName(objectTag)) + child = child->nextSibling(); // Don't descend into nested OBJECT tags + else + child = child->traverseNextNode(o); // Otherwise descend (EMBEDs may be inside COMMENT tags) + } + } + + // Use the attributes from the EMBED tag instead of the OBJECT tag including WIDTH and HEIGHT. + HTMLElement *embedOrObject; + if (embed) { + embedOrObject = (HTMLElement *)embed; + url = embed->url(); + serviceType = embed->serviceType(); + } else + embedOrObject = (HTMLElement *)o; + + // If there was no URL or type defined in EMBED, try the OBJECT tag. + if (url.isEmpty()) + url = o->url(); + if (serviceType.isEmpty()) + serviceType = o->serviceType(); + + HashSet<StringImpl*, CaseFoldingHash> uniqueParamNames; + + // Scan the PARAM children. + // Get the URL and type from the params if we don't already have them. + // Get the attributes from the params if there is no EMBED tag. + Node *child = o->firstChild(); + while (child && (url.isEmpty() || serviceType.isEmpty() || !embed)) { + if (child->hasTagName(paramTag)) { + HTMLParamElement* p = static_cast<HTMLParamElement*>(child); + String name = p->name(); + if (url.isEmpty() && (equalIgnoringCase(name, "src") || equalIgnoringCase(name, "movie") || equalIgnoringCase(name, "code") || equalIgnoringCase(name, "url"))) + url = p->value(); + if (serviceType.isEmpty() && equalIgnoringCase(name, "type")) { + serviceType = p->value(); + int pos = serviceType.find(";"); + if (pos != -1) + serviceType = serviceType.left(pos); + } + if (!embed && !name.isEmpty()) { + uniqueParamNames.add(name.impl()); + paramNames.append(p->name()); + paramValues.append(p->value()); + } + } + child = child->nextSibling(); + } + + // When OBJECT is used for an applet via Sun's Java plugin, the CODEBASE attribute in the tag + // points to the Java plugin itself (an ActiveX component) while the actual applet CODEBASE is + // in a PARAM tag. See <http://java.sun.com/products/plugin/1.2/docs/tags.html>. This means + // we have to explicitly suppress the tag's CODEBASE attribute if there is none in a PARAM, + // else our Java plugin will misinterpret it. [4004531] + String codebase; + if (!embed && MIMETypeRegistry::isJavaAppletMIMEType(serviceType)) { + codebase = "codebase"; + uniqueParamNames.add(codebase.impl()); // pretend we found it in a PARAM already + } - if (frame->loader()->client()->objectContentType(completedURL, serviceType) == ObjectContentNetscapePlugin) - return; - } - - bool success = frame->loader()->requestObject(this, url, AtomicString(o->name()), serviceType, paramNames, paramValues); - if (!success && m_hasFallbackContent) - o->renderFallbackContent(); - } else if (element()->hasTagName(embedTag)) { - HTMLEmbedElement *o = static_cast<HTMLEmbedElement*>(element()); - o->setNeedWidgetUpdate(false); - url = o->url(); - serviceType = o->serviceType(); - - if (url.isEmpty() && serviceType.isEmpty()) - return; - if (!isURLAllowed(document(), url)) - return; - - // add all attributes set on the embed object - NamedAttrMap* a = o->attributes(); - if (a) { - for (unsigned i = 0; i < a->length(); ++i) { - Attribute* it = a->attributeItem(i); - paramNames.append(it->name().localName().string()); - paramValues.append(it->value().string()); - } - } - - if (onlyCreateNonNetscapePlugins) { - KURL completedURL; - if (!url.isEmpty()) - completedURL = frame->loader()->completeURL(url); - - if (frame->loader()->client()->objectContentType(completedURL, serviceType) == ObjectContentNetscapePlugin) - return; - - } - - frame->loader()->requestObject(this, url, o->getAttribute(nameAttr), serviceType, paramNames, paramValues); - } + // Turn the attributes of either the EMBED tag or OBJECT tag into arrays, but don't override PARAM values. + NamedAttrMap* attributes = embedOrObject->attributes(); + if (attributes) { + for (unsigned i = 0; i < attributes->length(); ++i) { + Attribute* it = attributes->attributeItem(i); + const AtomicString& name = it->name().localName(); + if (embed || !uniqueParamNames.contains(name.impl())) { + paramNames.append(name.string()); + paramValues.append(it->value().string()); + } + } + } + + // If we still don't have a type, try to map from a specific CLASSID to a type. + if (serviceType.isEmpty()) + serviceType = serviceTypeForClassId(o->classId(), pluginData); + + if (!isURLAllowed(document(), url)) + return; + + // Find out if we support fallback content. + m_hasFallbackContent = false; + for (Node *child = o->firstChild(); child && !m_hasFallbackContent; child = child->nextSibling()) { + if ((!child->isTextNode() && !child->hasTagName(embedTag) && !child->hasTagName(paramTag)) || // Discount <embed> and <param> + (child->isTextNode() && !static_cast<Text*>(child)->containsOnlyWhitespace())) + m_hasFallbackContent = true; + } + + if (onlyCreateNonNetscapePlugins) { + KURL completedURL; + if (!url.isEmpty()) + completedURL = frame->loader()->completeURL(url); + + if (frame->loader()->client()->objectContentType(completedURL, serviceType) == ObjectContentNetscapePlugin) + return; + } + + bool success = frame->loader()->requestObject(this, url, AtomicString(o->name()), serviceType, paramNames, paramValues); + if (!success && m_hasFallbackContent) + o->renderFallbackContent(); + } else if (element()->hasTagName(embedTag)) { + HTMLEmbedElement *o = static_cast<HTMLEmbedElement*>(element()); + o->setNeedWidgetUpdate(false); + url = o->url(); + serviceType = o->serviceType(); + + if (url.isEmpty() && serviceType.isEmpty()) + return; + if (!isURLAllowed(document(), url)) + return; + + // add all attributes set on the embed object + NamedAttrMap* a = o->attributes(); + if (a) { + for (unsigned i = 0; i < a->length(); ++i) { + Attribute* it = a->attributeItem(i); + paramNames.append(it->name().localName().string()); + paramValues.append(it->value().string()); + } + } + + if (onlyCreateNonNetscapePlugins) { + KURL completedURL; + if (!url.isEmpty()) + completedURL = frame->loader()->completeURL(url); + + if (frame->loader()->client()->objectContentType(completedURL, serviceType) == ObjectContentNetscapePlugin) + return; + + } + + frame->loader()->requestObject(this, url, o->getAttribute(nameAttr), serviceType, paramNames, paramValues); + } } void RenderPartObject::layout() @@ -268,8 +306,10 @@ void RenderPartObject::layout() #ifdef FLATTEN_IFRAME // Some IFrames have a width and/or height of 1 when they are meant to be // hidden. If that is the case, don't try to expand. + int w = width(); + int h = height(); if (m_widget && m_widget->isFrameView() && - m_width > 1 && m_height > 1) { + w > 1 && h > 1) { FrameView* view = static_cast<FrameView*>(m_widget); RenderView* root = NULL; if (view->frame() && view->frame()->document() && @@ -280,12 +320,12 @@ void RenderPartObject::layout() updateWidgetPosition(); // Use the preferred width if it is larger. - m_width = max(m_width, root->minPrefWidth()); + setWidth(max(w, root->minPrefWidth())); int extraWidth = paddingLeft() + paddingRight() + borderLeft() + borderRight(); int extraHeight = paddingTop() + paddingBottom() + borderTop() + borderBottom(); // Resize the view to recalc the height. - int height = m_height - extraHeight; - int width = m_width - extraWidth; + int height = h - extraHeight; + int width = w - extraWidth; if (width > view->width()) height = 0; if (width != view->width() || height != view->height()) { @@ -298,9 +338,9 @@ void RenderPartObject::layout() int contentHeight = view->contentsHeight(); int contentWidth = view->contentsWidth(); // Do not shrink iframes with specified sizes - if (contentHeight > m_height || style()->height().isAuto()) - m_height = contentHeight; - m_width = std::min(contentWidth, 800); + if (contentHeight > h || style()->height().isAuto()) + setHeight(contentHeight); + setWidth(std::min(contentWidth, 800)); } } #endif @@ -310,7 +350,7 @@ void RenderPartObject::layout() if (!m_widget && m_view) m_view->addWidgetToUpdate(this); - + setNeedsLayout(false); } diff --git a/WebCore/rendering/RenderPath.cpp b/WebCore/rendering/RenderPath.cpp index e825f76..1f73c70 100644 --- a/WebCore/rendering/RenderPath.cpp +++ b/WebCore/rendering/RenderPath.cpp @@ -26,12 +26,12 @@ #if ENABLE(SVG) #include "RenderPath.h" -#include <math.h> - #include "FloatPoint.h" +#include "FloatQuad.h" #include "GraphicsContext.h" #include "PointerEventsHitRules.h" #include "RenderSVGContainer.h" +#include "StrokeStyleApplier.h" #include "SVGPaintServer.h" #include "SVGRenderSupport.h" #include "SVGResourceFilter.h" @@ -40,24 +40,37 @@ #include "SVGStyledTransformableElement.h" #include "SVGTransformList.h" #include "SVGURIReference.h" - #include <wtf/MathExtras.h> namespace WebCore { +class BoundingRectStrokeStyleApplier : public StrokeStyleApplier { +public: + BoundingRectStrokeStyleApplier(const RenderObject* object, RenderStyle* style) + : m_object(object) + , m_style(style) + { + ASSERT(style); + ASSERT(object); + } + + void strokeStyle(GraphicsContext* gc) + { + applyStrokeStyleToContext(gc, m_style, m_object); + } + +private: + const RenderObject* m_object; + RenderStyle* m_style; +}; + // RenderPath -RenderPath::RenderPath(RenderStyle* style, SVGStyledTransformableElement* node) +RenderPath::RenderPath(SVGStyledTransformableElement* node) : RenderObject(node) { - ASSERT(style != 0); - ASSERT(static_cast<SVGElement*>(node)->isStyledTransformable()); } -RenderPath::~RenderPath() -{ -} - -AffineTransform RenderPath::localTransform() const +TransformationMatrix RenderPath::localTransform() const { return m_localTransform; } @@ -83,14 +96,35 @@ bool RenderPath::fillContains(const FloatPoint& point, bool requiresFill) const return m_path.contains(point, style()->svgStyle()->fillRule()); } +bool RenderPath::strokeContains(const FloatPoint& point, bool requiresStroke) const +{ + if (m_path.isEmpty()) + return false; + + if (requiresStroke && !SVGPaintServer::strokePaintServer(style(), this)) + return false; + + BoundingRectStrokeStyleApplier strokeStyle(this, style()); + return m_path.strokeContains(&strokeStyle, point); +} + FloatRect RenderPath::relativeBBox(bool includeStroke) const { if (m_path.isEmpty()) return FloatRect(); if (includeStroke) { - if (m_strokeBbox.isEmpty()) - m_strokeBbox = strokeBBox(); + if (m_strokeBbox.isEmpty()) { + if (style()->svgStyle()->hasStroke()) { + BoundingRectStrokeStyleApplier strokeStyle(this, style()); + m_strokeBbox = m_path.strokeBoundingRect(&strokeStyle); + } else { + if (m_fillBBox.isEmpty()) + m_fillBBox = m_path.boundingRect(); + + m_strokeBbox = m_fillBBox; + } + } return m_strokeBbox; } @@ -115,7 +149,7 @@ const Path& RenderPath::path() const bool RenderPath::calculateLocalTransform() { - AffineTransform oldTransform = m_localTransform; + TransformationMatrix oldTransform = m_localTransform; m_localTransform = static_cast<SVGStyledTransformableElement*>(element())->animatedLocalTransform(); return (m_localTransform != oldTransform); } @@ -127,7 +161,7 @@ void RenderPath::layout() bool checkForRepaint = checkForRepaintDuringLayout() && selfNeedsLayout(); if (checkForRepaint) { oldBounds = m_absoluteBounds; - oldOutlineBox = absoluteOutlineBox(); + oldOutlineBox = absoluteOutlineBounds(); } calculateLocalTransform(); @@ -136,17 +170,15 @@ void RenderPath::layout() m_absoluteBounds = absoluteClippedOverflowRect(); - setWidth(m_absoluteBounds.width()); - setHeight(m_absoluteBounds.height()); - if (checkForRepaint) repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox); setNeedsLayout(false); } -IntRect RenderPath::absoluteClippedOverflowRect() +IntRect RenderPath::clippedOverflowRectForRepaint(RenderBox* /*repaintContainer*/) { + // FIXME: handle non-root repaintContainer FloatRect repaintRect = absoluteTransform().mapRect(relativeBBox(true)); // Markers can expand the bounding box @@ -165,17 +197,12 @@ IntRect RenderPath::absoluteClippedOverflowRect() return enclosingIntRect(repaintRect); } -bool RenderPath::requiresLayer() -{ - return false; -} - -int RenderPath::lineHeight(bool b, bool isRootLineBox) const +int RenderPath::lineHeight(bool, bool) const { return relativeBBox(true).height(); } -int RenderPath::baselinePosition(bool b, bool isRootLineBox) const +int RenderPath::baselinePosition(bool, bool) const { return relativeBBox(true).height(); } @@ -213,7 +240,7 @@ void RenderPath::paint(PaintInfo& paintInfo, int, int) prepareToRenderSVGContent(this, paintInfo, boundingBox, filter); if (style()->svgStyle()->shapeRendering() == SR_CRISPEDGES) - paintInfo.context->setUseAntialiasing(false); + paintInfo.context->setShouldAntialias(false); fillAndStrokePath(m_path, paintInfo.context, style(), this); if (static_cast<SVGStyledElement*>(element())->supportsMarkers()) @@ -239,7 +266,12 @@ void RenderPath::absoluteRects(Vector<IntRect>& rects, int, int, bool) rects.append(absoluteClippedOverflowRect()); } -bool RenderPath::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int _x, int _y, int, int, HitTestAction hitTestAction) +void RenderPath::absoluteQuads(Vector<FloatQuad>& quads, bool) +{ + quads.append(absoluteClippedOverflowRect()); +} + +bool RenderPath::nodeAtPoint(const HitTestRequest&, HitTestResult& result, int _x, int _y, int, int, HitTestAction hitTestAction) { // We only draw in the forground phase, so we only hit-test then. if (hitTestAction != HitTestForeground) @@ -247,7 +279,7 @@ bool RenderPath::nodeAtPoint(const HitTestRequest& request, HitTestResult& resul IntPoint absolutePoint(_x, _y); - PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_PATH_HITTESTING, style()->svgStyle()->pointerEvents()); + PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_PATH_HITTESTING, style()->pointerEvents()); bool isVisible = (style()->visibility() == VISIBLE); if (isVisible || !hitRules.requireVisible) { @@ -382,7 +414,7 @@ static void drawStartAndMidMarkers(void* info, const PathElement* element) data.elementIndex++; } -FloatRect RenderPath::drawMarkersIfNeeded(GraphicsContext* context, const FloatRect& rect, const Path& path) const +FloatRect RenderPath::drawMarkersIfNeeded(GraphicsContext* context, const FloatRect&, const Path& path) const { Document* doc = document(); @@ -444,6 +476,14 @@ FloatRect RenderPath::drawMarkersIfNeeded(GraphicsContext* context, const FloatR return bounds; } +IntRect RenderPath::outlineBoundsForRepaint(RenderBox* /*repaintContainer*/) const +{ + // FIXME: handle non-root repaintContainer + IntRect result = m_absoluteBounds; + adjustRectForOutlineAndShadow(result); + return result; +} + } #endif // ENABLE(SVG) diff --git a/WebCore/rendering/RenderPath.h b/WebCore/rendering/RenderPath.h index ab966e4..81b5c52 100644 --- a/WebCore/rendering/RenderPath.h +++ b/WebCore/rendering/RenderPath.h @@ -27,7 +27,7 @@ #if ENABLE(SVG) -#include "AffineTransform.h" +#include "TransformationMatrix.h" #include "FloatRect.h" #include "RenderObject.h" @@ -35,19 +35,16 @@ namespace WebCore { class FloatPoint; -class Path; class RenderSVGContainer; class SVGStyledTransformableElement; -class RenderPath : public RenderObject -{ +class RenderPath : public RenderObject { public: - RenderPath(RenderStyle*, SVGStyledTransformableElement*); - virtual ~RenderPath(); + RenderPath(SVGStyledTransformableElement*); // Hit-detection seperated for the fill and the stroke - virtual bool fillContains(const FloatPoint&, bool requiresFill = true) const; - virtual bool strokeContains(const FloatPoint&, bool requiresStroke = true) const; + bool fillContains(const FloatPoint&, bool requiresFill = true) const; + bool strokeContains(const FloatPoint&, bool requiresStroke = true) const; // Returns an unscaled bounding box (not even including localTransform()) for this vector path virtual FloatRect relativeBBox(bool includeStroke = true) const; @@ -59,31 +56,32 @@ public: virtual const char* renderName() const { return "RenderPath"; } bool calculateLocalTransform(); - virtual AffineTransform localTransform() const; + virtual TransformationMatrix localTransform() const; virtual void layout(); - virtual IntRect absoluteClippedOverflowRect(); - virtual bool requiresLayer(); + virtual IntRect clippedOverflowRectForRepaint(RenderBox* repaintContainer); + virtual bool requiresLayer() const { return false; } virtual int lineHeight(bool b, bool isRootLineBox = false) const; virtual int baselinePosition(bool b, bool isRootLineBox = false) const; virtual void paint(PaintInfo&, int parentX, int parentY); virtual void absoluteRects(Vector<IntRect>&, int tx, int ty, bool topLevel = true); + virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true); virtual void addFocusRingRects(GraphicsContext*, int tx, int ty); virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); FloatRect drawMarkersIfNeeded(GraphicsContext*, const FloatRect&, const Path&) const; - virtual FloatRect strokeBBox() const; private: FloatPoint mapAbsolutePointToLocal(const FloatPoint&) const; + virtual IntRect outlineBoundsForRepaint(RenderBox* repaintContainer) const; mutable Path m_path; mutable FloatRect m_fillBBox; mutable FloatRect m_strokeBbox; FloatRect m_markerBounds; - AffineTransform m_localTransform; + TransformationMatrix m_localTransform; IntRect m_absoluteBounds; }; diff --git a/WebCore/rendering/RenderReplaced.cpp b/WebCore/rendering/RenderReplaced.cpp index 52267d5..e74e227 100644 --- a/WebCore/rendering/RenderReplaced.cpp +++ b/WebCore/rendering/RenderReplaced.cpp @@ -26,6 +26,8 @@ #include "GraphicsContext.h" #include "RenderBlock.h" #include "RenderLayer.h" +#include "RenderTheme.h" +#include "RenderView.h" using namespace std; @@ -80,10 +82,10 @@ void RenderReplaced::layout() bool checkForRepaint = checkForRepaintDuringLayout(); if (checkForRepaint) { oldBounds = absoluteClippedOverflowRect(); - oldOutlineBox = absoluteOutlineBox(); + oldOutlineBox = absoluteOutlineBounds(); } - m_height = minimumReplacedHeight(); + setHeight(minimumReplacedHeight()); calcWidth(); calcHeight(); @@ -108,8 +110,8 @@ void RenderReplaced::paint(PaintInfo& paintInfo, int tx, int ty) if (!shouldPaint(paintInfo, tx, ty)) return; - tx += m_x; - ty += m_y; + tx += x(); + ty += y(); if (hasBoxDecorations() && (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection)) paintBoxDecorations(paintInfo, tx, ty); @@ -137,8 +139,11 @@ void RenderReplaced::paint(PaintInfo& paintInfo, int tx, int ty) paintReplaced(paintInfo, tx, ty); - if (drawSelectionTint) - paintInfo.context->fillRect(selectionRect(), selectionBackgroundColor()); + if (drawSelectionTint) { + IntRect selectionPaintingRect = localSelectionRect(); + selectionPaintingRect.move(tx, ty); + paintInfo.context->fillRect(selectionPaintingRect, selectionBackgroundColor()); + } } bool RenderReplaced::shouldPaint(PaintInfo& paintInfo, int& tx, int& ty) @@ -154,8 +159,8 @@ bool RenderReplaced::shouldPaint(PaintInfo& paintInfo, int& tx, int& ty) if (style()->visibility() != VISIBLE) return false; - int currentTX = tx + m_x; - int currentTY = ty + m_y; + int currentTX = tx + x(); + int currentTY = ty + y(); // Early exit if the element touches the edges. int top = currentTY + overflowTop(); @@ -210,7 +215,7 @@ unsigned RenderReplaced::caretMaxRenderedOffset() const return 1; } -VisiblePosition RenderReplaced::positionForCoordinates(int x, int y) +VisiblePosition RenderReplaced::positionForCoordinates(int xPos, int yPos) { InlineBox* box = inlineBoxWrapper(); if (!box) @@ -223,19 +228,19 @@ VisiblePosition RenderReplaced::positionForCoordinates(int x, int y) int top = root->topOverflow(); int bottom = root->nextRootBox() ? root->nextRootBox()->topOverflow() : root->bottomOverflow(); - if (y + yPos() < top) + if (yPos + y() < top) return VisiblePosition(element(), caretMinOffset(), DOWNSTREAM); // coordinates are above - if (y + yPos() >= bottom) + if (yPos + y() >= bottom) return VisiblePosition(element(), caretMaxOffset(), DOWNSTREAM); // coordinates are below if (element()) { - if (x <= width() / 2) + if (xPos <= width() / 2) return VisiblePosition(element(), 0, DOWNSTREAM); return VisiblePosition(element(), 1, DOWNSTREAM); } - return RenderBox::positionForCoordinates(x, y); + return RenderBox::positionForCoordinates(xPos, yPos); } IntRect RenderReplaced::selectionRect(bool clipToVisibleContent) @@ -244,26 +249,33 @@ IntRect RenderReplaced::selectionRect(bool clipToVisibleContent) if (!isSelected()) return IntRect(); + + IntRect rect = localSelectionRect(); + if (clipToVisibleContent) + computeAbsoluteRepaintRect(rect); + else { + FloatPoint absPos = localToAbsolute(FloatPoint()); + rect.move(absPos.x(), absPos.y()); + } + + return rect; +} + +IntRect RenderReplaced::localSelectionRect(bool checkWhetherSelected) const +{ + if (checkWhetherSelected && !isSelected()) + return IntRect(); + if (!m_inlineBoxWrapper) // We're a block-level replaced element. Just return our own dimensions. - return absoluteBoundingBoxRect(); + return IntRect(0, 0, width(), height()); RenderBlock* cb = containingBlock(); if (!cb) return IntRect(); RootInlineBox* root = m_inlineBoxWrapper->root(); - IntRect rect(0, root->selectionTop() - yPos(), width(), root->selectionHeight()); - - if (clipToVisibleContent) - computeAbsoluteRepaintRect(rect); - else { - int absx, absy; - absolutePositionForContent(absx, absy); - rect.move(absx, absy); - } - - return rect; + return IntRect(0, root->selectionTop() - y(), width(), root->selectionHeight()); } void RenderReplaced::setSelectionState(SelectionState s) @@ -315,7 +327,7 @@ void RenderReplaced::adjustOverflowForBoxShadow() { IntRect overflow; for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next) { - IntRect shadow = borderBox(); + IntRect shadow = borderBoxRect(); shadow.move(boxShadow->x, boxShadow->y); shadow.inflate(boxShadow->blur); overflow.unite(shadow); @@ -324,7 +336,7 @@ void RenderReplaced::adjustOverflowForBoxShadow() if (!overflow.isEmpty()) { if (!gOverflowRectMap) gOverflowRectMap = new OverflowRectMap(); - overflow.unite(borderBox()); + overflow.unite(borderBoxRect()); gOverflowRectMap->set(this, overflow); m_hasOverflow = true; } else if (m_hasOverflow) { @@ -333,7 +345,7 @@ void RenderReplaced::adjustOverflowForBoxShadow() } } -int RenderReplaced::overflowHeight(bool includeInterior) const +int RenderReplaced::overflowHeight(bool) const { if (m_hasOverflow) { IntRect *r = &gOverflowRectMap->find(this)->second; @@ -343,7 +355,7 @@ int RenderReplaced::overflowHeight(bool includeInterior) const return height(); } -int RenderReplaced::overflowWidth(bool includeInterior) const +int RenderReplaced::overflowWidth(bool) const { if (m_hasOverflow) { IntRect *r = &gOverflowRectMap->find(this)->second; @@ -353,7 +365,7 @@ int RenderReplaced::overflowWidth(bool includeInterior) const return width(); } -int RenderReplaced::overflowLeft(bool includeInterior) const +int RenderReplaced::overflowLeft(bool) const { if (m_hasOverflow) return gOverflowRectMap->get(this).x(); @@ -361,7 +373,7 @@ int RenderReplaced::overflowLeft(bool includeInterior) const return 0; } -int RenderReplaced::overflowTop(bool includeInterior) const +int RenderReplaced::overflowTop(bool) const { if (m_hasOverflow) return gOverflowRectMap->get(this).y(); @@ -369,12 +381,39 @@ int RenderReplaced::overflowTop(bool includeInterior) const return 0; } -IntRect RenderReplaced::overflowRect(bool includeInterior) const +IntRect RenderReplaced::overflowRect(bool) const { if (m_hasOverflow) return gOverflowRectMap->find(this)->second; - return borderBox(); + return borderBoxRect(); +} + +IntRect RenderReplaced::clippedOverflowRectForRepaint(RenderBox* repaintContainer) +{ + if (style()->visibility() != VISIBLE && !enclosingLayer()->hasVisibleContent()) + return IntRect(); + + // The selectionRect can project outside of the overflowRect, so use + // that for repainting to avoid selection painting glitches + IntRect r = localSelectionRect(false); + + RenderView* v = view(); + if (v) { + // FIXME: layoutDelta needs to be applied in parts before/after transforms and + // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308 + r.move(v->layoutDelta()); + } + + if (style()) { + if (style()->hasAppearance()) + // The theme may wish to inflate the rect used when repainting. + theme()->adjustRepaintRect(this, r); + if (v) + r.inflate(style()->outlineSize()); + } + computeRectForRepaint(r, repaintContainer); + return r; } } diff --git a/WebCore/rendering/RenderReplaced.h b/WebCore/rendering/RenderReplaced.h index f1ee32b..c87db58 100644 --- a/WebCore/rendering/RenderReplaced.h +++ b/WebCore/rendering/RenderReplaced.h @@ -43,7 +43,7 @@ public: virtual int minimumReplacedHeight() const { return 0; } virtual void paint(PaintInfo&, int tx, int ty); - virtual void paintReplaced(PaintInfo&, int tx, int ty) { } + virtual void paintReplaced(PaintInfo&, int /*tx*/, int /*ty*/) { } virtual IntSize intrinsicSize() const; @@ -53,6 +53,8 @@ public: virtual int overflowTop(bool includeInterior = true) const; virtual IntRect overflowRect(bool includeInterior = true) const; + virtual IntRect clippedOverflowRectForRepaint(RenderBox* repaintContainer); + virtual unsigned caretMaxRenderedOffset() const; virtual VisiblePosition positionForCoordinates(int x, int y); @@ -71,6 +73,7 @@ protected: bool shouldPaint(PaintInfo&, int& tx, int& ty); void adjustOverflowForBoxShadow(); + IntRect localSelectionRect(bool checkWhetherSelected = true) const; private: IntSize m_intrinsicSize; diff --git a/WebCore/rendering/RenderReplica.cpp b/WebCore/rendering/RenderReplica.cpp index be28171..183dd2e 100644 --- a/WebCore/rendering/RenderReplica.cpp +++ b/WebCore/rendering/RenderReplica.cpp @@ -42,17 +42,13 @@ RenderReplica::~RenderReplica() void RenderReplica::layout() { - IntRect box = parent()->borderBox(); - m_x = box.x(); - m_y = box.y(); - m_width = box.width(); - m_height = box.height(); + setFrameRect(parentBox()->borderBoxRect()); setNeedsLayout(false); } void RenderReplica::calcPrefWidths() { - m_minPrefWidth = parent()->width(); + m_minPrefWidth = parentBox()->width(); m_maxPrefWidth = m_minPrefWidth; setPrefWidthsDirty(false); } @@ -62,12 +58,17 @@ void RenderReplica::paint(PaintInfo& paintInfo, int tx, int ty) if (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseMask) return; - tx += m_x; - ty += m_y; + tx += x(); + ty += y(); if (paintInfo.phase == PaintPhaseForeground) - // Turn around and paint the parent layer. - layer()->parent()->paintLayer(layer()->transform() ? layer()->parent() : layer()->enclosingTransformedAncestor(), paintInfo.context, paintInfo.rect, true, PaintRestrictionNone, 0, true); + // Turn around and paint the parent layer. Use temporary clipRects, so that the layer doesn't end up caching clip rects + // computing using the wrong rootLayer + layer()->parent()->paintLayer(layer()->transform() ? layer()->parent() : layer()->enclosingTransformedAncestor(), + paintInfo.context, paintInfo.rect, + true, PaintRestrictionNone, 0, + true, // appliedTransform + true); // temporaryClipRects else if (paintInfo.phase == PaintPhaseMask) paintMask(paintInfo, tx, ty); } diff --git a/WebCore/rendering/RenderReplica.h b/WebCore/rendering/RenderReplica.h index d3a9026..d5db3b7 100644 --- a/WebCore/rendering/RenderReplica.h +++ b/WebCore/rendering/RenderReplica.h @@ -40,7 +40,7 @@ public: virtual const char* renderName() const { return "RenderReplica"; } - virtual bool requiresLayer() { return true; } + virtual bool requiresLayer() const { return true; } virtual void layout(); virtual void calcPrefWidths(); diff --git a/WebCore/rendering/RenderSVGContainer.cpp b/WebCore/rendering/RenderSVGContainer.cpp index c9c3cac..6e17c05 100644 --- a/WebCore/rendering/RenderSVGContainer.cpp +++ b/WebCore/rendering/RenderSVGContainer.cpp @@ -27,6 +27,7 @@ #include "RenderSVGContainer.h" #include "AXObjectCache.h" +#include "FloatQuad.h" #include "GraphicsContext.h" #include "RenderView.h" #include "SVGRenderSupport.h" @@ -44,7 +45,6 @@ RenderSVGContainer::RenderSVGContainer(SVGStyledElement* node) , m_height(0) , m_drawsContents(true) { - setReplaced(true); } RenderSVGContainer::~RenderSVGContainer() @@ -198,25 +198,19 @@ void RenderSVGContainer::setDrawsContents(bool drawsContents) m_drawsContents = drawsContents; } -AffineTransform RenderSVGContainer::localTransform() const +TransformationMatrix RenderSVGContainer::localTransform() const { return m_localTransform; } -bool RenderSVGContainer::requiresLayer() +int RenderSVGContainer::lineHeight(bool, bool) const { - // Only allow an <svg> element to generate a layer when it's positioned in a non-SVG context - return false; + return height(); } -int RenderSVGContainer::lineHeight(bool b, bool isRootLineBox) const +int RenderSVGContainer::baselinePosition(bool, bool) const { - return height() + marginTop() + marginBottom(); -} - -int RenderSVGContainer::baselinePosition(bool b, bool isRootLineBox) const -{ - return height() + marginTop() + marginBottom(); + return height(); } bool RenderSVGContainer::calculateLocalTransform() @@ -237,7 +231,7 @@ void RenderSVGContainer::layout() bool checkForRepaint = checkForRepaintDuringLayout() && selfWillPaint(); if (checkForRepaint) { oldBounds = m_absoluteBounds; - oldOutlineBox = absoluteOutlineBox(); + oldOutlineBox = absoluteOutlineBounds(); } calculateLocalTransform(); @@ -299,7 +293,7 @@ void RenderSVGContainer::applyContentTransforms(PaintInfo& paintInfo) paintInfo.context->concatCTM(localTransform()); } -void RenderSVGContainer::applyAdditionalTransforms(PaintInfo& paintInfo) +void RenderSVGContainer::applyAdditionalTransforms(PaintInfo&) { // no-op } @@ -322,7 +316,7 @@ bool RenderSVGContainer::selfWillPaint() const return false; } -void RenderSVGContainer::paint(PaintInfo& paintInfo, int parentX, int parentY) +void RenderSVGContainer::paint(PaintInfo& paintInfo, int, int) { if (paintInfo.context->paintingDisabled() || !drawsContents()) return; @@ -358,17 +352,17 @@ void RenderSVGContainer::paint(PaintInfo& paintInfo, int parentX, int parentY) paintOutline(paintInfo.context, m_absoluteBounds.x(), m_absoluteBounds.y(), m_absoluteBounds.width(), m_absoluteBounds.height(), style()); } -AffineTransform RenderSVGContainer::viewportTransform() const +TransformationMatrix RenderSVGContainer::viewportTransform() const { - return AffineTransform(); + return TransformationMatrix(); } -IntRect RenderSVGContainer::absoluteClippedOverflowRect() +IntRect RenderSVGContainer::clippedOverflowRectForRepaint(RenderBox* repaintContainer) { FloatRect repaintRect; for (RenderObject* current = firstChild(); current != 0; current = current->nextSibling()) - repaintRect.unite(current->absoluteClippedOverflowRect()); + repaintRect.unite(current->clippedOverflowRectForRepaint(repaintContainer)); #if ENABLE(SVG_FILTERS) // Filters can expand the bounding box @@ -383,7 +377,7 @@ IntRect RenderSVGContainer::absoluteClippedOverflowRect() return enclosingIntRect(repaintRect); } -void RenderSVGContainer::addFocusRingRects(GraphicsContext* graphicsContext, int tx, int ty) +void RenderSVGContainer::addFocusRingRects(GraphicsContext* graphicsContext, int, int) { graphicsContext->addFocusRingRect(m_absoluteBounds); } @@ -393,6 +387,11 @@ void RenderSVGContainer::absoluteRects(Vector<IntRect>& rects, int, int, bool) rects.append(absoluteClippedOverflowRect()); } +void RenderSVGContainer::absoluteQuads(Vector<FloatQuad>& quads, bool) +{ + quads.append(absoluteClippedOverflowRect()); +} + FloatRect RenderSVGContainer::relativeBBox(bool includeStroke) const { FloatRect rect; @@ -426,6 +425,14 @@ bool RenderSVGContainer::nodeAtPoint(const HitTestRequest& request, HitTestResul return false; } +IntRect RenderSVGContainer::outlineBoundsForRepaint(RenderBox* /*repaintContainer*/) const +{ + // FIXME: handle non-root repaintContainer + IntRect result = m_absoluteBounds; + adjustRectForOutlineAndShadow(result); + return result; +} + } #endif // ENABLE(SVG) diff --git a/WebCore/rendering/RenderSVGContainer.h b/WebCore/rendering/RenderSVGContainer.h index 06751a3..e498a8a 100644 --- a/WebCore/rendering/RenderSVGContainer.h +++ b/WebCore/rendering/RenderSVGContainer.h @@ -40,8 +40,8 @@ public: virtual RenderObject* firstChild() const { return m_firstChild; } virtual RenderObject* lastChild() const { return m_lastChild; } - virtual int width() const { return m_width; } - virtual int height() const { return m_height; } + int width() const { return m_width; } + int height() const { return m_height; } virtual bool canHaveChildren() const; virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0); @@ -69,22 +69,23 @@ public: virtual bool isSVGContainer() const { return true; } virtual const char* renderName() const { return "RenderSVGContainer"; } - virtual bool requiresLayer(); + virtual bool requiresLayer() const { return false; } virtual int lineHeight(bool b, bool isRootLineBox = false) const; virtual int baselinePosition(bool b, bool isRootLineBox = false) const; virtual void layout(); virtual void paint(PaintInfo&, int parentX, int parentY); - virtual IntRect absoluteClippedOverflowRect(); + virtual IntRect clippedOverflowRectForRepaint(RenderBox* repaintContainer); virtual void absoluteRects(Vector<IntRect>& rects, int tx, int ty, bool topLevel = true); + virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true); virtual void addFocusRingRects(GraphicsContext*, int tx, int ty); FloatRect relativeBBox(bool includeStroke = true) const; virtual bool calculateLocalTransform(); - virtual AffineTransform localTransform() const; - virtual AffineTransform viewportTransform() const; + virtual TransformationMatrix localTransform() const; + virtual TransformationMatrix viewportTransform() const; virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); @@ -94,6 +95,8 @@ protected: void calcBounds(); + virtual IntRect outlineBoundsForRepaint(RenderBox* /*repaintContainer*/) const; + private: int calcReplacedWidth() const; int calcReplacedHeight() const; @@ -110,7 +113,7 @@ private: protected: IntRect m_absoluteBounds; - AffineTransform m_localTransform; + TransformationMatrix m_localTransform; }; } // namespace WebCore diff --git a/WebCore/rendering/RenderSVGHiddenContainer.cpp b/WebCore/rendering/RenderSVGHiddenContainer.cpp index bc758e5..23ae13e 100644 --- a/WebCore/rendering/RenderSVGHiddenContainer.cpp +++ b/WebCore/rendering/RenderSVGHiddenContainer.cpp @@ -39,17 +39,12 @@ RenderSVGHiddenContainer::~RenderSVGHiddenContainer() { } -bool RenderSVGHiddenContainer::requiresLayer() -{ - return false; -} - -int RenderSVGHiddenContainer::lineHeight(bool b, bool isRootLineBox) const +int RenderSVGHiddenContainer::lineHeight(bool, bool) const { return 0; } -int RenderSVGHiddenContainer::baselinePosition(bool b, bool isRootLineBox) const +int RenderSVGHiddenContainer::baselinePosition(bool, bool) const { return 0; } @@ -76,32 +71,37 @@ void RenderSVGHiddenContainer::paint(PaintInfo&, int, int) // This subtree does not paint. } -IntRect RenderSVGHiddenContainer::absoluteClippedOverflowRect() +IntRect RenderSVGHiddenContainer::clippedOverflowRectForRepaint(RenderBox* /*repaintContainer*/) { return IntRect(); } -void RenderSVGHiddenContainer::absoluteRects(Vector<IntRect>& rects, int, int, bool) +void RenderSVGHiddenContainer::absoluteRects(Vector<IntRect>&, int, int, bool) +{ + // This subtree does not take up space or paint +} + +void RenderSVGHiddenContainer::absoluteQuads(Vector<FloatQuad>&, bool) { // This subtree does not take up space or paint } -AffineTransform RenderSVGHiddenContainer::absoluteTransform() const +TransformationMatrix RenderSVGHiddenContainer::absoluteTransform() const { - return AffineTransform(); + return TransformationMatrix(); } -AffineTransform RenderSVGHiddenContainer::localTransform() const +TransformationMatrix RenderSVGHiddenContainer::localTransform() const { - return AffineTransform(); + return TransformationMatrix(); } -bool RenderSVGHiddenContainer::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction) +bool RenderSVGHiddenContainer::nodeAtPoint(const HitTestRequest&, HitTestResult&, int, int, int, int, HitTestAction) { return false; } -FloatRect RenderSVGHiddenContainer::relativeBBox(bool includeStroke) const +FloatRect RenderSVGHiddenContainer::relativeBBox(bool) const { return FloatRect(); } diff --git a/WebCore/rendering/RenderSVGHiddenContainer.h b/WebCore/rendering/RenderSVGHiddenContainer.h index c428a79..282e3f3 100644 --- a/WebCore/rendering/RenderSVGHiddenContainer.h +++ b/WebCore/rendering/RenderSVGHiddenContainer.h @@ -43,7 +43,7 @@ namespace WebCore { virtual const char* renderName() const { return "RenderSVGHiddenContainer"; } - virtual bool requiresLayer(); + virtual bool requiresLayer() const { return false; } virtual int lineHeight(bool b, bool isRootLineBox = false) const; virtual int baselinePosition(bool b, bool isRootLineBox = false) const; @@ -51,11 +51,12 @@ namespace WebCore { virtual void layout(); virtual void paint(PaintInfo&, int parentX, int parentY); - virtual IntRect absoluteClippedOverflowRect(); + virtual IntRect clippedOverflowRectForRepaint(RenderBox* repaintContainer); virtual void absoluteRects(Vector<IntRect>& rects, int tx, int ty, bool topLevel = true); + virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true); - virtual AffineTransform absoluteTransform() const; - virtual AffineTransform localTransform() const; + virtual TransformationMatrix absoluteTransform() const; + virtual TransformationMatrix localTransform() const; virtual FloatRect relativeBBox(bool includeStroke = true) const; virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); diff --git a/WebCore/rendering/RenderSVGImage.cpp b/WebCore/rendering/RenderSVGImage.cpp index 345e79f..503663a 100644 --- a/WebCore/rendering/RenderSVGImage.cpp +++ b/WebCore/rendering/RenderSVGImage.cpp @@ -29,6 +29,7 @@ #include "Attr.h" #include "FloatConversion.h" +#include "FloatQuad.h" #include "GraphicsContext.h" #include "PointerEventsHitRules.h" #include "SVGImageElement.h" @@ -127,7 +128,7 @@ void RenderSVGImage::adjustRectsForAspectRatio(FloatRect& destRect, FloatRect& s bool RenderSVGImage::calculateLocalTransform() { - AffineTransform oldTransform = m_localTransform; + TransformationMatrix oldTransform = m_localTransform; m_localTransform = static_cast<SVGStyledTransformableElement*>(element())->animatedLocalTransform(); return (m_localTransform != oldTransform); } @@ -141,13 +142,13 @@ void RenderSVGImage::layout() bool checkForRepaint = checkForRepaintDuringLayout(); if (checkForRepaint) { oldBounds = absoluteClippedOverflowRect(); - oldOutlineBox = absoluteOutlineBox(); + oldOutlineBox = absoluteOutlineBounds(); } calculateLocalTransform(); // minimum height - m_height = errorOccurred() ? intrinsicSize().height() : 0; + setHeight(errorOccurred() ? intrinsicSize().height() : 0); calcWidth(); calcHeight(); @@ -193,13 +194,13 @@ void RenderSVGImage::paint(PaintInfo& paintInfo, int, int) paintInfo.context->restore(); } -bool RenderSVGImage::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int _x, int _y, int, int, HitTestAction hitTestAction) +bool RenderSVGImage::nodeAtPoint(const HitTestRequest&, HitTestResult& result, int _x, int _y, int, int, HitTestAction hitTestAction) { // We only draw in the forground phase, so we only hit-test then. if (hitTestAction != HitTestForeground) return false; - PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_IMAGE_HITTESTING, style()->svgStyle()->pointerEvents()); + PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_IMAGE_HITTESTING, style()->pointerEvents()); bool isVisible = (style()->visibility() == VISIBLE); if (isVisible || !hitRules.requireVisible) { @@ -217,19 +218,14 @@ bool RenderSVGImage::nodeAtPoint(const HitTestRequest& request, HitTestResult& r return false; } -bool RenderSVGImage::requiresLayer() -{ - return false; -} - FloatRect RenderSVGImage::relativeBBox(bool) const { return m_localBounds; } -void RenderSVGImage::imageChanged(WrappedImagePtr image) +void RenderSVGImage::imageChanged(WrappedImagePtr image, const IntRect* rect) { - RenderImage::imageChanged(image); + RenderImage::imageChanged(image, rect); // We override to invalidate a larger rect, since SVG images can draw outside their "bounds" repaintRectangle(absoluteClippedOverflowRect()); @@ -237,6 +233,7 @@ void RenderSVGImage::imageChanged(WrappedImagePtr image) void RenderSVGImage::calculateAbsoluteBounds() { + // FIXME: broken with CSS transforms FloatRect absoluteRect = absoluteTransform().mapRect(relativeBBox(true)); #if ENABLE(SVG_FILTERS) @@ -252,12 +249,13 @@ void RenderSVGImage::calculateAbsoluteBounds() m_absoluteBounds = enclosingIntRect(absoluteRect); } -IntRect RenderSVGImage::absoluteClippedOverflowRect() +IntRect RenderSVGImage::clippedOverflowRectForRepaint(RenderBox* /*repaintContainer*/) { + // FIXME: handle non-root repaintContainer return m_absoluteBounds; } -void RenderSVGImage::addFocusRingRects(GraphicsContext* graphicsContext, int tx, int ty) +void RenderSVGImage::addFocusRingRects(GraphicsContext* graphicsContext, int, int) { // this is called from paint() after the localTransform has already been applied IntRect contentRect = enclosingIntRect(relativeBBox()); @@ -269,6 +267,11 @@ void RenderSVGImage::absoluteRects(Vector<IntRect>& rects, int, int, bool) rects.append(absoluteClippedOverflowRect()); } +void RenderSVGImage::absoluteQuads(Vector<FloatQuad>& quads, bool) +{ + quads.append(FloatRect(absoluteClippedOverflowRect())); +} + } #endif // ENABLE(SVG) diff --git a/WebCore/rendering/RenderSVGImage.h b/WebCore/rendering/RenderSVGImage.h index 4891306..cb440d2 100644 --- a/WebCore/rendering/RenderSVGImage.h +++ b/WebCore/rendering/RenderSVGImage.h @@ -26,7 +26,7 @@ #if ENABLE(SVG) -#include "AffineTransform.h" +#include "TransformationMatrix.h" #include "FloatRect.h" #include "RenderImage.h" @@ -40,20 +40,21 @@ namespace WebCore { RenderSVGImage(SVGImageElement*); virtual ~RenderSVGImage(); - virtual AffineTransform localTransform() const { return m_localTransform; } + virtual TransformationMatrix localTransform() const { return m_localTransform; } virtual FloatRect relativeBBox(bool includeStroke = true) const; - virtual IntRect absoluteClippedOverflowRect(); + virtual IntRect clippedOverflowRectForRepaint(RenderBox* repaintContainer); virtual void absoluteRects(Vector<IntRect>&, int tx, int ty, bool topLevel = true); + virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true); virtual void addFocusRingRects(GraphicsContext*, int tx, int ty); - virtual void imageChanged(WrappedImagePtr); + virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); void adjustRectsForAspectRatio(FloatRect& destRect, FloatRect& srcRect, SVGPreserveAspectRatio*); virtual void layout(); virtual void paint(PaintInfo&, int parentX, int parentY); - bool requiresLayer(); + bool requiresLayer() const { return false; } virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int _x, int _y, int _tx, int _ty, HitTestAction); @@ -61,7 +62,7 @@ namespace WebCore { private: void calculateAbsoluteBounds(); - AffineTransform m_localTransform; + TransformationMatrix m_localTransform; FloatRect m_localBounds; IntRect m_absoluteBounds; }; diff --git a/WebCore/rendering/RenderSVGInline.cpp b/WebCore/rendering/RenderSVGInline.cpp index 11da004..81e0924 100644 --- a/WebCore/rendering/RenderSVGInline.cpp +++ b/WebCore/rendering/RenderSVGInline.cpp @@ -2,7 +2,7 @@ * This file is part of the WebKit project. * * Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz> - * (C) 2006 Apple Computer Inc. + * Copyright (C) 2006 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -27,6 +27,7 @@ #include "RenderSVGInline.h" #include "SVGInlineFlowBox.h" +#include <wtf/UnusedParam.h> namespace WebCore { @@ -35,10 +36,16 @@ RenderSVGInline::RenderSVGInline(Node* n) { } -InlineBox* RenderSVGInline::createInlineBox(bool makePlaceHolderBox, bool isRootLineBox, bool isOnlyRun) +InlineBox* RenderSVGInline::createInlineBox(bool unusedMakePlaceHolderBox, bool unusedIsRootLineBox, bool) { - ASSERT(!(!isRootLineBox && (isReplaced() || makePlaceHolderBox))); - ASSERT(isInlineFlow()); +#if ASSERT_DISABLED + UNUSED_PARAM(unusedIsRootLineBox); + UNUSED_PARAM(unusedMakePlaceHolderBox); +#endif + + ASSERT(!(!unusedIsRootLineBox && (isReplaced() || unusedMakePlaceHolderBox))); + + ASSERT(isRenderInline()); InlineFlowBox* flowBox = new (renderArena()) SVGInlineFlowBox(this); diff --git a/WebCore/rendering/RenderSVGInline.h b/WebCore/rendering/RenderSVGInline.h index 42fdafc..060ba58 100644 --- a/WebCore/rendering/RenderSVGInline.h +++ b/WebCore/rendering/RenderSVGInline.h @@ -33,7 +33,7 @@ public: RenderSVGInline(Node*); virtual const char* renderName() const { return "RenderSVGInline"; } virtual InlineBox* createInlineBox(bool makePlaceHolderBox, bool isRootLineBox, bool isOnlyRun = false); - virtual bool requiresLayer() { return false; } + virtual bool requiresLayer() const { return false; } }; } diff --git a/WebCore/rendering/RenderSVGInlineText.cpp b/WebCore/rendering/RenderSVGInlineText.cpp index 33a984c..215e9fe 100644 --- a/WebCore/rendering/RenderSVGInlineText.cpp +++ b/WebCore/rendering/RenderSVGInlineText.cpp @@ -29,10 +29,12 @@ #include "RenderSVGInlineText.h" #include "FloatConversion.h" +#include "FloatQuad.h" #include "RenderBlock.h" #include "RenderSVGRoot.h" #include "SVGInlineTextBox.h" #include "SVGRootInlineBox.h" +#include "VisiblePosition.h" namespace WebCore { @@ -53,11 +55,27 @@ RenderSVGInlineText::RenderSVGInlineText(Node* n, PassRefPtr<StringImpl> str) { } + +void RenderSVGInlineText::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle) +{ + // Skip RenderText's work. + RenderObject::styleDidChange(diff, oldStyle); + + // SVG text is apparently always transformed. + if (RefPtr<StringImpl> textToTransform = originalText()) + setText(textToTransform.release(), true); +} + void RenderSVGInlineText::absoluteRects(Vector<IntRect>& rects, int, int, bool) { rects.append(computeAbsoluteRectForRange(0, textLength())); } +void RenderSVGInlineText::absoluteQuads(Vector<FloatQuad>& quads, bool) +{ + quads.append(FloatRect(computeAbsoluteRectForRange(0, textLength()))); +} + IntRect RenderSVGInlineText::selectionRect(bool) { ASSERT(!needsLayout()); @@ -107,14 +125,15 @@ IntRect RenderSVGInlineText::computeAbsoluteRectForRange(int startPos, int endPo rect.unite(box->selectionRect(0, 0, startPos, endPos)); // Mimic RenderBox::computeAbsoluteRepaintRect() functionality. But only the subset needed for SVG and respecting SVG transformations. - int x, y; - cb->container()->absolutePosition(x, y); + FloatPoint absPos = cb->container()->localToAbsolute(); // Remove HTML parent translation offsets here! These need to be retrieved from the RenderSVGRoot object. // But do take the containingBlocks's container position into account, ie. SVG text in scrollable <div>. - AffineTransform htmlParentCtm = root->RenderContainer::absoluteTransform(); + TransformationMatrix htmlParentCtm = root->RenderContainer::absoluteTransform(); - FloatRect fixedRect(narrowPrecisionToFloat(rect.x() + x - xPos() - htmlParentCtm.e()), narrowPrecisionToFloat(rect.y() + y - yPos() - htmlParentCtm.f()), rect.width(), rect.height()); + FloatRect fixedRect(narrowPrecisionToFloat(rect.x() + absPos.x() - (firstTextBox() ? firstTextBox()->xPos() : 0) - htmlParentCtm.e()), + narrowPrecisionToFloat(rect.y() + absPos.y() - (firstTextBox() ? firstTextBox()->yPos() : 0) - htmlParentCtm.f()), rect.width(), rect.height()); + // FIXME: broken with CSS transforms return enclosingIntRect(absoluteTransform().mapRect(fixedRect)); } @@ -123,9 +142,10 @@ InlineTextBox* RenderSVGInlineText::createInlineTextBox() return new (renderArena()) SVGInlineTextBox(this); } -IntRect RenderSVGInlineText::caretRect(InlineBox* inlineBox, int caretOffset, int* extraWidthToEndOfLine) +IntRect RenderSVGInlineText::localCaretRect(InlineBox*, int, int*) { - // SVG doesn't have any editable content where a caret rect would be needed + // SVG doesn't have any editable content where a caret rect would be needed. + // FIXME: That's not sufficient. The localCaretRect function is also used for selection. return IntRect(); } @@ -137,7 +157,7 @@ VisiblePosition RenderSVGInlineText::positionForCoordinates(int x, int y) return VisiblePosition(element(), 0, DOWNSTREAM); SVGRootInlineBox* rootBox = textBox->svgRootInlineBox(); - RenderObject* object = rootBox ? rootBox->object() : 0; + RenderBlock* object = rootBox ? rootBox->block() : 0; if (!object) return VisiblePosition(element(), 0, DOWNSTREAM); @@ -145,7 +165,7 @@ VisiblePosition RenderSVGInlineText::positionForCoordinates(int x, int y) int offset = 0; for (SVGInlineTextBox* box = textBox; box; box = static_cast<SVGInlineTextBox*>(box->nextTextBox())) { - if (box->svgCharacterHitsPosition(x + object->xPos(), y + object->yPos(), offset)) { + if (box->svgCharacterHitsPosition(x + object->x(), y + object->y(), offset)) { // If we're not at the end/start of the box, stop looking for other selected boxes. if (box->direction() == LTR) { if (offset <= (int) box->end() + 1) diff --git a/WebCore/rendering/RenderSVGInlineText.h b/WebCore/rendering/RenderSVGInlineText.h index 786ba31..55fd838 100644 --- a/WebCore/rendering/RenderSVGInlineText.h +++ b/WebCore/rendering/RenderSVGInlineText.h @@ -34,13 +34,18 @@ class RenderSVGInlineText : public RenderText { public: RenderSVGInlineText(Node*, PassRefPtr<StringImpl>); virtual const char* renderName() const { return "RenderSVGInlineText"; } + + virtual void styleDidChange(RenderStyle::Diff, const RenderStyle*); + virtual void absoluteRects(Vector<IntRect>& rects, int tx, int ty, bool topLevel = true); - virtual bool requiresLayer() { return false; } + virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true); + + virtual bool requiresLayer() const { return false; } virtual IntRect selectionRect(bool clipToVisibleContent = true); virtual bool isSVGText() const { return true; } virtual InlineTextBox* createInlineTextBox(); - virtual IntRect caretRect(InlineBox*, int caretOffset, int* extraWidthToEndOfLine = 0); + virtual IntRect localCaretRect(InlineBox*, int caretOffset, int* extraWidthToEndOfLine = 0); virtual VisiblePosition positionForCoordinates(int x, int y); virtual void destroy(); diff --git a/WebCore/rendering/RenderSVGRoot.cpp b/WebCore/rendering/RenderSVGRoot.cpp index 1c59450..54a30df 100644 --- a/WebCore/rendering/RenderSVGRoot.cpp +++ b/WebCore/rendering/RenderSVGRoot.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org> - 2004, 2005, 2007, 2008 Rob Buis <buis@kde.org> + 2004, 2005, 2007, 2008, 2009 Rob Buis <buis@kde.org> 2007 Eric Seidel <eric@webkit.org> This file is part of the KDE project @@ -53,12 +53,12 @@ RenderSVGRoot::~RenderSVGRoot() { } -int RenderSVGRoot::lineHeight(bool b, bool isRootLineBox) const +int RenderSVGRoot::lineHeight(bool, bool) const { return height() + marginTop() + marginBottom(); } -int RenderSVGRoot::baselinePosition(bool b, bool isRootLineBox) const +int RenderSVGRoot::baselinePosition(bool, bool) const { return height() + marginTop() + marginBottom(); } @@ -95,19 +95,19 @@ void RenderSVGRoot::layout() IntRect oldOutlineBox; bool checkForRepaint = checkForRepaintDuringLayout() && selfNeedsLayout(); if (checkForRepaint) - oldOutlineBox = absoluteOutlineBox(); + oldOutlineBox = absoluteOutlineBounds(); calcWidth(); calcHeight(); m_absoluteBounds = absoluteClippedOverflowRect(); SVGSVGElement* svg = static_cast<SVGSVGElement*>(element()); - m_width = static_cast<int>(m_width * svg->currentScale()); - m_height = static_cast<int>(m_height * svg->currentScale()); + setWidth(static_cast<int>(width() * svg->currentScale())); + setHeight(static_cast<int>(height() * svg->currentScale())); for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { if (selfNeedsLayout()) // either bounds or transform changed, force kids to relayout - child->setNeedsLayout(true); + child->setNeedsLayout(true, false); child->layoutIfNeeded(); ASSERT(!child->needsLayout()); @@ -125,30 +125,30 @@ void RenderSVGRoot::applyContentTransforms(PaintInfo& paintInfo, int parentX, in // Translate from parent offsets (html renderers) to a relative transform (svg renderers) IntPoint origin; origin.move(parentX, parentY); - origin.move(m_x, m_y); + origin.move(x(), y()); origin.move(borderLeft(), borderTop()); origin.move(paddingLeft(), paddingTop()); if (origin.x() || origin.y()) { - paintInfo.context->concatCTM(AffineTransform().translate(origin.x(), origin.y())); + paintInfo.context->concatCTM(TransformationMatrix().translate(origin.x(), origin.y())); paintInfo.rect.move(-origin.x(), -origin.y()); } // Respect scroll offset caused by html parents - AffineTransform ctm = RenderContainer::absoluteTransform(); + TransformationMatrix ctm = RenderContainer::absoluteTransform(); paintInfo.rect.move(static_cast<int>(ctm.e()), static_cast<int>(ctm.f())); SVGSVGElement* svg = static_cast<SVGSVGElement*>(element()); - paintInfo.context->concatCTM(AffineTransform().scale(svg->currentScale())); + paintInfo.context->concatCTM(TransformationMatrix().scale(svg->currentScale())); if (!viewport().isEmpty()) { if (style()->overflowX() != OVISIBLE) paintInfo.context->clip(enclosingIntRect(viewport())); // FIXME: Eventually we'll want float-precision clipping - paintInfo.context->concatCTM(AffineTransform().translate(viewport().x(), viewport().y())); + paintInfo.context->concatCTM(TransformationMatrix().translate(viewport().x(), viewport().y())); } - paintInfo.context->concatCTM(AffineTransform().translate(svg->currentTranslate().x(), svg->currentTranslate().y())); + paintInfo.context->concatCTM(TransformationMatrix().translate(svg->currentTranslate().x(), svg->currentTranslate().y())); } void RenderSVGRoot::paint(PaintInfo& paintInfo, int parentX, int parentY) @@ -165,7 +165,7 @@ void RenderSVGRoot::paint(PaintInfo& paintInfo, int parentX, int parentY) // This should only exist for <svg> renderers if (hasBoxDecorations() && (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection)) - paintBoxDecorations(paintInfo, m_x + parentX, m_y + parentY); + paintBoxDecorations(paintInfo, x() + parentX, y() + parentY); if (!firstChild()) { #if ENABLE(SVG_FILTERS) @@ -231,12 +231,12 @@ void RenderSVGRoot::calcViewport() } } -IntRect RenderSVGRoot::absoluteClippedOverflowRect() +IntRect RenderSVGRoot::clippedOverflowRectForRepaint(RenderBox* repaintContainer) { IntRect repaintRect; for (RenderObject* current = firstChild(); current != 0; current = current->nextSibling()) - repaintRect.unite(current->absoluteClippedOverflowRect()); + repaintRect.unite(current->clippedOverflowRectForRepaint(repaintContainer)); #if ENABLE(SVG_FILTERS) // Filters can expand the bounding box @@ -259,10 +259,16 @@ void RenderSVGRoot::absoluteRects(Vector<IntRect>& rects, int, int) current->absoluteRects(rects, 0, 0); } -AffineTransform RenderSVGRoot::absoluteTransform() const +void RenderSVGRoot::absoluteQuads(Vector<FloatQuad>& quads, bool) { - AffineTransform ctm = RenderContainer::absoluteTransform(); - ctm.translate(m_x, m_y); + for (RenderObject* current = firstChild(); current != 0; current = current->nextSibling()) + current->absoluteQuads(quads); +} + +TransformationMatrix RenderSVGRoot::absoluteTransform() const +{ + TransformationMatrix ctm = RenderContainer::absoluteTransform(); + ctm.translate(x(), y()); SVGSVGElement* svg = static_cast<SVGSVGElement*>(element()); ctm.scale(svg->currentScale()); ctm.translate(svg->currentTranslate().x(), svg->currentTranslate().y()); @@ -287,14 +293,14 @@ FloatRect RenderSVGRoot::relativeBBox(bool includeStroke) const return rect; } -AffineTransform RenderSVGRoot::localTransform() const +TransformationMatrix RenderSVGRoot::localTransform() const { - return AffineTransform(); + return TransformationMatrix(); } bool RenderSVGRoot::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction) { - AffineTransform ctm = RenderContainer::absoluteTransform(); + TransformationMatrix ctm = RenderContainer::absoluteTransform(); int sx = (_tx - static_cast<int>(ctm.e())); // scroll offset int sy = (_ty - static_cast<int>(ctm.f())); // scroll offset @@ -302,8 +308,8 @@ bool RenderSVGRoot::nodeAtPoint(const HitTestRequest& request, HitTestResult& re if (!viewport().isEmpty() && style()->overflowX() == OHIDDEN && style()->overflowY() == OHIDDEN) { - int tx = m_x - _tx + sx; - int ty = m_y - _ty + sy; + int tx = x() - _tx + sx; + int ty = y() - _ty + sy; // Check if we need to do anything at all. IntRect overflowBox = overflowRect(false); @@ -327,6 +333,13 @@ bool RenderSVGRoot::nodeAtPoint(const HitTestRequest& request, HitTestResult& re return false; } +void RenderSVGRoot::position(InlineBox* box) +{ + RenderContainer::position(box); + if (m_absoluteBounds.isEmpty()) + setNeedsLayout(true, false); +} + } #endif // ENABLE(SVG) diff --git a/WebCore/rendering/RenderSVGRoot.h b/WebCore/rendering/RenderSVGRoot.h index 58359fd..048fc8b 100644 --- a/WebCore/rendering/RenderSVGRoot.h +++ b/WebCore/rendering/RenderSVGRoot.h @@ -30,7 +30,7 @@ namespace WebCore { class SVGStyledElement; -class AffineTransform; +class TransformationMatrix; class RenderSVGRoot : public RenderContainer { public: @@ -47,21 +47,24 @@ public: virtual void layout(); virtual void paint(PaintInfo&, int parentX, int parentY); - virtual IntRect absoluteClippedOverflowRect(); + virtual IntRect clippedOverflowRectForRepaint(RenderBox* repaintContainer); virtual void absoluteRects(Vector<IntRect>& rects, int tx, int ty); + virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true); virtual void addFocusRingRects(GraphicsContext*, int tx, int ty); - virtual AffineTransform absoluteTransform() const; + virtual TransformationMatrix absoluteTransform() const; bool fillContains(const FloatPoint&) const; bool strokeContains(const FloatPoint&) const; FloatRect relativeBBox(bool includeStroke = true) const; - virtual AffineTransform localTransform() const; + virtual TransformationMatrix localTransform() const; FloatRect viewport() const; virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); + + virtual void position(InlineBox*); private: void calcViewport(); diff --git a/WebCore/rendering/RenderSVGTSpan.cpp b/WebCore/rendering/RenderSVGTSpan.cpp index a8d6c57..49c45df 100644 --- a/WebCore/rendering/RenderSVGTSpan.cpp +++ b/WebCore/rendering/RenderSVGTSpan.cpp @@ -26,7 +26,8 @@ #if ENABLE(SVG) #include "RenderSVGTSpan.h" -#include "FloatRect.h" +#include "FloatQuad.h" +#include "RenderBlock.h" #include "SVGInlineTextBox.h" #include "SVGRootInlineBox.h" @@ -42,20 +43,41 @@ void RenderSVGTSpan::absoluteRects(Vector<IntRect>& rects, int, int, bool) InlineRunBox* firstBox = firstLineBox(); SVGRootInlineBox* rootBox = firstBox ? static_cast<SVGInlineTextBox*>(firstBox)->svgRootInlineBox() : 0; - RenderObject* object = rootBox ? rootBox->object() : 0; + RenderBox* object = rootBox ? rootBox->block() : 0; if (!object) return; - int xRef = object->xPos() + xPos(); - int yRef = object->yPos() + yPos(); + int xRef = object->x() + x(); + int yRef = object->y() + y(); for (InlineRunBox* curr = firstBox; curr; curr = curr->nextLineBox()) { FloatRect rect(xRef + curr->xPos(), yRef + curr->yPos(), curr->width(), curr->height()); + // FIXME: broken with CSS transforms rects.append(enclosingIntRect(absoluteTransform().mapRect(rect))); } } +void RenderSVGTSpan::absoluteQuads(Vector<FloatQuad>& quads, bool) +{ + InlineRunBox* firstBox = firstLineBox(); + + SVGRootInlineBox* rootBox = firstBox ? static_cast<SVGInlineTextBox*>(firstBox)->svgRootInlineBox() : 0; + RenderBox* object = rootBox ? rootBox->block() : 0; + + if (!object) + return; + + int xRef = object->x() + x(); + int yRef = object->y() + y(); + + for (InlineRunBox* curr = firstBox; curr; curr = curr->nextLineBox()) { + FloatRect rect(xRef + curr->xPos(), yRef + curr->yPos(), curr->width(), curr->height()); + // FIXME: broken with CSS transforms + quads.append(absoluteTransform().mapRect(rect)); + } +} + } #endif // ENABLE(SVG) diff --git a/WebCore/rendering/RenderSVGTSpan.h b/WebCore/rendering/RenderSVGTSpan.h index cabf2ef..d34cd2f 100644 --- a/WebCore/rendering/RenderSVGTSpan.h +++ b/WebCore/rendering/RenderSVGTSpan.h @@ -33,6 +33,7 @@ public: RenderSVGTSpan(Node*); virtual const char* renderName() const { return "RenderSVGTSpan"; } virtual void absoluteRects(Vector<IntRect>& rects, int tx, int ty, bool topLevel = true); + virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true); }; } diff --git a/WebCore/rendering/RenderSVGText.cpp b/WebCore/rendering/RenderSVGText.cpp index 2f0e2d6..ee5ab34 100644 --- a/WebCore/rendering/RenderSVGText.cpp +++ b/WebCore/rendering/RenderSVGText.cpp @@ -30,16 +30,17 @@ #include "RenderSVGText.h" #include "FloatConversion.h" +#include "FloatQuad.h" #include "GraphicsContext.h" #include "PointerEventsHitRules.h" #include "RenderSVGRoot.h" -#include "SimpleFontData.h" #include "SVGLengthList.h" #include "SVGResourceFilter.h" #include "SVGRootInlineBox.h" #include "SVGTextElement.h" #include "SVGTransformList.h" #include "SVGURIReference.h" +#include "SimpleFontData.h" namespace WebCore { @@ -48,8 +49,9 @@ RenderSVGText::RenderSVGText(SVGTextElement* node) { } -IntRect RenderSVGText::absoluteClippedOverflowRect() +IntRect RenderSVGText::clippedOverflowRectForRepaint(RenderBox* /*repaintContainer*/) { + // FIXME: handle non-root repaintContainer FloatRect repaintRect = absoluteTransform().mapRect(relativeBBox(true)); #if ENABLE(SVG_FILTERS) @@ -65,14 +67,9 @@ IntRect RenderSVGText::absoluteClippedOverflowRect() return enclosingIntRect(repaintRect); } -bool RenderSVGText::requiresLayer() -{ - return false; -} - bool RenderSVGText::calculateLocalTransform() { - AffineTransform oldTransform = m_localTransform; + TransformationMatrix oldTransform = m_localTransform; m_localTransform = static_cast<SVGTextElement*>(element())->animatedLocalTransform(); return (oldTransform != m_localTransform); } @@ -89,14 +86,14 @@ void RenderSVGText::layout() bool checkForRepaint = checkForRepaintDuringLayout(); if (checkForRepaint) { oldBounds = m_absoluteBounds; - oldOutlineBox = absoluteOutlineBox(); + oldOutlineBox = absoluteOutlineBounds(); } // Best guess for a relative starting point SVGTextElement* text = static_cast<SVGTextElement*>(element()); int xOffset = (int)(text->x()->getFirst().value(text)); int yOffset = (int)(text->y()->getFirst().value(text)); - setPos(xOffset, yOffset); + setLocation(xOffset, yOffset); calculateLocalTransform(); @@ -111,9 +108,9 @@ void RenderSVGText::layout() setNeedsLayout(false); } -InlineBox* RenderSVGText::createInlineBox(bool makePlaceHolderBox, bool isRootLineBox, bool isOnlyRun) +InlineBox* RenderSVGText::createInlineBox(bool, bool, bool) { - ASSERT(!isInlineFlow()); + ASSERT(!isRenderInline()); InlineFlowBox* flowBox = new (renderArena()) SVGRootInlineBox(this); if (!m_firstLineBox) @@ -129,12 +126,12 @@ InlineBox* RenderSVGText::createInlineBox(bool makePlaceHolderBox, bool isRootLi bool RenderSVGText::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction) { - PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_TEXT_HITTESTING, style()->svgStyle()->pointerEvents()); + PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_TEXT_HITTESTING, style()->pointerEvents()); bool isVisible = (style()->visibility() == VISIBLE); if (isVisible || !hitRules.requireVisible) { if ((hitRules.canHitStroke && (style()->svgStyle()->hasStroke() || !hitRules.requireStroke)) || (hitRules.canHitFill && (style()->svgStyle()->hasFill() || !hitRules.requireFill))) { - AffineTransform totalTransform = absoluteTransform(); + TransformationMatrix totalTransform = absoluteTransform(); double localX, localY; totalTransform.inverse().map(_x, _y, &localX, &localY); FloatPoint hitPoint(_x, _y); @@ -151,10 +148,9 @@ void RenderSVGText::absoluteRects(Vector<IntRect>& rects, int, int, bool) if (!root) return; - int x, y; - absolutePosition(x, y); + FloatPoint absPos = localToAbsolute(); - AffineTransform htmlParentCtm = root->RenderContainer::absoluteTransform(); + TransformationMatrix htmlParentCtm = root->RenderContainer::absoluteTransform(); // Don't use relativeBBox here, as it's unites the selection rects. Makes it hard // to spot errors, if there are any using WebInspector. Individually feed them into 'rects'. @@ -164,12 +160,38 @@ void RenderSVGText::absoluteRects(Vector<IntRect>& rects, int, int, bool) InlineFlowBox* flowBox = static_cast<InlineFlowBox*>(runBox); for (InlineBox* box = flowBox->firstChild(); box; box = box->nextOnLine()) { FloatRect boxRect(box->xPos(), box->yPos(), box->width(), box->height()); - boxRect.move(narrowPrecisionToFloat(x - htmlParentCtm.e()), narrowPrecisionToFloat(y - htmlParentCtm.f())); + boxRect.move(narrowPrecisionToFloat(absPos.x() - htmlParentCtm.e()), narrowPrecisionToFloat(absPos.y() - htmlParentCtm.f())); + // FIXME: broken with CSS transforms rects.append(enclosingIntRect(absoluteTransform().mapRect(boxRect))); } } } +void RenderSVGText::absoluteQuads(Vector<FloatQuad>& quads, bool) +{ + RenderSVGRoot* root = findSVGRootObject(parent()); + if (!root) + return; + + FloatPoint absPos = localToAbsolute(); + + TransformationMatrix htmlParentCtm = root->RenderContainer::absoluteTransform(); + + // Don't use relativeBBox here, as it's unites the selection rects. Makes it hard + // to spot errors, if there are any using WebInspector. Individually feed them into 'rects'. + for (InlineRunBox* runBox = firstLineBox(); runBox; runBox = runBox->nextLineBox()) { + ASSERT(runBox->isInlineFlowBox()); + + InlineFlowBox* flowBox = static_cast<InlineFlowBox*>(runBox); + for (InlineBox* box = flowBox->firstChild(); box; box = box->nextOnLine()) { + FloatRect boxRect(box->xPos(), box->yPos(), box->width(), box->height()); + boxRect.move(narrowPrecisionToFloat(absPos.x() - htmlParentCtm.e()), narrowPrecisionToFloat(absPos.y() - htmlParentCtm.f())); + // FIXME: broken with CSS transforms + quads.append(absoluteTransform().mapRect(boxRect)); + } + } +} + void RenderSVGText::paint(PaintInfo& paintInfo, int, int) { RenderObject::PaintInfo pi(paintInfo); @@ -206,7 +228,7 @@ FloatRect RenderSVGText::relativeBBox(bool includeStroke) const repaintRect.inflate(strokeWidth); } - repaintRect.move(xPos(), yPos()); + repaintRect.move(x(), y()); return repaintRect; } diff --git a/WebCore/rendering/RenderSVGText.h b/WebCore/rendering/RenderSVGText.h index ceadc82..4592f4e 100644 --- a/WebCore/rendering/RenderSVGText.h +++ b/WebCore/rendering/RenderSVGText.h @@ -26,7 +26,7 @@ #if ENABLE(SVG) -#include "AffineTransform.h" +#include "TransformationMatrix.h" #include "RenderSVGBlock.h" namespace WebCore { @@ -42,22 +42,24 @@ public: virtual bool isSVGText() const { return true; } bool calculateLocalTransform(); - virtual AffineTransform localTransform() const { return m_localTransform; } + virtual TransformationMatrix localTransform() const { return m_localTransform; } virtual void paint(PaintInfo&, int tx, int ty); virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); - virtual bool requiresLayer(); + virtual bool requiresLayer() const { return false; } virtual void layout(); virtual void absoluteRects(Vector<IntRect>&, int tx, int ty, bool topLevel = true); - virtual IntRect absoluteClippedOverflowRect(); + virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true); + + virtual IntRect clippedOverflowRectForRepaint(RenderBox* repaintContainer); virtual FloatRect relativeBBox(bool includeStroke = true) const; virtual InlineBox* createInlineBox(bool makePlaceHolderBox, bool isRootLineBox, bool isOnlyRun = false); private: - AffineTransform m_localTransform; + TransformationMatrix m_localTransform; IntRect m_absoluteBounds; }; diff --git a/WebCore/rendering/RenderSVGTextPath.cpp b/WebCore/rendering/RenderSVGTextPath.cpp index 53aa937..2d2894f 100644 --- a/WebCore/rendering/RenderSVGTextPath.cpp +++ b/WebCore/rendering/RenderSVGTextPath.cpp @@ -25,7 +25,8 @@ #if ENABLE(SVG) #include "RenderSVGTextPath.h" -#include "FloatRect.h" +#include "FloatQuad.h" +#include "RenderBlock.h" #include "SVGInlineTextBox.h" #include "SVGPathElement.h" #include "SVGRootInlineBox.h" @@ -82,20 +83,41 @@ void RenderSVGTextPath::absoluteRects(Vector<IntRect>& rects, int, int) InlineRunBox* firstBox = firstLineBox(); SVGRootInlineBox* rootBox = firstBox ? static_cast<SVGInlineTextBox*>(firstBox)->svgRootInlineBox() : 0; - RenderObject* object = rootBox ? rootBox->object() : 0; + RenderBlock* object = rootBox ? rootBox->block() : 0; if (!object) return; - int xRef = object->xPos() + xPos(); - int yRef = object->yPos() + yPos(); + int xRef = object->x() + x(); + int yRef = object->y() + y(); for (InlineRunBox* curr = firstBox; curr; curr = curr->nextLineBox()) { FloatRect rect(xRef + curr->xPos(), yRef + curr->yPos(), curr->width(), curr->height()); + // FIXME: broken with CSS transforms rects.append(enclosingIntRect(absoluteTransform().mapRect(rect))); } } +void RenderSVGTextPath::absoluteQuads(Vector<FloatQuad>& quads, bool) +{ + InlineRunBox* firstBox = firstLineBox(); + + SVGRootInlineBox* rootBox = firstBox ? static_cast<SVGInlineTextBox*>(firstBox)->svgRootInlineBox() : 0; + RenderBlock* object = rootBox ? rootBox->block() : 0; + + if (!object) + return; + + int xRef = object->x() + x(); + int yRef = object->y() + y(); + + for (InlineRunBox* curr = firstBox; curr; curr = curr->nextLineBox()) { + FloatRect rect(xRef + curr->xPos(), yRef + curr->yPos(), curr->width(), curr->height()); + // FIXME: broken with CSS transforms + quads.append(absoluteTransform().mapRect(rect)); + } +} + } #endif // ENABLE(SVG) diff --git a/WebCore/rendering/RenderSVGTextPath.h b/WebCore/rendering/RenderSVGTextPath.h index 2a66f65..4fd4cc3 100644 --- a/WebCore/rendering/RenderSVGTextPath.h +++ b/WebCore/rendering/RenderSVGTextPath.h @@ -39,6 +39,7 @@ namespace WebCore { virtual const char* renderName() const { return "RenderSVGTextPath"; } virtual void absoluteRects(Vector<IntRect>& rects, int tx, int ty); + virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true); private: float m_startOffset; diff --git a/WebCore/rendering/RenderSVGTransformableContainer.cpp b/WebCore/rendering/RenderSVGTransformableContainer.cpp index 98eaab0..17d64f3 100644 --- a/WebCore/rendering/RenderSVGTransformableContainer.cpp +++ b/WebCore/rendering/RenderSVGTransformableContainer.cpp @@ -37,7 +37,7 @@ RenderSVGTransformableContainer::RenderSVGTransformableContainer(SVGStyledTransf bool RenderSVGTransformableContainer::calculateLocalTransform() { - AffineTransform oldTransform = m_localTransform; + TransformationMatrix oldTransform = m_localTransform; m_localTransform = static_cast<SVGStyledTransformableElement*>(element())->animatedLocalTransform(); return (m_localTransform != oldTransform); } diff --git a/WebCore/rendering/RenderSVGViewportContainer.cpp b/WebCore/rendering/RenderSVGViewportContainer.cpp index b6d527b..4282efc 100644 --- a/WebCore/rendering/RenderSVGViewportContainer.cpp +++ b/WebCore/rendering/RenderSVGViewportContainer.cpp @@ -37,7 +37,6 @@ namespace WebCore { RenderSVGViewportContainer::RenderSVGViewportContainer(SVGStyledElement* node) : RenderSVGContainer(node) { - setReplaced(true); } RenderSVGViewportContainer::~RenderSVGViewportContainer() @@ -57,7 +56,7 @@ void RenderSVGViewportContainer::layout() IntRect oldOutlineBox; bool checkForRepaint = checkForRepaintDuringLayout() && selfNeedsLayout(); if (checkForRepaint) - oldOutlineBox = absoluteOutlineBox(); + oldOutlineBox = absoluteOutlineBounds(); calcBounds(); @@ -91,7 +90,7 @@ void RenderSVGViewportContainer::applyContentTransforms(PaintInfo& paintInfo) if (style()->overflowX() != OVISIBLE) paintInfo.context->clip(enclosingIntRect(viewport())); // FIXME: Eventually we'll want float-precision clipping - paintInfo.context->concatCTM(AffineTransform().translate(viewport().x(), viewport().y())); + paintInfo.context->concatCTM(TransformationMatrix().translate(viewport().x(), viewport().y())); } RenderSVGContainer::applyContentTransforms(paintInfo); @@ -133,7 +132,7 @@ void RenderSVGViewportContainer::calcViewport() } } -AffineTransform RenderSVGViewportContainer::viewportTransform() const +TransformationMatrix RenderSVGViewportContainer::viewportTransform() const { if (element()->hasTagName(SVGNames::svgTag)) { SVGSVGElement* svg = static_cast<SVGSVGElement*>(element()); @@ -143,12 +142,12 @@ AffineTransform RenderSVGViewportContainer::viewportTransform() const return marker->viewBoxToViewTransform(viewport().width(), viewport().height()); } - return AffineTransform(); + return TransformationMatrix(); } -AffineTransform RenderSVGViewportContainer::absoluteTransform() const +TransformationMatrix RenderSVGViewportContainer::absoluteTransform() const { - AffineTransform ctm = RenderObject::absoluteTransform(); + TransformationMatrix ctm = RenderObject::absoluteTransform(); ctm.translate(viewport().x(), viewport().y()); return viewportTransform() * ctm; } @@ -159,9 +158,9 @@ bool RenderSVGViewportContainer::nodeAtPoint(const HitTestRequest& request, HitT && style()->overflowX() == OHIDDEN && style()->overflowY() == OHIDDEN) { // Check if we need to do anything at all. - IntRect overflowBox = overflowRect(false); + IntRect overflowBox = IntRect(0, 0, width(), height()); overflowBox.move(_tx, _ty); - AffineTransform ctm = RenderObject::absoluteTransform(); + TransformationMatrix ctm = RenderObject::absoluteTransform(); ctm.translate(viewport().x(), viewport().y()); double localX, localY; ctm.inverse().map(_x - _tx, _y - _ty, &localX, &localY); diff --git a/WebCore/rendering/RenderSVGViewportContainer.h b/WebCore/rendering/RenderSVGViewportContainer.h index 23a885f..2e4a49c 100644 --- a/WebCore/rendering/RenderSVGViewportContainer.h +++ b/WebCore/rendering/RenderSVGViewportContainer.h @@ -40,8 +40,8 @@ public: virtual void layout(); virtual void paint(PaintInfo&, int parentX, int parentY); - virtual AffineTransform absoluteTransform() const; - virtual AffineTransform viewportTransform() const; + virtual TransformationMatrix absoluteTransform() const; + virtual TransformationMatrix viewportTransform() const; virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); diff --git a/WebCore/rendering/RenderScrollbar.cpp b/WebCore/rendering/RenderScrollbar.cpp index b7045d6..d6dd9cc 100644 --- a/WebCore/rendering/RenderScrollbar.cpp +++ b/WebCore/rendering/RenderScrollbar.cpp @@ -30,12 +30,12 @@ namespace WebCore { -PassRefPtr<Scrollbar> RenderScrollbar::createCustomScrollbar(ScrollbarClient* client, ScrollbarOrientation orientation, RenderObject* renderer) +PassRefPtr<Scrollbar> RenderScrollbar::createCustomScrollbar(ScrollbarClient* client, ScrollbarOrientation orientation, RenderBox* renderer) { return adoptRef(new RenderScrollbar(client, orientation, renderer)); } -RenderScrollbar::RenderScrollbar(ScrollbarClient* client, ScrollbarOrientation orientation, RenderObject* renderer) +RenderScrollbar::RenderScrollbar(ScrollbarClient* client, ScrollbarOrientation orientation, RenderBox* renderer) : Scrollbar(client, orientation, RegularScrollbar, RenderScrollbarTheme::renderScrollbarTheme()) , m_owner(renderer) { @@ -50,7 +50,7 @@ void RenderScrollbar::setParent(ScrollView* parent) { Scrollbar::setParent(parent); if (!parent) { - // Destroy all of the scrollbar's RenderObjects. + // Destroy all of the scrollbar's RenderBoxes. updateScrollbarParts(true); } } diff --git a/WebCore/rendering/RenderScrollbar.h b/WebCore/rendering/RenderScrollbar.h index ad97001..cc43a00 100644 --- a/WebCore/rendering/RenderScrollbar.h +++ b/WebCore/rendering/RenderScrollbar.h @@ -32,17 +32,17 @@ namespace WebCore { -class RenderObject; +class RenderBox; class RenderScrollbarPart; class RenderStyle; class RenderScrollbar : public Scrollbar { protected: - RenderScrollbar(ScrollbarClient*, ScrollbarOrientation, RenderObject*); + RenderScrollbar(ScrollbarClient*, ScrollbarOrientation, RenderBox*); public: friend class Scrollbar; - static PassRefPtr<Scrollbar> createCustomScrollbar(ScrollbarClient*, ScrollbarOrientation, RenderObject*); + static PassRefPtr<Scrollbar> createCustomScrollbar(ScrollbarClient*, ScrollbarOrientation, RenderBox*); virtual ~RenderScrollbar(); virtual void setParent(ScrollView*); @@ -60,7 +60,7 @@ public: virtual void styleChanged(); - RenderObject* owningRenderer() const { return m_owner; } + RenderBox* owningRenderer() const { return m_owner; } void paintPart(GraphicsContext*, ScrollbarPart, const IntRect&); @@ -74,7 +74,7 @@ private: PassRefPtr<RenderStyle> getScrollbarPseudoStyle(ScrollbarPart, RenderStyle::PseudoId); void updateScrollbarPart(ScrollbarPart, bool destroy = false); - RenderObject* m_owner; + RenderBox* m_owner; HashMap<unsigned, RenderScrollbarPart*> m_parts; }; diff --git a/WebCore/rendering/RenderScrollbarPart.cpp b/WebCore/rendering/RenderScrollbarPart.cpp index d5e72e9..6749d8c 100644 --- a/WebCore/rendering/RenderScrollbarPart.cpp +++ b/WebCore/rendering/RenderScrollbarPart.cpp @@ -45,14 +45,14 @@ RenderScrollbarPart::~RenderScrollbarPart() void RenderScrollbarPart::layout() { - setPos(0, 0); // We don't worry about positioning ourselves. We're just determining our minimum width/height. + setLocation(IntPoint()); // We don't worry about positioning ourselves. We're just determining our minimum width/height. if (m_scrollbar->orientation() == HorizontalScrollbar) layoutHorizontalPart(); else layoutVerticalPart(); - m_overflowWidth = max(m_width, m_overflowWidth); - m_overflowHeight = max(m_height, m_overflowHeight); + m_overflowWidth = max(width(), m_overflowWidth); + m_overflowHeight = max(height(), m_overflowHeight); setNeedsLayout(false); } @@ -60,11 +60,11 @@ void RenderScrollbarPart::layout() void RenderScrollbarPart::layoutHorizontalPart() { if (m_part == ScrollbarBGPart) { - m_width = m_scrollbar->width(); + setWidth(m_scrollbar->width()); computeScrollbarHeight(); } else { computeScrollbarWidth(); - m_height = m_scrollbar->height(); + setHeight(m_scrollbar->height()); } } @@ -72,9 +72,9 @@ void RenderScrollbarPart::layoutVerticalPart() { if (m_part == ScrollbarBGPart) { computeScrollbarWidth(); - m_height = m_scrollbar->height(); + setHeight(m_scrollbar->height()); } else { - m_width = m_scrollbar->width(); + setWidth(m_scrollbar->width()); computeScrollbarHeight(); } } @@ -89,10 +89,10 @@ static int calcScrollbarThicknessUsing(const Length& l, int containingLength) void RenderScrollbarPart::computeScrollbarWidth() { int visibleSize = m_scrollbar->owningRenderer()->width() - m_scrollbar->owningRenderer()->borderLeft() - m_scrollbar->owningRenderer()->borderRight(); - int width = calcScrollbarThicknessUsing(style()->width(), visibleSize); + int w = calcScrollbarThicknessUsing(style()->width(), visibleSize); int minWidth = calcScrollbarThicknessUsing(style()->minWidth(), visibleSize); - int maxWidth = style()->maxWidth().isUndefined() ? width : calcScrollbarThicknessUsing(style()->maxWidth(), visibleSize); - m_width = max(minWidth, min(maxWidth, width)); + int maxWidth = style()->maxWidth().isUndefined() ? w : calcScrollbarThicknessUsing(style()->maxWidth(), visibleSize); + setWidth(max(minWidth, min(maxWidth, w))); // Buttons and track pieces can all have margins along the axis of the scrollbar. m_marginLeft = style()->marginLeft().calcMinValue(visibleSize); @@ -102,10 +102,10 @@ void RenderScrollbarPart::computeScrollbarWidth() void RenderScrollbarPart::computeScrollbarHeight() { int visibleSize = m_scrollbar->owningRenderer()->height() - m_scrollbar->owningRenderer()->borderTop() - m_scrollbar->owningRenderer()->borderBottom(); - int height = calcScrollbarThicknessUsing(style()->height(), visibleSize); + int h = calcScrollbarThicknessUsing(style()->height(), visibleSize); int minHeight = calcScrollbarThicknessUsing(style()->minHeight(), visibleSize); - int maxHeight = style()->maxHeight().isUndefined() ? height : calcScrollbarThicknessUsing(style()->maxHeight(), visibleSize); - m_height = max(minHeight, min(maxHeight, height)); + int maxHeight = style()->maxHeight().isUndefined() ? h : calcScrollbarThicknessUsing(style()->maxHeight(), visibleSize); + setHeight(max(minHeight, min(maxHeight, h))); // Buttons and track pieces can all have margins along the axis of the scrollbar. m_marginTop = style()->marginTop().calcMinValue(visibleSize); @@ -122,6 +122,12 @@ void RenderScrollbarPart::calcPrefWidths() setPrefWidthsDirty(false); } +void RenderScrollbarPart::styleWillChange(RenderStyle::Diff diff, const RenderStyle* newStyle) +{ + RenderBlock::styleWillChange(diff, newStyle); + setInline(false); +} + void RenderScrollbarPart::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle) { RenderBlock::styleDidChange(diff, oldStyle); @@ -133,18 +139,18 @@ void RenderScrollbarPart::styleDidChange(RenderStyle::Diff diff, const RenderSty m_scrollbar->theme()->invalidatePart(m_scrollbar, m_part); } -void RenderScrollbarPart::imageChanged(WrappedImagePtr image) +void RenderScrollbarPart::imageChanged(WrappedImagePtr image, const IntRect* rect) { if (m_scrollbar && m_part != NoPart) m_scrollbar->theme()->invalidatePart(m_scrollbar, m_part); else - RenderBlock::imageChanged(image); + RenderBlock::imageChanged(image, rect); } void RenderScrollbarPart::paintIntoRect(GraphicsContext* graphicsContext, int tx, int ty, const IntRect& rect) { // Make sure our dimensions match the rect. - setPos(rect.x() - tx, rect.y() - ty); + setLocation(rect.x() - tx, rect.y() - ty); setWidth(rect.width()); setHeight(rect.height()); setOverflowWidth(max(rect.width(), overflowWidth())); diff --git a/WebCore/rendering/RenderScrollbarPart.h b/WebCore/rendering/RenderScrollbarPart.h index fa13774..7dae6e7 100644 --- a/WebCore/rendering/RenderScrollbarPart.h +++ b/WebCore/rendering/RenderScrollbarPart.h @@ -40,7 +40,7 @@ public: virtual const char* renderName() const { return "RenderScrollbarPart"; } - virtual bool requiresLayer() { return false; } + virtual bool requiresLayer() const { return false; } virtual void layout(); virtual void calcPrefWidths(); @@ -48,8 +48,9 @@ public: void paintIntoRect(GraphicsContext*, int tx, int ty, const IntRect&); protected: + virtual void styleWillChange(RenderStyle::Diff diff, const RenderStyle* newStyle); virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle); - virtual void imageChanged(WrappedImagePtr); + virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); private: void layoutHorizontalPart(); diff --git a/WebCore/rendering/RenderScrollbarTheme.cpp b/WebCore/rendering/RenderScrollbarTheme.cpp index 2b375d0..d7cfb2b 100644 --- a/WebCore/rendering/RenderScrollbarTheme.cpp +++ b/WebCore/rendering/RenderScrollbarTheme.cpp @@ -26,12 +26,13 @@ #include "config.h" #include "RenderScrollbarTheme.h" #include "RenderScrollbar.h" +#include <wtf/StdLibExtras.h> namespace WebCore { RenderScrollbarTheme* RenderScrollbarTheme::renderScrollbarTheme() { - static RenderScrollbarTheme theme; + DEFINE_STATIC_LOCAL(RenderScrollbarTheme, theme, ()); return &theme; } diff --git a/WebCore/rendering/RenderSlider.cpp b/WebCore/rendering/RenderSlider.cpp index 221b0a2..25f3e40 100644 --- a/WebCore/rendering/RenderSlider.cpp +++ b/WebCore/rendering/RenderSlider.cpp @@ -31,6 +31,7 @@ #include "HTMLInputElement.h" #include "HTMLDivElement.h" #include "HTMLNames.h" +#include "MediaControlElements.h" #include "MouseEvent.h" #include "RenderTheme.h" #include <wtf/MathExtras.h> @@ -58,13 +59,13 @@ public: bool inDragMode() const { return m_inDragMode; } private: Node* m_shadowParent; - IntPoint m_initialClickPoint; + FloatPoint m_initialClickPoint; // initial click point in RenderSlider-local coordinates int m_initialPosition; bool m_inDragMode; }; HTMLSliderThumbElement::HTMLSliderThumbElement(Document* doc, Node* shadowParent) - : HTMLDivElement(doc) + : HTMLDivElement(divTag, doc) , m_shadowParent(shadowParent) , m_initialClickPoint(IntPoint()) , m_initialPosition(0) @@ -77,12 +78,14 @@ void HTMLSliderThumbElement::defaultEventHandler(Event* event) const AtomicString& eventType = event->type(); if (eventType == eventNames().mousedownEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) { MouseEvent* mouseEvent = static_cast<MouseEvent*>(event); - if (document()->frame() && renderer() && renderer()->parent() - && static_cast<RenderSlider*>(renderer()->parent())->mouseEventIsInThumb(mouseEvent)) { - // Cache the initial point where the mouse down occurred. - m_initialClickPoint = IntPoint(mouseEvent->pageX(), mouseEvent->pageY()); + RenderSlider* slider; + if (document()->frame() && renderer() && renderer()->parent() && + (slider = static_cast<RenderSlider*>(renderer()->parent())) && + slider->mouseEventIsInThumb(mouseEvent)) { + // Cache the initial point where the mouse down occurred, in slider coordinates + m_initialClickPoint = slider->absoluteToLocal(FloatPoint(mouseEvent->pageX(), mouseEvent->pageY()), false, true); // Cache the initial position of the thumb. - m_initialPosition = static_cast<RenderSlider*>(renderer()->parent())->currentPosition(); + m_initialPosition = slider->currentPosition(); m_inDragMode = true; document()->frame()->eventHandler()->setCapturingMouseEventsNode(m_shadowParent); @@ -103,11 +106,12 @@ void HTMLSliderThumbElement::defaultEventHandler(Event* event) // Move the slider MouseEvent* mouseEvent = static_cast<MouseEvent*>(event); RenderSlider* slider = static_cast<RenderSlider*>(renderer()->parent()); + FloatPoint curPoint = slider->absoluteToLocal(FloatPoint(mouseEvent->pageX(), mouseEvent->pageY()), false, true); int newPosition = slider->positionForOffset( - IntPoint(m_initialPosition + mouseEvent->pageX() - m_initialClickPoint.x() - + (renderer()->width() / 2), - m_initialPosition + mouseEvent->pageY() - m_initialClickPoint.y() - + (renderer()->height() / 2))); + IntPoint(m_initialPosition + curPoint.x() - m_initialClickPoint.x() + + (renderBox()->width() / 2), + m_initialPosition + curPoint.y() - m_initialClickPoint.y() + + (renderBox()->height() / 2))); if (slider->currentPosition() != newPosition) { slider->setCurrentPosition(newPosition); slider->valueChanged(); @@ -132,7 +136,7 @@ RenderSlider::~RenderSlider() m_thumb->detach(); } -int RenderSlider::baselinePosition(bool b, bool isRootLineBox) const +int RenderSlider::baselinePosition(bool, bool) const { return height() + marginTop(); } @@ -217,12 +221,12 @@ void RenderSlider::layout() int oldVisibleWidth = m_visibleWidth; #endif - int oldWidth = m_width; + int oldWidth = width(); calcWidth(); - int oldHeight = m_height; + int oldHeight = height(); calcHeight(); - if (oldWidth != m_width || oldHeight != m_height) + if (oldWidth != width() || oldHeight != height()) relayoutChildren = true; #ifdef ANDROID_LAYOUT @@ -264,16 +268,26 @@ void RenderSlider::updateFromElement() addChild(m_thumb->renderer()); } setPositionFromValue(); - setNeedsLayout(true); + setNeedsLayout(true, false); } bool RenderSlider::mouseEventIsInThumb(MouseEvent* evt) { if (!m_thumb || !m_thumb->renderer()) return false; - - IntRect thumbBounds = m_thumb->renderer()->absoluteBoundingBoxRect(); - return thumbBounds.contains(evt->pageX(), evt->pageY()); + +#if ENABLE(VIDEO) + if (style()->appearance() == MediaSliderPart) { + MediaControlInputElement *sliderThumb = static_cast<MediaControlInputElement*>(m_thumb->renderer()->node()); + IntPoint absPoint(evt->pageX(), evt->pageY()); + return sliderThumb->hitTest(absPoint); + } else +#endif + { + FloatPoint localPoint = m_thumb->renderBox()->absoluteToLocal(FloatPoint(evt->pageX(), evt->pageY()), false, true); + IntRect thumbBounds = m_thumb->renderBox()->borderBoxRect(); + return thumbBounds.contains(roundedIntPoint(localPoint)); + } } void RenderSlider::setValueForPosition(int position) @@ -353,9 +367,9 @@ int RenderSlider::positionForOffset(const IntPoint& p) int position; if (style()->appearance() == SliderVerticalPart) - position = p.y() - m_thumb->renderer()->height() / 2; + position = p.y() - m_thumb->renderBox()->height() / 2; else - position = p.x() - m_thumb->renderer()->width() / 2; + position = p.x() - m_thumb->renderBox()->width() / 2; return max(0, min(position, trackSize())); } @@ -386,7 +400,7 @@ void RenderSlider::setCurrentPosition(int pos) else m_thumb->renderer()->style()->setLeft(Length(pos, Fixed)); - m_thumb->renderer()->layer()->updateLayerPosition(); + m_thumb->renderBox()->layer()->updateLayerPosition(); repaint(); m_thumb->renderer()->repaint(); } @@ -397,8 +411,8 @@ int RenderSlider::trackSize() return 0; if (style()->appearance() == SliderVerticalPart) - return contentHeight() - m_thumb->renderer()->height(); - return contentWidth() - m_thumb->renderer()->width(); + return contentHeight() - m_thumb->renderBox()->height(); + return contentWidth() - m_thumb->renderBox()->width(); } void RenderSlider::forwardEvent(Event* evt) diff --git a/WebCore/rendering/RenderSlider.h b/WebCore/rendering/RenderSlider.h index 2667672..95ceb0b 100644 --- a/WebCore/rendering/RenderSlider.h +++ b/WebCore/rendering/RenderSlider.h @@ -44,7 +44,7 @@ namespace WebCore { virtual void layout(); virtual void updateFromElement(); - bool mouseEventIsInThumb(MouseEvent*); + virtual bool mouseEventIsInThumb(MouseEvent*); void setValueForPosition(int position); double setPositionFromValue(bool inLayout = false); diff --git a/WebCore/rendering/RenderTable.cpp b/WebCore/rendering/RenderTable.cpp index b18ee3e..784a59a 100644 --- a/WebCore/rendering/RenderTable.cpp +++ b/WebCore/rendering/RenderTable.cpp @@ -235,12 +235,12 @@ void RenderTable::calcWidth() LengthType widthType = style()->width().type(); if (widthType > Relative && style()->width().isPositive()) { // Percent or fixed table - m_width = style()->width().calcMinValue(availableWidth); - m_width = max(minPrefWidth(), m_width); + setWidth(style()->width().calcMinValue(availableWidth)); + setWidth(max(minPrefWidth(), width())); } else { // An auto width table should shrink to fit within the line width if necessary in order to // avoid overlapping floats. - availableWidth = cb->lineWidth(m_y); + availableWidth = cb->lineWidth(y()); // Subtract out any fixed margins from our available width for auto width tables. int marginTotal = 0; @@ -253,10 +253,10 @@ void RenderTable::calcWidth() int availContentWidth = max(0, availableWidth - marginTotal); // Ensure we aren't bigger than our max width or smaller than our min width. - m_width = min(availContentWidth, maxPrefWidth()); + setWidth(min(availContentWidth, maxPrefWidth())); } - m_width = max(m_width, minPrefWidth()); + setWidth(max(width(), minPrefWidth())); // Finally, with our true width determined, compute our margins for real. m_marginRight = 0; @@ -283,12 +283,12 @@ void RenderTable::layout() bool checkForRepaint = checkForRepaintDuringLayout(); if (checkForRepaint) { oldBounds = absoluteClippedOverflowRect(); - oldOutlineBox = absoluteOutlineBox(); + oldOutlineBox = absoluteOutlineBounds(); } - view()->pushLayoutState(this, IntSize(m_x, m_y)); + LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y())); - m_height = 0; + setHeight(0); m_overflowHeight = 0; m_overflowTop = 0; initMaxMarginValues(); @@ -298,7 +298,7 @@ void RenderTable::layout() int oldVisibleWidth = m_visibleWidth; #endif - int oldWidth = m_width; + int oldWidth = width(); calcWidth(); #ifdef ANDROID_LAYOUT @@ -309,10 +309,10 @@ void RenderTable::layout() // if the width of a table is wider than its container width, or it has a nested table, // we will render it with single column. int cw = containingBlockWidth(); - if (m_width > cw || hasChildTable()) { + if (width() > cw || hasChildTable()) { m_singleColumn = true; - if (m_width > cw) - m_width = cw; + if (width() > cw) + setWidth(cw); if (m_minPrefWidth > cw) m_minPrefWidth = cw; if (m_maxPrefWidth > cw) @@ -320,14 +320,14 @@ void RenderTable::layout() } } #endif - if (m_caption && m_width != oldWidth) + if (m_caption && width() != oldWidth) m_caption->setNeedsLayout(true, false); // FIXME: The optimisation below doesn't work since the internal table // layout could have changed. we need to add a flag to the table // layout that tells us if something has changed in the min max // calculations to do it correctly. -// if ( oldWidth != m_width || columns.size() + 1 != columnPos.size() ) +// if ( oldWidth != width() || columns.size() + 1 != columnPos.size() ) m_tableLayout->layout(); setCellWidths(); @@ -347,7 +347,7 @@ void RenderTable::layout() child->layout(); } #else - if (child->needsLayout() && !(child->element() && child->element()->hasTagName(formTag))) + if (child->needsLayout() && !(child->element() && child->element()->hasTagName(formTag) && !child->isTableSection())) child->layout(); #endif if (child->isTableSection()) { @@ -355,10 +355,11 @@ void RenderTable::layout() calculatedHeight += section->calcRowHeight(); if (collapsing) section->recalcOuterBorder(); + ASSERT(!section->needsLayout()); } } - m_overflowWidth = m_width + (collapsing ? outerBorderRight() - borderRight() : 0); + m_overflowWidth = width() + (collapsing ? outerBorderRight() - borderRight() : 0); m_overflowLeft = collapsing ? borderLeft() - outerBorderLeft() : 0; // If any table section moved vertically, we will just repaint everything from that @@ -369,28 +370,28 @@ void RenderTable::layout() // FIXME: Collapse caption margin. if (m_caption && m_caption->style()->captionSide() != CAPBOTTOM) { - IntRect captionRect(m_caption->xPos(), m_caption->yPos(), m_caption->width(), m_caption->height()); + IntRect captionRect(m_caption->x(), m_caption->y(), m_caption->width(), m_caption->height()); - m_caption->setPos(m_caption->marginLeft(), m_height); + m_caption->setLocation(m_caption->marginLeft(), height()); if (!selfNeedsLayout() && m_caption->checkForRepaintDuringLayout()) m_caption->repaintDuringLayoutIfMoved(captionRect); - m_height += m_caption->height() + m_caption->marginTop() + m_caption->marginBottom(); - m_overflowLeft = min(m_overflowLeft, m_caption->xPos() + m_caption->overflowLeft(false)); - m_overflowWidth = max(m_overflowWidth, m_caption->xPos() + m_caption->overflowWidth(false)); - m_overflowTop = min(m_overflowTop, m_caption->yPos() + m_caption->overflowTop(false)); - m_overflowHeight = max(m_overflowHeight, m_caption->yPos() + m_caption->overflowHeight(false)); + setHeight(height() + m_caption->height() + m_caption->marginTop() + m_caption->marginBottom()); + m_overflowLeft = min(m_overflowLeft, m_caption->x() + m_caption->overflowLeft(false)); + m_overflowWidth = max(m_overflowWidth, m_caption->x() + m_caption->overflowWidth(false)); + m_overflowTop = min(m_overflowTop, m_caption->y() + m_caption->overflowTop(false)); + m_overflowHeight = max(m_overflowHeight, m_caption->y() + m_caption->overflowHeight(false)); - if (m_height != oldTableTop) { + if (height() != oldTableTop) { sectionMoved = true; - movedSectionTop = min(m_height, oldTableTop); + movedSectionTop = min(height(), oldTableTop); } } int bpTop = borderTop() + (collapsing ? 0 : paddingTop()); int bpBottom = borderBottom() + (collapsing ? 0 : paddingBottom()); - m_height += bpTop; + setHeight(height() + bpTop); if (!isPositioned()) calcHeight(); @@ -405,16 +406,15 @@ void RenderTable::layout() th = max(0, th); for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { - if (!child->isTableSection()) - continue; - // FIXME: Distribute extra height between all table body sections instead of giving it all to the first one. - static_cast<RenderTableSection*>(child)->layoutRows(child == m_firstBody ? max(0, th - calculatedHeight) : 0); + if (child->isTableSection()) + // FIXME: Distribute extra height between all table body sections instead of giving it all to the first one. + static_cast<RenderTableSection*>(child)->layoutRows(child == m_firstBody ? max(0, th - calculatedHeight) : 0); } if (!m_firstBody && th > calculatedHeight && !style()->htmlHacks()) { // Completely empty tables (with no sections or anything) should at least honor specified height // in strict mode. - m_height += th; + setHeight(height() + th); } int bl = borderLeft(); @@ -424,38 +424,38 @@ void RenderTable::layout() // position the table sections RenderTableSection* section = m_head ? m_head : (m_firstBody ? m_firstBody : m_foot); while (section) { - if (!sectionMoved && section->yPos() != m_height) { + if (!sectionMoved && section->y() != height()) { sectionMoved = true; - movedSectionTop = min(m_height, section->yPos()) + section->overflowTop(false); + movedSectionTop = min(height(), section->y()) + section->overflowTop(false); } - section->setPos(bl, m_height); + section->setLocation(bl, height()); - m_height += section->height(); - m_overflowLeft = min(m_overflowLeft, section->xPos() + section->overflowLeft(false)); - m_overflowWidth = max(m_overflowWidth, section->xPos() + section->overflowWidth(false)); - m_overflowTop = min(m_overflowTop, section->yPos() + section->overflowTop(false)); - m_overflowHeight = max(m_overflowHeight, section->yPos() + section->overflowHeight(false)); + setHeight(height() + section->height()); + m_overflowLeft = min(m_overflowLeft, section->x() + section->overflowLeft(false)); + m_overflowWidth = max(m_overflowWidth, section->x() + section->overflowWidth(false)); + m_overflowTop = min(m_overflowTop, section->y() + section->overflowTop(false)); + m_overflowHeight = max(m_overflowHeight, section->y() + section->overflowHeight(false)); section = sectionBelow(section); } - m_height += bpBottom; + setHeight(height() + bpBottom); if (m_caption && m_caption->style()->captionSide() == CAPBOTTOM) { - IntRect captionRect(m_caption->xPos(), m_caption->yPos(), m_caption->width(), m_caption->height()); + IntRect captionRect(m_caption->x(), m_caption->y(), m_caption->width(), m_caption->height()); - m_caption->setPos(m_caption->marginLeft(), m_height); + m_caption->setLocation(m_caption->marginLeft(), height()); if (!selfNeedsLayout() && m_caption->checkForRepaintDuringLayout()) m_caption->repaintDuringLayoutIfMoved(captionRect); - m_height += m_caption->height() + m_caption->marginTop() + m_caption->marginBottom(); - m_overflowLeft = min(m_overflowLeft, m_caption->xPos() + m_caption->overflowLeft(false)); - m_overflowWidth = max(m_overflowWidth, m_caption->xPos() + m_caption->overflowWidth(false)); + setHeight(height() + m_caption->height() + m_caption->marginTop() + m_caption->marginBottom()); + m_overflowLeft = min(m_overflowLeft, m_caption->x() + m_caption->overflowLeft(false)); + m_overflowWidth = max(m_overflowWidth, m_caption->x() + m_caption->overflowWidth(false)); } if (isPositioned()) calcHeight(); - m_overflowHeight = max(m_overflowHeight, m_height); + m_overflowHeight = max(m_overflowHeight, height()); // table can be containing block of positioned elements. // FIXME: Only pass true if width or height changed. @@ -464,9 +464,9 @@ void RenderTable::layout() if (!hasOverflowClip()) { for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next) { m_overflowLeft = min(m_overflowLeft, boxShadow->x - boxShadow->blur); - m_overflowWidth = max(m_overflowWidth, m_width + boxShadow->x + boxShadow->blur); + m_overflowWidth = max(m_overflowWidth, width() + boxShadow->x + boxShadow->blur); m_overflowTop = min(m_overflowTop, boxShadow->y - boxShadow->blur); - m_overflowHeight = max(m_overflowHeight, m_height + boxShadow->y + boxShadow->blur); + m_overflowHeight = max(m_overflowHeight, height() + boxShadow->y + boxShadow->blur); } if (hasReflection()) { @@ -478,7 +478,7 @@ void RenderTable::layout() } } - view()->popLayoutState(); + statePusher.pop(); bool didFullRepaint = true; // Repaint with our new bounds if they are different from our old bounds. @@ -500,8 +500,8 @@ void RenderTable::setCellWidths() void RenderTable::paint(PaintInfo& paintInfo, int tx, int ty) { - tx += xPos(); - ty += yPos(); + tx += x(); + ty += y(); PaintPhase paintPhase = paintInfo.phase; @@ -1181,7 +1181,7 @@ int RenderTable::getBaselineOfFirstLineBox() const if (!firstNonEmptySection) return -1; - return firstNonEmptySection->yPos() + firstNonEmptySection->getBaselineOfFirstLineBox(); + return firstNonEmptySection->y() + firstNonEmptySection->getBaselineOfFirstLineBox(); } IntRect RenderTable::getOverflowClipRect(int tx, int ty) diff --git a/WebCore/rendering/RenderTableCell.cpp b/WebCore/rendering/RenderTableCell.cpp index f8043ee..f5bf358 100644 --- a/WebCore/rendering/RenderTableCell.cpp +++ b/WebCore/rendering/RenderTableCell.cpp @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 1997 Martin Jones (mjones@kde.org) * (C) 1997 Torben Weis (weis@kde.org) * (C) 1998 Waldo Bastian (bastian@kde.org) @@ -25,6 +25,7 @@ #include "config.h" #include "RenderTableCell.h" +#include "FloatQuad.h" #include "GraphicsContext.h" #include "HTMLNames.h" #include "HTMLTableCellElement.h" @@ -48,9 +49,8 @@ RenderTableCell::RenderTableCell(Node* node) , m_column(-1) , m_rowSpan(1) , m_columnSpan(1) - , m_topExtra(0) - , m_bottomExtra(0) - , m_widthChanged(false) + , m_intrinsicPaddingTop(0) + , m_intrinsicPaddingBottom(0) , m_percentageHeight(0) { updateFromElement(); @@ -137,28 +137,44 @@ void RenderTableCell::calcWidth() #endif } -void RenderTableCell::setWidth(int width) +void RenderTableCell::updateWidth(int w) { - if (width != m_width) { - m_width = width; - m_widthChanged = true; + if (w != width()) { + setWidth(w); + m_cellWidthChanged = true; } } void RenderTableCell::layout() { - layoutBlock(m_widthChanged); - m_widthChanged = false; + layoutBlock(m_cellWidthChanged); + m_cellWidthChanged = false; } -IntRect RenderTableCell::absoluteClippedOverflowRect() +int RenderTableCell::paddingTop(bool includeIntrinsicPadding) const +{ + return RenderBlock::paddingTop() + (includeIntrinsicPadding ? intrinsicPaddingTop() : 0); +} + +int RenderTableCell::paddingBottom(bool includeIntrinsicPadding) const +{ + return RenderBlock::paddingBottom() + (includeIntrinsicPadding ? intrinsicPaddingBottom() : 0); +} + +void RenderTableCell::setOverrideSize(int size) +{ + clearIntrinsicPadding(); + RenderBlock::setOverrideSize(size); +} + +IntRect RenderTableCell::clippedOverflowRectForRepaint(RenderBox* repaintContainer) { // If the table grid is dirty, we cannot get reliable information about adjoining cells, // so we ignore outside borders. This should not be a problem because it means that // the table is going to recalculate the grid, relayout and repaint its current rect, which // includes any outside borders of this cell. if (!table()->collapseBorders() || table()->needsSectionRecalc()) - return RenderBlock::absoluteClippedOverflowRect(); + return RenderBlock::clippedOverflowRectForRepaint(repaintContainer); bool rtl = table()->style()->direction() == RTL; int outlineSize = style()->outlineSize(); @@ -191,34 +207,60 @@ IntRect RenderTableCell::absoluteClippedOverflowRect() } } left = max(left, -overflowLeft(false)); - top = max(top, -overflowTop(false) - borderTopExtra()); - IntRect r(-left, -borderTopExtra() - top, left + max(width() + right, overflowWidth(false)), borderTopExtra() + top + max(height() + bottom + borderBottomExtra(), overflowHeight(false))); + top = max(top, -overflowTop(false)); + IntRect r(-left, - top, left + max(width() + right, overflowWidth(false)), top + max(height() + bottom, overflowHeight(false))); - if (RenderView* v = view()) + if (RenderView* v = view()) { + // FIXME: layoutDelta needs to be applied in parts before/after transforms and + // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308 r.move(v->layoutDelta()); - - computeAbsoluteRepaintRect(r); + } + computeRectForRepaint(r, repaintContainer); return r; } -void RenderTableCell::computeAbsoluteRepaintRect(IntRect& r, bool fixed) +void RenderTableCell::computeRectForRepaint(IntRect& r, RenderBox* repaintContainer, bool fixed) { - r.setY(r.y() + m_topExtra); + if (repaintContainer == this) + return; + r.setY(r.y()); RenderView* v = view(); - if ((!v || !v->layoutState()) && parent()) - r.move(-parent()->xPos(), -parent()->yPos()); // Rows are in the same coordinate space, so don't add their offset in. - RenderBlock::computeAbsoluteRepaintRect(r, fixed); + if ((!v || !v->layoutStateEnabled()) && parent()) + r.move(-parentBox()->x(), -parentBox()->y()); // Rows are in the same coordinate space, so don't add their offset in. + RenderBlock::computeRectForRepaint(r, repaintContainer, fixed); } -bool RenderTableCell::absolutePosition(int& xPos, int& yPos, bool fixed) const +FloatPoint RenderTableCell::localToAbsolute(FloatPoint localPoint, bool fixed, bool useTransforms) const { - bool result = RenderBlock::absolutePosition(xPos, yPos, fixed); RenderView* v = view(); - if ((!v || !v->layoutState()) && parent()) { - xPos -= parent()->xPos(); // Rows are in the same coordinate space, so don't add their offset in. - yPos -= parent()->yPos(); + if ((!v || !v->layoutStateEnabled()) && parent()) { + // Rows are in the same coordinate space, so don't add their offset in. + localPoint.move(-parentBox()->x(), -parentBox()->y()); } - return result; + return RenderBlock::localToAbsolute(localPoint, fixed, useTransforms); +} + +FloatPoint RenderTableCell::absoluteToLocal(FloatPoint containerPoint, bool fixed, bool useTransforms) const +{ + FloatPoint localPoint = RenderBlock::absoluteToLocal(containerPoint, fixed, useTransforms); + if (parent()) { + // Rows are in the same coordinate space, so add their offset back in. + localPoint.move(parentBox()->x(), parentBox()->y()); + } + return localPoint; +} + +FloatQuad RenderTableCell::localToContainerQuad(const FloatQuad& localQuad, RenderBox* repaintContainer, bool fixed) const +{ + if (repaintContainer == this) + return localQuad; + + FloatQuad quad = localQuad; + if (parent()) { + // Rows are in the same coordinate space, so don't add their offset in. + quad.move(-parentBox()->x(), -parentBox()->y()); + } + return RenderBlock::localToContainerQuad(quad, repaintContainer, fixed); } int RenderTableCell::baselinePosition(bool /*firstLine*/, bool /*isRootLineBox*/) const @@ -226,11 +268,9 @@ int RenderTableCell::baselinePosition(bool /*firstLine*/, bool /*isRootLineBox*/ // <http://www.w3.org/TR/2007/CR-CSS21-20070719/tables.html#height-layout>: The baseline of a cell is the baseline of // the first in-flow line box in the cell, or the first in-flow table-row in the cell, whichever comes first. If there // is no such line box or table-row, the baseline is the bottom of content edge of the cell box. - int firstLineBaseline = getBaselineOfFirstLineBox(); if (firstLineBaseline != -1) return firstLineBaseline; - return paddingTop() + borderTop() + contentHeight(); } @@ -250,11 +290,6 @@ void RenderTableCell::styleDidChange(RenderStyle::Diff diff, const RenderStyle* setHasBoxDecorations(true); } -bool RenderTableCell::requiresLayer() -{ - return isPositioned() || isTransparent() || hasOverflowClip() || hasTransform() || hasMask() || hasReflection(); -} - // The following rules apply for resolving conflicts and figuring out which border // to use. // (1) Borders with the 'border-style' of 'hidden' take precedence over all other conflicting @@ -625,23 +660,21 @@ int RenderTableCell::borderHalfBottom(bool outer) const void RenderTableCell::paint(PaintInfo& paintInfo, int tx, int ty) { - tx += m_x; - ty += m_y; + tx += x(); + ty += y(); // check if we need to do anything at all... int os = 2 * maximalOutlineSize(paintInfo.phase); if (paintInfo.phase == PaintPhaseCollapsedTableBorders && style()->visibility() == VISIBLE) { if (ty - table()->outerBorderTop() >= paintInfo.rect.bottom() + os || - ty + m_topExtra + m_height + m_bottomExtra + table()->outerBorderBottom() <= paintInfo.rect.y() - os) + ty + height() + table()->outerBorderBottom() <= paintInfo.rect.y() - os) return; - int w = width(); - int h = height() + borderTopExtra() + borderBottomExtra(); - paintCollapsedBorder(paintInfo.context, tx, ty, w, h); + paintCollapsedBorder(paintInfo.context, tx, ty, width(), height()); } else { - if (ty + overflowTop(false) >= paintInfo.rect.bottom() + os || ty + m_topExtra + overflowHeight(false) + m_bottomExtra <= paintInfo.rect.y() - os) + if (ty + overflowTop(false) >= paintInfo.rect.bottom() + os || ty + overflowHeight(false) <= paintInfo.rect.y() - os) return; - RenderBlock::paintObject(paintInfo, tx, ty + m_topExtra); + RenderBlock::paintObject(paintInfo, tx, ty); } } @@ -815,13 +848,12 @@ void RenderTableCell::paintBackgroundsBehindCell(PaintInfo& paintInfo, int tx, i return; if (backgroundObject != this) { - tx += m_x; - ty += m_y + m_topExtra; + tx += x(); + ty += y(); } int w = width(); - int h = height() + borderTopExtra() + borderBottomExtra(); - ty -= borderTopExtra(); + int h = height(); int my = max(ty, paintInfo.rect.y()); int end = min(paintInfo.rect.bottom(), ty + h); @@ -853,10 +885,10 @@ void RenderTableCell::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty) return; int w = width(); - int h = height() + borderTopExtra() + borderBottomExtra(); + int h = height(); if (style()->boxShadow()) - paintBoxShadow(paintInfo.context, tx, ty - borderTopExtra(), w, h, style()); + paintBoxShadow(paintInfo.context, tx, ty, w, h, style()); // Paint our cell background. paintBackgroundsBehindCell(paintInfo, tx, ty, this); @@ -864,7 +896,6 @@ void RenderTableCell::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty) if (!style()->hasBorder() || tableElt->collapseBorders()) return; - ty -= borderTopExtra(); paintBorder(paintInfo.context, tx, ty, w, h, style()); } @@ -878,7 +909,7 @@ void RenderTableCell::paintMask(PaintInfo& paintInfo, int tx, int ty) return; int w = width(); - int h = height() + borderTopExtra() + borderBottomExtra(); + int h = height(); int my = max(ty, paintInfo.rect.y()); int end = min(paintInfo.rect.bottom(), ty + h); diff --git a/WebCore/rendering/RenderTableCell.h b/WebCore/rendering/RenderTableCell.h index eb093fb..97e2dda 100644 --- a/WebCore/rendering/RenderTableCell.h +++ b/WebCore/rendering/RenderTableCell.h @@ -59,18 +59,16 @@ public: Length styleOrColWidth() const; - virtual bool requiresLayer(); + virtual bool requiresLayer() const { return isPositioned() || isTransparent() || hasOverflowClip() || hasTransform() || hasMask() || hasReflection(); } virtual void calcPrefWidths(); virtual void calcWidth(); - virtual void setWidth(int); - #ifdef ANDROID_LAYOUT // RenderTableSection needs to access this in setCellWidths() int getVisibleWidth() { return m_visibleWidth; } #endif - virtual bool expandsToEncloseOverhangingFloats() const { return true; } + void updateWidth(int); int borderLeft() const; int borderRight() const; @@ -101,33 +99,39 @@ public: void paintCollapsedBorder(GraphicsContext*, int x, int y, int w, int h); void paintBackgroundsBehindCell(PaintInfo&, int tx, int ty, RenderObject* backgroundObject); - // Lie about position to outside observers. - virtual int yPos() const { return m_y + m_topExtra; } - - virtual IntRect absoluteClippedOverflowRect(); - virtual void computeAbsoluteRepaintRect(IntRect&, bool fixed = false); - virtual bool absolutePosition(int& x, int& y, bool fixed = false) const; + virtual IntRect clippedOverflowRectForRepaint(RenderBox* repaintContainer); + virtual void computeRectForRepaint(IntRect&, RenderBox* repaintContainer, bool fixed = false); + virtual FloatPoint localToAbsolute(FloatPoint localPoint = FloatPoint(), bool fixed = false, bool useTransforms = false) const; + virtual FloatPoint absoluteToLocal(FloatPoint containerPoint, bool fixed = false, bool useTransforms = false) const; virtual int baselinePosition(bool firstLine = false, bool isRootLineBox = false) const; - void setCellTopExtra(int p) { m_topExtra = p; } - void setCellBottomExtra(int p) { m_bottomExtra = p; } + void setIntrinsicPaddingTop(int p) { m_intrinsicPaddingTop = p; } + void setIntrinsicPaddingBottom(int p) { m_intrinsicPaddingBottom = p; } + void setIntrinsicPadding(int top, int bottom) { setIntrinsicPaddingTop(top); setIntrinsicPaddingBottom(bottom); } + void clearIntrinsicPadding() { setIntrinsicPadding(0, 0); } + + int intrinsicPaddingTop() const { return m_intrinsicPaddingTop; } + int intrinsicPaddingBottom() const { return m_intrinsicPaddingBottom; } - virtual int borderTopExtra() const { return m_topExtra; } - virtual int borderBottomExtra() const { return m_bottomExtra; } + virtual int paddingTop(bool includeIntrinsicPadding = true) const; + virtual int paddingBottom(bool includeIntrinsicPadding = true) const; + + virtual void setOverrideSize(int); protected: virtual void styleWillChange(RenderStyle::Diff, const RenderStyle* newStyle); virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle); + virtual FloatQuad localToContainerQuad(const FloatQuad&, RenderBox* repaintContainer, bool fixed = false) const; + private: int m_row; int m_column; int m_rowSpan; int m_columnSpan; - int m_topExtra : 31; - int m_bottomExtra : 31; - bool m_widthChanged : 1; + int m_intrinsicPaddingTop; + int m_intrinsicPaddingBottom; int m_percentageHeight; }; diff --git a/WebCore/rendering/RenderTableCol.cpp b/WebCore/rendering/RenderTableCol.cpp index 0d714da..19538fa 100644 --- a/WebCore/rendering/RenderTableCol.cpp +++ b/WebCore/rendering/RenderTableCol.cpp @@ -69,11 +69,12 @@ bool RenderTableCol::canHaveChildren() const return style()->display() == TABLE_COLUMN_GROUP; } -IntRect RenderTableCol::absoluteClippedOverflowRect() +IntRect RenderTableCol::clippedOverflowRectForRepaint(RenderBox* /*repaintContainer*/) { // For now, just repaint the whole table. // FIXME: Find a better way to do this, e.g., need to repaint all the cells that we // might have propagated a background color or borders into. + // FIXME: check for repaintContainer each time here? RenderObject* table = parent(); if (table && !table->isTable()) table = table->parent(); @@ -83,7 +84,7 @@ IntRect RenderTableCol::absoluteClippedOverflowRect() return IntRect(); } -void RenderTableCol::imageChanged(WrappedImagePtr image) +void RenderTableCol::imageChanged(WrappedImagePtr, const IntRect*) { // FIXME: Repaint only the rect the image paints in. repaint(); diff --git a/WebCore/rendering/RenderTableCol.h b/WebCore/rendering/RenderTableCol.h index 9d46e2b..3472965 100644 --- a/WebCore/rendering/RenderTableCol.h +++ b/WebCore/rendering/RenderTableCol.h @@ -44,10 +44,10 @@ public: virtual bool isChildAllowed(RenderObject*, RenderStyle*) const; virtual bool canHaveChildren() const; - virtual bool requiresLayer() { return false; } + virtual bool requiresLayer() const { return false; } - virtual IntRect absoluteClippedOverflowRect(); - virtual void imageChanged(WrappedImagePtr); + virtual IntRect clippedOverflowRectForRepaint(RenderBox* repaintContainer); + virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); int span() const { return m_span; } void setSpan(int s) { m_span = s; } diff --git a/WebCore/rendering/RenderTableRow.cpp b/WebCore/rendering/RenderTableRow.cpp index 4e9323d..6b83769 100644 --- a/WebCore/rendering/RenderTableRow.cpp +++ b/WebCore/rendering/RenderTableRow.cpp @@ -33,6 +33,10 @@ #include "RenderTableCell.h" #include "RenderView.h" +#if ENABLE(WML) +#include "WMLNames.h" +#endif + namespace WebCore { using namespace HTMLNames; @@ -71,7 +75,12 @@ void RenderTableRow::addChild(RenderObject* child, RenderObject* beforeChild) beforeChild = lastChild(); bool isTableRow = element() && element()->hasTagName(trTag); - + +#if ENABLE(WML) + if (!isTableRow && element() && element()->isWMLElement()) + isTableRow = element()->hasTagName(WMLNames::trTag); +#endif + if (!child->isTableCell()) { if (isTableRow && child->element() && child->element()->hasTagName(formTag) && document()->isHTMLDocument()) { RenderContainer::addChild(child, beforeChild); @@ -124,7 +133,7 @@ void RenderTableRow::layout() ASSERT(needsLayout()); // Table rows do not add translation. - view()->pushLayoutState(this, IntSize()); + LayoutStateMaintainer statePusher(view(), this, IntSize()); for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { if (child->isTableCell()) { @@ -148,17 +157,18 @@ void RenderTableRow::layout() } } - view()->popLayoutState(); + statePusher.pop(); setNeedsLayout(false); } -IntRect RenderTableRow::absoluteClippedOverflowRect() +IntRect RenderTableRow::clippedOverflowRectForRepaint(RenderBox* repaintContainer) { // For now, just repaint the whole table. // FIXME: Find a better way to do this, e.g., need to repaint all the cells that we // might have propagated a background color into. + // FIXME: do repaintContainer checks here if (RenderTable* parentTable = table()) - return parentTable->absoluteClippedOverflowRect(); + return parentTable->clippedOverflowRectForRepaint(repaintContainer); return IntRect(); } @@ -173,7 +183,7 @@ bool RenderTableRow::nodeAtPoint(const HitTestRequest& request, HitTestResult& r // at the moment (a demoted inline <form> for example). If we ever implement a // table-specific hit-test method (which we should do for performance reasons anyway), // then we can remove this check. - if (!child->hasLayer() && !child->isInlineFlow() && child->nodeAtPoint(request, result, x, y, tx, ty, action)) { + if (!child->hasLayer() && !child->isRenderInline() && child->nodeAtPoint(request, result, x, y, tx, ty, action)) { updateHitTestResult(result, IntPoint(x - tx, y - ty)); return true; } @@ -201,7 +211,7 @@ void RenderTableRow::paint(PaintInfo& paintInfo, int tx, int ty) } } -void RenderTableRow::imageChanged(WrappedImagePtr image) +void RenderTableRow::imageChanged(WrappedImagePtr, const IntRect*) { // FIXME: Examine cells and repaint only the rect the image paints in. repaint(); diff --git a/WebCore/rendering/RenderTableRow.h b/WebCore/rendering/RenderTableRow.h index 99482be..79d32d8 100644 --- a/WebCore/rendering/RenderTableRow.h +++ b/WebCore/rendering/RenderTableRow.h @@ -35,29 +35,29 @@ class RenderTableRow : public RenderContainer { public: RenderTableRow(Node*); + RenderTableSection* section() const { return static_cast<RenderTableSection*>(parent()); } + RenderTable* table() const { return static_cast<RenderTable*>(parent()->parent()); } + +private: virtual const char* renderName() const { return isAnonymous() ? "RenderTableRow (anonymous)" : "RenderTableRow"; } virtual bool isTableRow() const { return true; } virtual void destroy(); - RenderTableSection* section() const { return static_cast<RenderTableSection*>(parent()); } - RenderTable* table() const { return static_cast<RenderTable*>(parent()->parent()); } - virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0); - virtual int lineHeight(bool firstLine, bool isRootLineBox = false) const { return 0; } + virtual int lineHeight(bool, bool) const { return 0; } virtual void position(InlineBox*) { } virtual void layout(); - virtual IntRect absoluteClippedOverflowRect(); + virtual IntRect clippedOverflowRectForRepaint(RenderBox* repaintContainer); virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); // The only time rows get a layer is when they have transparency. - virtual bool requiresLayer() { return isTransparent() || hasOverflowClip(); } + virtual bool requiresLayer() const { return isTransparent() || hasOverflowClip(); } virtual void paint(PaintInfo&, int tx, int ty); - virtual void imageChanged(WrappedImagePtr); + virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); -protected: virtual void styleWillChange(RenderStyle::Diff, const RenderStyle* newStyle); }; diff --git a/WebCore/rendering/RenderTableSection.cpp b/WebCore/rendering/RenderTableSection.cpp index acc5596..ad2bfaf 100644 --- a/WebCore/rendering/RenderTableSection.cpp +++ b/WebCore/rendering/RenderTableSection.cpp @@ -135,7 +135,7 @@ void RenderTableSection::addChild(RenderObject* child, RenderObject* beforeChild if (!ensureRows(m_cRow + 1)) return; - m_grid[m_cRow].rowRenderer = child; + m_grid[m_cRow].rowRenderer = static_cast<RenderTableRow*>(child); if (!beforeChild) { m_grid[m_cRow].height = child->style()->height(); @@ -178,7 +178,7 @@ bool RenderTableSection::ensureRows(int numRows) return true; } -void RenderTableSection::addCell(RenderTableCell* cell, RenderObject* row) +void RenderTableSection::addCell(RenderTableCell* cell, RenderTableRow* row) { int rSpan = cell->rowSpan(); int cSpan = cell->colSpan(); @@ -261,8 +261,9 @@ void RenderTableSection::addCell(RenderTableCell* cell, RenderObject* row) void RenderTableSection::setCellWidths() { Vector<int>& columnPos = table()->columnPositions(); - bool pushedLayoutState = false; + LayoutStateMaintainer statePusher(view()); + #ifdef ANDROID_LAYOUT int visibleWidth = 0; if (view()->frameView()) { @@ -304,38 +305,41 @@ void RenderTableSection::setCellWidths() #endif cell->setNeedsLayout(true); if (!table()->selfNeedsLayout() && cell->checkForRepaintDuringLayout()) { - if (!pushedLayoutState) { + if (!statePusher.didPush()) { // Technically, we should also push state for the row, but since // rows don't push a coordinate transform, that's not necessary. - view()->pushLayoutState(this, IntSize(m_x, m_y)); - pushedLayoutState = true; + statePusher.push(this, IntSize(x(), y())); } cell->repaint(); } #ifdef ANDROID_LAYOUT if (w != oldWidth) - cell->setWidth(w); -#else - cell->setWidth(w); #endif + cell->updateWidth(w); } } } - if (pushedLayoutState) - view()->popLayoutState(); + statePusher.pop(); // only pops if we pushed } int RenderTableSection::calcRowHeight() { +#ifndef NDEBUG + setNeedsLayoutIsForbidden(true); +#endif + + ASSERT(!needsLayout()); #ifdef ANDROID_LAYOUT if (table()->isSingleColumn()) return m_rowPos[m_gridRows]; #endif + RenderTableCell* cell; int spacing = table()->vBorderSpacing(); - bool pushedLayoutState = false; + + LayoutStateMaintainer statePusher(view()); m_rowPos.resize(m_gridRows + 1); m_rowPos[0] = spacing; @@ -364,23 +368,26 @@ int RenderTableSection::calcRowHeight() int indx = max(r - cell->rowSpan() + 1, 0); if (cell->overrideSize() != -1) { - if (!pushedLayoutState) { + if (!statePusher.didPush()) { // Technically, we should also push state for the row, but since // rows don't push a coordinate transform, that's not necessary. - view()->pushLayoutState(this, IntSize(m_x, m_y)); - pushedLayoutState = true; + statePusher.push(this, IntSize(x(), y())); } cell->setOverrideSize(-1); cell->setChildNeedsLayout(true, false); cell->layoutIfNeeded(); } + int adjustedPaddingTop = cell->paddingTop() - cell->intrinsicPaddingTop(); + int adjustedPaddingBottom = cell->paddingBottom() - cell->intrinsicPaddingBottom(); + int adjustedHeight = cell->height() - (cell->intrinsicPaddingTop() + cell->intrinsicPaddingBottom()); + // Explicit heights use the border box in quirks mode. In strict mode do the right // thing and actually add in the border and padding. ch = cell->style()->height().calcValue(0) + - (cell->style()->htmlHacks() ? 0 : (cell->paddingTop() + cell->paddingBottom() + + (cell->style()->htmlHacks() ? 0 : (adjustedPaddingTop + adjustedPaddingBottom + cell->borderTop() + cell->borderBottom())); - ch = max(ch, cell->height()); + ch = max(ch, adjustedHeight); pos = m_rowPos[indx] + ch + (m_grid[r].rowRenderer ? spacing : 0); @@ -391,8 +398,8 @@ int RenderTableSection::calcRowHeight() if (va == BASELINE || va == TEXT_BOTTOM || va == TEXT_TOP || va == SUPER || va == SUB) { int b = cell->baselinePosition(); if (b > cell->borderTop() + cell->paddingTop()) { - baseline = max(baseline, b); - bdesc = max(bdesc, m_rowPos[indx] + ch - b); + baseline = max(baseline, b - cell->intrinsicPaddingTop()); + bdesc = max(bdesc, m_rowPos[indx] + ch - (b - cell->intrinsicPaddingTop())); } } } @@ -407,14 +414,24 @@ int RenderTableSection::calcRowHeight() m_rowPos[r + 1] = max(m_rowPos[r + 1], m_rowPos[r]); } - if (pushedLayoutState) - view()->popLayoutState(); +#ifndef NDEBUG + setNeedsLayoutIsForbidden(false); +#endif + + ASSERT(!needsLayout()); + + statePusher.pop(); return m_rowPos[m_gridRows]; } int RenderTableSection::layoutRows(int toAdd) { +#ifndef NDEBUG + setNeedsLayoutIsForbidden(true); +#endif + + ASSERT(!needsLayout()); #ifdef ANDROID_LAYOUT if (table()->isSingleColumn()) { int totalRows = m_gridRows; @@ -435,40 +452,45 @@ int RenderTableSection::layoutRows(int toAdd) if (r > 0 && (cellAt(r-1, c).cell == cell)) continue; - cell->setCellTopExtra(0); - cell->setCellBottomExtra(0); +// cell->setCellTopExtra(0); +// cell->setCellBottomExtra(0); - int oldCellX = cell->xPos(); - int oldCellY = cell->yPos(); + int oldCellX = cell->x(); + int oldCellY = cell->y(); - if (style()->direction() == RTL) - cell->setPos(table()->width(), rHeight); - else - cell->setPos(leftOffset, rHeight); - + if (style()->direction() == RTL) { + cell->setX(table()->width()); + cell->setY(rHeight); + } else { + cell->setX(leftOffset); + cell->setY(rHeight); + } + // If the cell moved, we have to repaint it as well as any floating/positioned // descendants. An exception is if we need a layout. In this case, we know we're going to // repaint ourselves (and the cell) anyway. if (!table()->selfNeedsLayout() && cell->checkForRepaintDuringLayout()) { - IntRect cellRect(oldCellX, oldCellY - cell->borderTopExtra() , cell->width(), cell->height()); +// IntRect cellRect(oldCellX, oldCellY - cell->borderTopExtra() , cell->width(), cell->height()); + IntRect cellRect(oldCellX, oldCellY, cell->width(), cell->height()); cell->repaintDuringLayoutIfMoved(cellRect); } rHeight += cell->height() + vspacing; } } - m_height = rHeight; - return m_height; + setHeight(rHeight); + return height(); } #endif + int rHeight; int rindx; int totalRows = m_gridRows; // Set the width of our section now. The rows will also be this width. - m_width = table()->contentWidth(); + setWidth(table()->contentWidth()); m_overflowLeft = 0; - m_overflowWidth = m_width; + m_overflowWidth = width(); m_overflowTop = 0; m_overflowHeight = 0; m_hasOverflowingCell = false; @@ -536,13 +558,13 @@ int RenderTableSection::layoutRows(int toAdd) int vspacing = table()->vBorderSpacing(); int nEffCols = table()->numEffCols(); - view()->pushLayoutState(this, IntSize(m_x, m_y)); + LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y())); for (int r = 0; r < totalRows; r++) { // Set the row's x/y position and width/height. - if (RenderObject* rowRenderer = m_grid[r].rowRenderer) { - rowRenderer->setPos(0, m_rowPos[r]); - rowRenderer->setWidth(m_width); + if (RenderTableRow* rowRenderer = m_grid[r].rowRenderer) { + rowRenderer->setLocation(0, m_rowPos[r]); + rowRenderer->setWidth(width()); rowRenderer->setHeight(m_rowPos[r + 1] - m_rowPos[r] - vspacing); } @@ -576,7 +598,7 @@ int RenderTableSection::layoutRows(int toAdd) (!table()->style()->height().isAuto() && rHeight != cell->height()); for (RenderObject* o = cell->firstChild(); o; o = o->nextSibling()) { - if (!o->isText() && o->style()->height().isPercent() && (o->isReplaced() || o->scrollsOverflow() || flexAllChildren)) { + if (!o->isText() && o->style()->height().isPercent() && (o->isReplaced() || (o->isBox() && toRenderBox(o)->scrollsOverflow()) || flexAllChildren)) { // Tables with no sections do not flex. if (!o->isTable() || static_cast<RenderTable*>(o)->hasSections()) { o->setNeedsLayout(true, false); @@ -585,10 +607,11 @@ int RenderTableSection::layoutRows(int toAdd) } } } + if (cellChildrenFlex) { // Alignment within a cell is based off the calculated // height, which becomes irrelevant once the cell has - // been resized based off its percentage. -dwh + // been resized based off its percentage. cell->setOverrideSize(max(0, rHeight - cell->borderTop() - cell->paddingTop() - cell->borderBottom() - cell->paddingBottom())); @@ -603,48 +626,57 @@ int RenderTableSection::layoutRows(int toAdd) } } + int oldTe = cell->intrinsicPaddingTop(); + int oldBe = cell->intrinsicPaddingBottom(); + int heightWithoutIntrinsicPadding = cell->height() - oldTe - oldBe; + int te = 0; switch (cell->style()->verticalAlign()) { case SUB: case SUPER: case TEXT_TOP: case TEXT_BOTTOM: - case BASELINE: - te = getBaseline(r) - cell->baselinePosition(); + case BASELINE: { + int b = cell->baselinePosition(); + if (b > cell->borderTop() + cell->paddingTop()) + te = getBaseline(r) - (b - oldTe); break; + } case TOP: te = 0; break; case MIDDLE: - te = (rHeight - cell->height()) / 2; + te = (rHeight - heightWithoutIntrinsicPadding) / 2; break; case BOTTOM: - te = rHeight - cell->height(); + te = rHeight - heightWithoutIntrinsicPadding; break; default: break; } - - int oldTe = cell->borderTopExtra(); - int oldBe = cell->borderBottomExtra(); - - int be = rHeight - cell->height() - te; - cell->setCellTopExtra(te); - cell->setCellBottomExtra(be); + + int be = rHeight - heightWithoutIntrinsicPadding - te; + cell->setIntrinsicPaddingTop(te); + cell->setIntrinsicPaddingBottom(be); + if (te != oldTe || be != oldBe) { + cell->setNeedsLayout(true, false); + cell->layoutIfNeeded(); + } + if ((te != oldTe || be > oldBe) && !table()->selfNeedsLayout() && cell->checkForRepaintDuringLayout()) cell->repaint(); - IntRect oldCellRect(cell->xPos(), cell->yPos() - cell->borderTopExtra() , cell->width(), cell->height()); + IntRect oldCellRect(cell->x(), cell->y() , cell->width(), cell->height()); if (style()->direction() == RTL) { - cell->setPos(table()->columnPositions()[nEffCols] - table()->columnPositions()[table()->colToEffCol(cell->col() + cell->colSpan())] + hspacing, m_rowPos[rindx]); + cell->setLocation(table()->columnPositions()[nEffCols] - table()->columnPositions()[table()->colToEffCol(cell->col() + cell->colSpan())] + hspacing, m_rowPos[rindx]); } else - cell->setPos(table()->columnPositions()[c] + hspacing, m_rowPos[rindx]); + cell->setLocation(table()->columnPositions()[c] + hspacing, m_rowPos[rindx]); - m_overflowLeft = min(m_overflowLeft, cell->xPos() + cell->overflowLeft(false)); - m_overflowWidth = max(m_overflowWidth, cell->xPos() + cell->overflowWidth(false)); - m_overflowTop = min(m_overflowTop, cell->yPos() + cell->overflowTop(false)); - m_overflowHeight = max(m_overflowHeight, cell->yPos() + cell->overflowHeight(false)); + m_overflowLeft = min(m_overflowLeft, cell->x() + cell->overflowLeft(false)); + m_overflowWidth = max(m_overflowWidth, cell->x() + cell->overflowWidth(false)); + m_overflowTop = min(m_overflowTop, cell->y() + cell->overflowTop(false)); + m_overflowHeight = max(m_overflowHeight, cell->y() + cell->overflowHeight(false)); m_hasOverflowingCell |= cell->overflowLeft(false) || cell->overflowWidth(false) > cell->width() || cell->overflowTop(false) || cell->overflowHeight(false) > cell->height(); // If the cell moved, we have to repaint it as well as any floating/positioned @@ -655,11 +687,17 @@ int RenderTableSection::layoutRows(int toAdd) } } - view()->popLayoutState(); +#ifndef NDEBUG + setNeedsLayoutIsForbidden(false); +#endif - m_height = m_rowPos[totalRows]; - m_overflowHeight = max(m_overflowHeight, m_height); - return m_height; + ASSERT(!needsLayout()); + + statePusher.pop(); + + setHeight(m_rowPos[totalRows]); + m_overflowHeight = max(m_overflowHeight, height()); + return height(); } int RenderTableSection::lowestPosition(bool includeOverflowInterior, bool includeSelf) const @@ -671,7 +709,7 @@ int RenderTableSection::lowestPosition(bool includeOverflowInterior, bool includ for (RenderObject* row = firstChild(); row; row = row->nextSibling()) { for (RenderObject* cell = row->firstChild(); cell; cell = cell->nextSibling()) { if (cell->isTableCell()) - bottom = max(bottom, cell->yPos() + cell->lowestPosition(false)); + bottom = max(bottom, static_cast<RenderTableCell*>(cell)->y() + cell->lowestPosition(false)); } } @@ -687,7 +725,7 @@ int RenderTableSection::rightmostPosition(bool includeOverflowInterior, bool inc for (RenderObject* row = firstChild(); row; row = row->nextSibling()) { for (RenderObject* cell = row->firstChild(); cell; cell = cell->nextSibling()) { if (cell->isTableCell()) - right = max(right, cell->xPos() + cell->rightmostPosition(false)); + right = max(right, static_cast<RenderTableCell*>(cell)->x() + cell->rightmostPosition(false)); } } @@ -703,7 +741,7 @@ int RenderTableSection::leftmostPosition(bool includeOverflowInterior, bool incl for (RenderObject* row = firstChild(); row; row = row->nextSibling()) { for (RenderObject* cell = row->firstChild(); cell; cell = cell->nextSibling()) { if (cell->isTableCell()) - left = min(left, cell->xPos() + cell->leftmostPosition(false)); + left = min(left, static_cast<RenderTableCell*>(cell)->x() + cell->leftmostPosition(false)); } } @@ -933,7 +971,7 @@ int RenderTableSection::getBaselineOfFirstLineBox() const for (size_t i = 0; i < firstRow->size(); ++i) { RenderTableCell* cell = firstRow->at(i).cell; if (cell) - firstLineBaseline = max(firstLineBaseline, cell->yPos() + cell->paddingTop() + cell->borderTop() + cell->contentHeight()); + firstLineBaseline = max(firstLineBaseline, cell->y() + cell->paddingTop() + cell->borderTop() + cell->contentHeight()); } return firstLineBaseline; @@ -953,8 +991,8 @@ void RenderTableSection::paint(PaintInfo& paintInfo, int tx, int ty) if (!totalRows || !totalCols) return; - tx += m_x; - ty += m_y; + tx += x(); + ty += y(); // Check which rows and cols are visible and only paint these. // FIXME: Could use a binary search here. @@ -1074,7 +1112,7 @@ void RenderTableSection::paint(PaintInfo& paintInfo, int tx, int ty) } } -void RenderTableSection::imageChanged(WrappedImagePtr image) +void RenderTableSection::imageChanged(WrappedImagePtr, const IntRect*) { // FIXME: Examine cells and repaint only the rect the image paints in. repaint(); @@ -1093,11 +1131,13 @@ void RenderTableSection::recalcCells() m_cCol = 0; if (!ensureRows(m_cRow + 1)) break; - m_grid[m_cRow].rowRenderer = row; + + RenderTableRow* tableRow = static_cast<RenderTableRow*>(row); + m_grid[m_cRow].rowRenderer = tableRow; for (RenderObject* cell = row->firstChild(); cell; cell = cell->nextSibling()) { if (cell->isTableCell()) - addCell(static_cast<RenderTableCell*>(cell), row); + addCell(static_cast<RenderTableCell*>(cell), tableRow); } } } @@ -1157,20 +1197,20 @@ RenderObject* RenderTableSection::removeChildNode(RenderObject* child, bool full } // Hit Testing -bool RenderTableSection::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction action) +bool RenderTableSection::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int xPos, int yPos, int tx, int ty, HitTestAction action) { // Table sections cannot ever be hit tested. Effectively they do not exist. // Just forward to our children always. - tx += m_x; - ty += m_y; + tx += x(); + ty += y(); for (RenderObject* child = lastChild(); child; child = child->previousSibling()) { // FIXME: We have to skip over inline flows, since they can show up inside table rows // at the moment (a demoted inline <form> for example). If we ever implement a // table-specific hit-test method (which we should do for performance reasons anyway), // then we can remove this check. - if (!child->hasLayer() && !child->isInlineFlow() && child->nodeAtPoint(request, result, x, y, tx, ty, action)) { - updateHitTestResult(result, IntPoint(x - tx, y - ty)); + if (!child->hasLayer() && !child->isRenderInline() && child->nodeAtPoint(request, result, xPos, yPos, tx, ty, action)) { + updateHitTestResult(result, IntPoint(xPos - tx, yPos - ty)); return true; } } diff --git a/WebCore/rendering/RenderTableSection.h b/WebCore/rendering/RenderTableSection.h index 1866fd5..71839d1 100644 --- a/WebCore/rendering/RenderTableSection.h +++ b/WebCore/rendering/RenderTableSection.h @@ -33,6 +33,7 @@ namespace WebCore { class RenderTableCell; +class RenderTableRow; class RenderTableSection : public RenderContainer { public: @@ -47,12 +48,9 @@ public: virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0); - virtual int lineHeight(bool firstLine, bool isRootLineBox = false) const { return 0; } - virtual void position(InlineBox*) { } - virtual int getBaselineOfFirstLineBox() const; - void addCell(RenderTableCell*, RenderObject* row); + void addCell(RenderTableCell*, RenderTableRow* row); void setCellWidths(); int calcRowHeight(); @@ -69,7 +67,7 @@ public: struct RowStruct { Row* row; - RenderObject* rowRenderer; + RenderTableRow* rowRenderer; int baseline; Length height; }; @@ -80,9 +78,9 @@ public: void appendColumn(int pos); void splitColumn(int pos, int newSize); - virtual int overflowWidth(bool includeInterior = true) const { return (!includeInterior && hasOverflowClip()) ? m_width : m_overflowWidth; } + virtual int overflowWidth(bool includeInterior = true) const { return (!includeInterior && hasOverflowClip()) ? width() : m_overflowWidth; } virtual int overflowLeft(bool includeInterior = true) const { return (!includeInterior && hasOverflowClip()) ? 0 : m_overflowLeft; } - virtual int overflowHeight(bool includeInterior = true) const { return (!includeInterior && hasOverflowClip()) ? m_height : m_overflowHeight; } + virtual int overflowHeight(bool includeInterior = true) const { return (!includeInterior && hasOverflowClip()) ? height() : m_overflowHeight; } virtual int overflowTop(bool includeInterior = true) const { return (!includeInterior && hasOverflowClip()) ? 0 : m_overflowTop; } virtual int lowestPosition(bool includeOverflowInterior, bool includeSelf) const; @@ -101,7 +99,7 @@ public: int outerBorderRight() const { return m_outerBorderRight; } virtual void paint(PaintInfo&, int tx, int ty); - virtual void imageChanged(WrappedImagePtr); + virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); int numRows() const { return m_gridRows; } int numColumns() const; @@ -126,6 +124,9 @@ public: virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); private: + virtual int lineHeight(bool, bool) const { return 0; } + virtual void position(InlineBox*) { } + bool ensureRows(int); void clearGrid(); diff --git a/WebCore/rendering/RenderText.cpp b/WebCore/rendering/RenderText.cpp index be8e337..084be71 100644 --- a/WebCore/rendering/RenderText.cpp +++ b/WebCore/rendering/RenderText.cpp @@ -1,4 +1,4 @@ -/** +/* * (C) 1999 Lars Knoll (knoll@kde.org) * (C) 2000 Dirk Mueller (mueller@kde.org) * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. @@ -26,11 +26,14 @@ #include "RenderText.h" #include "CharacterNames.h" +#include "FloatQuad.h" +#include "FrameView.h" #include "InlineTextBox.h" #include "Range.h" #include "RenderArena.h" #include "RenderBlock.h" #include "RenderLayer.h" +#include "RenderView.h" #include "Text.h" #include "TextBreakIterator.h" #include "break_lines.h" @@ -55,6 +58,8 @@ RenderText::RenderText(Node* node, PassRefPtr<StringImpl> str) , m_lastTextBox(0) , m_minWidth(-1) , m_maxWidth(-1) + , m_beginMinWidth(0) + , m_endMinWidth(0) , m_selectionState(SelectionNone) , m_hasTab(false) , m_linesDirty(false) @@ -62,8 +67,10 @@ RenderText::RenderText(Node* node, PassRefPtr<StringImpl> str) , m_isAllASCII(charactersAreAllASCII(m_text.get())) { ASSERT(m_text); - setRenderText(); - m_text = m_text->replace('\\', backslashAsCurrencySymbol()); + setIsText(); + m_text = document()->displayStringModifiedByEncoding(PassRefPtr<StringImpl>(m_text)); + + view()->frameView()->setIsVisuallyNonEmpty(); } #ifndef NDEBUG @@ -93,16 +100,17 @@ bool RenderText::isWordBreak() const void RenderText::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle) { - RenderObject::styleDidChange(diff, oldStyle); + // There is no need to ever schedule repaints from a style change of a text run, since + // we already did this for the parent of the text run. + // We do have to schedule layouts, though, since a style change can force us to + // need to relayout. + if (diff == RenderStyle::Layout) + setNeedsLayoutAndPrefWidthsRecalc(); ETextTransform oldTransform = oldStyle ? oldStyle->textTransform() : TTNONE; ETextSecurity oldSecurity = oldStyle ? oldStyle->textSecurity() : TSNONE; - if (oldTransform != style()->textTransform() || oldSecurity != style()->textSecurity() -#if ENABLE(SVG) - || isSVGText() /* All SVG text has to be transformed */ -#endif - ) { + if (oldTransform != style()->textTransform() || oldSecurity != style()->textSecurity()) { if (RefPtr<StringImpl> textToTransform = originalText()) setText(textToTransform.release(), true); } @@ -214,27 +222,26 @@ void RenderText::addLineBoxRects(Vector<IntRect>& rects, unsigned start, unsigne start = min(start, static_cast<unsigned>(INT_MAX)); end = min(end, static_cast<unsigned>(INT_MAX)); - int x, y; - absolutePositionForContent(x, y); + FloatPoint absPos = localToAbsolute(FloatPoint()); for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) { // Note: box->end() returns the index of the last character, not the index past it if (start <= box->start() && box->end() < end) { - IntRect r = IntRect(x + box->xPos(), y + box->yPos(), box->width(), box->height()); + IntRect r = IntRect(absPos.x() + box->xPos(), absPos.y() + box->yPos(), box->width(), box->height()); if (useSelectionHeight) { - IntRect selectionRect = box->selectionRect(x, y, start, end); + IntRect selectionRect = box->selectionRect(absPos.x(), absPos.y(), start, end); r.setHeight(selectionRect.height()); r.setY(selectionRect.y()); } rects.append(r); } else { unsigned realEnd = min(box->end() + 1, end); - IntRect r = box->selectionRect(x, y, start, realEnd); + IntRect r = box->selectionRect(absPos.x(), absPos.y(), start, realEnd); if (!r.isEmpty()) { if (!useSelectionHeight) { // change the height and y position because selectionRect uses selection-specific values r.setHeight(box->height()); - r.setY(y + box->yPos()); + r.setY(absPos.y() + box->yPos()); } rects.append(r); } @@ -242,6 +249,49 @@ void RenderText::addLineBoxRects(Vector<IntRect>& rects, unsigned start, unsigne } } +void RenderText::absoluteQuads(Vector<FloatQuad>& quads, bool) +{ + for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) + quads.append(localToAbsoluteQuad(FloatRect(box->xPos(), box->yPos(), box->width(), box->height()))); +} + +void RenderText::collectAbsoluteLineBoxQuads(Vector<FloatQuad>& quads, unsigned start, unsigned end, bool useSelectionHeight) +{ + // Work around signed/unsigned issues. This function takes unsigneds, and is often passed UINT_MAX + // to mean "all the way to the end". InlineTextBox coordinates are unsigneds, so changing this + // function to take ints causes various internal mismatches. But selectionRect takes ints, and + // passing UINT_MAX to it causes trouble. Ideally we'd change selectionRect to take unsigneds, but + // that would cause many ripple effects, so for now we'll just clamp our unsigned parameters to INT_MAX. + ASSERT(end == UINT_MAX || end <= INT_MAX); + ASSERT(start <= INT_MAX); + start = min(start, static_cast<unsigned>(INT_MAX)); + end = min(end, static_cast<unsigned>(INT_MAX)); + + for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) { + // Note: box->end() returns the index of the last character, not the index past it + if (start <= box->start() && box->end() < end) { + IntRect r = IntRect(box->xPos(), box->yPos(), box->width(), box->height()); + if (useSelectionHeight) { + IntRect selectionRect = box->selectionRect(0, 0, start, end); + r.setHeight(selectionRect.height()); + r.setY(selectionRect.y()); + } + quads.append(localToAbsoluteQuad(FloatRect(r))); + } else { + unsigned realEnd = min(box->end() + 1, end); + IntRect r = box->selectionRect(0, 0, start, realEnd); + if (!r.isEmpty()) { + if (!useSelectionHeight) { + // change the height and y position because selectionRect uses selection-specific values + r.setHeight(box->height()); + r.setY(box->yPos()); + } + quads.append(localToAbsoluteQuad(FloatRect(r))); + } + } + } +} + InlineTextBox* RenderText::findNextInlineTextBox(int offset, int& pos) const { // The text runs point to parts of the RenderText's m_text @@ -253,13 +303,13 @@ InlineTextBox* RenderText::findNextInlineTextBox(int offset, int& pos) const return 0; InlineTextBox* s = m_firstTextBox; - int off = s->m_len; + int off = s->len(); while (offset > off && s->nextTextBox()) { s = s->nextTextBox(); - off = s->m_start + s->m_len; + off = s->start() + s->len(); } // we are now in the correct text run - pos = (offset > off ? s->m_len : s->m_len - (off - offset) ); + pos = (offset > off ? s->len() : s->len() - (off - offset) ); return s; } @@ -276,13 +326,13 @@ VisiblePosition RenderText::positionForCoordinates(int x, int y) // at the y coordinate of the first line or above // and the x coordinate is to the left of the first text box left edge offset = firstTextBox()->offsetForPosition(x); - return VisiblePosition(element(), offset + firstTextBox()->m_start, DOWNSTREAM); + return VisiblePosition(element(), offset + firstTextBox()->start(), DOWNSTREAM); } if (lastTextBox() && y >= lastTextBox()->root()->topOverflow() && x >= lastTextBox()->m_x + lastTextBox()->m_width) { // at the y coordinate of the last line or below // and the x coordinate is to the right of the last text box right edge offset = lastTextBox()->offsetForPosition(x); - return VisiblePosition(element(), offset + lastTextBox()->m_start, DOWNSTREAM); + return VisiblePosition(element(), offset + lastTextBox()->start(), DOWNSTREAM); } InlineTextBox* lastBoxAbove = 0; @@ -295,32 +345,32 @@ VisiblePosition RenderText::positionForCoordinates(int x, int y) if (x == box->m_x) // the x coordinate is equal to the left edge of this box // the affinity must be downstream so the position doesn't jump back to the previous line - return VisiblePosition(element(), offset + box->m_start, DOWNSTREAM); + return VisiblePosition(element(), offset + box->start(), DOWNSTREAM); if (x < box->m_x + box->m_width) // and the x coordinate is to the left of the right edge of this box // check to see if position goes in this box - return VisiblePosition(element(), offset + box->m_start, offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM); + return VisiblePosition(element(), offset + box->start(), offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM); if (!box->prevOnLine() && x < box->m_x) // box is first on line // and the x coordinate is to the left of the first text box left edge - return VisiblePosition(element(), offset + box->m_start, DOWNSTREAM); + return VisiblePosition(element(), offset + box->start(), DOWNSTREAM); if (!box->nextOnLine()) // box is last on line // and the x coordinate is to the right of the last text box right edge // generate VisiblePosition, use UPSTREAM affinity if possible - return VisiblePosition(element(), offset + box->m_start, offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM); + return VisiblePosition(element(), offset + box->start(), offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM); } lastBoxAbove = box; } } - return VisiblePosition(element(), lastBoxAbove ? lastBoxAbove->m_start + lastBoxAbove->m_len : 0, DOWNSTREAM); + return VisiblePosition(element(), lastBoxAbove ? lastBoxAbove->start() + lastBoxAbove->len() : 0, DOWNSTREAM); } -IntRect RenderText::caretRect(InlineBox* inlineBox, int caretOffset, int* extraWidthToEndOfLine) +IntRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, int* extraWidthToEndOfLine) { if (!inlineBox) return IntRect(); @@ -342,21 +392,17 @@ IntRect RenderText::caretRect(InlineBox* inlineBox, int caretOffset, int* extraW if (extraWidthToEndOfLine) *extraWidthToEndOfLine = (box->root()->width() + rootLeft) - (left + 1); - int absx, absy; - absolutePositionForContent(absx, absy); - left += absx; - top += absy; - RenderBlock* cb = containingBlock(); if (style()->autoWrap()) { int availableWidth = cb->lineWidth(top); if (box->direction() == LTR) - left = min(left, absx + rootLeft + availableWidth - 1); + left = min(left, rootLeft + availableWidth - 1); else - left = max(left, absx + rootLeft); + left = max(left, rootLeft); } - return IntRect(left, top, 1, height); + const int caretWidth = 1; + return IntRect(left, top, caretWidth, height); } ALWAYS_INLINE int RenderText::widthFromCache(const Font& f, int start, int len, int xPos) const @@ -690,28 +736,16 @@ bool RenderText::containsOnlyWhitespace(unsigned from, unsigned len) const return currPos >= (from + len); } -int RenderText::minXPos() const -{ - if (!m_firstTextBox) - return 0; - - // FIXME: we should not use an arbitrary value like this. Perhaps we should use INT_MAX. - int minXPos = 6666666; - for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) - minXPos = min(minXPos, static_cast<int>(box->m_x)); - return minXPos; -} - -int RenderText::xPos() const +int RenderText::firstRunX() const { return m_firstTextBox ? m_firstTextBox->m_x : 0; } -int RenderText::yPos() const +int RenderText::firstRunY() const { return m_firstTextBox ? m_firstTextBox->m_y : 0; } - + void RenderText::setSelectionState(SelectionState state) { InlineTextBox* box; @@ -820,11 +854,11 @@ void RenderText::setTextWithOffset(PassRefPtr<StringImpl> text, unsigned offset, static inline bool isInlineFlowOrEmptyText(RenderObject* o) { - if (o->isInlineFlow()) + if (o->isRenderInline()) return true; if (!o->isText()) return false; - StringImpl* text = static_cast<RenderText*>(o)->text(); + StringImpl* text = toRenderText(o)->text(); if (!text) return true; return !text->length(); @@ -839,7 +873,7 @@ UChar RenderText::previousCharacter() break; UChar prev = ' '; if (previousText && previousText->isText()) - if (StringImpl* previousString = static_cast<RenderText*>(previousText)->text()) + if (StringImpl* previousString = toRenderText(previousText)->text()) prev = (*previousString)[previousString->length() - 1]; return prev; } @@ -849,8 +883,7 @@ void RenderText::setTextInternal(PassRefPtr<StringImpl> text) m_text = text; ASSERT(m_text); - m_text = m_text->replace('\\', backslashAsCurrencySymbol()); - + m_text = document()->displayStringModifiedByEncoding(PassRefPtr<StringImpl>(m_text)); #if ENABLE(SVG) if (isSVGText()) { if (style() && style()->whiteSpace() == PRE) { @@ -929,14 +962,6 @@ void RenderText::setText(PassRefPtr<StringImpl> text, bool force) setNeedsLayoutAndPrefWidthsRecalc(); } -int RenderText::height() const -{ - int retval = 0; - if (firstTextBox()) - retval = lastTextBox()->m_y + lastTextBox()->height() - firstTextBox()->m_y; - return retval; -} - int RenderText::lineHeight(bool firstLine, bool) const { // Always use the interior line height of the parent (e.g., if our parent is an inline block). @@ -959,9 +984,10 @@ InlineTextBox* RenderText::createInlineTextBox() return new (renderArena()) InlineTextBox(this); } -InlineBox* RenderText::createInlineBox(bool, bool isRootLineBox, bool) +InlineBox* RenderText::createInlineBox(bool, bool unusedIsRootLineBox, bool) { - ASSERT(!isRootLineBox); + ASSERT_UNUSED(unusedIsRootLineBox, !unusedIsRootLineBox); + InlineTextBox* textBox = createInlineTextBox(); if (!m_firstTextBox) m_firstTextBox = m_lastTextBox = textBox; @@ -978,7 +1004,7 @@ void RenderText::position(InlineBox* box) InlineTextBox* s = static_cast<InlineTextBox*>(box); // FIXME: should not be needed!!! - if (!s->m_len) { + if (!s->len()) { // We want the box to be destroyed. s->remove(); s->destroy(renderArena()); @@ -1020,26 +1046,34 @@ unsigned int RenderText::width(unsigned int from, unsigned int len, const Font& return w; } -int RenderText::width() const +IntRect RenderText::linesBoundingBox() const { - // FIXME: we should not use an arbitrary value like this. Perhaps we should use INT_MAX. - int minx = 100000000; - int maxx = 0; - // slooow - for (InlineTextBox* s = firstTextBox(); s; s = s->nextTextBox()) { - if (s->m_x < minx) - minx = s->m_x; - if (s->m_x + s->m_width > maxx) - maxx = s->m_x + s->m_width; + IntRect result; + + ASSERT(!firstTextBox() == !lastTextBox()); // Either both are null or both exist. + if (firstTextBox() && lastTextBox()) { + // Return the width of the minimal left side and the maximal right side. + int leftSide = 0; + int rightSide = 0; + for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBox()) { + if (curr == firstTextBox() || curr->xPos() < leftSide) + leftSide = curr->xPos(); + if (curr == firstTextBox() || curr->xPos() + curr->width() > rightSide) + rightSide = curr->xPos() + curr->width(); + } + result.setWidth(rightSide - leftSide); + result.setX(leftSide); + result.setHeight(lastTextBox()->yPos() + lastTextBox()->height() - firstTextBox()->yPos()); + result.setY(firstTextBox()->yPos()); } - return max(0, maxx - minx); + return result; } -IntRect RenderText::absoluteClippedOverflowRect() +IntRect RenderText::clippedOverflowRectForRepaint(RenderBox* repaintContainer) { RenderObject* cb = containingBlock(); - return cb->absoluteClippedOverflowRect(); + return cb->clippedOverflowRectForRepaint(repaintContainer); } IntRect RenderText::selectionRect(bool clipToVisibleContent) @@ -1079,9 +1113,9 @@ IntRect RenderText::selectionRect(bool clipToVisibleContent) else { if (cb->hasColumns()) cb->adjustRectForColumns(rect); - int absx, absy; - absolutePosition(absx, absy); - rect.move(absx, absy); + // FIXME: This doesn't work correctly with transforms. + FloatPoint absPos = localToAbsolute(); + rect.move(absPos.x(), absPos.y()); } return rect; @@ -1099,9 +1133,9 @@ int RenderText::caretMinOffset() const InlineTextBox* box = firstTextBox(); if (!box) return 0; - int minOffset = box->m_start; + int minOffset = box->start(); for (box = box->nextTextBox(); box; box = box->nextTextBox()) - minOffset = min(minOffset, box->m_start); + minOffset = min<int>(minOffset, box->start()); return minOffset; } @@ -1110,9 +1144,9 @@ int RenderText::caretMaxOffset() const InlineTextBox* box = lastTextBox(); if (!box) return textLength(); - int maxOffset = box->m_start + box->m_len; + int maxOffset = box->start() + box->len(); for (box = box->prevTextBox(); box; box = box->prevTextBox()) - maxOffset = max(maxOffset, box->m_start + box->m_len); + maxOffset = max<int>(maxOffset, box->start() + box->len()); return maxOffset; } @@ -1120,7 +1154,7 @@ unsigned RenderText::caretMaxRenderedOffset() const { int l = 0; for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) - l += box->m_len; + l += box->len(); return l; } diff --git a/WebCore/rendering/RenderText.h b/WebCore/rendering/RenderText.h index a68ba57..6a09605 100644 --- a/WebCore/rendering/RenderText.h +++ b/WebCore/rendering/RenderText.h @@ -1,7 +1,7 @@ /* * (C) 1999 Lars Knoll (knoll@kde.org) * (C) 2000 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -56,14 +56,12 @@ public: virtual InlineTextBox* createInlineTextBox(); virtual void dirtyLineBoxes(bool fullLayout, bool isRootInlineBox = false); - virtual void paint(PaintInfo&, int tx, int ty) { ASSERT_NOT_REACHED(); } - virtual void layout() { ASSERT_NOT_REACHED(); } - - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int, int, int, int, HitTestAction) { ASSERT_NOT_REACHED(); return false; } - virtual void absoluteRects(Vector<IntRect>&, int tx, int ty, bool topLevel = true); virtual void addLineBoxRects(Vector<IntRect>&, unsigned startOffset = 0, unsigned endOffset = UINT_MAX, bool useSelectionHeight = false); + virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true); + virtual void collectAbsoluteLineBoxQuads(Vector<FloatQuad>&, unsigned startOffset = 0, unsigned endOffset = UINT_MAX, bool useSelectionHeight = false); + virtual VisiblePosition positionForCoordinates(int x, int y); const UChar* characters() const { return m_text->characters(); } @@ -72,8 +70,6 @@ public: virtual unsigned width(unsigned from, unsigned len, const Font&, int xPos) const; virtual unsigned width(unsigned from, unsigned len, int xPos, bool firstLine = false) const; - virtual int width() const; - virtual int height() const; virtual int lineHeight(bool firstLine, bool isRootLineBox = false) const; @@ -87,12 +83,10 @@ public: int& beginMaxW, int& endMaxW, int& minW, int& maxW, bool& stripFrontSpaces); - // returns the minimum x position of all runs relative to the parent. - // defaults to 0. - int minXPos() const; + IntRect linesBoundingBox() const; - virtual int xPos() const; - virtual int yPos() const; + int firstRunX() const; + int firstRunY() const; virtual int verticalPositionHint(bool firstLine) const; @@ -103,12 +97,12 @@ public: virtual SelectionState selectionState() const { return static_cast<SelectionState>(m_selectionState); } virtual void setSelectionState(SelectionState s); virtual IntRect selectionRect(bool clipToVisibleContent = true); - virtual IntRect caretRect(InlineBox*, int caretOffset, int* extraWidthToEndOfLine = 0); + virtual IntRect localCaretRect(InlineBox*, int caretOffset, int* extraWidthToEndOfLine = 0); virtual int marginLeft() const { return style()->marginLeft().calcMinValue(0); } virtual int marginRight() const { return style()->marginRight().calcMinValue(0); } - virtual IntRect absoluteClippedOverflowRect(); + virtual IntRect clippedOverflowRectForRepaint(RenderBox* repaintContainer); InlineTextBox* firstTextBox() const { return m_firstTextBox; } InlineTextBox* lastTextBox() const { return m_lastTextBox; } @@ -129,6 +123,7 @@ public: void checkConsistency() const; protected: + virtual void styleWillChange(RenderStyle::Diff, const RenderStyle*) { } virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle); virtual void setTextInternal(PassRefPtr<StringImpl>); @@ -141,6 +136,10 @@ private: // callers with a RenderObject* can continue to use length(). virtual unsigned length() const { return textLength(); } + virtual void paint(PaintInfo&, int, int) { ASSERT_NOT_REACHED(); } + virtual void layout() { ASSERT_NOT_REACHED(); } + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int, int, int, int, HitTestAction) { ASSERT_NOT_REACHED(); return false; } + void deleteTextBoxes(); bool containsOnlyWhitespace(unsigned from, unsigned len) const; int widthFromCache(const Font&, int start, int len, int xPos) const; @@ -170,6 +169,18 @@ private: bool m_isAllASCII : 1; }; +inline RenderText* toRenderText(RenderObject* o) +{ + ASSERT(!o || o->isText()); + return static_cast<RenderText*>(o); +} + +inline const RenderText* toRenderText(const RenderObject* o) +{ + ASSERT(!o || o->isText()); + return static_cast<const RenderText*>(o); +} + #ifdef NDEBUG inline void RenderText::checkConsistency() const { diff --git a/WebCore/rendering/RenderTextControl.cpp b/WebCore/rendering/RenderTextControl.cpp index a971028..642ef1f 100644 --- a/WebCore/rendering/RenderTextControl.cpp +++ b/WebCore/rendering/RenderTextControl.cpp @@ -1,5 +1,6 @@ /** * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -22,35 +23,20 @@ #include "RenderTextControl.h" #include "CharacterNames.h" -#include "CSSStyleSelector.h" -#include "Document.h" #include "Editor.h" -#include "EditorClient.h" #include "Event.h" #include "EventNames.h" -#include "FontSelector.h" #include "Frame.h" -#include "FrameView.h" #include "HTMLBRElement.h" -#include "HTMLInputElement.h" +#include "HTMLFormControlElement.h" #include "HTMLNames.h" -#include "HTMLTextAreaElement.h" #include "HitTestResult.h" -#include "LocalizedStrings.h" -#include "MouseEvent.h" -#include "PlatformKeyboardEvent.h" -#include "RenderScrollbar.h" -#include "RenderTheme.h" +#include "RenderText.h" #include "ScrollbarTheme.h" -#include "SearchPopupMenu.h" #include "SelectionController.h" -#include "Settings.h" -#include "Text.h" #include "TextControlInnerElements.h" +#include "Text.h" #include "TextIterator.h" -#include "htmlediting.h" -#include "visible_units.h" -#include <math.h> #ifdef ANDROID_LAYOUT #include "FrameView.h" @@ -84,50 +70,29 @@ static Color disabledTextColor(const Color& textColor, const Color& backgroundCo return disabledColor; } -RenderTextControl::RenderTextControl(Node* node, bool multiLine) +RenderTextControl::RenderTextControl(Node* node) : RenderBlock(node) - , m_dirty(false) - , m_multiLine(multiLine) - , m_placeholderVisible(false) + , m_edited(false) , m_userEdited(false) - , m_shouldDrawCapsLockIndicator(false) - , m_searchPopup(0) - , m_searchPopupIsVisible(false) - , m_searchEventTimer(this, &RenderTextControl::searchEventTimerFired) { } RenderTextControl::~RenderTextControl() { - if (m_searchPopup) { - m_searchPopup->disconnectClient(); - m_searchPopup = 0; - } - if (m_multiLine && node()) - static_cast<HTMLTextAreaElement*>(node())->rendererWillBeDestroyed(); // The children renderers have already been destroyed by destroyLeftoverChildren - if (m_innerBlock) - m_innerBlock->detach(); - else if (m_innerText) + if (m_innerText) m_innerText->detach(); } void RenderTextControl::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle) { RenderBlock::styleDidChange(diff, oldStyle); - if (m_innerBlock) { - // We may have set the width and the height in the old style in layout(). Reset them now to avoid - // getting a spurious layout hint. - m_innerBlock->renderer()->style()->setHeight(Length()); - m_innerBlock->renderer()->style()->setWidth(Length()); - m_innerBlock->renderer()->setStyle(createInnerBlockStyle(style())); - } if (m_innerText) { RenderBlock* textBlockRenderer = static_cast<RenderBlock*>(m_innerText->renderer()); RefPtr<RenderStyle> textBlockStyle = createInnerTextStyle(style()); - // We may have set the width and the height in the old style in layout(). Reset them now to avoid - // getting a spurious layout hint. + // We may have set the width and the height in the old style in layout(). + // Reset them now to avoid getting a spurious layout hint. textBlockRenderer->style()->setHeight(Length()); textBlockRenderer->style()->setWidth(Length()); textBlockRenderer->setStyle(textBlockStyle); @@ -136,214 +101,81 @@ void RenderTextControl::styleDidChange(RenderStyle::Diff diff, const RenderStyle n->renderer()->setStyle(textBlockStyle); } } - if (m_resultsButton && m_resultsButton->renderer()) - m_resultsButton->renderer()->setStyle(createResultsButtonStyle(style())); - - if (m_cancelButton && m_cancelButton->renderer()) - m_cancelButton->renderer()->setStyle(createCancelButtonStyle(style())); setHasOverflowClip(false); setReplaced(isInline()); } -PassRefPtr<RenderStyle> RenderTextControl::createInnerBlockStyle(const RenderStyle* startStyle) +void RenderTextControl::adjustInnerTextStyle(const RenderStyle* startStyle, RenderStyle* textBlockStyle) const { - RefPtr<RenderStyle> innerBlockStyle = RenderStyle::create(); - - innerBlockStyle->inheritFrom(startStyle); - innerBlockStyle->setDisplay(BLOCK); - innerBlockStyle->setDirection(LTR); - // We don't want the shadow dom to be editable, so we set this block to read-only in case the input itself is editable. - innerBlockStyle->setUserModify(READ_ONLY); - - return innerBlockStyle.release(); -} - -PassRefPtr<RenderStyle> RenderTextControl::createInnerTextStyle(const RenderStyle* startStyle) -{ - HTMLFormControlElement* element = static_cast<HTMLFormControlElement*>(node()); - bool placeholderShouldBeVisible = !m_multiLine && static_cast<HTMLInputElement*>(element)->placeholderShouldBeVisible(); - - RefPtr<RenderStyle> textBlockStyle; - if (placeholderShouldBeVisible) { - RenderStyle* pseudoStyle = getCachedPseudoStyle(RenderStyle::INPUT_PLACEHOLDER); - textBlockStyle = RenderStyle::clone(pseudoStyle); - } else { - textBlockStyle = RenderStyle::create(); - textBlockStyle->inheritFrom(startStyle); - } - // The inner block, if present, always has its direction set to LTR, // so we need to inherit the direction from the element. textBlockStyle->setDirection(style()->direction()); - textBlockStyle->setUserModify(element->isReadOnlyControl() || element->disabled() ? READ_ONLY : READ_WRITE_PLAINTEXT_ONLY); - if (m_innerBlock) - textBlockStyle->setDisplay(INLINE_BLOCK); - else - textBlockStyle->setDisplay(BLOCK); - - if (m_multiLine) { - // Forward overflow properties. - textBlockStyle->setOverflowX(startStyle->overflowX() == OVISIBLE ? OAUTO : startStyle->overflowX()); - textBlockStyle->setOverflowY(startStyle->overflowY() == OVISIBLE ? OAUTO : startStyle->overflowY()); - - // Set word wrap property based on wrap attribute. - if (!static_cast<HTMLTextAreaElement*>(element)->shouldWrapText()) { - textBlockStyle->setWhiteSpace(PRE); - textBlockStyle->setWordWrap(NormalWordWrap); - } else { - textBlockStyle->setWhiteSpace(PRE_WRAP); - textBlockStyle->setWordWrap(BreakWordWrap); - } - } else { - textBlockStyle->setWhiteSpace(PRE); - textBlockStyle->setWordWrap(NormalWordWrap); - textBlockStyle->setOverflowX(OHIDDEN); - textBlockStyle->setOverflowY(OHIDDEN); - - // Do not allow line-height to be smaller than our default. - if (textBlockStyle->font().lineSpacing() > lineHeight(true, true)) - textBlockStyle->setLineHeight(Length(-100.0f, Percent)); - } + textBlockStyle->setUserModify((node()->isReadOnlyControl() || !node()->isEnabled()) ? READ_ONLY : READ_WRITE_PLAINTEXT_ONLY); - if (!m_multiLine) { - // We're adding one extra pixel of padding to match WinIE. - textBlockStyle->setPaddingLeft(Length(1, Fixed)); - textBlockStyle->setPaddingRight(Length(1, Fixed)); - } else { - // We're adding three extra pixels of padding to line textareas up with text fields. - textBlockStyle->setPaddingLeft(Length(3, Fixed)); - textBlockStyle->setPaddingRight(Length(3, Fixed)); - } - - // When the placeholder is going to be displayed, temporarily override the text security to be "none". - // After this, updateFromElement will immediately update the text displayed. - // When the placeholder is no longer visible, updatePlaceholderVisiblity will reset the style, - // and the text security mode will be set back to the computed value correctly. - if (!m_multiLine && static_cast<HTMLInputElement*>(element)->placeholderShouldBeVisible()) - textBlockStyle->setTextSecurity(TSNONE); - - if (!element->isEnabled()) + if (!node()->isEnabled()) textBlockStyle->setColor(disabledTextColor(textBlockStyle->color(), startStyle->backgroundColor())); - - return textBlockStyle.release(); } -PassRefPtr<RenderStyle> RenderTextControl::createResultsButtonStyle(const RenderStyle* startStyle) +void RenderTextControl::createSubtreeIfNeeded(TextControlInnerElement* innerBlock) { - ASSERT(!m_multiLine); - HTMLInputElement* input = static_cast<HTMLInputElement*>(node()); - RefPtr<RenderStyle> resultsBlockStyle; - if (input->maxResults() < 0) - resultsBlockStyle = getCachedPseudoStyle(RenderStyle::SEARCH_DECORATION); - else if (!input->maxResults()) - resultsBlockStyle = getCachedPseudoStyle(RenderStyle::SEARCH_RESULTS_DECORATION); - else - resultsBlockStyle = getCachedPseudoStyle(RenderStyle::SEARCH_RESULTS_BUTTON); - - if (!resultsBlockStyle) - resultsBlockStyle = RenderStyle::create(); - - if (startStyle) - resultsBlockStyle->inheritFrom(startStyle); - - return resultsBlockStyle.release(); + if (!m_innerText) { + // Create the text block element + // For non-search fields, there is no intermediate innerBlock as the shadow node. + // m_innerText will be the shadow node in that case. + RenderStyle* parentStyle = innerBlock ? innerBlock->renderer()->style() : style(); + m_innerText = new TextControlInnerTextElement(document(), innerBlock ? 0 : node()); + m_innerText->attachInnerElement(innerBlock ? innerBlock : node(), createInnerTextStyle(parentStyle), renderArena()); + } } -PassRefPtr<RenderStyle> RenderTextControl::createCancelButtonStyle(const RenderStyle* startStyle) +int RenderTextControl::textBlockHeight() const { - RefPtr<RenderStyle> cancelBlockStyle; - - if (RefPtr<RenderStyle> pseudoStyle = getCachedPseudoStyle(RenderStyle::SEARCH_CANCEL_BUTTON)) - // We may be sharing style with another search field, but we must not share the cancel button style. - cancelBlockStyle = RenderStyle::clone(pseudoStyle.get()); - else - cancelBlockStyle = RenderStyle::create(); - - if (startStyle) - cancelBlockStyle->inheritFrom(startStyle); - - updateCancelButtonVisibility(cancelBlockStyle.get()); - - return cancelBlockStyle.release(); + return height() - paddingTop() - paddingBottom() - borderTop() - borderBottom(); } -void RenderTextControl::createSubtreeIfNeeded() +int RenderTextControl::textBlockWidth() const { - bool isSearchField = !m_multiLine && static_cast<HTMLInputElement*>(node())->isSearchField(); - if (isSearchField && !m_innerBlock) { - // Create the inner block element - m_innerBlock = new TextControlInnerElement(document(), node()); - m_innerBlock->attachInnerElement(node(), createInnerBlockStyle(style()), renderArena()); - } - if (isSearchField && !m_resultsButton) { - // Create the search results button element - m_resultsButton = new SearchFieldResultsButtonElement(document()); - m_resultsButton->attachInnerElement(m_innerBlock.get(), createResultsButtonStyle(m_innerBlock->renderer()->style()), renderArena()); - } - if (!m_innerText) { - // Create the text block element - // For non-search fields, there is no intermediate m_innerBlock as the shadow node. - // m_innerText will be the shadow node in that case. - - RenderStyle* parentStyle = style(); - if (m_innerBlock) - parentStyle = m_innerBlock->renderer()->style(); - m_innerText = new TextControlInnerTextElement(document(), m_innerBlock ? 0 : node()); - m_innerText->attachInnerElement(m_innerBlock ? m_innerBlock.get() : node(), createInnerTextStyle(parentStyle), renderArena()); - } - if (isSearchField && !m_cancelButton) { - // Create the cancel button element - m_cancelButton = new SearchFieldCancelButtonElement(document()); - m_cancelButton->attachInnerElement(m_innerBlock.get(), createCancelButtonStyle(m_innerBlock->renderer()->style()), renderArena()); - } + return width() - paddingLeft() - paddingRight() - borderLeft() - borderRight() + - m_innerText->renderBox()->paddingLeft() - m_innerText->renderBox()->paddingRight(); } void RenderTextControl::updateFromElement() { - HTMLFormControlElement* element = static_cast<HTMLFormControlElement*>(node()); + m_innerText->renderer()->style()->setUserModify((node()->isReadOnlyControl() || !node()->isEnabled()) ? READ_ONLY : READ_WRITE_PLAINTEXT_ONLY); +} - bool placeholderShouldBeVisible = !m_multiLine && static_cast<HTMLInputElement*>(element)->placeholderShouldBeVisible(); - bool placeholderVisibilityShouldChange = m_placeholderVisible != placeholderShouldBeVisible; - m_placeholderVisible = placeholderShouldBeVisible; +void RenderTextControl::setInnerTextValue(const String& innerTextValue) +{ + String value; - createSubtreeIfNeeded(); + if (innerTextValue.isNull()) + value = ""; + else { + value = innerTextValue; + value = document()->displayStringModifiedByEncoding(value); + } - if (m_cancelButton && m_cancelButton->renderer()) - updateCancelButtonVisibility(m_cancelButton->renderer()->style()); + if (value != text() || !m_innerText->hasChildNodes()) { + if (value != text()) { + if (Frame* frame = document()->frame()) + frame->editor()->clearUndoRedoOperations(); + } - m_innerText->renderer()->style()->setUserModify(element->isReadOnlyControl() || element->disabled() ? READ_ONLY : READ_WRITE_PLAINTEXT_ONLY); - - if (m_placeholderVisible) { - ExceptionCode ec; - m_innerText->setInnerText(static_cast<HTMLInputElement*>(element)->getAttribute(placeholderAttr), ec); - } else if (!element->valueMatchesRenderer() || m_multiLine || placeholderVisibilityShouldChange) { - String value; - if (m_multiLine) - value = static_cast<HTMLTextAreaElement*>(element)->value(); - else - value = static_cast<HTMLInputElement*>(element)->value(); - if (value.isNull()) - value = ""; - else - value = value.replace('\\', backslashAsCurrencySymbol()); - if (value != text() || !m_innerText->hasChildNodes()) { - if (value != text()) { - if (Frame* frame = document()->frame()) - frame->editor()->clearUndoRedoOperations(); - } - ExceptionCode ec = 0; - m_innerText->setInnerText(value, ec); - if (value.endsWith("\n") || value.endsWith("\r")) - m_innerText->appendChild(new HTMLBRElement(document()), ec); - m_dirty = false; - m_userEdited = false; + ExceptionCode ec = 0; + m_innerText->setInnerText(value, ec); + ASSERT(!ec); + + if (value.endsWith("\n") || value.endsWith("\r")) { + m_innerText->appendChild(new HTMLBRElement(brTag, document()), ec); + ASSERT(!ec); } - element->setValueMatchesRenderer(); + + m_edited = false; + m_userEdited = false; } - if (m_searchPopupIsVisible) - m_searchPopup->updateFromElement(); + formControlElement()->setValueMatchesRenderer(); } void RenderTextControl::setUserEdited(bool isUserEdited) @@ -390,11 +222,8 @@ void RenderTextControl::setSelectionRange(int start, int end) document()->updateLayout(); - if (style()->visibility() == HIDDEN || !m_innerText || !m_innerText->renderer() || !m_innerText->renderer()->height()) { - if (m_multiLine) - static_cast<HTMLTextAreaElement*>(node())->cacheSelection(start, end); - else - static_cast<HTMLInputElement*>(node())->cacheSelection(start, end); + if (style()->visibility() == HIDDEN || !m_innerText || !m_innerText->renderer() || !m_innerText->renderBox()->height()) { + cacheSelection(start, end); return; } VisiblePosition startPosition = visiblePositionForIndex(start); @@ -431,9 +260,14 @@ VisiblePosition RenderTextControl::visiblePositionForIndex(int index) ExceptionCode ec = 0; RefPtr<Range> range = Range::create(document()); range->selectNodeContents(m_innerText.get(), ec); + ASSERT(!ec); CharacterIterator it(range.get()); it.advance(index - 1); - return VisiblePosition(it.range()->endContainer(ec), it.range()->endOffset(ec), UPSTREAM); + Node* endContainer = it.range()->endContainer(ec); + ASSERT(!ec); + int endOffset = it.range()->endOffset(ec); + ASSERT(!ec); + return VisiblePosition(endContainer, endOffset, UPSTREAM); } int RenderTextControl::indexForVisiblePosition(const VisiblePosition& pos) @@ -444,50 +278,16 @@ int RenderTextControl::indexForVisiblePosition(const VisiblePosition& pos) ExceptionCode ec = 0; RefPtr<Range> range = Range::create(document()); range->setStart(m_innerText.get(), 0, ec); + ASSERT(!ec); range->setEnd(indexPosition.node(), indexPosition.offset(), ec); + ASSERT(!ec); return TextIterator::rangeLength(range.get()); } -void RenderTextControl::updateCancelButtonVisibility(RenderStyle* style) -{ - ASSERT(!m_multiLine); - HTMLInputElement* input = static_cast<HTMLInputElement*>(node()); - if (input->value().isEmpty()) - style->setVisibility(HIDDEN); - else - style->setVisibility(VISIBLE); -} - void RenderTextControl::subtreeHasChanged() { - bool wasDirty = m_dirty; - m_dirty = true; + m_edited = true; m_userEdited = true; - HTMLFormControlElement* element = static_cast<HTMLFormControlElement*>(node()); - if (m_multiLine) { - element->setValueMatchesRenderer(false); - if (element->focused()) - if (Frame* frame = document()->frame()) - frame->textDidChangeInTextArea(element); - } else { - HTMLInputElement* input = static_cast<HTMLInputElement*>(element); - input->setValueFromRenderer(input->constrainValue(text())); - if (m_cancelButton && m_cancelButton->renderer()) - updateCancelButtonVisibility(m_cancelButton->renderer()->style()); - - // If the incremental attribute is set, then dispatch the search event - if (!input->getAttribute(incrementalAttr).isNull()) - startSearchEventTimer(); - - if (!wasDirty) { - if (input->focused()) - if (Frame* frame = document()->frame()) - frame->textFieldDidBeginEditing(input); - } - if (input->focused()) - if (Frame* frame = document()->frame()) - frame->textDidChangeInTextField(input); - } } String RenderTextControl::finishText(Vector<UChar>& result) const @@ -501,22 +301,11 @@ String RenderTextControl::finishText(Vector<UChar>& result) const result.shrink(--size); // Convert backslash to currency symbol. - UChar symbol = backslashAsCurrencySymbol(); - if (symbol != '\\') { - for (size_t i = 0; i < size; ++i) { - if (result[i] == '\\') - result[i] = symbol; - } - } - + document()->displayBufferModifiedByEncoding(result.data(), result.size()); + return String::adopt(result); } -HTMLElement* RenderTextControl::innerTextElement() const -{ - return m_innerText.get(); -} - String RenderTextControl::text() { if (!m_innerText) @@ -528,7 +317,9 @@ String RenderTextControl::text() Vector<UChar> result; for (Node* n = m_innerText.get(); n; n = n->traverseNextNode(m_innerText.get())) { - if (n->isTextNode()) { + if (n->hasTagName(brTag)) + result.append(&newlineCharacter, 1); + else if (n->isTextNode()) { Text* text = static_cast<Text*>(n); String data = text->data(); unsigned length = data.length(); @@ -576,7 +367,7 @@ String RenderTextControl::textWithHardLineBreaks() if (!renderer) return ""; - InlineBox* box = renderer->isText() ? static_cast<RenderText*>(renderer)->firstTextBox() : renderer->inlineBoxWrapper(); + InlineBox* box = renderer->isText() ? toRenderText(renderer)->firstTextBox() : renderer->inlineBoxWrapper(); if (!box) return ""; @@ -627,210 +418,49 @@ String RenderTextControl::textWithHardLineBreaks() return finishText(result); } -void RenderTextControl::calcHeight() +int RenderTextControl::scrollbarThickness() const { - int rows = 1; - if (m_multiLine) - rows = static_cast<HTMLTextAreaElement*>(node())->rows(); + // FIXME: We should get the size of the scrollbar from the RenderTheme instead. + return ScrollbarTheme::nativeTheme()->scrollbarThickness(); +} - int line = m_innerText->renderer()->lineHeight(true, true); - int toAdd = paddingTop() + paddingBottom() + borderTop() + borderBottom(); +void RenderTextControl::calcHeight() +{ + setHeight(m_innerText->renderBox()->borderTop() + m_innerText->renderBox()->borderBottom() + + m_innerText->renderBox()->paddingTop() + m_innerText->renderBox()->paddingBottom() + + m_innerText->renderBox()->marginTop() + m_innerText->renderBox()->marginBottom()); - int innerToAdd = m_innerText->renderer()->borderTop() + m_innerText->renderer()->borderBottom() + - m_innerText->renderer()->paddingTop() + m_innerText->renderer()->paddingBottom() + - m_innerText->renderer()->marginTop() + m_innerText->renderer()->marginBottom(); - - if (m_resultsButton && m_resultsButton->renderer()) { - static_cast<RenderBlock*>(m_resultsButton->renderer())->calcHeight(); - innerToAdd = max(innerToAdd, - m_resultsButton->renderer()->borderTop() + m_resultsButton->renderer()->borderBottom() + - m_resultsButton->renderer()->paddingTop() + m_resultsButton->renderer()->paddingBottom() + - m_resultsButton->renderer()->marginTop() + m_resultsButton->renderer()->marginBottom()); - line = max(line, m_resultsButton->renderer()->height()); - } - if (m_cancelButton && m_cancelButton->renderer()) { - static_cast<RenderBlock*>(m_cancelButton->renderer())->calcHeight(); - innerToAdd = max(innerToAdd, - m_cancelButton->renderer()->borderTop() + m_cancelButton->renderer()->borderBottom() + - m_cancelButton->renderer()->paddingTop() + m_cancelButton->renderer()->paddingBottom() + - m_cancelButton->renderer()->marginTop() + m_cancelButton->renderer()->marginBottom()); - line = max(line, m_cancelButton->renderer()->height()); - } - toAdd += innerToAdd; + adjustControlHeightBasedOnLineHeight(m_innerText->renderer()->lineHeight(true, true)); + setHeight(height() + paddingTop() + paddingBottom() + borderTop() + borderBottom()); - // FIXME: We should get the size of the scrollbar from the RenderTheme instead. - int scrollbarSize = 0; // We are able to have a horizontal scrollbar if the overflow style is scroll, or if its auto and there's no word wrap. if (m_innerText->renderer()->style()->overflowX() == OSCROLL || (m_innerText->renderer()->style()->overflowX() == OAUTO && m_innerText->renderer()->style()->wordWrap() == NormalWordWrap)) - scrollbarSize = ScrollbarTheme::nativeTheme()->scrollbarThickness(); - - m_height = line * rows + toAdd + scrollbarSize; + setHeight(height() + scrollbarThickness()); RenderBlock::calcHeight(); } -int RenderTextControl::baselinePosition(bool b, bool isRootLineBox) const +void RenderTextControl::hitInnerTextBlock(HitTestResult& result, int xPos, int yPos, int tx, int ty) { - if (m_multiLine) - return height() + marginTop() + marginBottom(); - return RenderBlock::baselinePosition(b, isRootLineBox); + result.setInnerNode(m_innerText.get()); + result.setLocalPoint(IntPoint(xPos - tx - x() - m_innerText->renderBox()->x(), + yPos - ty - y() - m_innerText->renderBox()->y())); } -bool RenderTextControl::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction) +void RenderTextControl::forwardEvent(Event* event) { - // If we're within the text control, we want to act as if we've hit the inner text block element, in case the point - // was on the control but not on the inner element (see Radar 4617841). - - // In a search field, we want to act as if we've hit the results block if we're to the left of the inner text block, - // and act as if we've hit the close block if we're to the right of the inner text block. - - if (RenderBlock::nodeAtPoint(request, result, x, y, tx, ty, hitTestAction) && - (result.innerNode() == element() || result.innerNode() == m_innerBlock)) { - IntPoint localPoint = IntPoint(x - tx - m_x, y - ty - m_y); - if (m_innerBlock) { - int textLeft = tx + m_x + m_innerBlock->renderer()->xPos() + m_innerText->renderer()->xPos(); - int textRight = textLeft + m_innerText->renderer()->width(); - if (m_resultsButton && m_resultsButton->renderer() && x < textLeft) { - result.setInnerNode(m_resultsButton.get()); - result.setLocalPoint(IntPoint(localPoint.x() - m_innerText->renderer()->xPos() - m_innerBlock->renderer()->xPos() - m_resultsButton->renderer()->xPos(), - localPoint.y() - m_innerText->renderer()->yPos() - m_innerBlock->renderer()->yPos() - m_resultsButton->renderer()->yPos())); - return true; - } - if (m_cancelButton && m_cancelButton->renderer() && x > textRight) { - result.setInnerNode(m_cancelButton.get()); - result.setLocalPoint(IntPoint(localPoint.x() - m_innerText->renderer()->xPos() - m_innerBlock->renderer()->xPos() - m_cancelButton->renderer()->xPos(), - localPoint.y() - m_innerText->renderer()->yPos() - m_innerBlock->renderer()->yPos() - m_cancelButton->renderer()->yPos())); - return true; - } - } - - // Hit the inner text block. - result.setInnerNode(m_innerText.get()); - result.setLocalPoint(IntPoint(localPoint.x() - m_innerText->renderer()->xPos() - (m_innerBlock.get() ? m_innerBlock->renderer()->xPos() : 0), - localPoint.y() - m_innerText->renderer()->yPos() - (m_innerBlock.get() ? m_innerBlock->renderer()->yPos() : 0))); - - return true; - } - - return false; + if (event->type() == eventNames().blurEvent || event->type() == eventNames().focusEvent) + return; + m_innerText->defaultEventHandler(event); } IntRect RenderTextControl::controlClipRect(int tx, int ty) const { - IntRect clipRect = contentBox(); + IntRect clipRect = contentBoxRect(); clipRect.move(tx, ty); return clipRect; } -void RenderTextControl::layout() -{ - int oldHeight = m_height; - calcHeight(); - bool relayoutChildren = oldHeight != m_height; - - // Set the text block's height - int textBlockHeight = m_height - paddingTop() - paddingBottom() - borderTop() - borderBottom(); - int currentTextBlockHeight = m_innerText->renderer()->height(); - if (m_multiLine || m_innerBlock || currentTextBlockHeight > m_height) { - if (textBlockHeight != currentTextBlockHeight) - relayoutChildren = true; - m_innerText->renderer()->style()->setHeight(Length(textBlockHeight, Fixed)); - } - if (m_innerBlock) { - if (textBlockHeight != m_innerBlock->renderer()->height()) - relayoutChildren = true; - m_innerBlock->renderer()->style()->setHeight(Length(textBlockHeight, Fixed)); - } - -#ifdef ANDROID_LAYOUT - int oldVisibleWidth = m_visibleWidth; -#endif - - int oldWidth = m_width; - calcWidth(); - - // FIXME: This causes cnn.com loading way slow. Comment it out for now -//#ifdef ANDROID_LAYOUT -#if 0 - Frame* frame = document()->frame(); - if (frame && frame->settings()->layoutAlgorithm() == Settings::kLayoutFitColumnToScreen) { - int maxWidth = frame->view()->visibleWidth() - 2 * ANDROID_FCTS_MARGIN_PADDING; - if (maxWidth > 0 && maxWidth < m_width) { - m_width = maxWidth; - // not only modify the control's width, we also need to modify its - // parent (even grandparent) width if it is not auto - Length styleWidth = style()->width(); - if (styleWidth.isFixed()) { - // now we need to get max style width - maxWidth -= borderLeft() + borderRight() + paddingLeft() + paddingRight(); - style()->setWidth(Length(maxWidth, Fixed)); - } else if (styleWidth.isPercent()) { - RenderObject* o = this; - while (RenderBox* p = (RenderBox*)(o->parent())) { - int maxParentWidth = (int)(maxWidth * 100 / styleWidth.percent()); - if (p->width() <= maxParentWidth) - break; - p->setWidth(maxParentWidth); - styleWidth = p->style()->width(); - if (!styleWidth.isPercent()) - break; - o = p; - maxWidth = maxParentWidth; - } - } - } - } -#endif - if (oldWidth != m_width) - relayoutChildren = true; - -#ifdef ANDROID_LAYOUT - if (oldVisibleWidth != m_visibleWidth - && document()->settings()->layoutAlgorithm() == Settings::kLayoutFitColumnToScreen) - relayoutChildren = true; -#endif - - int searchExtrasWidth = 0; - if (m_resultsButton && m_resultsButton->renderer()) { - m_resultsButton->renderer()->calcWidth(); - searchExtrasWidth += m_resultsButton->renderer()->width(); - } - if (m_cancelButton && m_cancelButton->renderer()) { - m_cancelButton->renderer()->calcWidth(); - searchExtrasWidth += m_cancelButton->renderer()->width(); - } - - // Set the text block's width - int textBlockWidth = m_width - paddingLeft() - paddingRight() - borderLeft() - borderRight() - - m_innerText->renderer()->paddingLeft() - m_innerText->renderer()->paddingRight() - searchExtrasWidth; - if (textBlockWidth != m_innerText->renderer()->width()) - relayoutChildren = true; - m_innerText->renderer()->style()->setWidth(Length(textBlockWidth, Fixed)); - if (m_innerBlock) { - int innerBlockWidth = m_width - paddingLeft() - paddingRight() - borderLeft() - borderRight(); - if (innerBlockWidth != m_innerBlock->renderer()->width()) - relayoutChildren = true; - m_innerBlock->renderer()->style()->setWidth(Length(innerBlockWidth, Fixed)); - } - - RenderBlock::layoutBlock(relayoutChildren); - - // For text fields, center the inner text vertically - // Don't do this for search fields, since we don't honor height for them - if (!m_multiLine) { - currentTextBlockHeight = m_innerText->renderer()->height(); - if (!m_innerBlock && currentTextBlockHeight < m_height) - m_innerText->renderer()->setPos(m_innerText->renderer()->xPos(), (m_height - currentTextBlockHeight) / 2); - } -} - -void RenderTextControl::paint(PaintInfo& paintInfo, int tx, int ty) -{ - RenderBlock::paint(paintInfo, tx, ty); - if (paintInfo.phase == PaintPhaseBlockBackground && m_shouldDrawCapsLockIndicator) - theme()->paintCapsLockIndicator(this, paintInfo, absoluteContentBox()); -} - void RenderTextControl::calcPrefWidths() { ASSERT(prefWidthsDirty()); @@ -845,27 +475,7 @@ void RenderTextControl::calcPrefWidths() // (using "0" as the nominal character). const UChar ch = '0'; float charWidth = style()->font().floatWidth(TextRun(&ch, 1, false, 0, 0, false, false, false)); - int factor; - int scrollbarSize = 0; - if (m_multiLine) { - factor = static_cast<HTMLTextAreaElement*>(node())->cols(); - // FIXME: We should get the size of the scrollbar from the RenderTheme instead. - if (m_innerText->renderer()->style()->overflowY() != OHIDDEN) - scrollbarSize = ScrollbarTheme::nativeTheme()->scrollbarThickness(); - } else { - factor = static_cast<HTMLInputElement*>(node())->size(); - if (factor <= 0) - factor = 20; - } - m_maxPrefWidth = static_cast<int>(ceilf(charWidth * factor)) + scrollbarSize + - m_innerText->renderer()->paddingLeft() + m_innerText->renderer()->paddingRight(); - - if (m_resultsButton && m_resultsButton->renderer()) - m_maxPrefWidth += m_resultsButton->renderer()->borderLeft() + m_resultsButton->renderer()->borderRight() + - m_resultsButton->renderer()->paddingLeft() + m_resultsButton->renderer()->paddingRight(); - if (m_cancelButton && m_cancelButton->renderer()) - m_maxPrefWidth += m_cancelButton->renderer()->borderLeft() + m_cancelButton->renderer()->borderRight() + - m_cancelButton->renderer()->paddingLeft() + m_cancelButton->renderer()->paddingRight(); + m_maxPrefWidth = preferredContentWidth(charWidth) + m_innerText->renderBox()->paddingLeft() + m_innerText->renderBox()->paddingRight(); } if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) { @@ -901,43 +511,24 @@ void RenderTextControl::calcPrefWidths() setPrefWidthsDirty(false); } -void RenderTextControl::forwardEvent(Event* evt) +void RenderTextControl::selectionChanged(bool userTriggered) { - if (evt->type() == eventNames().blurEvent) { - RenderObject* innerRenderer = m_innerText->renderer(); - if (innerRenderer) { - RenderLayer* innerLayer = innerRenderer->layer(); - if (innerLayer && !m_multiLine) - innerLayer->scrollToOffset(style()->direction() == RTL ? innerLayer->scrollWidth() : 0, 0); - } - capsLockStateMayHaveChanged(); - } else if (evt->type() == eventNames().focusEvent) - capsLockStateMayHaveChanged(); - else { - if (evt->isMouseEvent() && m_resultsButton && static_cast<MouseEvent*>(evt)->x() < m_innerText->renderer()->absoluteBoundingBoxRect().x()) - m_resultsButton->defaultEventHandler(evt); - else if (evt->isMouseEvent() && m_cancelButton && static_cast<MouseEvent*>(evt)->x() > m_innerText->renderer()->absoluteBoundingBoxRect().right()) - m_cancelButton->defaultEventHandler(evt); - else - m_innerText->defaultEventHandler(evt); + cacheSelection(selectionStart(), selectionEnd()); + + if (Frame* frame = document()->frame()) { + if (frame->selection()->isRange() && userTriggered) + static_cast<EventTargetNode*>(node())->dispatchEventForType(eventNames().selectEvent, true, false); } } -void RenderTextControl::selectionChanged(bool userTriggered) +void RenderTextControl::addFocusRingRects(GraphicsContext* graphicsContext, int tx, int ty) { - HTMLFormControlElement* element = static_cast<HTMLFormControlElement*>(node()); - if (m_multiLine) - static_cast<HTMLTextAreaElement*>(element)->cacheSelection(selectionStart(), selectionEnd()); - else - static_cast<HTMLInputElement*>(element)->cacheSelection(selectionStart(), selectionEnd()); - if (Frame* frame = document()->frame()) - if (frame->selection()->isRange() && userTriggered) - element->dispatchEventForType(eventNames().selectEvent, true, false); + graphicsContext->addFocusRingRect(IntRect(tx, ty, width(), height())); } void RenderTextControl::autoscroll() { - RenderLayer* layer = m_innerText->renderer()->layer(); + RenderLayer* layer = m_innerText->renderBox()->layer(); if (layer) layer->autoscroll(); } @@ -982,291 +573,22 @@ void RenderTextControl::setScrollTop(int newTop) m_innerText->setScrollTop(newTop); } -const AtomicString& RenderTextControl::autosaveName() const -{ - return static_cast<Element*>(node())->getAttribute(autosaveAttr); -} - -void RenderTextControl::addSearchResult() -{ - ASSERT(!m_multiLine); - - HTMLInputElement* input = static_cast<HTMLInputElement*>(node()); - if (input->maxResults() <= 0) - return; - - String value = input->value(); - if (value.isEmpty()) - return; - - Settings* settings = document()->settings(); - if (!settings || settings->privateBrowsingEnabled()) - return; - - int size = static_cast<int>(m_recentSearches.size()); - for (int i = size - 1; i >= 0; --i) - if (m_recentSearches[i] == value) - m_recentSearches.remove(i); - - m_recentSearches.insert(0, value); - while (static_cast<int>(m_recentSearches.size()) > input->maxResults()) - m_recentSearches.removeLast(); - - const AtomicString& name = autosaveName(); - if (!m_searchPopup) - m_searchPopup = SearchPopupMenu::create(this); - m_searchPopup->saveRecentSearches(name, m_recentSearches); -} - -void RenderTextControl::showPopup() -{ - if (m_searchPopupIsVisible) - return; - - if (!m_searchPopup) - m_searchPopup = SearchPopupMenu::create(this); - - if (!m_searchPopup->enabled()) - return; - - m_searchPopupIsVisible = true; - - const AtomicString& name = autosaveName(); - m_searchPopup->loadRecentSearches(name, m_recentSearches); - - // Trim the recent searches list if the maximum size has changed since we last saved. - HTMLInputElement* input = static_cast<HTMLInputElement*>(node()); - if (static_cast<int>(m_recentSearches.size()) > input->maxResults()) { - do - m_recentSearches.removeLast(); - while (static_cast<int>(m_recentSearches.size()) > input->maxResults()); - m_searchPopup->saveRecentSearches(name, m_recentSearches); - } - - m_searchPopup->show(absoluteBoundingBoxRect(), document()->view(), -1); -} - -void RenderTextControl::hidePopup() -{ - if (m_searchPopup) - m_searchPopup->hide(); - m_searchPopupIsVisible = false; -} - -void RenderTextControl::valueChanged(unsigned listIndex, bool fireEvents) -{ - ASSERT(static_cast<int>(listIndex) < listSize()); - HTMLInputElement* input = static_cast<HTMLInputElement*>(node()); - if (static_cast<int>(listIndex) == (listSize() - 1)) { - if (fireEvents) { - m_recentSearches.clear(); - const AtomicString& name = autosaveName(); - if (!name.isEmpty()) { - if (!m_searchPopup) - m_searchPopup = SearchPopupMenu::create(this); - m_searchPopup->saveRecentSearches(name, m_recentSearches); - } - } - } else { - input->setValue(itemText(listIndex)); - if (fireEvents) - input->onSearch(); - input->select(); - } -} - -String RenderTextControl::itemText(unsigned listIndex) const -{ - int size = listSize(); - if (size == 1) { - ASSERT(!listIndex); - return searchMenuNoRecentSearchesText(); - } - if (!listIndex) - return searchMenuRecentSearchesText(); - if (itemIsSeparator(listIndex)) - return String(); - if (static_cast<int>(listIndex) == (size - 1)) - return searchMenuClearRecentSearchesText(); - return m_recentSearches[listIndex - 1]; -} - -bool RenderTextControl::itemIsEnabled(unsigned listIndex) const -{ - if (!listIndex || itemIsSeparator(listIndex)) - return false; - return true; -} - -PopupMenuStyle RenderTextControl::itemStyle(unsigned listIndex) const -{ - return menuStyle(); -} - -PopupMenuStyle RenderTextControl::menuStyle() const -{ - return PopupMenuStyle(style()->color(), style()->backgroundColor(), style()->font(), style()->visibility() == VISIBLE); -} - -HostWindow* RenderTextControl::hostWindow() const -{ - return document()->view()->hostWindow(); -} - -PassRefPtr<Scrollbar> RenderTextControl::createScrollbar(ScrollbarClient* client, ScrollbarOrientation orientation, ScrollbarControlSize controlSize) -{ - RefPtr<Scrollbar> widget; - bool hasCustomScrollbarStyle = style()->hasPseudoStyle(RenderStyle::SCROLLBAR); - if (hasCustomScrollbarStyle) - widget = RenderScrollbar::createCustomScrollbar(client, orientation, this); - else - widget = Scrollbar::createNativeScrollbar(client, orientation, controlSize); - return widget.release(); -} - -int RenderTextControl::clientInsetLeft() const -{ - // Inset the menu by the radius of the cap on the left so that - // it only runs along the straight part of the bezel. - return height() / 2; -} - -int RenderTextControl::clientInsetRight() const -{ - // Inset the menu by the radius of the cap on the right so that - // it only runs along the straight part of the bezel (unless it needs - // to be wider). - return height() / 2; -} - -int RenderTextControl::clientPaddingLeft() const -{ - int padding = paddingLeft(); - if (m_resultsButton->renderer()) - padding += m_resultsButton->renderer()->width(); - return padding; -} - -int RenderTextControl::clientPaddingRight() const -{ - int padding = paddingRight(); - if (m_cancelButton->renderer()) - padding += m_cancelButton->renderer()->width(); - return padding; -} - -int RenderTextControl::listSize() const -{ - // If there are no recent searches, then our menu will have 1 "No recent searches" item. - if (!m_recentSearches.size()) - return 1; - // Otherwise, leave room in the menu for a header, a separator, and the "Clear recent searches" item. - return m_recentSearches.size() + 3; -} - -int RenderTextControl::selectedIndex() const -{ - return -1; -} - -bool RenderTextControl::itemIsSeparator(unsigned listIndex) const -{ - // The separator will be the second to last item in our list. - return static_cast<int>(listIndex) == (listSize() - 2); -} - -bool RenderTextControl::itemIsLabel(unsigned listIndex) const -{ - return listIndex == 0; -} - -bool RenderTextControl::itemIsSelected(unsigned listIndex) const -{ - return false; -} - -void RenderTextControl::setTextFromItem(unsigned listIndex) -{ - static_cast<HTMLInputElement*>(node())->setValue(itemText(listIndex)); -} - bool RenderTextControl::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier) { - RenderLayer* layer = m_innerText->renderer()->layer(); + RenderLayer* layer = m_innerText->renderBox()->layer(); if (layer && layer->scroll(direction, granularity, multiplier)) return true; - return RenderObject::scroll(direction, granularity, multiplier); -} - -void RenderTextControl::searchEventTimerFired(Timer<RenderTextControl>*) -{ - static_cast<HTMLInputElement*>(node())->onSearch(); + return RenderBlock::scroll(direction, granularity, multiplier); } -void RenderTextControl::stopSearchEventTimer() -{ - m_searchEventTimer.stop(); -} - -void RenderTextControl::startSearchEventTimer() -{ - unsigned length = text().length(); - - // If there's no text, fire the event right away. - if (!length) { - m_searchEventTimer.stop(); - static_cast<HTMLInputElement*>(node())->onSearch(); - return; - } - - // After typing the first key, we wait 0.5 seconds. - // After the second key, 0.4 seconds, then 0.3, then 0.2 from then on. - m_searchEventTimer.startOneShot(max(0.2, 0.6 - 0.1 * length)); -} - -bool RenderTextControl::isScrollable() const -{ - if (m_innerText && m_innerText->renderer()->isScrollable()) - return true; - return RenderObject::isScrollable(); -} - -FontSelector* RenderTextControl::fontSelector() const -{ - return document()->styleSelector()->fontSelector(); -} - -void RenderTextControl::updatePlaceholderVisibility() +HTMLElement* RenderTextControl::innerTextElement() const { - RenderStyle* parentStyle = m_innerBlock ? m_innerBlock->renderer()->style() : style(); - RefPtr<RenderStyle> textBlockStyle = createInnerTextStyle(parentStyle); - m_innerText->renderer()->setStyle(textBlockStyle); - for (Node* n = m_innerText->firstChild(); n; n = n->traverseNextNode(m_innerText.get())) { - if (n->renderer()) - n->renderer()->setStyle(textBlockStyle); - } - updateFromElement(); + return m_innerText.get(); } -void RenderTextControl::capsLockStateMayHaveChanged() +FormControlElement* RenderTextControl::formControlElement() const { - // Only draw the caps lock indicator if these things are true: - // 1) The field is a password field - // 2) The frame is active - // 3) The element is focused - // 4) The caps lock is on - - bool shouldDrawCapsLockIndicator = false; - if (Node* n = node()) - if (Document* d = document()) - if (Frame* f = d->frame()) - shouldDrawCapsLockIndicator = !m_multiLine && static_cast<HTMLInputElement*>(n)->inputType() == HTMLInputElement::PASSWORD && - f->selection()->isFocusedAndActive() && d->focusedNode() == n && PlatformKeyboardEvent::currentCapsLockState(); - - if (shouldDrawCapsLockIndicator != m_shouldDrawCapsLockIndicator) { - m_shouldDrawCapsLockIndicator = shouldDrawCapsLockIndicator; - repaint(); - } + return toFormControlElement(static_cast<Element*>(node())); } } // namespace WebCore diff --git a/WebCore/rendering/RenderTextControl.h b/WebCore/rendering/RenderTextControl.h index 74fdd26..86d3f8a 100644 --- a/WebCore/rendering/RenderTextControl.h +++ b/WebCore/rendering/RenderTextControl.h @@ -1,5 +1,6 @@ /* - * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.s + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -21,45 +22,32 @@ #ifndef RenderTextControl_h #define RenderTextControl_h -#include "PopupMenuClient.h" #include "RenderBlock.h" -#include "Timer.h" namespace WebCore { -class FontSelector; -class SearchFieldCancelButtonElement; -class SearchFieldResultsButtonElement; -class SearchPopupMenu; +class FormControlElement; class Selection; class TextControlInnerElement; class TextControlInnerTextElement; -class RenderTextControl : public RenderBlock, private PopupMenuClient { +class RenderTextControl : public RenderBlock { public: - RenderTextControl(Node*, bool multiLine); virtual ~RenderTextControl(); virtual const char* renderName() const { return "RenderTextControl"; } - - virtual bool hasControlClip() const { return m_cancelButton; } + virtual bool hasControlClip() const { return false; } virtual IntRect controlClipRect(int tx, int ty) const; virtual void calcHeight(); virtual void calcPrefWidths(); virtual void removeLeftoverAnonymousBlock(RenderBlock*) { } virtual void updateFromElement(); virtual bool canHaveChildren() const { return false; } - virtual int baselinePosition(bool firstLine, bool isRootLineBox) const; - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); - virtual void layout(); virtual bool avoidsFloats() const { return true; } - virtual void paint(PaintInfo&, int tx, int ty); - - virtual bool isEdited() const { return m_dirty; } - virtual void setEdited(bool isEdited) { m_dirty = isEdited; } - virtual bool isTextField() const { return !m_multiLine; } - virtual bool isTextArea() const { return m_multiLine; } + virtual bool isEdited() const { return m_edited; } + virtual void setEdited(bool isEdited) { m_edited = isEdited; } + bool isUserEdited() const { return m_userEdited; } void setUserEdited(bool isUserEdited); @@ -71,12 +59,13 @@ public: void setSelectionRange(int start, int end); Selection selection(int start, int end) const; - void subtreeHasChanged(); + virtual void subtreeHasChanged(); String text(); String textWithHardLineBreaks(); - void forwardEvent(Event*); void selectionChanged(bool userTriggered); + virtual void addFocusRingRects(GraphicsContext*, int tx, int ty); + virtual bool canBeProgramaticallyScrolled(bool) const { return true; } virtual void autoscroll(); @@ -88,81 +77,42 @@ public: virtual void setScrollLeft(int); virtual void setScrollTop(int); virtual bool scroll(ScrollDirection, ScrollGranularity, float multiplier = 1.0f); - virtual bool isScrollable() const; VisiblePosition visiblePositionForIndex(int index); int indexForVisiblePosition(const VisiblePosition&); - void addSearchResult(); +protected: + RenderTextControl(Node*); - bool popupIsVisible() const { return m_searchPopupIsVisible; } - void showPopup(); - void hidePopup(); + int scrollbarThickness() const; + void adjustInnerTextStyle(const RenderStyle* startStyle, RenderStyle* textBlockStyle) const; + void setInnerTextValue(const String&); - void stopSearchEventTimer(); - - bool placeholderIsVisible() const { return m_placeholderVisible; } - void updatePlaceholderVisibility(); + virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle); - virtual void capsLockStateMayHaveChanged(); + void createSubtreeIfNeeded(TextControlInnerElement* innerBlock); + void hitInnerTextBlock(HitTestResult&, int x, int y, int tx, int ty); + void forwardEvent(Event*); -protected: - virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle); + int textBlockWidth() const; + int textBlockHeight() const; -private: - // PopupMenuClient methods - virtual void valueChanged(unsigned listIndex, bool fireEvents = true); - virtual String itemText(unsigned listIndex) const; - virtual bool itemIsEnabled(unsigned listIndex) const; - virtual PopupMenuStyle itemStyle(unsigned listIndex) const; - virtual PopupMenuStyle menuStyle() const; - virtual int clientInsetLeft() const; - virtual int clientInsetRight() const; - virtual int clientPaddingLeft() const; - virtual int clientPaddingRight() const; - virtual int listSize() const; - virtual int selectedIndex() const; - virtual bool itemIsSeparator(unsigned listIndex) const; - virtual bool itemIsLabel(unsigned listIndex) const; - virtual bool itemIsSelected(unsigned listIndex) const; - virtual void setTextFromItem(unsigned listIndex); - virtual bool shouldPopOver() const { return false; } - virtual bool valueShouldChangeOnHotTrack() const { return false; } - virtual FontSelector* fontSelector() const; - virtual HostWindow* hostWindow() const; - virtual PassRefPtr<Scrollbar> createScrollbar(ScrollbarClient*, ScrollbarOrientation, ScrollbarControlSize); - - PassRefPtr<RenderStyle> createInnerBlockStyle(const RenderStyle* startStyle); - PassRefPtr<RenderStyle> createInnerTextStyle(const RenderStyle* startStyle); - PassRefPtr<RenderStyle> createCancelButtonStyle(const RenderStyle* startStyle); - PassRefPtr<RenderStyle> createResultsButtonStyle(const RenderStyle* startStyle); - - void createSubtreeIfNeeded(); - void updateCancelButtonVisibility(RenderStyle*); - const AtomicString& autosaveName() const; - void startSearchEventTimer(); - void searchEventTimerFired(Timer<RenderTextControl>*); - String finishText(Vector<UChar>&) const; + virtual int preferredContentWidth(float charWidth) const = 0; + virtual void adjustControlHeightBasedOnLineHeight(int lineHeight) = 0; + virtual void cacheSelection(int start, int end) = 0; + virtual PassRefPtr<RenderStyle> createInnerTextStyle(const RenderStyle* startStyle) const = 0; friend class TextIterator; HTMLElement* innerTextElement() const; - RefPtr<TextControlInnerElement> m_innerBlock; - RefPtr<TextControlInnerTextElement> m_innerText; - RefPtr<SearchFieldResultsButtonElement> m_resultsButton; - RefPtr<SearchFieldCancelButtonElement> m_cancelButton; + FormControlElement* formControlElement() const; - bool m_dirty; - bool m_multiLine; - bool m_placeholderVisible; - bool m_userEdited; - bool m_shouldDrawCapsLockIndicator; - - RefPtr<SearchPopupMenu> m_searchPopup; - bool m_searchPopupIsVisible; - mutable Vector<String> m_recentSearches; +private: + String finishText(Vector<UChar>&) const; - Timer<RenderTextControl> m_searchEventTimer; + bool m_edited; + bool m_userEdited; + RefPtr<TextControlInnerTextElement> m_innerText; }; } // namespace WebCore diff --git a/WebCore/rendering/RenderTextControlMultiLine.cpp b/WebCore/rendering/RenderTextControlMultiLine.cpp new file mode 100644 index 0000000..253f53f --- /dev/null +++ b/WebCore/rendering/RenderTextControlMultiLine.cpp @@ -0,0 +1,171 @@ +/** + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "RenderTextControlMultiLine.h" + +#include "EventNames.h" +#include "Frame.h" +#include "HitTestResult.h" +#include "HTMLTextAreaElement.h" +#ifdef ANDROID_LAYOUT +#include "Settings.h" +#endif + +namespace WebCore { + +RenderTextControlMultiLine::RenderTextControlMultiLine(Node* node) + : RenderTextControl(node) +{ +} + +RenderTextControlMultiLine::~RenderTextControlMultiLine() +{ + if (node()) + static_cast<HTMLTextAreaElement*>(node())->rendererWillBeDestroyed(); +} + +void RenderTextControlMultiLine::subtreeHasChanged() +{ + RenderTextControl::subtreeHasChanged(); + formControlElement()->setValueMatchesRenderer(false); + + if (!node()->focused()) + return; + + if (Frame* frame = document()->frame()) + frame->textDidChangeInTextArea(static_cast<Element*>(node())); +} + +void RenderTextControlMultiLine::layout() +{ + int oldHeight = height(); + calcHeight(); + +#ifdef ANDROID_LAYOUT + int oldVisibleWidth = m_visibleWidth; +#endif + + int oldWidth = width(); + calcWidth(); + + bool relayoutChildren = oldHeight != height() || oldWidth != width(); +#ifdef ANDROID_LAYOUT + if (oldVisibleWidth != m_visibleWidth + && document()->settings()->layoutAlgorithm() == Settings::kLayoutFitColumnToScreen) { + relayoutChildren = true; + } +#endif + + RenderBox* innerTextRenderer = innerTextElement()->renderBox(); + + // Set the text block height + int desiredHeight = textBlockHeight(); + if (desiredHeight != innerTextRenderer->height()) + relayoutChildren = true; + innerTextRenderer->style()->setHeight(Length(desiredHeight, Fixed)); + + // Set the text block width + int desiredWidth = textBlockWidth(); + if (desiredWidth != innerTextRenderer->width()) + relayoutChildren = true; + innerTextRenderer->style()->setWidth(Length(desiredWidth, Fixed)); + + RenderBlock::layoutBlock(relayoutChildren); +} + +bool RenderTextControlMultiLine::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction) +{ + if (!RenderTextControl::nodeAtPoint(request, result, x, y, tx, ty, hitTestAction)) + return false; + + if (result.innerNode() == element()) { + hitInnerTextBlock(result, x, y, tx, ty); + return true; + } + + return false; +} + +void RenderTextControlMultiLine::forwardEvent(Event* event) +{ + RenderTextControl::forwardEvent(event); +} + +int RenderTextControlMultiLine::preferredContentWidth(float charWidth) const +{ + int factor = static_cast<HTMLTextAreaElement*>(node())->cols(); + return static_cast<int>(ceilf(charWidth * factor)) + scrollbarThickness(); +} + +void RenderTextControlMultiLine::adjustControlHeightBasedOnLineHeight(int lineHeight) +{ + setHeight(height() + lineHeight * static_cast<HTMLTextAreaElement*>(node())->rows()); +} + +int RenderTextControlMultiLine::baselinePosition(bool, bool) const +{ + return height() + marginTop() + marginBottom(); +} + +void RenderTextControlMultiLine::updateFromElement() +{ + createSubtreeIfNeeded(0); + RenderTextControl::updateFromElement(); + + setInnerTextValue(static_cast<HTMLTextAreaElement*>(node())->value()); +} + +void RenderTextControlMultiLine::cacheSelection(int start, int end) +{ + static_cast<HTMLTextAreaElement*>(node())->cacheSelection(start, end); +} + +PassRefPtr<RenderStyle> RenderTextControlMultiLine::createInnerTextStyle(const RenderStyle* startStyle) const +{ + RefPtr<RenderStyle> textBlockStyle = RenderStyle::create(); + textBlockStyle->inheritFrom(startStyle); + + adjustInnerTextStyle(startStyle, textBlockStyle.get()); + + // Forward overflow properties. + textBlockStyle->setOverflowX(startStyle->overflowX() == OVISIBLE ? OAUTO : startStyle->overflowX()); + textBlockStyle->setOverflowY(startStyle->overflowY() == OVISIBLE ? OAUTO : startStyle->overflowY()); + + // Set word wrap property based on wrap attribute. + if (static_cast<HTMLTextAreaElement*>(node())->shouldWrapText()) { + textBlockStyle->setWhiteSpace(PRE_WRAP); + textBlockStyle->setWordWrap(BreakWordWrap); + } else { + textBlockStyle->setWhiteSpace(PRE); + textBlockStyle->setWordWrap(NormalWordWrap); + } + + textBlockStyle->setDisplay(BLOCK); + + // We're adding three extra pixels of padding to line textareas up with text fields. + textBlockStyle->setPaddingLeft(Length(3, Fixed)); + textBlockStyle->setPaddingRight(Length(3, Fixed)); + + return textBlockStyle.release(); +} + +} diff --git a/WebCore/rendering/RenderTextControlMultiLine.h b/WebCore/rendering/RenderTextControlMultiLine.h new file mode 100644 index 0000000..591a65d --- /dev/null +++ b/WebCore/rendering/RenderTextControlMultiLine.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) + * + * 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 RenderTextControlMultiLine_h +#define RenderTextControlMultiLine_h + +#include "RenderTextControl.h" + +namespace WebCore { + +class RenderTextControlMultiLine : public RenderTextControl { +public: + RenderTextControlMultiLine(Node*); + virtual ~RenderTextControlMultiLine(); + + virtual bool isTextArea() const { return true; } + + virtual void subtreeHasChanged(); + virtual void layout(); + + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); + void forwardEvent(Event*); + +private: + virtual int preferredContentWidth(float charWidth) const; + virtual void adjustControlHeightBasedOnLineHeight(int lineHeight); + virtual int baselinePosition(bool firstLine, bool isRootLineBox) const; + + virtual void updateFromElement(); + virtual void cacheSelection(int start, int end); + + virtual PassRefPtr<RenderStyle> createInnerTextStyle(const RenderStyle* startStyle) const; +}; + +} + +#endif diff --git a/WebCore/rendering/RenderTextControlSingleLine.cpp b/WebCore/rendering/RenderTextControlSingleLine.cpp new file mode 100644 index 0000000..fccea00 --- /dev/null +++ b/WebCore/rendering/RenderTextControlSingleLine.cpp @@ -0,0 +1,787 @@ +/** + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "RenderTextControlSingleLine.h" + +#include "CSSStyleSelector.h" +#include "Event.h" +#include "EventNames.h" +#include "Frame.h" +#include "FrameView.h" +#include "HitTestResult.h" +#include "HTMLInputElement.h" +#include "HTMLNames.h" +#include "InputElement.h" +#include "LocalizedStrings.h" +#include "MouseEvent.h" +#include "PlatformKeyboardEvent.h" +#include "RenderScrollbar.h" +#include "RenderTheme.h" +#include "SearchPopupMenu.h" +#include "SelectionController.h" +#include "Settings.h" +#include "TextControlInnerElements.h" + +using namespace std; + +namespace WebCore { + +using namespace HTMLNames; + +RenderTextControlSingleLine::RenderTextControlSingleLine(Node* node) + : RenderTextControl(node) + , m_placeholderVisible(false) + , m_searchPopupIsVisible(false) + , m_shouldDrawCapsLockIndicator(false) + , m_searchEventTimer(this, &RenderTextControlSingleLine::searchEventTimerFired) + , m_searchPopup(0) +{ +} + +RenderTextControlSingleLine::~RenderTextControlSingleLine() +{ + if (m_searchPopup) { + m_searchPopup->disconnectClient(); + m_searchPopup = 0; + } + + if (m_innerBlock) + m_innerBlock->detach(); +} + +bool RenderTextControlSingleLine::placeholderShouldBeVisible() const +{ + return inputElement()->placeholderShouldBeVisible(); +} + +void RenderTextControlSingleLine::updatePlaceholderVisibility() +{ + RenderStyle* parentStyle = m_innerBlock ? m_innerBlock->renderer()->style() : style(); + + RefPtr<RenderStyle> textBlockStyle = createInnerTextStyle(parentStyle); + HTMLElement* innerText = innerTextElement(); + innerText->renderer()->setStyle(textBlockStyle); + + for (Node* n = innerText->firstChild(); n; n = n->traverseNextNode(innerText)) { + if (RenderObject* renderer = n->renderer()) + renderer->setStyle(textBlockStyle); + } + + updateFromElement(); +} + +void RenderTextControlSingleLine::addSearchResult() +{ + ASSERT(node()->isHTMLElement()); + HTMLInputElement* input = static_cast<HTMLInputElement*>(node()); + if (input->maxResults() <= 0) + return; + + String value = input->value(); + if (value.isEmpty()) + return; + + Settings* settings = document()->settings(); + if (!settings || settings->privateBrowsingEnabled()) + return; + + int size = static_cast<int>(m_recentSearches.size()); + for (int i = size - 1; i >= 0; --i) { + if (m_recentSearches[i] == value) + m_recentSearches.remove(i); + } + + m_recentSearches.insert(0, value); + while (static_cast<int>(m_recentSearches.size()) > input->maxResults()) + m_recentSearches.removeLast(); + + const AtomicString& name = autosaveName(); + if (!m_searchPopup) + m_searchPopup = SearchPopupMenu::create(this); + + m_searchPopup->saveRecentSearches(name, m_recentSearches); +} + +void RenderTextControlSingleLine::stopSearchEventTimer() +{ + ASSERT(node()->isHTMLElement()); + m_searchEventTimer.stop(); +} + +void RenderTextControlSingleLine::showPopup() +{ + ASSERT(node()->isHTMLElement()); + if (m_searchPopupIsVisible) + return; + + if (!m_searchPopup) + m_searchPopup = SearchPopupMenu::create(this); + + if (!m_searchPopup->enabled()) + return; + + m_searchPopupIsVisible = true; + + const AtomicString& name = autosaveName(); + m_searchPopup->loadRecentSearches(name, m_recentSearches); + + // Trim the recent searches list if the maximum size has changed since we last saved. + HTMLInputElement* input = static_cast<HTMLInputElement*>(node()); + if (static_cast<int>(m_recentSearches.size()) > input->maxResults()) { + do { + m_recentSearches.removeLast(); + } while (static_cast<int>(m_recentSearches.size()) > input->maxResults()); + + m_searchPopup->saveRecentSearches(name, m_recentSearches); + } + + m_searchPopup->show(absoluteBoundingBoxRect(true), document()->view(), -1); +} + +void RenderTextControlSingleLine::hidePopup() +{ + ASSERT(node()->isHTMLElement()); + if (m_searchPopup) + m_searchPopup->hide(); + + m_searchPopupIsVisible = false; +} + +void RenderTextControlSingleLine::subtreeHasChanged() +{ + bool wasEdited = isEdited(); + RenderTextControl::subtreeHasChanged(); + + InputElement* input = inputElement(); + input->setValueFromRenderer(input->constrainValue(text())); + + if (RenderObject* cancelButtonRenderer = m_cancelButton ? m_cancelButton->renderer() : 0) + updateCancelButtonVisibility(cancelButtonRenderer->style()); + + // If the incremental attribute is set, then dispatch the search event + if (input->searchEventsShouldBeDispatched()) + startSearchEventTimer(); + + if (!wasEdited && node()->focused()) { + if (Frame* frame = document()->frame()) + frame->textFieldDidBeginEditing(static_cast<Element*>(node())); + } + + if (node()->focused()) { + if (Frame* frame = document()->frame()) + frame->textDidChangeInTextField(static_cast<Element*>(node())); + } +} + +void RenderTextControlSingleLine::paint(PaintInfo& paintInfo, int tx, int ty) +{ + RenderTextControl::paint(paintInfo, tx, ty); + + if (paintInfo.phase == PaintPhaseBlockBackground && m_shouldDrawCapsLockIndicator) { + IntRect contentsRect = contentBoxRect(); + + // Convert the rect into the coords used for painting the content + contentsRect.move(tx + x(), ty + y()); + theme()->paintCapsLockIndicator(this, paintInfo, contentsRect); + } +} + +void RenderTextControlSingleLine::layout() +{ + int oldHeight = height(); + calcHeight(); + +#ifdef ANDROID_LAYOUT + int oldVisibleWidth = m_visibleWidth; +#endif + + int oldWidth = width(); + calcWidth(); + + bool relayoutChildren = oldHeight != height() || oldWidth != width(); + +#ifdef ANDROID_LAYOUT + if (oldVisibleWidth != m_visibleWidth + && document()->settings()->layoutAlgorithm() == Settings::kLayoutFitColumnToScreen) { + relayoutChildren = true; + } +#endif + + RenderBox* innerTextRenderer = innerTextElement()->renderBox(); + RenderBox* innerBlockRenderer = m_innerBlock ? m_innerBlock->renderBox() : 0; + + // Set the text block height + int desiredHeight = textBlockHeight(); + int currentHeight = innerTextRenderer->height(); + + if (m_innerBlock || currentHeight > height()) { + if (desiredHeight != currentHeight) + relayoutChildren = true; + innerTextRenderer->style()->setHeight(Length(desiredHeight, Fixed)); + } + + if (m_innerBlock) { + ASSERT(innerBlockRenderer); + if (desiredHeight != innerBlockRenderer->height()) + relayoutChildren = true; + innerBlockRenderer->style()->setHeight(Length(desiredHeight, Fixed)); + } + + // Set the text block width + int desiredWidth = textBlockWidth(); + if (desiredWidth != innerTextRenderer->width()) + relayoutChildren = true; + innerTextRenderer->style()->setWidth(Length(desiredWidth, Fixed)); + + if (m_innerBlock) { + int innerBlockWidth = width() - paddingLeft() - paddingRight() - borderLeft() - borderRight(); + if (innerBlockWidth != innerBlockRenderer->width()) + relayoutChildren = true; + innerBlockRenderer->style()->setWidth(Length(innerBlockWidth, Fixed)); + } + + RenderBlock::layoutBlock(relayoutChildren); + + // For text fields, center the inner text vertically + // Don't do this for search fields, since we don't honor height for them + if (!m_innerBlock) { + currentHeight = innerTextRenderer->height(); + if (currentHeight < height()) + innerTextRenderer->setLocation(innerTextRenderer->x(), (height() - currentHeight) / 2); + } +} + +bool RenderTextControlSingleLine::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int xPos, int yPos, int tx, int ty, HitTestAction hitTestAction) +{ + // If we're within the text control, we want to act as if we've hit the inner text block element, in case the point + // was on the control but not on the inner element (see Radar 4617841). + + // In a search field, we want to act as if we've hit the results block if we're to the left of the inner text block, + // and act as if we've hit the close block if we're to the right of the inner text block. + + if (!RenderTextControl::nodeAtPoint(request, result, xPos, yPos, tx, ty, hitTestAction)) + return false; + + if (result.innerNode() != element() && result.innerNode() != m_innerBlock.get()) + return false; + + hitInnerTextBlock(result, xPos, yPos, tx, ty); + + if (!m_innerBlock) + return true; + + Node* innerNode = 0; + RenderBox* innerBlockRenderer = m_innerBlock->renderBox(); + RenderBox* innerTextRenderer = innerTextElement()->renderBox(); + + IntPoint localPoint = result.localPoint(); + localPoint.move(-innerBlockRenderer->x(), -innerBlockRenderer->y()); + + int textLeft = tx + x() + innerBlockRenderer->x() + innerTextRenderer->x(); + if (m_resultsButton && m_resultsButton->renderer() && xPos < textLeft) + innerNode = m_resultsButton.get(); + + if (!innerNode) { + int textRight = textLeft + innerTextRenderer->width(); + if (m_cancelButton && m_cancelButton->renderer() && xPos > textRight) + innerNode = m_cancelButton.get(); + } + + if (innerNode) { + result.setInnerNode(innerNode); + localPoint.move(-innerNode->renderBox()->x(), -innerNode->renderBox()->y()); + } + + result.setLocalPoint(localPoint); + return true; +} + +void RenderTextControlSingleLine::forwardEvent(Event* event) +{ + RenderBox* innerTextRenderer = innerTextElement()->renderBox(); + + if (event->type() == eventNames().blurEvent) { + if (innerTextRenderer) { + if (RenderLayer* innerLayer = innerTextRenderer->layer()) + innerLayer->scrollToOffset(style()->direction() == RTL ? innerLayer->scrollWidth() : 0, 0); + } + + capsLockStateMayHaveChanged(); + } else if (event->type() == eventNames().focusEvent) + capsLockStateMayHaveChanged(); + + if (!event->isMouseEvent()) { + RenderTextControl::forwardEvent(event); + return; + } + + FloatPoint localPoint = innerTextRenderer->absoluteToLocal(FloatPoint(static_cast<MouseEvent*>(event)->pageX(), static_cast<MouseEvent*>(event)->pageY()), false, true); + if (m_resultsButton && localPoint.x() < innerTextRenderer->borderBoxRect().x()) + m_resultsButton->defaultEventHandler(event); + else if (m_cancelButton && localPoint.x() > innerTextRenderer->borderBoxRect().right()) + m_cancelButton->defaultEventHandler(event); + else + RenderTextControl::forwardEvent(event); +} + +void RenderTextControlSingleLine::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle) +{ + RenderTextControl::styleDidChange(diff, oldStyle); + + if (RenderObject* innerBlockRenderer = m_innerBlock ? m_innerBlock->renderer() : 0) { + // We may have set the width and the height in the old style in layout(). + // Reset them now to avoid getting a spurious layout hint. + innerBlockRenderer->style()->setHeight(Length()); + innerBlockRenderer->style()->setWidth(Length()); + innerBlockRenderer->setStyle(createInnerBlockStyle(style())); + } + + if (RenderObject* resultsRenderer = m_resultsButton ? m_resultsButton->renderer() : 0) + resultsRenderer->setStyle(createResultsButtonStyle(style())); + + if (RenderObject* cancelRenderer = m_cancelButton ? m_cancelButton->renderer() : 0) + cancelRenderer->setStyle(createCancelButtonStyle(style())); +} + +void RenderTextControlSingleLine::capsLockStateMayHaveChanged() +{ + if (!node() || !document()) + return; + + // Only draw the caps lock indicator if these things are true: + // 1) The field is a password field + // 2) The frame is active + // 3) The element is focused + // 4) The caps lock is on + bool shouldDrawCapsLockIndicator = false; + + if (Frame* frame = document()->frame()) + shouldDrawCapsLockIndicator = inputElement()->isPasswordField() + && frame->selection()->isFocusedAndActive() + && document()->focusedNode() == node() + && PlatformKeyboardEvent::currentCapsLockState(); + + if (shouldDrawCapsLockIndicator != m_shouldDrawCapsLockIndicator) { + m_shouldDrawCapsLockIndicator = shouldDrawCapsLockIndicator; + repaint(); + } +} + +int RenderTextControlSingleLine::textBlockWidth() const +{ + int width = RenderTextControl::textBlockWidth(); + + if (RenderBox* resultsRenderer = m_resultsButton ? m_resultsButton->renderBox() : 0) { + resultsRenderer->calcWidth(); + width -= resultsRenderer->width() + resultsRenderer->marginLeft() + resultsRenderer->marginRight(); + } + + if (RenderBox* cancelRenderer = m_cancelButton ? m_cancelButton->renderBox() : 0) { + cancelRenderer->calcWidth(); + width -= cancelRenderer->width() + cancelRenderer->marginLeft() + cancelRenderer->marginRight(); + } + + return width; +} + +int RenderTextControlSingleLine::preferredContentWidth(float charWidth) const +{ + int factor = inputElement()->size(); + if (factor <= 0) + factor = 20; + + int result = static_cast<int>(ceilf(charWidth * factor)); + + if (RenderBox* resultsRenderer = m_resultsButton ? m_resultsButton->renderBox() : 0) + result += resultsRenderer->borderLeft() + resultsRenderer->borderRight() + + resultsRenderer->paddingLeft() + resultsRenderer->paddingRight(); + + if (RenderBox* cancelRenderer = m_cancelButton ? m_cancelButton->renderBox() : 0) + result += cancelRenderer->borderLeft() + cancelRenderer->borderRight() + + cancelRenderer->paddingLeft() + cancelRenderer->paddingRight(); + + return result; +} + +void RenderTextControlSingleLine::adjustControlHeightBasedOnLineHeight(int lineHeight) +{ + if (RenderBox* resultsRenderer = m_resultsButton ? m_resultsButton->renderBox() : 0) { + static_cast<RenderBlock*>(resultsRenderer)->calcHeight(); + setHeight(max(height(), + resultsRenderer->borderTop() + resultsRenderer->borderBottom() + + resultsRenderer->paddingTop() + resultsRenderer->paddingBottom() + + resultsRenderer->marginTop() + resultsRenderer->marginBottom())); + lineHeight = max(lineHeight, resultsRenderer->height()); + } + + if (RenderBox* cancelRenderer = m_cancelButton ? m_cancelButton->renderBox() : 0) { + static_cast<RenderBlock*>(cancelRenderer)->calcHeight(); + setHeight(max(height(), + cancelRenderer->borderTop() + cancelRenderer->borderBottom() + + cancelRenderer->paddingTop() + cancelRenderer->paddingBottom() + + cancelRenderer->marginTop() + cancelRenderer->marginBottom())); + lineHeight = max(lineHeight, cancelRenderer->height()); + } + + setHeight(height() + lineHeight); +} + +void RenderTextControlSingleLine::createSubtreeIfNeeded() +{ + if (!inputElement()->isSearchField()) { + RenderTextControl::createSubtreeIfNeeded(m_innerBlock.get()); + return; + } + + if (!m_innerBlock) { + // Create the inner block element + m_innerBlock = new TextControlInnerElement(document(), node()); + m_innerBlock->attachInnerElement(node(), createInnerBlockStyle(style()), renderArena()); + } + + if (!m_resultsButton) { + // Create the search results button element + m_resultsButton = new SearchFieldResultsButtonElement(document()); + m_resultsButton->attachInnerElement(m_innerBlock.get(), createResultsButtonStyle(m_innerBlock->renderer()->style()), renderArena()); + } + + // Create innerText element before adding the cancel button + RenderTextControl::createSubtreeIfNeeded(m_innerBlock.get()); + + if (!m_cancelButton) { + // Create the cancel button element + m_cancelButton = new SearchFieldCancelButtonElement(document()); + m_cancelButton->attachInnerElement(m_innerBlock.get(), createCancelButtonStyle(m_innerBlock->renderer()->style()), renderArena()); + } +} + +void RenderTextControlSingleLine::updateFromElement() +{ + createSubtreeIfNeeded(); + RenderTextControl::updateFromElement(); + + bool placeholderVisibilityShouldChange = m_placeholderVisible != placeholderShouldBeVisible(); + m_placeholderVisible = placeholderShouldBeVisible(); + + if (RenderObject* cancelButtonRenderer = m_cancelButton ? m_cancelButton->renderer() : 0) + updateCancelButtonVisibility(cancelButtonRenderer->style()); + + if (m_placeholderVisible) { + ExceptionCode ec = 0; + innerTextElement()->setInnerText(inputElement()->placeholderValue(), ec); + ASSERT(!ec); + } else if (!formControlElement()->valueMatchesRenderer() || placeholderVisibilityShouldChange) + setInnerTextValue(inputElement()->value()); + + if (m_searchPopupIsVisible) + m_searchPopup->updateFromElement(); +} + +void RenderTextControlSingleLine::cacheSelection(int start, int end) +{ + inputElement()->cacheSelection(start, end); +} + +PassRefPtr<RenderStyle> RenderTextControlSingleLine::createInnerTextStyle(const RenderStyle* startStyle) const +{ + RefPtr<RenderStyle> textBlockStyle; + if (placeholderShouldBeVisible()) { + RenderStyle* pseudoStyle = getCachedPseudoStyle(RenderStyle::INPUT_PLACEHOLDER); + textBlockStyle = RenderStyle::clone(pseudoStyle); + } else { + textBlockStyle = RenderStyle::create(); + textBlockStyle->inheritFrom(startStyle); + } + + adjustInnerTextStyle(startStyle, textBlockStyle.get()); + + textBlockStyle->setWhiteSpace(PRE); + textBlockStyle->setWordWrap(NormalWordWrap); + textBlockStyle->setOverflowX(OHIDDEN); + textBlockStyle->setOverflowY(OHIDDEN); + + // Do not allow line-height to be smaller than our default. + if (textBlockStyle->font().lineSpacing() > lineHeight(true, true)) + textBlockStyle->setLineHeight(Length(-100.0f, Percent)); + + textBlockStyle->setDisplay(m_innerBlock ? INLINE_BLOCK : BLOCK); + + // We're adding one extra pixel of padding to match WinIE. + textBlockStyle->setPaddingLeft(Length(1, Fixed)); + textBlockStyle->setPaddingRight(Length(1, Fixed)); + + // When the placeholder is going to be displayed, temporarily override the text security to be "none". + // After this, updateFromElement will immediately update the text displayed. + // When the placeholder is no longer visible, updatePlaceholderVisiblity will reset the style, + // and the text security mode will be set back to the computed value correctly. + if (placeholderShouldBeVisible()) + textBlockStyle->setTextSecurity(TSNONE); + + return textBlockStyle.release(); +} + +PassRefPtr<RenderStyle> RenderTextControlSingleLine::createInnerBlockStyle(const RenderStyle* startStyle) const +{ + ASSERT(node()->isHTMLElement()); + + RefPtr<RenderStyle> innerBlockStyle = RenderStyle::create(); + innerBlockStyle->inheritFrom(startStyle); + + innerBlockStyle->setDisplay(BLOCK); + innerBlockStyle->setDirection(LTR); + + // We don't want the shadow dom to be editable, so we set this block to read-only in case the input itself is editable. + innerBlockStyle->setUserModify(READ_ONLY); + + return innerBlockStyle.release(); +} + +PassRefPtr<RenderStyle> RenderTextControlSingleLine::createResultsButtonStyle(const RenderStyle* startStyle) const +{ + ASSERT(node()->isHTMLElement()); + HTMLInputElement* input = static_cast<HTMLInputElement*>(node()); + + RefPtr<RenderStyle> resultsBlockStyle; + if (input->maxResults() < 0) + resultsBlockStyle = getCachedPseudoStyle(RenderStyle::SEARCH_DECORATION); + else if (!input->maxResults()) + resultsBlockStyle = getCachedPseudoStyle(RenderStyle::SEARCH_RESULTS_DECORATION); + else + resultsBlockStyle = getCachedPseudoStyle(RenderStyle::SEARCH_RESULTS_BUTTON); + + if (!resultsBlockStyle) + resultsBlockStyle = RenderStyle::create(); + + if (startStyle) + resultsBlockStyle->inheritFrom(startStyle); + + return resultsBlockStyle.release(); +} + +PassRefPtr<RenderStyle> RenderTextControlSingleLine::createCancelButtonStyle(const RenderStyle* startStyle) const +{ + ASSERT(node()->isHTMLElement()); + RefPtr<RenderStyle> cancelBlockStyle; + + if (RefPtr<RenderStyle> pseudoStyle = getCachedPseudoStyle(RenderStyle::SEARCH_CANCEL_BUTTON)) + // We may be sharing style with another search field, but we must not share the cancel button style. + cancelBlockStyle = RenderStyle::clone(pseudoStyle.get()); + else + cancelBlockStyle = RenderStyle::create(); + + if (startStyle) + cancelBlockStyle->inheritFrom(startStyle); + + updateCancelButtonVisibility(cancelBlockStyle.get()); + return cancelBlockStyle.release(); +} + +void RenderTextControlSingleLine::updateCancelButtonVisibility(RenderStyle* style) const +{ + ASSERT(node()->isHTMLElement()); + HTMLInputElement* input = static_cast<HTMLInputElement*>(node()); + style->setVisibility(input->value().isEmpty() ? HIDDEN : VISIBLE); +} + +const AtomicString& RenderTextControlSingleLine::autosaveName() const +{ + return static_cast<Element*>(node())->getAttribute(autosaveAttr); +} + +void RenderTextControlSingleLine::startSearchEventTimer() +{ + ASSERT(node()->isHTMLElement()); + unsigned length = text().length(); + + // If there's no text, fire the event right away. + if (!length) { + stopSearchEventTimer(); + static_cast<HTMLInputElement*>(node())->onSearch(); + return; + } + + // After typing the first key, we wait 0.5 seconds. + // After the second key, 0.4 seconds, then 0.3, then 0.2 from then on. + m_searchEventTimer.startOneShot(max(0.2, 0.6 - 0.1 * length)); +} + +void RenderTextControlSingleLine::searchEventTimerFired(Timer<RenderTextControlSingleLine>*) +{ + ASSERT(node()->isHTMLElement()); + static_cast<HTMLInputElement*>(node())->onSearch(); +} + +// PopupMenuClient methods +void RenderTextControlSingleLine::valueChanged(unsigned listIndex, bool fireEvents) +{ + ASSERT(node()->isHTMLElement()); + ASSERT(static_cast<int>(listIndex) < listSize()); + HTMLInputElement* input = static_cast<HTMLInputElement*>(node()); + if (static_cast<int>(listIndex) == (listSize() - 1)) { + if (fireEvents) { + m_recentSearches.clear(); + const AtomicString& name = autosaveName(); + if (!name.isEmpty()) { + if (!m_searchPopup) + m_searchPopup = SearchPopupMenu::create(this); + m_searchPopup->saveRecentSearches(name, m_recentSearches); + } + } + } else { + input->setValue(itemText(listIndex)); + if (fireEvents) + input->onSearch(); + input->select(); + } +} + +String RenderTextControlSingleLine::itemText(unsigned listIndex) const +{ + int size = listSize(); + if (size == 1) { + ASSERT(!listIndex); + return searchMenuNoRecentSearchesText(); + } + if (!listIndex) + return searchMenuRecentSearchesText(); + if (itemIsSeparator(listIndex)) + return String(); + if (static_cast<int>(listIndex) == (size - 1)) + return searchMenuClearRecentSearchesText(); + return m_recentSearches[listIndex - 1]; +} + +bool RenderTextControlSingleLine::itemIsEnabled(unsigned listIndex) const +{ + if (!listIndex || itemIsSeparator(listIndex)) + return false; + return true; +} + +PopupMenuStyle RenderTextControlSingleLine::itemStyle(unsigned) const +{ + return menuStyle(); +} + +PopupMenuStyle RenderTextControlSingleLine::menuStyle() const +{ + return PopupMenuStyle(style()->color(), style()->backgroundColor(), style()->font(), style()->visibility() == VISIBLE); +} + +int RenderTextControlSingleLine::clientInsetLeft() const +{ + // Inset the menu by the radius of the cap on the left so that + // it only runs along the straight part of the bezel. + return height() / 2; +} + +int RenderTextControlSingleLine::clientInsetRight() const +{ + // Inset the menu by the radius of the cap on the right so that + // it only runs along the straight part of the bezel (unless it needs + // to be wider). + return height() / 2; +} + +int RenderTextControlSingleLine::clientPaddingLeft() const +{ + int padding = paddingLeft(); + + if (RenderBox* resultsRenderer = m_resultsButton ? m_resultsButton->renderBox() : 0) + padding += resultsRenderer->width(); + + return padding; +} + +int RenderTextControlSingleLine::clientPaddingRight() const +{ + int padding = paddingRight(); + + if (RenderBox* cancelRenderer = m_cancelButton ? m_cancelButton->renderBox() : 0) + padding += cancelRenderer->width(); + + return padding; +} + +int RenderTextControlSingleLine::listSize() const +{ + // If there are no recent searches, then our menu will have 1 "No recent searches" item. + if (!m_recentSearches.size()) + return 1; + // Otherwise, leave room in the menu for a header, a separator, and the "Clear recent searches" item. + return m_recentSearches.size() + 3; +} + +int RenderTextControlSingleLine::selectedIndex() const +{ + return -1; +} + +bool RenderTextControlSingleLine::itemIsSeparator(unsigned listIndex) const +{ + // The separator will be the second to last item in our list. + return static_cast<int>(listIndex) == (listSize() - 2); +} + +bool RenderTextControlSingleLine::itemIsLabel(unsigned listIndex) const +{ + return listIndex == 0; +} + +bool RenderTextControlSingleLine::itemIsSelected(unsigned) const +{ + return false; +} + +void RenderTextControlSingleLine::setTextFromItem(unsigned listIndex) +{ + ASSERT(node()->isHTMLElement()); + static_cast<HTMLInputElement*>(node())->setValue(itemText(listIndex)); +} + +FontSelector* RenderTextControlSingleLine::fontSelector() const +{ + return document()->styleSelector()->fontSelector(); +} + +HostWindow* RenderTextControlSingleLine::hostWindow() const +{ + return document()->view()->hostWindow(); +} + +PassRefPtr<Scrollbar> RenderTextControlSingleLine::createScrollbar(ScrollbarClient* client, ScrollbarOrientation orientation, ScrollbarControlSize controlSize) +{ + RefPtr<Scrollbar> widget; + bool hasCustomScrollbarStyle = style()->hasPseudoStyle(RenderStyle::SCROLLBAR); + if (hasCustomScrollbarStyle) + widget = RenderScrollbar::createCustomScrollbar(client, orientation, this); + else + widget = Scrollbar::createNativeScrollbar(client, orientation, controlSize); + return widget.release(); +} + +InputElement* RenderTextControlSingleLine::inputElement() const +{ + return toInputElement(static_cast<Element*>(node())); +} + +} diff --git a/WebCore/rendering/RenderTextControlSingleLine.h b/WebCore/rendering/RenderTextControlSingleLine.h new file mode 100644 index 0000000..a7b58e1 --- /dev/null +++ b/WebCore/rendering/RenderTextControlSingleLine.h @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) + * + * 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 RenderTextControlSingleLine_h +#define RenderTextControlSingleLine_h + +#include "PopupMenuClient.h" +#include "RenderTextControl.h" +#include "Timer.h" + +namespace WebCore { + +class InputElement; +class SearchFieldCancelButtonElement; +class SearchFieldResultsButtonElement; +class SearchPopupMenu; +class TextControlInnerElement; + +class RenderTextControlSingleLine : public RenderTextControl, private PopupMenuClient { +public: + RenderTextControlSingleLine(Node*); + virtual ~RenderTextControlSingleLine(); + + virtual bool hasControlClip() const { return m_cancelButton; } + virtual bool isTextField() const { return true; } + + bool placeholderIsVisible() const { return m_placeholderVisible; } + bool placeholderShouldBeVisible() const; + void updatePlaceholderVisibility(); + + void addSearchResult(); + void stopSearchEventTimer(); + + bool popupIsVisible() const { return m_searchPopupIsVisible; } + void showPopup(); + virtual void hidePopup(); // PopupMenuClient method + + virtual void subtreeHasChanged(); + virtual void paint(PaintInfo&, int tx, int ty); + virtual void layout(); + + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); + void forwardEvent(Event*); + +private: + virtual void capsLockStateMayHaveChanged(); + + int textBlockWidth() const; + virtual int preferredContentWidth(float charWidth) const; + virtual void adjustControlHeightBasedOnLineHeight(int lineHeight); + + void createSubtreeIfNeeded(); + virtual void updateFromElement(); + virtual void cacheSelection(int start, int end); + virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle); + + virtual PassRefPtr<RenderStyle> createInnerTextStyle(const RenderStyle* startStyle) const; + PassRefPtr<RenderStyle> createInnerBlockStyle(const RenderStyle* startStyle) const; + PassRefPtr<RenderStyle> createResultsButtonStyle(const RenderStyle* startStyle) const; + PassRefPtr<RenderStyle> createCancelButtonStyle(const RenderStyle* startStyle) const; + + void updateCancelButtonVisibility(RenderStyle*) const; + const AtomicString& autosaveName() const; + + void startSearchEventTimer(); + void searchEventTimerFired(Timer<RenderTextControlSingleLine>*); + +private: + // PopupMenuClient methods + virtual void valueChanged(unsigned listIndex, bool fireEvents = true); + virtual String itemText(unsigned listIndex) const; + virtual bool itemIsEnabled(unsigned listIndex) const; + virtual PopupMenuStyle itemStyle(unsigned listIndex) const; + virtual PopupMenuStyle menuStyle() const; + virtual int clientInsetLeft() const; + virtual int clientInsetRight() const; + virtual int clientPaddingLeft() const; + virtual int clientPaddingRight() const; + virtual int listSize() const; + virtual int selectedIndex() const; + virtual bool itemIsSeparator(unsigned listIndex) const; + virtual bool itemIsLabel(unsigned listIndex) const; + virtual bool itemIsSelected(unsigned listIndex) const; + virtual bool shouldPopOver() const { return false; } + virtual bool valueShouldChangeOnHotTrack() const { return false; } + virtual void setTextFromItem(unsigned listIndex); + virtual FontSelector* fontSelector() const; + virtual HostWindow* hostWindow() const; + virtual PassRefPtr<Scrollbar> createScrollbar(ScrollbarClient*, ScrollbarOrientation, ScrollbarControlSize); + + InputElement* inputElement() const; + +private: + bool m_placeholderVisible; + bool m_searchPopupIsVisible; + bool m_shouldDrawCapsLockIndicator; + + RefPtr<TextControlInnerElement> m_innerBlock; + RefPtr<SearchFieldResultsButtonElement> m_resultsButton; + RefPtr<SearchFieldCancelButtonElement> m_cancelButton; + + Timer<RenderTextControlSingleLine> m_searchEventTimer; + RefPtr<SearchPopupMenu> m_searchPopup; + Vector<String> m_recentSearches; +}; + +} + +#endif diff --git a/WebCore/rendering/RenderTheme.cpp b/WebCore/rendering/RenderTheme.cpp index 9eb3ac2..e7fa5de 100644 --- a/WebCore/rendering/RenderTheme.cpp +++ b/WebCore/rendering/RenderTheme.cpp @@ -202,12 +202,6 @@ void RenderTheme::adjustStyle(CSSStyleSelector* selector, RenderStyle* style, El } } -#if !PLATFORM(QT) -void RenderTheme::adjustDefaultStyleSheet(CSSStyleSheet*) -{ -} -#endif - bool RenderTheme::paint(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) { // If painting is disabled, but we aren't updating control tints, then just bail. @@ -278,6 +272,12 @@ bool RenderTheme::paint(RenderObject* o, const RenderObject::PaintInfo& paintInf if (o->parent()->isSlider()) return paintMediaSliderThumb(o, paintInfo, r); break; + case MediaTimeRemainingPart: + return paintMediaTimeRemaining(o, paintInfo, r); + case MediaCurrentTimePart: + return paintMediaCurrentTime(o, paintInfo, r); + case MediaTimelineContainerPart: + return paintMediaTimelineContainer(o, paintInfo, r); case MenulistButtonPart: case TextFieldPart: case TextAreaPart: @@ -372,18 +372,71 @@ bool RenderTheme::paintDecorations(RenderObject* o, const RenderObject::PaintInf return false; } +#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)); +} +#endif + Color RenderTheme::activeSelectionBackgroundColor() const { - if (!m_activeSelectionColor.isValid()) - m_activeSelectionColor = platformActiveSelectionBackgroundColor().blendWithWhite(); - return m_activeSelectionColor; + if (!m_activeSelectionBackgroundColor.isValid()) + m_activeSelectionBackgroundColor = platformActiveSelectionBackgroundColor().blendWithWhite(); + return m_activeSelectionBackgroundColor; } Color RenderTheme::inactiveSelectionBackgroundColor() const { - if (!m_inactiveSelectionColor.isValid()) - m_inactiveSelectionColor = platformInactiveSelectionBackgroundColor().blendWithWhite(); - return m_inactiveSelectionColor; + if (!m_inactiveSelectionBackgroundColor.isValid()) + m_inactiveSelectionBackgroundColor = platformInactiveSelectionBackgroundColor().blendWithWhite(); + return m_inactiveSelectionBackgroundColor; +} + +Color RenderTheme::activeSelectionForegroundColor() const +{ + if (!m_activeSelectionForegroundColor.isValid() && supportsSelectionForegroundColors()) + m_activeSelectionForegroundColor = platformActiveSelectionForegroundColor(); + return m_activeSelectionForegroundColor; +} + +Color RenderTheme::inactiveSelectionForegroundColor() const +{ + if (!m_inactiveSelectionForegroundColor.isValid() && supportsSelectionForegroundColors()) + m_inactiveSelectionForegroundColor = platformInactiveSelectionForegroundColor(); + return m_inactiveSelectionForegroundColor; +} + +Color RenderTheme::activeListBoxSelectionBackgroundColor() const +{ + if (!m_activeListBoxSelectionBackgroundColor.isValid()) + m_activeListBoxSelectionBackgroundColor = platformActiveListBoxSelectionBackgroundColor(); + return m_activeListBoxSelectionBackgroundColor; +} + +Color RenderTheme::inactiveListBoxSelectionBackgroundColor() const +{ + if (!m_inactiveListBoxSelectionBackgroundColor.isValid()) + m_inactiveListBoxSelectionBackgroundColor = platformInactiveListBoxSelectionBackgroundColor(); + return m_inactiveListBoxSelectionBackgroundColor; +} + +Color RenderTheme::activeListBoxSelectionForegroundColor() const +{ + if (!m_activeListBoxSelectionForegroundColor.isValid() && supportsListBoxSelectionForegroundColors()) + m_activeListBoxSelectionForegroundColor = platformActiveListBoxSelectionForegroundColor(); + return m_activeListBoxSelectionForegroundColor; +} + +Color RenderTheme::inactiveListBoxSelectionForegroundColor() const +{ + if (!m_inactiveListBoxSelectionForegroundColor.isValid() && supportsListBoxSelectionForegroundColors()) + m_inactiveListBoxSelectionForegroundColor = platformInactiveListBoxSelectionForegroundColor(); + return m_inactiveListBoxSelectionForegroundColor; } Color RenderTheme::platformActiveSelectionBackgroundColor() const @@ -392,50 +445,56 @@ Color RenderTheme::platformActiveSelectionBackgroundColor() const return Color(0, 0, 255); } -Color RenderTheme::platformInactiveSelectionBackgroundColor() const +Color RenderTheme::platformActiveSelectionForegroundColor() const { - // Use a grey color by default if the platform theme doesn't define anything. - return Color(128, 128, 128); + // Use a white color by default if the platform theme doesn't define anything. + return Color::white; } -Color RenderTheme::platformActiveSelectionForegroundColor() const +Color RenderTheme::platformInactiveSelectionBackgroundColor() const { - return Color(); + // Use a grey color by default if the platform theme doesn't define anything. + // This color matches Firefox's inactive color. + return Color(176, 176, 176); } Color RenderTheme::platformInactiveSelectionForegroundColor() const { - return Color(); + // Use a black color by default. + return Color::black; } -Color RenderTheme::activeListBoxSelectionBackgroundColor() const +Color RenderTheme::platformActiveListBoxSelectionBackgroundColor() const { - return activeSelectionBackgroundColor(); + return platformActiveSelectionBackgroundColor(); } -Color RenderTheme::activeListBoxSelectionForegroundColor() const +Color RenderTheme::platformActiveListBoxSelectionForegroundColor() const { - // Use a white color by default if the platform theme doesn't define anything. - return Color(255, 255, 255); + return platformActiveSelectionForegroundColor(); } -Color RenderTheme::inactiveListBoxSelectionBackgroundColor() const +Color RenderTheme::platformInactiveListBoxSelectionBackgroundColor() const { - return inactiveSelectionBackgroundColor(); + return platformInactiveSelectionBackgroundColor(); } -Color RenderTheme::inactiveListBoxSelectionForegroundColor() const +Color RenderTheme::platformInactiveListBoxSelectionForegroundColor() const { - // Use a black color by default if the platform theme doesn't define anything. - return Color(0, 0, 0); + return platformInactiveSelectionForegroundColor(); } int RenderTheme::baselinePosition(const RenderObject* o) const { + if (!o->isBox()) + return 0; + + const RenderBox* box = toRenderBox(o); + #if USE(NEW_THEME) - return o->height() + o->marginTop() + m_theme->baselinePositionAdjustment(o->style()->appearance()) * o->style()->effectiveZoom(); + return box->height() + box->marginTop() + m_theme->baselinePositionAdjustment(o->style()->appearance()) * o->style()->effectiveZoom(); #else - return o->height() + o->marginTop(); + return box->height() + box->marginTop(); #endif } @@ -602,7 +661,8 @@ bool RenderTheme::isDefault(const RenderObject* o) const } #if !USE(NEW_THEME) -void RenderTheme::adjustCheckboxStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const + +void RenderTheme::adjustCheckboxStyle(CSSStyleSelector*, RenderStyle* style, Element*) const { // A summary of the rules for checkbox designed to match WinIE: // width/height - honored (WinIE actually scales its control for small widths, but lets it overflow for small heights.) @@ -619,7 +679,7 @@ void RenderTheme::adjustCheckboxStyle(CSSStyleSelector* selector, RenderStyle* s style->setBoxShadow(0); } -void RenderTheme::adjustRadioStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderTheme::adjustRadioStyle(CSSStyleSelector*, RenderStyle* style, Element*) const { // A summary of the rules for checkbox designed to match WinIE: // width/height - honored (WinIE actually scales its control for small widths, but lets it overflow for small heights.) @@ -636,35 +696,40 @@ void RenderTheme::adjustRadioStyle(CSSStyleSelector* selector, RenderStyle* styl style->setBoxShadow(0); } -void RenderTheme::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderTheme::adjustButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const { // Most platforms will completely honor all CSS, and so we have no need to adjust the style // at all by default. We will still allow the theme a crack at setting up a desired vertical size. setButtonSize(style); } + #endif -void RenderTheme::adjustTextFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderTheme::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const +{ +} + +void RenderTheme::adjustTextAreaStyle(CSSStyleSelector*, RenderStyle*, Element*) const { } -void RenderTheme::adjustTextAreaStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderTheme::adjustMenuListStyle(CSSStyleSelector*, RenderStyle*, Element*) const { } -void RenderTheme::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderTheme::adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const { } -void RenderTheme::adjustMenuListButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderTheme::adjustButtonInnerStyle(RenderStyle*) const { } -void RenderTheme::adjustSliderTrackStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderTheme::adjustSliderTrackStyle(CSSStyleSelector*, RenderStyle*, Element*) const { } -void RenderTheme::adjustSliderThumbStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderTheme::adjustSliderThumbStyle(CSSStyleSelector*, RenderStyle*, Element*) const { } @@ -672,30 +737,37 @@ void RenderTheme::adjustSliderThumbSize(RenderObject*) const { } -void RenderTheme::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderTheme::adjustSearchFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const { } -void RenderTheme::adjustSearchFieldCancelButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderTheme::adjustSearchFieldCancelButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const { } -void RenderTheme::adjustSearchFieldDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderTheme::adjustSearchFieldDecorationStyle(CSSStyleSelector*, RenderStyle*, Element*) const { } -void RenderTheme::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderTheme::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector*, RenderStyle*, Element*) const { } -void RenderTheme::adjustSearchFieldResultsButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderTheme::adjustSearchFieldResultsButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const { } void RenderTheme::platformColorsDidChange() { - m_activeSelectionColor = Color(); - m_inactiveSelectionColor = Color(); + m_activeSelectionForegroundColor = Color(); + m_inactiveSelectionForegroundColor = Color(); + m_activeSelectionBackgroundColor = Color(); + m_inactiveSelectionBackgroundColor = Color(); + + m_activeListBoxSelectionForegroundColor = Color(); + m_inactiveListBoxSelectionForegroundColor = Color(); + m_activeListBoxSelectionBackgroundColor = Color(); + m_inactiveListBoxSelectionForegroundColor = Color(); } Color RenderTheme::systemColor(int cssValueId) const diff --git a/WebCore/rendering/RenderTheme.h b/WebCore/rendering/RenderTheme.h index 2935d42..828e789 100644 --- a/WebCore/rendering/RenderTheme.h +++ b/WebCore/rendering/RenderTheme.h @@ -50,10 +50,6 @@ public: void adjustStyle(CSSStyleSelector*, RenderStyle*, Element*, bool UAHasAppearance, const BorderData&, const FillLayer&, const Color& backgroundColor); - // This method is called once, from CSSStyleSelector::loadDefaultStyle(), to let each platform adjust - // the default CSS rules in html4.css. - static void adjustDefaultStyleSheet(CSSStyleSheet*); - // This method is called to paint the widget as a background of the RenderObject. A widget's foreground, e.g., the // text of a button, is always rendered by the engine itself. The boolean return value indicates // whether the CSS border/background should also be painted. @@ -64,6 +60,14 @@ public: // The remaining methods should be implemented by the platform-specific portion of the theme, e.g., // RenderThemeMac.cpp for Mac OS X. + // These methods return the theme's extra style sheets rules, to let each platform + // adjust the default CSS rules in html4.css, quirks.css, or mediaControls.css + virtual String extraDefaultStyleSheet() { return String(); } + virtual String extraQuirksStyleSheet() { return String(); } +#if ENABLE(VIDEO) + virtual String extraMediaControlsStyleSheet() { return String(); }; +#endif + // A method to obtain the baseline position for a "leaf" control. This will only be used if a baseline // position cannot be determined by examining child content. Checkboxes and radio buttons are examples of // controls that need to do this. @@ -100,27 +104,23 @@ public: // A method asking if the theme's controls actually care about redrawing when hovered. virtual bool supportsHover(const RenderStyle*) const { return false; } - // The selection color. + // Text selection colors. Color activeSelectionBackgroundColor() const; Color inactiveSelectionBackgroundColor() const; + Color activeSelectionForegroundColor() const; + Color inactiveSelectionForegroundColor() const; - virtual Color platformTextSearchHighlightColor() const; - - // The platform selection color. - virtual Color platformActiveSelectionBackgroundColor() const; - virtual Color platformInactiveSelectionBackgroundColor() const; - virtual Color platformActiveSelectionForegroundColor() const; - virtual Color platformInactiveSelectionForegroundColor() const; + // List box selection colors + Color activeListBoxSelectionBackgroundColor() const; + Color activeListBoxSelectionForegroundColor() const; + Color inactiveListBoxSelectionBackgroundColor() const; + Color inactiveListBoxSelectionForegroundColor() const; - // List Box selection color - virtual Color activeListBoxSelectionBackgroundColor() const; - virtual Color activeListBoxSelectionForegroundColor() const; - virtual Color inactiveListBoxSelectionBackgroundColor() const; - virtual Color inactiveListBoxSelectionForegroundColor() const; + virtual Color platformTextSearchHighlightColor() const; virtual void platformColorsDidChange(); - virtual double caretBlinkFrequency() const { return 0.5; } + virtual double caretBlinkInterval() const { return 0.5; } // System fonts and colors for CSS. virtual void systemFont(int cssValueId, FontDescription&) const = 0; @@ -128,6 +128,7 @@ public: virtual int minimumMenuListSize(RenderStyle*) const { return 0; } + virtual void adjustButtonInnerStyle(RenderStyle*) const; virtual void adjustSliderThumbSize(RenderObject*) const; virtual int popupInternalPaddingLeft(RenderStyle*) const { return 0; } @@ -138,7 +139,26 @@ public: // Method for painting the caps lock indicator virtual bool paintCapsLockIndicator(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return 0; }; +#if ENABLE(VIDEO) + // Media controls + virtual bool hitTestMediaControlPart(RenderObject*, const IntPoint& absPoint); +#endif + protected: + // The platform selection color. + virtual Color platformActiveSelectionBackgroundColor() const; + virtual Color platformInactiveSelectionBackgroundColor() const; + virtual Color platformActiveSelectionForegroundColor() const; + virtual Color platformInactiveSelectionForegroundColor() const; + + virtual Color platformActiveListBoxSelectionBackgroundColor() const; + virtual Color platformInactiveListBoxSelectionBackgroundColor() const; + virtual Color platformActiveListBoxSelectionForegroundColor() const; + virtual Color platformInactiveListBoxSelectionForegroundColor() const; + + virtual bool supportsSelectionForegroundColors() const { return true; } + virtual bool supportsListBoxSelectionForegroundColors() const { return true; } + #if !USE(NEW_THEME) // Methods for each appearance value. virtual void adjustCheckboxStyle(CSSStyleSelector*, RenderStyle*, Element*) const; @@ -197,6 +217,9 @@ protected: virtual bool paintMediaSeekForwardButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; } virtual bool paintMediaSliderTrack(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; } virtual bool paintMediaSliderThumb(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; } + virtual bool paintMediaTimelineContainer(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; } + virtual bool paintMediaCurrentTime(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; } + virtual bool paintMediaTimeRemaining(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; } public: // Methods for state querying @@ -212,8 +235,16 @@ public: bool isDefault(const RenderObject*) const; private: - mutable Color m_activeSelectionColor; - mutable Color m_inactiveSelectionColor; + mutable Color m_activeSelectionBackgroundColor; + mutable Color m_inactiveSelectionBackgroundColor; + mutable Color m_activeSelectionForegroundColor; + mutable Color m_inactiveSelectionForegroundColor; + + mutable Color m_activeListBoxSelectionBackgroundColor; + mutable Color m_inactiveListBoxSelectionBackgroundColor; + mutable Color m_activeListBoxSelectionForegroundColor; + mutable Color m_inactiveListBoxSelectionForegroundColor; + #if USE(NEW_THEME) Theme* m_theme; // The platform-specific theme. #endif diff --git a/WebCore/rendering/RenderThemeChromiumGtk.cpp b/WebCore/rendering/RenderThemeChromiumGtk.cpp new file mode 100644 index 0000000..220ce07 --- /dev/null +++ b/WebCore/rendering/RenderThemeChromiumGtk.cpp @@ -0,0 +1,532 @@ +/* + * Copyright (C) 2007 Apple Inc. + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * Copyright (C) 2008 Collabora Ltd. + * Copyright (C) 2008, 2009 Google Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "RenderThemeChromiumGtk.h" + +#include "ChromiumBridge.h" +#include "CSSValueKeywords.h" +#include "GraphicsContext.h" +#include "NotImplemented.h" +#include "PlatformContextSkia.h" +#include "RenderObject.h" +#include "ScrollbarTheme.h" +#include "gtkdrawing.h" +#include "GdkSkia.h" +#include "TransformationMatrix.h" +#include "UserAgentStyleSheets.h" + +#include <gdk/gdk.h> + +namespace WebCore { + +enum PaddingType { + TopPadding, + RightPadding, + BottomPadding, + LeftPadding +}; + +static const int styledMenuListInternalPadding[4] = { 1, 4, 1, 4 }; + +// The default variable-width font size. We use this as the default font +// size for the "system font", and as a base size (which we then shrink) for +// form control fonts. +static float DefaultFontSize = 16.0; + +static Color makeColor(const GdkColor& c) +{ + return Color(makeRGB(c.red >> 8, c.green >> 8, c.blue >> 8)); +} + +// We aim to match IE here. +// -IE uses a font based on the encoding as the default font for form controls. +// -Gecko uses MS Shell Dlg (actually calls GetStockObject(DEFAULT_GUI_FONT), +// which returns MS Shell Dlg) +// -Safari uses Lucida Grande. +// +// FIXME: The only case where we know we don't match IE is for ANSI encodings. +// IE uses MS Shell Dlg there, which we render incorrectly at certain pixel +// sizes (e.g. 15px). So, for now we just use Arial. +static const char* defaultGUIFont(Document* document) +{ + return "Arial"; +} + +// Converts points to pixels. One point is 1/72 of an inch. +static float pointsToPixels(float points) +{ + static float pixelsPerInch = 0.0f; + if (!pixelsPerInch) { + GdkScreen* screen = gdk_screen_get_default(); + // FIXME: I'm getting floating point values of ~75 and ~100, + // and it's making my fonts look all wrong. Figure this out. +#if 0 + if (screen) + pixelsPerInch = gdk_screen_get_resolution(screen); + else +#endif + pixelsPerInch = 96.0f; // Match the default we set on Windows. + } + + static const float pointsPerInch = 72.0f; + return points / pointsPerInch * pixelsPerInch; +} + +static void setSizeIfAuto(RenderStyle* style, const IntSize& size) +{ + if (style->width().isIntrinsicOrAuto()) + style->setWidth(Length(size.width(), Fixed)); + if (style->height().isAuto()) + style->setHeight(Length(size.height(), Fixed)); +} + +static bool supportsFocus(ControlPart appearance) +{ + switch (appearance) { + case PushButtonPart: + case ButtonPart: + case TextFieldPart: + case TextAreaPart: + case SearchFieldPart: + case MenulistPart: + case RadioPart: + case CheckboxPart: + return true; + default: + return false; + } +} + +static GtkTextDirection gtkTextDirection(TextDirection direction) +{ + switch (direction) { + case RTL: + return GTK_TEXT_DIR_RTL; + case LTR: + return GTK_TEXT_DIR_LTR; + default: + return GTK_TEXT_DIR_NONE; + } +} + +static void setMozState(RenderTheme* theme, GtkWidgetState* state, RenderObject* o) +{ + state->active = theme->isPressed(o); + state->focused = theme->isFocused(o); + state->inHover = theme->isHovered(o); + // FIXME: Disabled does not always give the correct appearance for ReadOnly + state->disabled = !theme->isEnabled(o) || theme->isReadOnlyControl(o); + state->isDefault = false; + state->canDefault = false; + state->depressed = false; +} + +static bool paintMozWidget(RenderTheme* theme, GtkThemeWidgetType type, RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) +{ + // Painting is disabled so just claim to have succeeded + if (i.context->paintingDisabled()) + return false; + + GtkWidgetState mozState; + setMozState(theme, &mozState, o); + + int flags; + + // We might want to make setting flags the caller's job at some point rather than doing it here. + switch (type) { + case MOZ_GTK_BUTTON: + flags = GTK_RELIEF_NORMAL; + break; + case MOZ_GTK_CHECKBUTTON: + case MOZ_GTK_RADIOBUTTON: + flags = theme->isChecked(o); + break; + default: + flags = 0; + break; + } + + PlatformContextSkia* pcs = i.context->platformContext(); + SkCanvas* canvas = pcs->canvas(); + if (!canvas) + return false; + + GdkRectangle gdkRect; + gdkRect.x = rect.x(); + gdkRect.y = rect.y(); + gdkRect.width = rect.width(); + gdkRect.height = rect.height(); + + // getTotalClip returns the currently set clip region in device coordinates, + // so we have to apply the current transform (actually we only support translations) + // to get the page coordinates that our gtk widget rendering expects. + // We invert it because we want to map from device coordinates to page coordinates. + const SkIRect clipRegion = canvas->getTotalClip().getBounds(); + TransformationMatrix ctm = i.context->getCTM().inverse(); + IntPoint pos = ctm.mapPoint(IntPoint(SkScalarRound(clipRegion.fLeft), SkScalarRound(clipRegion.fTop))); + GdkRectangle gdkClipRect; + gdkClipRect.x = pos.x(); + gdkClipRect.y = pos.y(); + gdkClipRect.width = clipRegion.width(); + gdkClipRect.height = clipRegion.height(); + + // moz_gtk_widget_paint will paint outside the bounds of gdkRect unless we further restrict |gdkClipRect|. + gdk_rectangle_intersect(&gdkRect, &gdkClipRect, &gdkClipRect); + + GtkTextDirection direction = gtkTextDirection(o->style()->direction()); + + return moz_gtk_widget_paint(type, pcs->gdk_skia(), &gdkRect, &gdkClipRect, &mozState, flags, direction) != MOZ_GTK_SUCCESS; +} + +static void gtkStyleSetCallback(GtkWidget* widget, GtkStyle* previous, RenderTheme* renderTheme) +{ + // FIXME: Make sure this function doesn't get called many times for a single GTK+ style change signal. + renderTheme->platformColorsDidChange(); +} + +static double querySystemBlinkInterval(double defaultInterval) +{ + GtkSettings* settings = gtk_settings_get_default(); + + gboolean shouldBlink; + gint time; + + g_object_get(settings, "gtk-cursor-blink", &shouldBlink, "gtk-cursor-blink-time", &time, NULL); + + if (!shouldBlink) + return 0; + + return time / 1000.0; +} + +// Implement WebCore::theme() for getting the global RenderTheme. +RenderTheme* theme() +{ + static RenderThemeChromiumGtk gtkTheme; + return >kTheme; +} + +RenderThemeChromiumGtk::RenderThemeChromiumGtk() + : m_gtkWindow(0) + , m_gtkContainer(0) + , m_gtkEntry(0) + , m_gtkTreeView(0) +{ +} + +// Use the Windows style sheets to match their metrics. +String RenderThemeChromiumGtk::extraDefaultStyleSheet() +{ + return String(themeWinUserAgentStyleSheet, sizeof(themeWinUserAgentStyleSheet)); +} + +String RenderThemeChromiumGtk::extraQuirksStyleSheet() +{ + return String(themeWinQuirksUserAgentStyleSheet, sizeof(themeWinQuirksUserAgentStyleSheet)); +} + +bool RenderThemeChromiumGtk::supportsFocusRing(const RenderStyle* style) const +{ + return supportsFocus(style->appearance()); +} + +Color RenderThemeChromiumGtk::platformActiveSelectionBackgroundColor() const +{ + GtkWidget* widget = gtkEntry(); + return makeColor(widget->style->base[GTK_STATE_SELECTED]); +} + +Color RenderThemeChromiumGtk::platformInactiveSelectionBackgroundColor() const +{ + GtkWidget* widget = gtkEntry(); + return makeColor(widget->style->base[GTK_STATE_ACTIVE]); +} + +Color RenderThemeChromiumGtk::platformActiveSelectionForegroundColor() const +{ + GtkWidget* widget = gtkEntry(); + return makeColor(widget->style->text[GTK_STATE_SELECTED]); +} + +Color RenderThemeChromiumGtk::platformInactiveSelectionForegroundColor() const +{ + GtkWidget* widget = gtkEntry(); + return makeColor(widget->style->text[GTK_STATE_ACTIVE]); +} + +Color RenderThemeChromiumGtk::platformTextSearchHighlightColor() const +{ + return Color(255, 255, 150); +} + +double RenderThemeChromiumGtk::caretBlinkInterval() const +{ + // Disable the blinking caret in layout test mode, as it introduces + // a race condition for the pixel tests. http://b/1198440 + if (ChromiumBridge::layoutTestMode()) + return 0; + + // We cache the interval so we don't have to repeatedly request it from gtk. + static double blinkInterval = querySystemBlinkInterval(RenderTheme::caretBlinkInterval()); + return blinkInterval; +} + +void RenderThemeChromiumGtk::systemFont(int propId, Document* document, FontDescription& fontDescription) const +{ + const char* faceName = 0; + float fontSize = 0; + // FIXME: see also RenderThemeChromiumWin.cpp + switch (propId) { + case CSSValueMenu: + case CSSValueStatusBar: + case CSSValueSmallCaption: + // triggered by LayoutTests/fast/css/css2-system-fonts.html + notImplemented(); + break; + case CSSValueWebkitMiniControl: + case CSSValueWebkitSmallControl: + case CSSValueWebkitControl: + faceName = defaultGUIFont(document); + // Why 2 points smaller? Because that's what Gecko does. + fontSize = DefaultFontSize - pointsToPixels(2); + break; + default: + faceName = defaultGUIFont(document); + fontSize = DefaultFontSize; + } + + // Only update if the size makes sense. + if (fontSize > 0) { + fontDescription.firstFamily().setFamily(faceName); + fontDescription.setSpecifiedSize(fontSize); + fontDescription.setIsAbsoluteSize(true); + fontDescription.setGenericFamily(FontDescription::NoFamily); + fontDescription.setWeight(FontWeightNormal); + fontDescription.setItalic(false); + } +} + +int RenderThemeChromiumGtk::minimumMenuListSize(RenderStyle* style) const +{ + return 0; +} + +bool RenderThemeChromiumGtk::paintCheckbox(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) +{ + return paintMozWidget(this, MOZ_GTK_CHECKBUTTON, o, i, rect); +} + +void RenderThemeChromiumGtk::setCheckboxSize(RenderStyle* style) const +{ + // If the width and height are both specified, then we have nothing to do. + if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto()) + return; + + // FIXME: A hard-coded size of 13 is used. This is wrong but necessary for now. It matches Firefox. + // At different DPI settings on Windows, querying the theme gives you a larger size that accounts for + // the higher DPI. Until our entire engine honors a DPI setting other than 96, we can't rely on the theme's + // metrics. + const IntSize size(13, 13); + setSizeIfAuto(style, size); +} + +bool RenderThemeChromiumGtk::paintRadio(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) +{ + return paintMozWidget(this, MOZ_GTK_RADIOBUTTON, o, i, rect); +} + +void RenderThemeChromiumGtk::setRadioSize(RenderStyle* style) const +{ + // Use same sizing for radio box as checkbox. + setCheckboxSize(style); +} + +bool RenderThemeChromiumGtk::paintButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) +{ + return paintMozWidget(this, MOZ_GTK_BUTTON, o, i, rect); +} + +bool RenderThemeChromiumGtk::paintTextField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) +{ + return paintMozWidget(this, MOZ_GTK_ENTRY, o, i, rect); +} + +bool RenderThemeChromiumGtk::paintSearchField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) +{ + return paintTextField(o, i, rect); +} + +bool RenderThemeChromiumGtk::paintSearchFieldResultsDecoration(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) +{ + return paintMozWidget(this, MOZ_GTK_CHECKMENUITEM, o, i, rect); +} + +bool RenderThemeChromiumGtk::paintSearchFieldResultsButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) +{ + return paintMozWidget(this, MOZ_GTK_DROPDOWN_ARROW, o, i, rect); +} + +bool RenderThemeChromiumGtk::paintSearchFieldCancelButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) +{ + return paintMozWidget(this, MOZ_GTK_CHECKMENUITEM, o, i, rect); +} + +void RenderThemeChromiumGtk::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, WebCore::Element* e) const +{ + // Height is locked to auto on all browsers. + style->setLineHeight(RenderStyle::initialLineHeight()); +} + +bool RenderThemeChromiumGtk::paintMenuList(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) +{ + return paintMozWidget(this, MOZ_GTK_DROPDOWN, o, i, rect); +} + +void RenderThemeChromiumGtk::adjustMenuListButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +{ + adjustMenuListStyle(selector, style, e); +} + +// Used to paint styled menulists (i.e. with a non-default border) +bool RenderThemeChromiumGtk::paintMenuListButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) +{ + return paintMenuList(o, i, r); +} + +int RenderThemeChromiumGtk::popupInternalPaddingLeft(RenderStyle* style) const +{ + return menuListInternalPadding(style, LeftPadding); +} + +int RenderThemeChromiumGtk::popupInternalPaddingRight(RenderStyle* style) const +{ + return menuListInternalPadding(style, RightPadding); +} + +int RenderThemeChromiumGtk::popupInternalPaddingTop(RenderStyle* style) const +{ + return menuListInternalPadding(style, TopPadding); +} + +int RenderThemeChromiumGtk::popupInternalPaddingBottom(RenderStyle* style) const +{ + return menuListInternalPadding(style, BottomPadding); +} + +void RenderThemeChromiumGtk::adjustButtonInnerStyle(RenderStyle* style) const +{ + // This inner padding matches Firefox. + style->setPaddingTop(Length(1, Fixed)); + style->setPaddingRight(Length(3, Fixed)); + style->setPaddingBottom(Length(1, Fixed)); + style->setPaddingLeft(Length(3, Fixed)); +} + +bool RenderThemeChromiumGtk::controlSupportsTints(const RenderObject* o) const +{ + return isEnabled(o); +} + +Color RenderThemeChromiumGtk::activeListBoxSelectionBackgroundColor() const +{ + GtkWidget* widget = gtkTreeView(); + return makeColor(widget->style->base[GTK_STATE_SELECTED]); +} + +Color RenderThemeChromiumGtk::activeListBoxSelectionForegroundColor() const +{ + GtkWidget* widget = gtkTreeView(); + return makeColor(widget->style->text[GTK_STATE_SELECTED]); +} + +Color RenderThemeChromiumGtk::inactiveListBoxSelectionBackgroundColor() const +{ + GtkWidget* widget = gtkTreeView(); + return makeColor(widget->style->base[GTK_STATE_ACTIVE]); +} + +Color RenderThemeChromiumGtk::inactiveListBoxSelectionForegroundColor() const +{ + GtkWidget* widget = gtkTreeView(); + return makeColor(widget->style->text[GTK_STATE_ACTIVE]); +} + +GtkWidget* RenderThemeChromiumGtk::gtkEntry() const +{ + if (m_gtkEntry) + return m_gtkEntry; + + m_gtkEntry = gtk_entry_new(); + g_signal_connect(m_gtkEntry, "style-set", G_CALLBACK(gtkStyleSetCallback), theme()); + gtk_container_add(gtkContainer(), m_gtkEntry); + gtk_widget_realize(m_gtkEntry); + + return m_gtkEntry; +} + +GtkWidget* RenderThemeChromiumGtk::gtkTreeView() const +{ + if (m_gtkTreeView) + return m_gtkTreeView; + + m_gtkTreeView = gtk_tree_view_new(); + g_signal_connect(m_gtkTreeView, "style-set", G_CALLBACK(gtkStyleSetCallback), theme()); + gtk_container_add(gtkContainer(), m_gtkTreeView); + gtk_widget_realize(m_gtkTreeView); + + return m_gtkTreeView; +} + +GtkContainer* RenderThemeChromiumGtk::gtkContainer() const +{ + if (m_gtkContainer) + return m_gtkContainer; + + m_gtkWindow = gtk_window_new(GTK_WINDOW_POPUP); + m_gtkContainer = GTK_CONTAINER(gtk_fixed_new()); + gtk_container_add(GTK_CONTAINER(m_gtkWindow), GTK_WIDGET(m_gtkContainer)); + gtk_widget_realize(m_gtkWindow); + + return m_gtkContainer; +} + +int RenderThemeChromiumGtk::menuListInternalPadding(RenderStyle* style, int paddingType) const +{ + // This internal padding is in addition to the user-supplied padding. + // Matches the FF behavior. + int padding = styledMenuListInternalPadding[paddingType]; + + // Reserve the space for right arrow here. The rest of the padding is + // set by adjustMenuListStyle, since PopMenuWin.cpp uses the padding from + // RenderMenuList to lay out the individual items in the popup. + // If the MenuList actually has appearance "NoAppearance", then that means + // we don't draw a button, so don't reserve space for it. + const int bar_type = style->direction() == LTR ? RightPadding : LeftPadding; + if (paddingType == bar_type && style->appearance() != NoControlPart) + padding += ScrollbarTheme::nativeTheme()->scrollbarThickness(); + + return padding; +} + +} // namespace WebCore diff --git a/WebCore/rendering/RenderThemeChromiumGtk.h b/WebCore/rendering/RenderThemeChromiumGtk.h new file mode 100644 index 0000000..77d927f --- /dev/null +++ b/WebCore/rendering/RenderThemeChromiumGtk.h @@ -0,0 +1,136 @@ +/* + * This file is part of the WebKit project. + * + * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com + * Copyright (C) 2007 Holger Hans Peter Freyther + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * Copyright (C) 2008, 2009 Google, Inc. + * All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef RenderThemeChromiumGtk_h +#define RenderThemeChromiumGtk_h + +#include "RenderTheme.h" + +#include <gtk/gtk.h> + +namespace WebCore { + + class RenderThemeChromiumGtk : public RenderTheme { + public: + RenderThemeChromiumGtk(); + ~RenderThemeChromiumGtk() { } + + virtual String extraDefaultStyleSheet(); + virtual String extraQuirksStyleSheet(); + + // A method asking if the theme's controls actually care about redrawing when hovered. + virtual bool supportsHover(const RenderStyle*) const { return true; } + + // A method asking if the theme is able to draw the focus ring. + virtual bool supportsFocusRing(const RenderStyle*) const; + + // The platform selection color. + virtual Color platformActiveSelectionBackgroundColor() const; + virtual Color platformInactiveSelectionBackgroundColor() const; + virtual Color platformActiveSelectionForegroundColor() const; + virtual Color platformInactiveSelectionForegroundColor() const; + virtual Color platformTextSearchHighlightColor() const; + + virtual double caretBlinkInterval() const; + + // System fonts. + virtual void systemFont(int propId, Document*, FontDescription&) const; + + virtual int minimumMenuListSize(RenderStyle*) const; + + virtual bool paintCheckbox(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual void setCheckboxSize(RenderStyle*) const; + + virtual bool paintRadio(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual void setRadioSize(RenderStyle*) const; + + virtual bool paintButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + virtual bool paintTextField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + virtual bool paintTextArea(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) { return paintTextField(o, i, r); } + + virtual bool paintSearchField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + virtual bool paintSearchFieldResultsDecoration(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual bool paintSearchFieldResultsButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual bool paintSearchFieldCancelButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + // MenuList refers to an unstyled menulist (meaning a menulist without + // background-color or border set) and MenuListButton refers to a styled + // menulist (a menulist with background-color or border set). They have + // this distinction to support showing aqua style themes whenever they + // possibly can, which is something we don't want to replicate. + // + // In short, we either go down the MenuList code path or the MenuListButton + // codepath. We never go down both. And in both cases, they render the + // entire menulist. + virtual void adjustMenuListStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual bool paintMenuList(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual void adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual bool paintMenuListButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + // These methods define the padding for the MenuList's inner block. + virtual int popupInternalPaddingLeft(RenderStyle*) const; + virtual int popupInternalPaddingRight(RenderStyle*) const; + virtual int popupInternalPaddingTop(RenderStyle*) const; + virtual int popupInternalPaddingBottom(RenderStyle*) const; + + virtual void adjustButtonInnerStyle(RenderStyle* style) const; + + // A method asking if the control changes its tint when the window has focus or not. + virtual bool controlSupportsTints(const RenderObject*) const; + + // A general method asking if any control tinting is supported at all. + virtual bool supportsControlTints() const { return true; } + + // List Box selection color + virtual Color activeListBoxSelectionBackgroundColor() const; + virtual Color activeListBoxSelectionForegroundColor() const; + virtual Color inactiveListBoxSelectionBackgroundColor() const; + virtual Color inactiveListBoxSelectionForegroundColor() const; + + private: + // Hold the state + GtkWidget* gtkEntry() const; + GtkWidget* gtkTreeView() const; + + // Unmapped GdkWindow having a container. This is holding all our fake widgets + GtkContainer* gtkContainer() const; + + private: + int menuListInternalPadding(RenderStyle*, int paddingType) const; + + mutable GtkWidget* m_gtkWindow; + mutable GtkContainer* m_gtkContainer; + mutable GtkWidget* m_gtkEntry; + mutable GtkWidget* m_gtkTreeView; + }; + +} // namespace WebCore + +#endif diff --git a/WebCore/rendering/RenderThemeChromiumMac.h b/WebCore/rendering/RenderThemeChromiumMac.h new file mode 100644 index 0000000..b750213 --- /dev/null +++ b/WebCore/rendering/RenderThemeChromiumMac.h @@ -0,0 +1,210 @@ +/* + * This file is part of the theme implementation for form controls in WebCore. + * + * Copyright (C) 2005 Apple Computer, Inc. + * Copyright (C) 2008, 2009 Google, Inc. + * + * 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 RenderThemeChromiumMac_h +#define RenderThemeChromiumMac_h + +#import "RenderTheme.h" +#import <wtf/HashMap.h> +#import <wtf/RetainPtr.h> + +#ifdef __OBJC__ +@class WebCoreRenderThemeNotificationObserver; +#else +class WebCoreRenderThemeNotificationObserver; +#endif + +namespace WebCore { + + class RenderStyle; + + class RenderThemeChromiumMac : public RenderTheme { + public: + RenderThemeChromiumMac(); + virtual ~RenderThemeChromiumMac(); + + // A method to obtain the baseline position for a "leaf" control. This will only be used if a baseline + // position cannot be determined by examining child content. Checkboxes and radio buttons are examples of + // controls that need to do this. + virtual int baselinePosition(const RenderObject*) const; + + // A method asking if the control changes its tint when the window has focus or not. + virtual bool controlSupportsTints(const RenderObject*) const; + + // A general method asking if any control tinting is supported at all. + virtual bool supportsControlTints() const { return true; } + + virtual void adjustRepaintRect(const RenderObject*, IntRect&); + + virtual bool isControlStyled(const RenderStyle*, const BorderData&, + const FillLayer&, const Color& backgroundColor) const; + + virtual Color platformActiveSelectionBackgroundColor() const; + virtual Color platformInactiveSelectionBackgroundColor() const; + virtual Color activeListBoxSelectionBackgroundColor() const; + + virtual void platformColorsDidChange(); + + // System fonts. + virtual void systemFont(int cssValueId, Document*, FontDescription&) const; + + virtual int minimumMenuListSize(RenderStyle*) const; + + virtual void adjustSliderThumbSize(RenderObject*) const; + + virtual int popupInternalPaddingLeft(RenderStyle*) const; + virtual int popupInternalPaddingRight(RenderStyle*) const; + virtual int popupInternalPaddingTop(RenderStyle*) const; + virtual int popupInternalPaddingBottom(RenderStyle*) const; + + virtual bool paintCapsLockIndicator(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + virtual Color systemColor(int cssValueId) const; + + protected: + // Methods for each appearance value. + virtual bool paintCheckbox(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual void setCheckboxSize(RenderStyle*) const; + + virtual bool paintRadio(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual void setRadioSize(RenderStyle*) const; + + virtual void adjustButtonStyle(CSSStyleSelector*, RenderStyle*, WebCore::Element*) const; + virtual bool paintButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual void setButtonSize(RenderStyle*) const; + + virtual bool paintTextField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual void adjustTextFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + + virtual bool paintTextArea(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual void adjustTextAreaStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + + virtual bool paintMenuList(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual void adjustMenuListStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + + virtual bool paintMenuListButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual void adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + + virtual bool paintSliderTrack(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual void adjustSliderTrackStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + + virtual bool paintSliderThumb(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual void adjustSliderThumbStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + + virtual bool paintSearchField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual void adjustSearchFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + + virtual void adjustSearchFieldCancelButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual bool paintSearchFieldCancelButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + virtual void adjustSearchFieldDecorationStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual bool paintSearchFieldDecoration(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + virtual void adjustSearchFieldResultsDecorationStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual bool paintSearchFieldResultsDecoration(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + virtual void adjustSearchFieldResultsButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual bool paintSearchFieldResultsButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + virtual bool paintMediaFullscreenButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual bool paintMediaPlayButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual bool paintMediaMuteButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual bool paintMediaSeekBackButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual bool paintMediaSeekForwardButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual bool paintMediaSliderTrack(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual bool paintMediaSliderThumb(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + private: + IntRect inflateRect(const IntRect&, const IntSize&, const int* margins, float zoomLevel = 1.0f) const; + + // Get the control size based off the font. Used by some of the controls (like buttons). + NSControlSize controlSizeForFont(RenderStyle*) const; + NSControlSize controlSizeForSystemFont(RenderStyle*) const; + void setControlSize(NSCell*, const IntSize* sizes, const IntSize& minSize, float zoomLevel = 1.0f); + void setSizeFromFont(RenderStyle*, const IntSize* sizes) const; + IntSize sizeForFont(RenderStyle*, const IntSize* sizes) const; + IntSize sizeForSystemFont(RenderStyle*, const IntSize* sizes) const; + void setFontFromControlSize(CSSStyleSelector*, RenderStyle*, NSControlSize) const; + + void updateCheckedState(NSCell*, const RenderObject*); + void updateEnabledState(NSCell*, const RenderObject*); + void updateFocusedState(NSCell*, const RenderObject*); + void updatePressedState(NSCell*, const RenderObject*); + + // Helpers for adjusting appearance and for painting + const IntSize* checkboxSizes() const; + const int* checkboxMargins() const; + void setCheckboxCellState(const RenderObject*, const IntRect&); + + const IntSize* radioSizes() const; + const int* radioMargins() const; + void setRadioCellState(const RenderObject*, const IntRect&); + + void setButtonPaddingFromControlSize(RenderStyle*, NSControlSize) const; + const IntSize* buttonSizes() const; + const int* buttonMargins() const; + void setButtonCellState(const RenderObject*, const IntRect&); + + void setPopupButtonCellState(const RenderObject*, const IntRect&); + const IntSize* popupButtonSizes() const; + const int* popupButtonMargins() const; + const int* popupButtonPadding(NSControlSize) const; + void paintMenuListButtonGradients(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + const IntSize* menuListSizes() const; + + const IntSize* searchFieldSizes() const; + const IntSize* cancelButtonSizes() const; + const IntSize* resultsButtonSizes() const; + void setSearchCellState(RenderObject*, const IntRect&); + void setSearchFieldSize(RenderStyle*) const; + + NSButtonCell* checkbox() const; + NSButtonCell* radio() const; + NSButtonCell* button() const; + NSPopUpButtonCell* popupButton() const; + NSSearchFieldCell* search() const; + NSMenu* searchMenuTemplate() const; + NSSliderCell* sliderThumbHorizontal() const; + NSSliderCell* sliderThumbVertical() const; + + private: + mutable RetainPtr<NSButtonCell> m_checkbox; + mutable RetainPtr<NSButtonCell> m_radio; + mutable RetainPtr<NSButtonCell> m_button; + mutable RetainPtr<NSPopUpButtonCell> m_popupButton; + mutable RetainPtr<NSSearchFieldCell> m_search; + mutable RetainPtr<NSMenu> m_searchMenuTemplate; + mutable RetainPtr<NSSliderCell> m_sliderThumbHorizontal; + mutable RetainPtr<NSSliderCell> m_sliderThumbVertical; + + bool m_isSliderThumbHorizontalPressed; + bool m_isSliderThumbVerticalPressed; + + mutable HashMap<int, RGBA32> m_systemColorCache; + + RetainPtr<WebCoreRenderThemeNotificationObserver> m_notificationObserver; + }; + +} // namespace WebCore + +#endif diff --git a/WebCore/rendering/RenderThemeChromiumMac.mm b/WebCore/rendering/RenderThemeChromiumMac.mm new file mode 100644 index 0000000..6318fd9 --- /dev/null +++ b/WebCore/rendering/RenderThemeChromiumMac.mm @@ -0,0 +1,1973 @@ +/* + * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009 Google, Inc. + * + * 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. + */ + +// FIXME: we still need to figure out if passing a null view to the cell +// drawing routines will work. I expect not, and if that's the case we'll have +// to figure out something else. For now, at least leave the lines commented +// in, but the procurement of the view if 0'd. + +#import "config.h" +#import "RenderThemeChromiumMac.h" + +#import <Carbon/Carbon.h> +#import <Cocoa/Cocoa.h> +#import <math.h> + +#import "BitmapImage.h" +#import "CSSStyleSelector.h" +#import "CSSValueKeywords.h" +#import "Document.h" +#import "Element.h" +#import "FoundationExtras.h" +#import "FrameView.h" +#import "GraphicsContext.h" +#import "HTMLInputElement.h" +#import "HTMLMediaElement.h" +#import "HTMLNames.h" +#import "Image.h" +#import "LocalCurrentGraphicsContext.h" +#import "MediaControlElements.h" +#import "RenderSlider.h" +#import "RenderView.h" +#import "SharedBuffer.h" +#import "WebCoreSystemInterface.h" +#import <wtf/RetainPtr.h> + +#ifdef BUILDING_ON_TIGER +typedef int NSInteger; +typedef unsigned NSUInteger; +#endif + +using std::min; + +// The methods in this file are specific to the Mac OS X platform. + +// FIXME: The platform-independent code in this class should be factored out and merged with RenderThemeSafari. + +@interface WebCoreRenderThemeNotificationObserver : NSObject +{ + WebCore::RenderTheme *_theme; +} + +- (id)initWithTheme:(WebCore::RenderTheme *)theme; +- (void)systemColorsDidChange:(NSNotification *)notification; + +@end + +@implementation WebCoreRenderThemeNotificationObserver + +- (id)initWithTheme:(WebCore::RenderTheme *)theme +{ + [super init]; + _theme = theme; + + return self; +} + +- (void)systemColorsDidChange:(NSNotification *)notification +{ + ASSERT([[notification name] isEqualToString:NSSystemColorsDidChangeNotification]); + _theme->platformColorsDidChange(); +} + +@end + +namespace WebCore { + +using namespace HTMLNames; + +enum { + TopMargin, + RightMargin, + BottomMargin, + LeftMargin +}; + +enum { + TopPadding, + RightPadding, + BottomPadding, + LeftPadding +}; + +// In our Mac port, we don't define PLATFORM(MAC) and thus don't pick up the +// |operator NSRect()| on WebCore::IntRect and FloatRect. This substitues for +// that missing conversion operator. +NSRect IntRectToNSRect(const IntRect & rect) +{ + return NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height()); +} + +NSRect FloatRectToNSRect(const FloatRect & rect) +{ + return NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height()); +} + +IntRect NSRectToIntRect(const NSRect & rect) +{ + return IntRect(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height); +} + +RenderTheme* theme() +{ + static RenderThemeChromiumMac* macTheme = new RenderThemeChromiumMac; + return macTheme; +} + +RenderThemeChromiumMac::RenderThemeChromiumMac() + : m_isSliderThumbHorizontalPressed(false) + , m_isSliderThumbVerticalPressed(false) + , m_notificationObserver(AdoptNS, [[WebCoreRenderThemeNotificationObserver alloc] initWithTheme:this]) +{ + [[NSNotificationCenter defaultCenter] addObserver:m_notificationObserver.get() + selector:@selector(systemColorsDidChange:) + name:NSSystemColorsDidChangeNotification + object:nil]; +} + +RenderThemeChromiumMac::~RenderThemeChromiumMac() +{ + [[NSNotificationCenter defaultCenter] removeObserver:m_notificationObserver.get()]; +} + +Color RenderThemeChromiumMac::platformActiveSelectionBackgroundColor() const +{ + NSColor* color = [[NSColor selectedTextBackgroundColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace]; + return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent])); +} + +Color RenderThemeChromiumMac::platformInactiveSelectionBackgroundColor() const +{ + NSColor* color = [[NSColor secondarySelectedControlColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace]; + return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent])); +} + +Color RenderThemeChromiumMac::activeListBoxSelectionBackgroundColor() const +{ + NSColor* color = [[NSColor alternateSelectedControlColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace]; + return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent])); +} + +static FontWeight toFontWeight(NSInteger appKitFontWeight) +{ + ASSERT(appKitFontWeight > 0 && appKitFontWeight < 15); + if (appKitFontWeight > 14) + appKitFontWeight = 14; + else if (appKitFontWeight < 1) + appKitFontWeight = 1; + + static FontWeight fontWeights[] = { + FontWeight100, + FontWeight100, + FontWeight200, + FontWeight300, + FontWeight400, + FontWeight500, + FontWeight600, + FontWeight600, + FontWeight700, + FontWeight800, + FontWeight800, + FontWeight900, + FontWeight900, + FontWeight900 + }; + return fontWeights[appKitFontWeight - 1]; +} + +void RenderThemeChromiumMac::systemFont(int cssValueId, Document* document, FontDescription& fontDescription) const +{ + static FontDescription systemFont; + static FontDescription smallSystemFont; + static FontDescription menuFont; + static FontDescription labelFont; + static FontDescription miniControlFont; + static FontDescription smallControlFont; + static FontDescription controlFont; + + FontDescription* cachedDesc; + NSFont* font = nil; + switch (cssValueId) { + case CSSValueSmallCaption: + cachedDesc = &smallSystemFont; + if (!smallSystemFont.isAbsoluteSize()) + font = [NSFont systemFontOfSize:[NSFont smallSystemFontSize]]; + break; + case CSSValueMenu: + cachedDesc = &menuFont; + if (!menuFont.isAbsoluteSize()) + font = [NSFont menuFontOfSize:[NSFont systemFontSize]]; + break; + case CSSValueStatusBar: + cachedDesc = &labelFont; + if (!labelFont.isAbsoluteSize()) + font = [NSFont labelFontOfSize:[NSFont labelFontSize]]; + break; + case CSSValueWebkitMiniControl: + cachedDesc = &miniControlFont; + if (!miniControlFont.isAbsoluteSize()) + font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSMiniControlSize]]; + break; + case CSSValueWebkitSmallControl: + cachedDesc = &smallControlFont; + if (!smallControlFont.isAbsoluteSize()) + font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]]; + break; + case CSSValueWebkitControl: + cachedDesc = &controlFont; + if (!controlFont.isAbsoluteSize()) + font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]]; + break; + default: + cachedDesc = &systemFont; + if (!systemFont.isAbsoluteSize()) + font = [NSFont systemFontOfSize:[NSFont systemFontSize]]; + } + + if (font) { + NSFontManager *fontManager = [NSFontManager sharedFontManager]; + cachedDesc->setIsAbsoluteSize(true); + cachedDesc->setGenericFamily(FontDescription::NoFamily); + cachedDesc->firstFamily().setFamily([font familyName]); + cachedDesc->setSpecifiedSize([font pointSize]); + cachedDesc->setWeight(toFontWeight([fontManager weightOfFont:font])); + cachedDesc->setItalic([fontManager traitsOfFont:font] & NSItalicFontMask); + } + fontDescription = *cachedDesc; +} + +static RGBA32 convertNSColorToColor(NSColor *color) +{ + NSColor *colorInColorSpace = [color colorUsingColorSpaceName:NSCalibratedRGBColorSpace]; + if (colorInColorSpace) { + static const double scaleFactor = nextafter(256.0, 0.0); + return makeRGB(static_cast<int>(scaleFactor * [colorInColorSpace redComponent]), + static_cast<int>(scaleFactor * [colorInColorSpace greenComponent]), + static_cast<int>(scaleFactor * [colorInColorSpace blueComponent])); + } + + // This conversion above can fail if the NSColor in question is an NSPatternColor + // (as many system colors are). These colors are actually a repeating pattern + // not just a solid color. To work around this we simply draw a 1x1 image of + // the color and use that pixel's color. It might be better to use an average of + // the colors in the pattern instead. + NSBitmapImageRep *offscreenRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil + pixelsWide:1 + pixelsHigh:1 + bitsPerSample:8 + samplesPerPixel:4 + hasAlpha:YES + isPlanar:NO + colorSpaceName:NSCalibratedRGBColorSpace + bytesPerRow:4 + bitsPerPixel:32]; + + [NSGraphicsContext saveGraphicsState]; + [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:offscreenRep]]; + NSEraseRect(NSMakeRect(0, 0, 1, 1)); + [color drawSwatchInRect:NSMakeRect(0, 0, 1, 1)]; + [NSGraphicsContext restoreGraphicsState]; + + NSUInteger pixel[4]; + [offscreenRep getPixel:pixel atX:0 y:0]; + + [offscreenRep release]; + + return makeRGB(pixel[0], pixel[1], pixel[2]); +} + +static RGBA32 menuBackgroundColor() +{ + NSBitmapImageRep *offscreenRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil + pixelsWide:1 + pixelsHigh:1 + bitsPerSample:8 + samplesPerPixel:4 + hasAlpha:YES + isPlanar:NO + colorSpaceName:NSCalibratedRGBColorSpace + bytesPerRow:4 + bitsPerPixel:32]; + + CGContextRef context = static_cast<CGContextRef>([[NSGraphicsContext graphicsContextWithBitmapImageRep:offscreenRep] graphicsPort]); + CGRect rect = CGRectMake(0, 0, 1, 1); + HIThemeMenuDrawInfo drawInfo; + drawInfo.version = 0; + drawInfo.menuType = kThemeMenuTypePopUp; + HIThemeDrawMenuBackground(&rect, &drawInfo, context, kHIThemeOrientationInverted); + + NSUInteger pixel[4]; + [offscreenRep getPixel:pixel atX:0 y:0]; + + [offscreenRep release]; + + return makeRGB(pixel[0], pixel[1], pixel[2]); +} + +void RenderThemeChromiumMac::platformColorsDidChange() +{ + m_systemColorCache.clear(); + RenderTheme::platformColorsDidChange(); +} + +Color RenderThemeChromiumMac::systemColor(int cssValueId) const +{ + if (m_systemColorCache.contains(cssValueId)) + return m_systemColorCache.get(cssValueId); + + Color color; + switch (cssValueId) { + case CSSValueActiveborder: + color = convertNSColorToColor([NSColor keyboardFocusIndicatorColor]); + break; + case CSSValueActivecaption: + color = convertNSColorToColor([NSColor windowFrameTextColor]); + break; + case CSSValueAppworkspace: + color = convertNSColorToColor([NSColor headerColor]); + break; + case CSSValueBackground: + // Use theme independent default + break; + case CSSValueButtonface: + // We use this value instead of NSColor's controlColor to avoid website incompatibilities. + // We may want to change this to use the NSColor in future. + color = 0xFFC0C0C0; + break; + case CSSValueButtonhighlight: + color = convertNSColorToColor([NSColor controlHighlightColor]); + break; + case CSSValueButtonshadow: + color = convertNSColorToColor([NSColor controlShadowColor]); + break; + case CSSValueButtontext: + color = convertNSColorToColor([NSColor controlTextColor]); + break; + case CSSValueCaptiontext: + color = convertNSColorToColor([NSColor textColor]); + break; + case CSSValueGraytext: + color = convertNSColorToColor([NSColor disabledControlTextColor]); + break; + case CSSValueHighlight: + color = convertNSColorToColor([NSColor selectedTextBackgroundColor]); + break; + case CSSValueHighlighttext: + color = convertNSColorToColor([NSColor selectedTextColor]); + break; + case CSSValueInactiveborder: + color = convertNSColorToColor([NSColor controlBackgroundColor]); + break; + case CSSValueInactivecaption: + color = convertNSColorToColor([NSColor controlBackgroundColor]); + break; + case CSSValueInactivecaptiontext: + color = convertNSColorToColor([NSColor textColor]); + break; + case CSSValueInfobackground: + // There is no corresponding NSColor for this so we use a hard coded value. + color = 0xFFFBFCC5; + break; + case CSSValueInfotext: + color = convertNSColorToColor([NSColor textColor]); + break; + case CSSValueMenu: + color = menuBackgroundColor(); + break; + case CSSValueMenutext: + color = convertNSColorToColor([NSColor selectedMenuItemTextColor]); + break; + case CSSValueScrollbar: + color = convertNSColorToColor([NSColor scrollBarColor]); + break; + case CSSValueText: + color = convertNSColorToColor([NSColor textColor]); + break; + case CSSValueThreeddarkshadow: + color = convertNSColorToColor([NSColor controlDarkShadowColor]); + break; + case CSSValueThreedshadow: + color = convertNSColorToColor([NSColor shadowColor]); + break; + case CSSValueThreedface: + // We use this value instead of NSColor's controlColor to avoid website incompatibilities. + // We may want to change this to use the NSColor in future. + color = 0xFFC0C0C0; + break; + case CSSValueThreedhighlight: + color = convertNSColorToColor([NSColor highlightColor]); + break; + case CSSValueThreedlightshadow: + color = convertNSColorToColor([NSColor controlLightHighlightColor]); + break; + case CSSValueWindow: + color = convertNSColorToColor([NSColor windowBackgroundColor]); + break; + case CSSValueWindowframe: + color = convertNSColorToColor([NSColor windowFrameColor]); + break; + case CSSValueWindowtext: + color = convertNSColorToColor([NSColor windowFrameTextColor]); + break; + } + + if (!color.isValid()) + color = RenderTheme::systemColor(cssValueId); + + if (color.isValid()) + m_systemColorCache.set(cssValueId, color.rgb()); + + return color; +} + +bool RenderThemeChromiumMac::isControlStyled(const RenderStyle* style, const BorderData& border, + const FillLayer& background, const Color& backgroundColor) const +{ + if (style->appearance() == TextFieldPart || style->appearance() == TextAreaPart || style->appearance() == ListboxPart) + return style->border() != border; + + // FIXME: This is horrible, but there is not much else that can be done. Menu lists cannot draw properly when + // scaled. They can't really draw properly when transformed either. We can't detect the transform case at style + // adjustment time so that will just have to stay broken. We can however detect that we're zooming. If zooming + // is in effect we treat it like the control is styled. + if (style->appearance() == MenulistPart && style->effectiveZoom() != 1.0f) + return true; + + return RenderTheme::isControlStyled(style, border, background, backgroundColor); +} + +// FIXME: Use the code from the old upstream version, before it was converted to the new theme API in r37731. +void RenderThemeChromiumMac::adjustRepaintRect(const RenderObject* o, IntRect& r) +{ + float zoomLevel = o->style()->effectiveZoom(); + + switch (o->style()->appearance()) { + case CheckboxPart: { + // Since we query the prototype cell, we need to update its state to match. + setCheckboxCellState(o, r); + + // We inflate the rect as needed to account for padding included in the cell to accommodate the checkbox + // shadow" and the check. We don't consider this part of the bounds of the control in WebKit. + IntSize size = checkboxSizes()[[checkbox() controlSize]]; + size.setHeight(size.height() * zoomLevel); + size.setWidth(size.width() * zoomLevel); + r = inflateRect(r, size, checkboxMargins(), zoomLevel); + break; + } + case RadioPart: { + // Since we query the prototype cell, we need to update its state to match. + setRadioCellState(o, r); + + // We inflate the rect as needed to account for padding included in the cell to accommodate the checkbox + // shadow" and the check. We don't consider this part of the bounds of the control in WebKit. + IntSize size = radioSizes()[[radio() controlSize]]; + size.setHeight(size.height() * zoomLevel); + size.setWidth(size.width() * zoomLevel); + r = inflateRect(r, size, radioMargins(), zoomLevel); + break; + } + case PushButtonPart: + case DefaultButtonPart: + case ButtonPart: { + // Since we query the prototype cell, we need to update its state to match. + setButtonCellState(o, r); + + // We inflate the rect as needed to account for padding included in the cell to accommodate the checkbox + // shadow" and the check. We don't consider this part of the bounds of the control in WebKit. + if ([button() bezelStyle] == NSRoundedBezelStyle) { + IntSize size = buttonSizes()[[button() controlSize]]; + size.setHeight(size.height() * zoomLevel); + size.setWidth(r.width()); + r = inflateRect(r, size, buttonMargins(), zoomLevel); + } + break; + } + case MenulistPart: { + setPopupButtonCellState(o, r); + IntSize size = popupButtonSizes()[[popupButton() controlSize]]; + size.setHeight(size.height() * zoomLevel); + size.setWidth(r.width()); + r = inflateRect(r, size, popupButtonMargins(), zoomLevel); + break; + } + default: + break; + } +} + +IntRect RenderThemeChromiumMac::inflateRect(const IntRect& r, const IntSize& size, const int* margins, float zoomLevel) const +{ + // Only do the inflation if the available width/height are too small. Otherwise try to + // fit the glow/check space into the available box's width/height. + int widthDelta = r.width() - (size.width() + margins[LeftMargin] * zoomLevel + margins[RightMargin] * zoomLevel); + int heightDelta = r.height() - (size.height() + margins[TopMargin] * zoomLevel + margins[BottomMargin] * zoomLevel); + IntRect result(r); + if (widthDelta < 0) { + result.setX(result.x() - margins[LeftMargin] * zoomLevel); + result.setWidth(result.width() - widthDelta); + } + if (heightDelta < 0) { + result.setY(result.y() - margins[TopMargin] * zoomLevel); + result.setHeight(result.height() - heightDelta); + } + return result; +} + +void RenderThemeChromiumMac::updateCheckedState(NSCell* cell, const RenderObject* o) +{ + bool oldIndeterminate = [cell state] == NSMixedState; + bool indeterminate = isIndeterminate(o); + bool checked = isChecked(o); + + if (oldIndeterminate != indeterminate) { + [cell setState:indeterminate ? NSMixedState : (checked ? NSOnState : NSOffState)]; + return; + } + + bool oldChecked = [cell state] == NSOnState; + if (checked != oldChecked) + [cell setState:checked ? NSOnState : NSOffState]; +} + +void RenderThemeChromiumMac::updateEnabledState(NSCell* cell, const RenderObject* o) +{ + bool oldEnabled = [cell isEnabled]; + bool enabled = isEnabled(o); + if (enabled != oldEnabled) + [cell setEnabled:enabled]; +} + +void RenderThemeChromiumMac::updateFocusedState(NSCell* cell, const RenderObject* o) +{ + bool oldFocused = [cell showsFirstResponder]; + bool focused = isFocused(o) && o->style()->outlineStyleIsAuto(); + if (focused != oldFocused) + [cell setShowsFirstResponder:focused]; +} + +void RenderThemeChromiumMac::updatePressedState(NSCell* cell, const RenderObject* o) +{ + bool oldPressed = [cell isHighlighted]; + bool pressed = (o->element() && o->element()->active()); + if (pressed != oldPressed) + [cell setHighlighted:pressed]; +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +int RenderThemeChromiumMac::baselinePosition(const RenderObject* o) const +{ + if (o->style()->appearance() == CheckboxPart || o->style()->appearance() == RadioPart) + return o->marginTop() + o->height() - 2 * o->style()->effectiveZoom(); // The baseline is 2px up from the bottom of the checkbox/radio in AppKit. + return RenderTheme::baselinePosition(o); +} + +bool RenderThemeChromiumMac::controlSupportsTints(const RenderObject* o) const +{ + // An alternate way to implement this would be to get the appropriate cell object + // and call the private _needRedrawOnWindowChangedKeyState method. An advantage of + // that would be that we would match AppKit behavior more closely, but a disadvantage + // would be that we would rely on an AppKit SPI method. + + if (!isEnabled(o)) + return false; + + // Checkboxes only have tint when checked. + if (o->style()->appearance() == CheckboxPart) + return isChecked(o); + + // For now assume other controls have tint if enabled. + return true; +} + +NSControlSize RenderThemeChromiumMac::controlSizeForFont(RenderStyle* style) const +{ + int fontSize = style->fontSize(); + if (fontSize >= 16) + return NSRegularControlSize; + if (fontSize >= 11) + return NSSmallControlSize; + return NSMiniControlSize; +} + +void RenderThemeChromiumMac::setControlSize(NSCell* cell, const IntSize* sizes, const IntSize& minSize, float zoomLevel) +{ + NSControlSize size; + if (minSize.width() >= static_cast<int>(sizes[NSRegularControlSize].width() * zoomLevel) && + minSize.height() >= static_cast<int>(sizes[NSRegularControlSize].height() * zoomLevel)) + size = NSRegularControlSize; + else if (minSize.width() >= static_cast<int>(sizes[NSSmallControlSize].width() * zoomLevel) && + minSize.height() >= static_cast<int>(sizes[NSSmallControlSize].height() * zoomLevel)) + size = NSSmallControlSize; + else + size = NSMiniControlSize; + if (size != [cell controlSize]) // Only update if we have to, since AppKit does work even if the size is the same. + [cell setControlSize:size]; +} + +IntSize RenderThemeChromiumMac::sizeForFont(RenderStyle* style, const IntSize* sizes) const +{ + if (style->effectiveZoom() != 1.0f) { + IntSize result = sizes[controlSizeForFont(style)]; + return IntSize(result.width() * style->effectiveZoom(), result.height() * style->effectiveZoom()); + } + return sizes[controlSizeForFont(style)]; +} + +IntSize RenderThemeChromiumMac::sizeForSystemFont(RenderStyle* style, const IntSize* sizes) const +{ + if (style->effectiveZoom() != 1.0f) { + IntSize result = sizes[controlSizeForSystemFont(style)]; + return IntSize(result.width() * style->effectiveZoom(), result.height() * style->effectiveZoom()); + } + return sizes[controlSizeForSystemFont(style)]; +} + +void RenderThemeChromiumMac::setSizeFromFont(RenderStyle* style, const IntSize* sizes) const +{ + // FIXME: Check is flawed, since it doesn't take min-width/max-width into account. + IntSize size = sizeForFont(style, sizes); + if (style->width().isIntrinsicOrAuto() && size.width() > 0) + style->setWidth(Length(size.width(), Fixed)); + if (style->height().isAuto() && size.height() > 0) + style->setHeight(Length(size.height(), Fixed)); +} + +void RenderThemeChromiumMac::setFontFromControlSize(CSSStyleSelector* selector, RenderStyle* style, NSControlSize controlSize) const +{ + FontDescription fontDescription; + fontDescription.setIsAbsoluteSize(true); + fontDescription.setGenericFamily(FontDescription::SerifFamily); + + NSFont* font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:controlSize]]; + fontDescription.firstFamily().setFamily([font familyName]); + fontDescription.setComputedSize([font pointSize] * style->effectiveZoom()); + fontDescription.setSpecifiedSize([font pointSize] * style->effectiveZoom()); + + // Reset line height + style->setLineHeight(RenderStyle::initialLineHeight()); + + if (style->setFontDescription(fontDescription)) + style->font().update(0); +} + +NSControlSize RenderThemeChromiumMac::controlSizeForSystemFont(RenderStyle* style) const +{ + int fontSize = style->fontSize(); + if (fontSize >= [NSFont systemFontSizeForControlSize:NSRegularControlSize]) + return NSRegularControlSize; + if (fontSize >= [NSFont systemFontSizeForControlSize:NSSmallControlSize]) + return NSSmallControlSize; + return NSMiniControlSize; +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +bool RenderThemeChromiumMac::paintCheckbox(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + // Determine the width and height needed for the control and prepare the cell for painting. + setCheckboxCellState(o, r); + + paintInfo.context->save(); + + float zoomLevel = o->style()->effectiveZoom(); + + // We inflate the rect as needed to account for padding included in the cell to accommodate the checkbox + // shadow" and the check. We don't consider this part of the bounds of the control in WebKit. + NSButtonCell* checkbox = this->checkbox(); + IntSize size = checkboxSizes()[[checkbox controlSize]]; + size.setWidth(size.width() * zoomLevel); + size.setHeight(size.height() * zoomLevel); + IntRect inflatedRect = inflateRect(r, size, checkboxMargins(), zoomLevel); + + if (zoomLevel != 1.0f) { + inflatedRect.setWidth(inflatedRect.width() / zoomLevel); + inflatedRect.setHeight(inflatedRect.height() / zoomLevel); + paintInfo.context->translate(inflatedRect.x(), inflatedRect.y()); + paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); + paintInfo.context->translate(-inflatedRect.x(), -inflatedRect.y()); + } + + [checkbox drawWithFrame:NSRect(IntRectToNSRect(inflatedRect)) inView:nil]; + [checkbox setControlView:nil]; + + paintInfo.context->restore(); + + return false; +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +const IntSize* RenderThemeChromiumMac::checkboxSizes() const +{ + static const IntSize sizes[3] = { IntSize(14, 14), IntSize(12, 12), IntSize(10, 10) }; + return sizes; +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +const int* RenderThemeChromiumMac::checkboxMargins() const +{ + static const int margins[3][4] = + { + { 3, 4, 4, 2 }, + { 4, 3, 3, 3 }, + { 4, 3, 3, 3 }, + }; + return margins[[checkbox() controlSize]]; +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +void RenderThemeChromiumMac::setCheckboxCellState(const RenderObject* o, const IntRect& r) +{ + NSButtonCell* checkbox = this->checkbox(); + + // Set the control size based off the rectangle we're painting into. + setControlSize(checkbox, checkboxSizes(), r.size(), o->style()->effectiveZoom()); + + // Update the various states we respond to. + updateCheckedState(checkbox, o); + updateEnabledState(checkbox, o); + updatePressedState(checkbox, o); + updateFocusedState(checkbox, o); +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +void RenderThemeChromiumMac::setCheckboxSize(RenderStyle* style) const +{ + // If the width and height are both specified, then we have nothing to do. + if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto()) + return; + + // Use the font size to determine the intrinsic width of the control. + setSizeFromFont(style, checkboxSizes()); +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +bool RenderThemeChromiumMac::paintRadio(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + // Determine the width and height needed for the control and prepare the cell for painting. + setRadioCellState(o, r); + + paintInfo.context->save(); + + float zoomLevel = o->style()->effectiveZoom(); + + // We inflate the rect as needed to account for padding included in the cell to accommodate the checkbox + // shadow" and the check. We don't consider this part of the bounds of the control in WebKit. + NSButtonCell* radio = this->radio(); + IntSize size = radioSizes()[[radio controlSize]]; + size.setWidth(size.width() * zoomLevel); + size.setHeight(size.height() * zoomLevel); + IntRect inflatedRect = inflateRect(r, size, radioMargins(), zoomLevel); + + if (zoomLevel != 1.0f) { + inflatedRect.setWidth(inflatedRect.width() / zoomLevel); + inflatedRect.setHeight(inflatedRect.height() / zoomLevel); + paintInfo.context->translate(inflatedRect.x(), inflatedRect.y()); + paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); + paintInfo.context->translate(-inflatedRect.x(), -inflatedRect.y()); + } + + [radio drawWithFrame:NSRect(IntRectToNSRect(inflatedRect)) inView:nil]; + [radio setControlView:nil]; + + paintInfo.context->restore(); + + return false; +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +const IntSize* RenderThemeChromiumMac::radioSizes() const +{ + static const IntSize sizes[3] = { IntSize(14, 15), IntSize(12, 13), IntSize(10, 10) }; + return sizes; +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +const int* RenderThemeChromiumMac::radioMargins() const +{ + static const int margins[3][4] = + { + { 2, 2, 4, 2 }, + { 3, 2, 3, 2 }, + { 1, 0, 2, 0 }, + }; + return margins[[radio() controlSize]]; +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +void RenderThemeChromiumMac::setRadioCellState(const RenderObject* o, const IntRect& r) +{ + NSButtonCell* radio = this->radio(); + + // Set the control size based off the rectangle we're painting into. + setControlSize(radio, radioSizes(), r.size(), o->style()->effectiveZoom()); + + // Update the various states we respond to. + updateCheckedState(radio, o); + updateEnabledState(radio, o); + updatePressedState(radio, o); + updateFocusedState(radio, o); +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +void RenderThemeChromiumMac::setRadioSize(RenderStyle* style) const +{ + // If the width and height are both specified, then we have nothing to do. + if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto()) + return; + + // Use the font size to determine the intrinsic width of the control. + setSizeFromFont(style, radioSizes()); +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +void RenderThemeChromiumMac::setButtonPaddingFromControlSize(RenderStyle* style, NSControlSize size) const +{ + // Just use 8px. AppKit wants to use 11px for mini buttons, but that padding is just too large + // for real-world Web sites (creating a huge necessary minimum width for buttons whose space is + // by definition constrained, since we select mini only for small cramped environments. + // This also guarantees the HTML4 <button> will match our rendering by default, since we're using a consistent + // padding. + const int padding = 8 * style->effectiveZoom(); + style->setPaddingLeft(Length(padding, Fixed)); + style->setPaddingRight(Length(padding, Fixed)); + style->setPaddingTop(Length(0, Fixed)); + style->setPaddingBottom(Length(0, Fixed)); +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +void RenderThemeChromiumMac::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +{ + // There are three appearance constants for buttons. + // (1) Push-button is the constant for the default Aqua system button. Push buttons will not scale vertically and will not allow + // custom fonts or colors. <input>s use this constant. This button will allow custom colors and font weights/variants but won't + // scale vertically. + // (2) square-button is the constant for the square button. This button will allow custom fonts and colors and will scale vertically. + // (3) Button is the constant that means "pick the best button as appropriate." <button>s use this constant. This button will + // also scale vertically and allow custom fonts and colors. It will attempt to use Aqua if possible and will make this determination + // solely on the rectangle of the control. + + // Determine our control size based off our font. + NSControlSize controlSize = controlSizeForFont(style); + + if (style->appearance() == PushButtonPart) { + // Ditch the border. + style->resetBorder(); + + // Height is locked to auto. + style->setHeight(Length(Auto)); + + // White-space is locked to pre + style->setWhiteSpace(PRE); + + // Set the button's vertical size. + setButtonSize(style); + + // Add in the padding that we'd like to use. + setButtonPaddingFromControlSize(style, controlSize); + + // Our font is locked to the appropriate system font size for the control. To clarify, we first use the CSS-specified font to figure out + // a reasonable control size, but once that control size is determined, we throw that font away and use the appropriate + // system font for the control size instead. + setFontFromControlSize(selector, style, controlSize); + } else { + // Set a min-height so that we can't get smaller than the mini button. + style->setMinHeight(Length(static_cast<int>(15 * style->effectiveZoom()), Fixed)); + + // Reset the top and bottom borders. + style->resetBorderTop(); + style->resetBorderBottom(); + } + + style->setBoxShadow(0); +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +const IntSize* RenderThemeChromiumMac::buttonSizes() const +{ + static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) }; + return sizes; +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +const int* RenderThemeChromiumMac::buttonMargins() const +{ + static const int margins[3][4] = + { + { 4, 6, 7, 6 }, + { 4, 5, 6, 5 }, + { 0, 1, 1, 1 }, + }; + return margins[[button() controlSize]]; +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +void RenderThemeChromiumMac::setButtonSize(RenderStyle* style) const +{ + // If the width and height are both specified, then we have nothing to do. + if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto()) + return; + + // Use the font size to determine the intrinsic width of the control. + setSizeFromFont(style, buttonSizes()); +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +void RenderThemeChromiumMac::setButtonCellState(const RenderObject* o, const IntRect& r) +{ + NSButtonCell* button = this->button(); + + // Set the control size based off the rectangle we're painting into. + if (o->style()->appearance() == SquareButtonPart || + r.height() > buttonSizes()[NSRegularControlSize].height() * o->style()->effectiveZoom()) { + // Use the square button + if ([button bezelStyle] != NSShadowlessSquareBezelStyle) + [button setBezelStyle:NSShadowlessSquareBezelStyle]; + } else if ([button bezelStyle] != NSRoundedBezelStyle) + [button setBezelStyle:NSRoundedBezelStyle]; + + setControlSize(button, buttonSizes(), r.size(), o->style()->effectiveZoom()); + + NSWindow *window = [nil window]; + BOOL isDefaultButton = (isDefault(o) && [window isKeyWindow]); + [button setKeyEquivalent:(isDefaultButton ? @"\r" : @"")]; + + // Update the various states we respond to. + updateCheckedState(button, o); + updateEnabledState(button, o); + updatePressedState(button, o); + updateFocusedState(button, o); +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +bool RenderThemeChromiumMac::paintButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + NSButtonCell* button = this->button(); + LocalCurrentGraphicsContext localContext(paintInfo.context); + + // Determine the width and height needed for the control and prepare the cell for painting. + setButtonCellState(o, r); + + paintInfo.context->save(); + + // We inflate the rect as needed to account for padding included in the cell to accommodate the button + // shadow. We don't consider this part of the bounds of the control in WebKit. + float zoomLevel = o->style()->effectiveZoom(); + IntSize size = buttonSizes()[[button controlSize]]; + size.setWidth(r.width()); + size.setHeight(size.height() * zoomLevel); + IntRect inflatedRect = r; + if ([button bezelStyle] == NSRoundedBezelStyle) { + // Center the button within the available space. + if (inflatedRect.height() > size.height()) { + inflatedRect.setY(inflatedRect.y() + (inflatedRect.height() - size.height()) / 2); + inflatedRect.setHeight(size.height()); + } + + // Now inflate it to account for the shadow. + inflatedRect = inflateRect(inflatedRect, size, buttonMargins(), zoomLevel); + + if (zoomLevel != 1.0f) { + inflatedRect.setWidth(inflatedRect.width() / zoomLevel); + inflatedRect.setHeight(inflatedRect.height() / zoomLevel); + paintInfo.context->translate(inflatedRect.x(), inflatedRect.y()); + paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); + paintInfo.context->translate(-inflatedRect.x(), -inflatedRect.y()); + } + } + + NSView *view = nil; + NSWindow *window = [view window]; + NSButtonCell *previousDefaultButtonCell = [window defaultButtonCell]; + + if (isDefault(o) && [window isKeyWindow]) { + [window setDefaultButtonCell:button]; + wkAdvanceDefaultButtonPulseAnimation(button); + } else if ([previousDefaultButtonCell isEqual:button]) + [window setDefaultButtonCell:nil]; + + [button drawWithFrame:NSRect(IntRectToNSRect(inflatedRect)) inView:view]; + [button setControlView:nil]; + + if (![previousDefaultButtonCell isEqual:button]) + [window setDefaultButtonCell:previousDefaultButtonCell]; + + paintInfo.context->restore(); + + return false; +} + +bool RenderThemeChromiumMac::paintTextField(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + LocalCurrentGraphicsContext localContext(paintInfo.context); + wkDrawBezeledTextFieldCell(IntRectToNSRect(r), isEnabled(o) && !isReadOnlyControl(o)); + return false; +} + +void RenderThemeChromiumMac::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const +{ +} + +bool RenderThemeChromiumMac::paintCapsLockIndicator(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + if (paintInfo.context->paintingDisabled()) + return true; + + LocalCurrentGraphicsContext localContext(paintInfo.context); + wkDrawCapsLockIndicator(paintInfo.context->platformContext(), r); + + return false; +} + +bool RenderThemeChromiumMac::paintTextArea(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + LocalCurrentGraphicsContext localContext(paintInfo.context); + wkDrawBezeledTextArea(IntRectToNSRect(r), isEnabled(o) && !isReadOnlyControl(o)); + return false; +} + +void RenderThemeChromiumMac::adjustTextAreaStyle(CSSStyleSelector*, RenderStyle*, Element*) const +{ +} + +const int* RenderThemeChromiumMac::popupButtonMargins() const +{ + static const int margins[3][4] = + { + { 0, 3, 1, 3 }, + { 0, 3, 2, 3 }, + { 0, 1, 0, 1 } + }; + return margins[[popupButton() controlSize]]; +} + +const IntSize* RenderThemeChromiumMac::popupButtonSizes() const +{ + static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) }; + return sizes; +} + +const int* RenderThemeChromiumMac::popupButtonPadding(NSControlSize size) const +{ + static const int padding[3][4] = + { + { 2, 26, 3, 8 }, + { 2, 23, 3, 8 }, + { 2, 22, 3, 10 } + }; + return padding[size]; +} + +bool RenderThemeChromiumMac::paintMenuList(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + setPopupButtonCellState(o, r); + + NSPopUpButtonCell* popupButton = this->popupButton(); + + float zoomLevel = o->style()->effectiveZoom(); + IntSize size = popupButtonSizes()[[popupButton controlSize]]; + size.setHeight(size.height() * zoomLevel); + size.setWidth(r.width()); + + // Now inflate it to account for the shadow. + IntRect inflatedRect = r; + if (r.width() >= minimumMenuListSize(o->style())) + inflatedRect = inflateRect(inflatedRect, size, popupButtonMargins(), zoomLevel); + + paintInfo.context->save(); + +#ifndef BUILDING_ON_TIGER + // On Leopard, the cell will draw outside of the given rect, so we have to clip to the rect + paintInfo.context->clip(inflatedRect); +#endif + + if (zoomLevel != 1.0f) { + inflatedRect.setWidth(inflatedRect.width() / zoomLevel); + inflatedRect.setHeight(inflatedRect.height() / zoomLevel); + paintInfo.context->translate(inflatedRect.x(), inflatedRect.y()); + paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); + paintInfo.context->translate(-inflatedRect.x(), -inflatedRect.y()); + } + + [popupButton drawWithFrame:IntRectToNSRect(inflatedRect) inView:nil]; + [popupButton setControlView:nil]; + + paintInfo.context->restore(); + + return false; +} + +static const float baseFontSize = 11.0f; +static const float baseArrowHeight = 4.0f; +static const float baseArrowWidth = 5.0f; +static const float baseSpaceBetweenArrows = 2.0f; +static const int arrowPaddingLeft = 6; +static const int arrowPaddingRight = 6; +static const int paddingBeforeSeparator = 4; +static const int baseBorderRadius = 5; +static const int styledPopupPaddingLeft = 8; +static const int styledPopupPaddingTop = 1; +static const int styledPopupPaddingBottom = 2; + +static void TopGradientInterpolate(void* info, const CGFloat* inData, CGFloat* outData) +{ + static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.4f }; + static float light[4] = { 1.0f, 1.0f, 1.0f, 0.15f }; + float a = inData[0]; + int i = 0; + for (i = 0; i < 4; i++) + outData[i] = (1.0f - a) * dark[i] + a * light[i]; +} + +static void BottomGradientInterpolate(void* info, const CGFloat* inData, CGFloat* outData) +{ + static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.0f }; + static float light[4] = { 1.0f, 1.0f, 1.0f, 0.3f }; + float a = inData[0]; + int i = 0; + for (i = 0; i < 4; i++) + outData[i] = (1.0f - a) * dark[i] + a * light[i]; +} + +static void MainGradientInterpolate(void* info, const CGFloat* inData, CGFloat* outData) +{ + static float dark[4] = { 0.0f, 0.0f, 0.0f, 0.15f }; + static float light[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + float a = inData[0]; + int i = 0; + for (i = 0; i < 4; i++) + outData[i] = (1.0f - a) * dark[i] + a * light[i]; +} + +static void TrackGradientInterpolate(void* info, const CGFloat* inData, CGFloat* outData) +{ + static float dark[4] = { 0.0f, 0.0f, 0.0f, 0.678f }; + static float light[4] = { 0.0f, 0.0f, 0.0f, 0.13f }; + float a = inData[0]; + int i = 0; + for (i = 0; i < 4; i++) + outData[i] = (1.0f - a) * dark[i] + a * light[i]; +} + +void RenderThemeChromiumMac::paintMenuListButtonGradients(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + CGContextRef context = paintInfo.context->platformContext(); + + paintInfo.context->save(); + + int radius = o->style()->borderTopLeftRadius().width(); + + RetainPtr<CGColorSpaceRef> cspace(AdoptCF, CGColorSpaceCreateDeviceRGB()); + + FloatRect topGradient(r.x(), r.y(), r.width(), r.height() / 2.0f); + struct CGFunctionCallbacks topCallbacks = { 0, TopGradientInterpolate, NULL }; + RetainPtr<CGFunctionRef> topFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &topCallbacks)); + RetainPtr<CGShadingRef> topShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(topGradient.x(), topGradient.y()), CGPointMake(topGradient.x(), topGradient.bottom()), topFunction.get(), false, false)); + + FloatRect bottomGradient(r.x() + radius, r.y() + r.height() / 2.0f, r.width() - 2.0f * radius, r.height() / 2.0f); + struct CGFunctionCallbacks bottomCallbacks = { 0, BottomGradientInterpolate, NULL }; + RetainPtr<CGFunctionRef> bottomFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &bottomCallbacks)); + RetainPtr<CGShadingRef> bottomShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(bottomGradient.x(), bottomGradient.y()), CGPointMake(bottomGradient.x(), bottomGradient.bottom()), bottomFunction.get(), false, false)); + + struct CGFunctionCallbacks mainCallbacks = { 0, MainGradientInterpolate, NULL }; + RetainPtr<CGFunctionRef> mainFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks)); + RetainPtr<CGShadingRef> mainShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(r.x(), r.y()), CGPointMake(r.x(), r.bottom()), mainFunction.get(), false, false)); + + RetainPtr<CGShadingRef> leftShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(r.x(), r.y()), CGPointMake(r.x() + radius, r.y()), mainFunction.get(), false, false)); + + RetainPtr<CGShadingRef> rightShading(AdoptCF, CGShadingCreateAxial(cspace.get(), CGPointMake(r.right(), r.y()), CGPointMake(r.right() - radius, r.y()), mainFunction.get(), false, false)); + paintInfo.context->save(); + CGContextClipToRect(context, r); + paintInfo.context->addRoundedRectClip(r, + o->style()->borderTopLeftRadius(), o->style()->borderTopRightRadius(), + o->style()->borderBottomLeftRadius(), o->style()->borderBottomRightRadius()); + CGContextDrawShading(context, mainShading.get()); + paintInfo.context->restore(); + + paintInfo.context->save(); + CGContextClipToRect(context, topGradient); + paintInfo.context->addRoundedRectClip(enclosingIntRect(topGradient), + o->style()->borderTopLeftRadius(), o->style()->borderTopRightRadius(), + IntSize(), IntSize()); + CGContextDrawShading(context, topShading.get()); + paintInfo.context->restore(); + + paintInfo.context->save(); + CGContextClipToRect(context, bottomGradient); + paintInfo.context->addRoundedRectClip(enclosingIntRect(bottomGradient), + IntSize(), IntSize(), + o->style()->borderBottomLeftRadius(), o->style()->borderBottomRightRadius()); + CGContextDrawShading(context, bottomShading.get()); + paintInfo.context->restore(); + + paintInfo.context->save(); + CGContextClipToRect(context, r); + paintInfo.context->addRoundedRectClip(r, + o->style()->borderTopLeftRadius(), o->style()->borderTopRightRadius(), + o->style()->borderBottomLeftRadius(), o->style()->borderBottomRightRadius()); + CGContextDrawShading(context, leftShading.get()); + CGContextDrawShading(context, rightShading.get()); + paintInfo.context->restore(); + + paintInfo.context->restore(); +} + +bool RenderThemeChromiumMac::paintMenuListButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + paintInfo.context->save(); + + IntRect bounds = IntRect(r.x() + o->style()->borderLeftWidth(), + r.y() + o->style()->borderTopWidth(), + r.width() - o->style()->borderLeftWidth() - o->style()->borderRightWidth(), + r.height() - o->style()->borderTopWidth() - o->style()->borderBottomWidth()); + // Draw the gradients to give the styled popup menu a button appearance + paintMenuListButtonGradients(o, paintInfo, bounds); + + // Since we actually know the size of the control here, we restrict the font scale to make sure the arrows will fit vertically in the bounds + float fontScale = min(o->style()->fontSize() / baseFontSize, bounds.height() / (baseArrowHeight * 2 + baseSpaceBetweenArrows)); + float centerY = bounds.y() + bounds.height() / 2.0f; + float arrowHeight = baseArrowHeight * fontScale; + float arrowWidth = baseArrowWidth * fontScale; + float leftEdge = bounds.right() - arrowPaddingRight * o->style()->effectiveZoom() - arrowWidth; + float spaceBetweenArrows = baseSpaceBetweenArrows * fontScale; + + if (bounds.width() < arrowWidth + arrowPaddingLeft * o->style()->effectiveZoom()) + return false; + + paintInfo.context->setFillColor(o->style()->color()); + paintInfo.context->setStrokeStyle(NoStroke); + + FloatPoint arrow1[3]; + arrow1[0] = FloatPoint(leftEdge, centerY - spaceBetweenArrows / 2.0f); + arrow1[1] = FloatPoint(leftEdge + arrowWidth, centerY - spaceBetweenArrows / 2.0f); + arrow1[2] = FloatPoint(leftEdge + arrowWidth / 2.0f, centerY - spaceBetweenArrows / 2.0f - arrowHeight); + + // Draw the top arrow + paintInfo.context->drawConvexPolygon(3, arrow1, true); + + FloatPoint arrow2[3]; + arrow2[0] = FloatPoint(leftEdge, centerY + spaceBetweenArrows / 2.0f); + arrow2[1] = FloatPoint(leftEdge + arrowWidth, centerY + spaceBetweenArrows / 2.0f); + arrow2[2] = FloatPoint(leftEdge + arrowWidth / 2.0f, centerY + spaceBetweenArrows / 2.0f + arrowHeight); + + // Draw the bottom arrow + paintInfo.context->drawConvexPolygon(3, arrow2, true); + + Color leftSeparatorColor(0, 0, 0, 40); + Color rightSeparatorColor(255, 255, 255, 40); + + // FIXME: Should the separator thickness and space be scaled up by fontScale? + int separatorSpace = 2; // Deliberately ignores zoom since it looks nicer if it stays thin. + int leftEdgeOfSeparator = static_cast<int>(leftEdge - arrowPaddingLeft * o->style()->effectiveZoom()); // FIXME: Round? + + // Draw the separator to the left of the arrows + paintInfo.context->setStrokeThickness(1.0f); // Deliberately ignores zoom since it looks nicer if it stays thin. + paintInfo.context->setStrokeStyle(SolidStroke); + paintInfo.context->setStrokeColor(leftSeparatorColor); + paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator, bounds.y()), + IntPoint(leftEdgeOfSeparator, bounds.bottom())); + + paintInfo.context->setStrokeColor(rightSeparatorColor); + paintInfo.context->drawLine(IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.y()), + IntPoint(leftEdgeOfSeparator + separatorSpace, bounds.bottom())); + + paintInfo.context->restore(); + return false; +} + +static const IntSize* menuListButtonSizes() +{ + static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) }; + return sizes; +} + +void RenderThemeChromiumMac::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +{ + NSControlSize controlSize = controlSizeForFont(style); + + style->resetBorder(); + style->resetPadding(); + + // Height is locked to auto. + style->setHeight(Length(Auto)); + + // White-space is locked to pre + style->setWhiteSpace(PRE); + + // Set the foreground color to black or gray when we have the aqua look. + // Cast to RGB32 is to work around a compiler bug. + style->setColor(e->isEnabled() ? static_cast<RGBA32>(Color::black) : Color::darkGray); + + // Set the button's vertical size. + setSizeFromFont(style, menuListButtonSizes()); + + // Our font is locked to the appropriate system font size for the control. To clarify, we first use the CSS-specified font to figure out + // a reasonable control size, but once that control size is determined, we throw that font away and use the appropriate + // system font for the control size instead. + setFontFromControlSize(selector, style, controlSize); + + style->setBoxShadow(0); +} + +int RenderThemeChromiumMac::popupInternalPaddingLeft(RenderStyle* style) const +{ + if (style->appearance() == MenulistPart) + return popupButtonPadding(controlSizeForFont(style))[LeftPadding] * style->effectiveZoom(); + if (style->appearance() == MenulistButtonPart) + return styledPopupPaddingLeft * style->effectiveZoom(); + return 0; +} + +int RenderThemeChromiumMac::popupInternalPaddingRight(RenderStyle* style) const +{ + if (style->appearance() == MenulistPart) + return popupButtonPadding(controlSizeForFont(style))[RightPadding] * style->effectiveZoom(); + if (style->appearance() == MenulistButtonPart) { + float fontScale = style->fontSize() / baseFontSize; + float arrowWidth = baseArrowWidth * fontScale; + return static_cast<int>(ceilf(arrowWidth + (arrowPaddingLeft + arrowPaddingRight + paddingBeforeSeparator) * style->effectiveZoom())); + } + return 0; +} + +int RenderThemeChromiumMac::popupInternalPaddingTop(RenderStyle* style) const +{ + if (style->appearance() == MenulistPart) + return popupButtonPadding(controlSizeForFont(style))[TopPadding] * style->effectiveZoom(); + if (style->appearance() == MenulistButtonPart) + return styledPopupPaddingTop * style->effectiveZoom(); + return 0; +} + +int RenderThemeChromiumMac::popupInternalPaddingBottom(RenderStyle* style) const +{ + if (style->appearance() == MenulistPart) + return popupButtonPadding(controlSizeForFont(style))[BottomPadding] * style->effectiveZoom(); + if (style->appearance() == MenulistButtonPart) + return styledPopupPaddingBottom * style->effectiveZoom(); + return 0; +} + +void RenderThemeChromiumMac::adjustMenuListButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +{ + float fontScale = style->fontSize() / baseFontSize; + + style->resetPadding(); + style->setBorderRadius(IntSize(int(baseBorderRadius + fontScale - 1), int(baseBorderRadius + fontScale - 1))); // FIXME: Round up? + + const int minHeight = 15; + style->setMinHeight(Length(minHeight, Fixed)); + + style->setLineHeight(RenderStyle::initialLineHeight()); +} + +void RenderThemeChromiumMac::setPopupButtonCellState(const RenderObject* o, const IntRect& r) +{ + NSPopUpButtonCell* popupButton = this->popupButton(); + + // Set the control size based off the rectangle we're painting into. + setControlSize(popupButton, popupButtonSizes(), r.size(), o->style()->effectiveZoom()); + + // Update the various states we respond to. + updateCheckedState(popupButton, o); + updateEnabledState(popupButton, o); + updatePressedState(popupButton, o); + updateFocusedState(popupButton, o); +} + +const IntSize* RenderThemeChromiumMac::menuListSizes() const +{ + static const IntSize sizes[3] = { IntSize(9, 0), IntSize(5, 0), IntSize(0, 0) }; + return sizes; +} + +int RenderThemeChromiumMac::minimumMenuListSize(RenderStyle* style) const +{ + return sizeForSystemFont(style, menuListSizes()).width(); +} + +static const int trackWidth = 5; +static const int trackRadius = 2; + +void RenderThemeChromiumMac::adjustSliderTrackStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +{ + style->setBoxShadow(0); +} + +bool RenderThemeChromiumMac::paintSliderTrack(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + IntRect bounds = r; + float zoomLevel = o->style()->effectiveZoom(); + float zoomedTrackWidth = trackWidth * zoomLevel; + + if (o->style()->appearance() == SliderHorizontalPart || o->style()->appearance() == MediaSliderPart) { + bounds.setHeight(zoomedTrackWidth); + bounds.setY(r.y() + r.height() / 2 - zoomedTrackWidth / 2); + } else if (o->style()->appearance() == SliderVerticalPart) { + bounds.setWidth(zoomedTrackWidth); + bounds.setX(r.x() + r.width() / 2 - zoomedTrackWidth / 2); + } + + LocalCurrentGraphicsContext localContext(paintInfo.context); + CGContextRef context = paintInfo.context->platformContext(); + RetainPtr<CGColorSpaceRef> cspace(AdoptCF, CGColorSpaceCreateDeviceRGB()); + + paintInfo.context->save(); + CGContextClipToRect(context, bounds); + + struct CGFunctionCallbacks mainCallbacks = { 0, TrackGradientInterpolate, NULL }; + RetainPtr<CGFunctionRef> mainFunction(AdoptCF, CGFunctionCreate(NULL, 1, NULL, 4, NULL, &mainCallbacks)); + RetainPtr<CGShadingRef> mainShading; + if (o->style()->appearance() == SliderVerticalPart) + mainShading.adoptCF(CGShadingCreateAxial(cspace.get(), CGPointMake(bounds.x(), bounds.bottom()), CGPointMake(bounds.right(), bounds.bottom()), mainFunction.get(), false, false)); + else + mainShading.adoptCF(CGShadingCreateAxial(cspace.get(), CGPointMake(bounds.x(), bounds.y()), CGPointMake(bounds.x(), bounds.bottom()), mainFunction.get(), false, false)); + + IntSize radius(trackRadius, trackRadius); + paintInfo.context->addRoundedRectClip(bounds, + radius, radius, + radius, radius); + CGContextDrawShading(context, mainShading.get()); + paintInfo.context->restore(); + + return false; +} + +void RenderThemeChromiumMac::adjustSliderThumbStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +{ + style->setBoxShadow(0); +} + +static const float verticalSliderHeightPadding = 0.1f; + +bool RenderThemeChromiumMac::paintSliderThumb(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + ASSERT(o->parent()->isSlider()); + + NSSliderCell* sliderThumbCell = o->style()->appearance() == SliderThumbVerticalPart + ? sliderThumbVertical() + : sliderThumbHorizontal(); + + LocalCurrentGraphicsContext localContext(paintInfo.context); + + // Update the various states we respond to. + updateEnabledState(sliderThumbCell, o->parent()); + updateFocusedState(sliderThumbCell, o->parent()); + + // Update the pressed state using the NSCell tracking methods, since that's how NSSliderCell keeps track of it. + bool oldPressed; + if (o->style()->appearance() == SliderThumbVerticalPart) + oldPressed = m_isSliderThumbVerticalPressed; + else + oldPressed = m_isSliderThumbHorizontalPressed; + + bool pressed = static_cast<RenderSlider*>(o->parent())->inDragMode(); + + if (o->style()->appearance() == SliderThumbVerticalPart) + m_isSliderThumbVerticalPressed = pressed; + else + m_isSliderThumbHorizontalPressed = pressed; + + if (pressed != oldPressed) { + if (pressed) + [sliderThumbCell startTrackingAt:NSPoint() inView:nil]; + else + [sliderThumbCell stopTracking:NSPoint() at:NSPoint() inView:nil mouseIsUp:YES]; + } + + FloatRect bounds = r; + // Make the height of the vertical slider slightly larger so NSSliderCell will draw a vertical slider. + if (o->style()->appearance() == SliderThumbVerticalPart) + bounds.setHeight(bounds.height() + verticalSliderHeightPadding * o->style()->effectiveZoom()); + + paintInfo.context->save(); + float zoomLevel = o->style()->effectiveZoom(); + + FloatRect unzoomedRect = bounds; + if (zoomLevel != 1.0f) { + unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel); + unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel); + paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y()); + paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); + paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y()); + } + + [sliderThumbCell drawWithFrame:FloatRectToNSRect(unzoomedRect) inView:nil]; + [sliderThumbCell setControlView:nil]; + + paintInfo.context->restore(); + + return false; +} + +const int sliderThumbWidth = 15; +const int sliderThumbHeight = 15; +const int mediaSliderThumbWidth = 13; +const int mediaSliderThumbHeight = 14; + +void RenderThemeChromiumMac::adjustSliderThumbSize(RenderObject* o) const +{ + float zoomLevel = o->style()->effectiveZoom(); + if (o->style()->appearance() == SliderThumbHorizontalPart || o->style()->appearance() == SliderThumbVerticalPart) { + o->style()->setWidth(Length(static_cast<int>(sliderThumbWidth * zoomLevel), Fixed)); + o->style()->setHeight(Length(static_cast<int>(sliderThumbHeight * zoomLevel), Fixed)); + } else if (o->style()->appearance() == MediaSliderThumbPart) { + o->style()->setWidth(Length(mediaSliderThumbWidth, Fixed)); + o->style()->setHeight(Length(mediaSliderThumbHeight, Fixed)); + } +} + +bool RenderThemeChromiumMac::paintSearchField(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + NSSearchFieldCell* search = this->search(); + LocalCurrentGraphicsContext localContext(paintInfo.context); + + setSearchCellState(o, r); + + paintInfo.context->save(); + + float zoomLevel = o->style()->effectiveZoom(); + + IntRect unzoomedRect = r; + + if (zoomLevel != 1.0f) { + unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel); + unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel); + paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y()); + paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); + paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y()); + } + + // Set the search button to nil before drawing. Then reset it so we can draw it later. + [search setSearchButtonCell:nil]; + + [search drawWithFrame:NSRect(IntRectToNSRect(unzoomedRect)) inView:nil]; +#ifdef BUILDING_ON_TIGER + if ([search showsFirstResponder]) + wkDrawTextFieldCellFocusRing(search, NSRect(unzoomedRect)); +#endif + + [search setControlView:nil]; + [search resetSearchButtonCell]; + + paintInfo.context->restore(); + + return false; +} + +void RenderThemeChromiumMac::setSearchCellState(RenderObject* o, const IntRect& r) +{ + NSSearchFieldCell* search = this->search(); + + [search setControlSize:controlSizeForFont(o->style())]; + + // Update the various states we respond to. + updateEnabledState(search, o); + updateFocusedState(search, o); +} + +const IntSize* RenderThemeChromiumMac::searchFieldSizes() const +{ + static const IntSize sizes[3] = { IntSize(0, 22), IntSize(0, 19), IntSize(0, 17) }; + return sizes; +} + +void RenderThemeChromiumMac::setSearchFieldSize(RenderStyle* style) const +{ + // If the width and height are both specified, then we have nothing to do. + if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto()) + return; + + // Use the font size to determine the intrinsic width of the control. + setSizeFromFont(style, searchFieldSizes()); +} + +void RenderThemeChromiumMac::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +{ + // Override border. + style->resetBorder(); + const short borderWidth = 2 * style->effectiveZoom(); + style->setBorderLeftWidth(borderWidth); + style->setBorderLeftStyle(INSET); + style->setBorderRightWidth(borderWidth); + style->setBorderRightStyle(INSET); + style->setBorderBottomWidth(borderWidth); + style->setBorderBottomStyle(INSET); + style->setBorderTopWidth(borderWidth); + style->setBorderTopStyle(INSET); + + // Override height. + style->setHeight(Length(Auto)); + setSearchFieldSize(style); + + // Override padding size to match AppKit text positioning. + const int padding = 1 * style->effectiveZoom(); + style->setPaddingLeft(Length(padding, Fixed)); + style->setPaddingRight(Length(padding, Fixed)); + style->setPaddingTop(Length(padding, Fixed)); + style->setPaddingBottom(Length(padding, Fixed)); + + NSControlSize controlSize = controlSizeForFont(style); + setFontFromControlSize(selector, style, controlSize); + + style->setBoxShadow(0); +} + +bool RenderThemeChromiumMac::paintSearchFieldCancelButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + Node* input = o->node()->shadowAncestorNode(); + setSearchCellState(input->renderer(), r); + + NSSearchFieldCell* search = this->search(); + + updatePressedState([search cancelButtonCell], o); + + paintInfo.context->save(); + + float zoomLevel = o->style()->effectiveZoom(); + + NSRect bounds = [search cancelButtonRectForBounds:NSRect(IntRectToNSRect(input->renderer()->absoluteBoundingBoxRect()))]; + + IntRect unzoomedRect(NSRectToIntRect(bounds)); + if (zoomLevel != 1.0f) { + unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel); + unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel); + paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y()); + paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); + paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y()); + } + + [[search cancelButtonCell] drawWithFrame:IntRectToNSRect(unzoomedRect) inView:nil]; + [[search cancelButtonCell] setControlView:nil]; + + paintInfo.context->restore(); + return false; +} + +const IntSize* RenderThemeChromiumMac::cancelButtonSizes() const +{ + static const IntSize sizes[3] = { IntSize(16, 13), IntSize(13, 11), IntSize(13, 9) }; + return sizes; +} + +void RenderThemeChromiumMac::adjustSearchFieldCancelButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +{ + IntSize size = sizeForSystemFont(style, cancelButtonSizes()); + style->setWidth(Length(size.width(), Fixed)); + style->setHeight(Length(size.height(), Fixed)); + style->setBoxShadow(0); +} + +const IntSize* RenderThemeChromiumMac::resultsButtonSizes() const +{ + static const IntSize sizes[3] = { IntSize(19, 13), IntSize(17, 11), IntSize(17, 9) }; + return sizes; +} + +static const int emptyResultsOffset = 9; +void RenderThemeChromiumMac::adjustSearchFieldDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +{ + IntSize size = sizeForSystemFont(style, resultsButtonSizes()); + style->setWidth(Length(size.width() - emptyResultsOffset, Fixed)); + style->setHeight(Length(size.height(), Fixed)); + style->setBoxShadow(0); +} + +bool RenderThemeChromiumMac::paintSearchFieldDecoration(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + return false; +} + +void RenderThemeChromiumMac::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +{ + IntSize size = sizeForSystemFont(style, resultsButtonSizes()); + style->setWidth(Length(size.width(), Fixed)); + style->setHeight(Length(size.height(), Fixed)); + style->setBoxShadow(0); +} + +bool RenderThemeChromiumMac::paintSearchFieldResultsDecoration(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + Node* input = o->node()->shadowAncestorNode(); + setSearchCellState(input->renderer(), r); + + NSSearchFieldCell* search = this->search(); + + if ([search searchMenuTemplate] != nil) + [search setSearchMenuTemplate:nil]; + + NSRect bounds = [search searchButtonRectForBounds:NSRect(IntRectToNSRect(input->renderer()->absoluteBoundingBoxRect()))]; + [[search searchButtonCell] drawWithFrame:bounds inView:nil]; + [[search searchButtonCell] setControlView:nil]; + return false; +} + +static const int resultsArrowWidth = 5; +void RenderThemeChromiumMac::adjustSearchFieldResultsButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +{ + IntSize size = sizeForSystemFont(style, resultsButtonSizes()); + style->setWidth(Length(size.width() + resultsArrowWidth, Fixed)); + style->setHeight(Length(size.height(), Fixed)); + style->setBoxShadow(0); +} + +bool RenderThemeChromiumMac::paintSearchFieldResultsButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + Node* input = o->node()->shadowAncestorNode(); + setSearchCellState(input->renderer(), r); + + NSSearchFieldCell* search = this->search(); + + if (![search searchMenuTemplate]) + [search setSearchMenuTemplate:searchMenuTemplate()]; + + paintInfo.context->save(); + + float zoomLevel = o->style()->effectiveZoom(); + + NSRect bounds = [search searchButtonRectForBounds:NSRect(IntRectToNSRect(input->renderer()->absoluteBoundingBoxRect()))]; + + IntRect unzoomedRect(NSRectToIntRect(bounds)); + if (zoomLevel != 1.0f) { + unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel); + unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel); + paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y()); + paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel)); + paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y()); + } + + [[search searchButtonCell] drawWithFrame:IntRectToNSRect(unzoomedRect) inView:nil]; + [[search searchButtonCell] setControlView:nil]; + + paintInfo.context->restore(); + + return false; +} + +bool RenderThemeChromiumMac::paintMediaFullscreenButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ +#if ENABLE(VIDEO) + Node* node = o->element(); + if (!node) + return false; + + LocalCurrentGraphicsContext localContext(paintInfo.context); + wkDrawMediaUIPart(MediaFullscreenButton, paintInfo.context->platformContext(), r, node->active()); +#endif + return false; +} + +bool RenderThemeChromiumMac::paintMediaMuteButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ +#if ENABLE(VIDEO) + Node* node = o->element(); + Node* mediaNode = node ? node->shadowAncestorNode() : 0; + if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag))) + return false; + + HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(mediaNode); + if (!mediaElement) + return false; + + LocalCurrentGraphicsContext localContext(paintInfo.context); + wkDrawMediaUIPart(mediaElement->muted() ? MediaUnMuteButton : MediaMuteButton, paintInfo.context->platformContext(), r, node->active()); +#endif + return false; +} + +bool RenderThemeChromiumMac::paintMediaPlayButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ +#if ENABLE(VIDEO) + Node* node = o->element(); + Node* mediaNode = node ? node->shadowAncestorNode() : 0; + if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag))) + return false; + + HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(mediaNode); + if (!mediaElement) + return false; + + LocalCurrentGraphicsContext localContext(paintInfo.context); + wkDrawMediaUIPart(mediaElement->canPlay() ? MediaPlayButton : MediaPauseButton, paintInfo.context->platformContext(), r, node->active()); +#endif + return false; +} + +bool RenderThemeChromiumMac::paintMediaSeekBackButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ +#if ENABLE(VIDEO) + Node* node = o->element(); + if (!node) + return false; + + LocalCurrentGraphicsContext localContext(paintInfo.context); + wkDrawMediaUIPart(MediaSeekBackButton, paintInfo.context->platformContext(), r, node->active()); +#endif + return false; +} + +bool RenderThemeChromiumMac::paintMediaSeekForwardButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ +#if ENABLE(VIDEO) + Node* node = o->element(); + if (!node) + return false; + + LocalCurrentGraphicsContext localContext(paintInfo.context); + wkDrawMediaUIPart(MediaSeekForwardButton, paintInfo.context->platformContext(), r, node->active()); +#endif + return false; +} + +bool RenderThemeChromiumMac::paintMediaSliderTrack(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ +#if ENABLE(VIDEO) + Node* node = o->element(); + Node* mediaNode = node ? node->shadowAncestorNode() : 0; + if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag))) + return false; + + HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(mediaNode); + if (!mediaElement) + return false; + + float timeLoaded = 0; + float currentTime = 0; + float duration = 0; + if (MediaPlayer* player = mediaElement->player()) { + duration = player->duration(); + timeLoaded = player->maxTimeBuffered(); + currentTime = player->currentTime(); + } + + wkDrawMediaSliderTrack(paintInfo.context->platformContext(), r, timeLoaded, currentTime, duration); +#endif + return false; +} + +bool RenderThemeChromiumMac::paintMediaSliderThumb(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ +#if ENABLE(VIDEO) + Node* node = o->element(); + if (!node) + return false; + + LocalCurrentGraphicsContext localContext(paintInfo.context); + wkDrawMediaUIPart(MediaSliderThumb, paintInfo.context->platformContext(), r, node->active()); +#endif + return false; +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +NSButtonCell* RenderThemeChromiumMac::checkbox() const +{ + if (!m_checkbox) { + m_checkbox.adoptNS([[NSButtonCell alloc] init]); + [m_checkbox.get() setButtonType:NSSwitchButton]; + [m_checkbox.get() setTitle:nil]; + [m_checkbox.get() setAllowsMixedState:YES]; + [m_checkbox.get() setFocusRingType:NSFocusRingTypeExterior]; + } + + return m_checkbox.get(); +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +NSButtonCell* RenderThemeChromiumMac::radio() const +{ + if (!m_radio) { + m_radio.adoptNS([[NSButtonCell alloc] init]); + [m_radio.get() setButtonType:NSRadioButton]; + [m_radio.get() setTitle:nil]; + [m_radio.get() setFocusRingType:NSFocusRingTypeExterior]; + } + + return m_radio.get(); +} + +// FIXME: This used to be in the upstream version until it was converted to the new theme API in r37731. +NSButtonCell* RenderThemeChromiumMac::button() const +{ + if (!m_button) { + m_button.adoptNS([[NSButtonCell alloc] init]); + [m_button.get() setTitle:nil]; + [m_button.get() setButtonType:NSMomentaryPushInButton]; + } + + return m_button.get(); +} + +NSPopUpButtonCell* RenderThemeChromiumMac::popupButton() const +{ + if (!m_popupButton) { + m_popupButton.adoptNS([[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:NO]); + [m_popupButton.get() setUsesItemFromMenu:NO]; + [m_popupButton.get() setFocusRingType:NSFocusRingTypeExterior]; + } + + return m_popupButton.get(); +} + +NSSearchFieldCell* RenderThemeChromiumMac::search() const +{ + if (!m_search) { + m_search.adoptNS([[NSSearchFieldCell alloc] initTextCell:@""]); + [m_search.get() setBezelStyle:NSTextFieldRoundedBezel]; + [m_search.get() setBezeled:YES]; + [m_search.get() setEditable:YES]; + [m_search.get() setFocusRingType:NSFocusRingTypeExterior]; + } + + return m_search.get(); +} + +NSMenu* RenderThemeChromiumMac::searchMenuTemplate() const +{ + if (!m_searchMenuTemplate) + m_searchMenuTemplate.adoptNS([[NSMenu alloc] initWithTitle:@""]); + + return m_searchMenuTemplate.get(); +} + +NSSliderCell* RenderThemeChromiumMac::sliderThumbHorizontal() const +{ + if (!m_sliderThumbHorizontal) { + m_sliderThumbHorizontal.adoptNS([[NSSliderCell alloc] init]); + [m_sliderThumbHorizontal.get() setTitle:nil]; + [m_sliderThumbHorizontal.get() setSliderType:NSLinearSlider]; + [m_sliderThumbHorizontal.get() setControlSize:NSSmallControlSize]; + [m_sliderThumbHorizontal.get() setFocusRingType:NSFocusRingTypeExterior]; + } + + return m_sliderThumbHorizontal.get(); +} + +NSSliderCell* RenderThemeChromiumMac::sliderThumbVertical() const +{ + if (!m_sliderThumbVertical) { + m_sliderThumbVertical.adoptNS([[NSSliderCell alloc] init]); + [m_sliderThumbVertical.get() setTitle:nil]; + [m_sliderThumbVertical.get() setSliderType:NSLinearSlider]; + [m_sliderThumbVertical.get() setControlSize:NSSmallControlSize]; + [m_sliderThumbVertical.get() setFocusRingType:NSFocusRingTypeExterior]; + } + + return m_sliderThumbVertical.get(); +} + +} // namespace WebCore diff --git a/WebCore/rendering/RenderThemeChromiumWin.cpp b/WebCore/rendering/RenderThemeChromiumWin.cpp new file mode 100644 index 0000000..c304385 --- /dev/null +++ b/WebCore/rendering/RenderThemeChromiumWin.cpp @@ -0,0 +1,614 @@ +/* + * This file is part of the WebKit project. + * + * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2008, 2009 Google, Inc. + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#include "config.h" +#include "RenderThemeChromiumWin.h" + +#include <windows.h> +#include <uxtheme.h> +#include <vssym32.h> + +#include "ChromiumBridge.h" +#include "CSSStyleSheet.h" +#include "CSSValueKeywords.h" +#include "Document.h" +#include "FontSelector.h" +#include "FontUtilsChromiumWin.h" +#include "GraphicsContext.h" +#include "ScrollbarTheme.h" +#include "SkiaUtils.h" +#include "ThemeHelperChromiumWin.h" +#include "UserAgentStyleSheets.h" +#include "WindowsVersion.h" + +// FIXME: This dependency should eventually be removed. +#include <skia/ext/skia_utils_win.h> + +#define SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(structName, member) \ + offsetof(structName, member) + \ + (sizeof static_cast<structName*>(0)->member) +#define NONCLIENTMETRICS_SIZE_PRE_VISTA \ + SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(NONCLIENTMETRICS, lfMessageFont) + +namespace WebCore { + +static void getNonClientMetrics(NONCLIENTMETRICS* metrics) { + static UINT size = WebCore::isVistaOrNewer() ? + sizeof(NONCLIENTMETRICS) : NONCLIENTMETRICS_SIZE_PRE_VISTA; + metrics->cbSize = size; + bool success = !!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, size, metrics, 0); + ASSERT(success); +} + +enum PaddingType { + TopPadding, + RightPadding, + BottomPadding, + LeftPadding +}; + +static const int styledMenuListInternalPadding[4] = { 1, 4, 1, 4 }; + +// The default variable-width font size. We use this as the default font +// size for the "system font", and as a base size (which we then shrink) for +// form control fonts. +static float defaultFontSize = 16.0; + +static FontDescription smallSystemFont; +static FontDescription menuFont; +static FontDescription labelFont; + +bool RenderThemeChromiumWin::m_findInPageMode = false; + +// Internal static helper functions. We don't put them in an anonymous +// namespace so they have easier access to the WebCore namespace. + +static bool supportsFocus(ControlPart appearance) +{ + switch (appearance) { + case PushButtonPart: + case ButtonPart: + case DefaultButtonPart: + case TextFieldPart: + case TextAreaPart: + return true; + } + return false; +} + +static void setFixedPadding(RenderStyle* style, const int padding[4]) +{ + style->setPaddingLeft(Length(padding[LeftPadding], Fixed)); + style->setPaddingRight(Length(padding[RightPadding], Fixed)); + style->setPaddingTop(Length(padding[TopPadding], Fixed)); + style->setPaddingBottom(Length(padding[BottomPadding], Fixed)); +} + +// Return the height of system font |font| in pixels. We use this size by +// default for some non-form-control elements. +static float systemFontSize(const LOGFONT& font) +{ + float size = -font.lfHeight; + if (size < 0) { + HFONT hFont = CreateFontIndirect(&font); + if (hFont) { + HDC hdc = GetDC(0); // What about printing? Is this the right DC? + if (hdc) { + HGDIOBJ hObject = SelectObject(hdc, hFont); + TEXTMETRIC tm; + GetTextMetrics(hdc, &tm); + SelectObject(hdc, hObject); + ReleaseDC(0, hdc); + size = tm.tmAscent; + } + DeleteObject(hFont); + } + } + + // The "codepage 936" bit here is from Gecko; apparently this helps make + // fonts more legible in Simplified Chinese where the default font size is + // too small. + // + // FIXME: http://b/1119883 Since this is only used for "small caption", + // "menu", and "status bar" objects, I'm not sure how much this even + // matters. Plus the Gecko patch went in back in 2002, and maybe this + // isn't even relevant anymore. We should investigate whether this should + // be removed, or perhaps broadened to be "any CJK locale". + // + return ((size < 12.0f) && (GetACP() == 936)) ? 12.0f : size; +} + +// We aim to match IE here. +// -IE uses a font based on the encoding as the default font for form controls. +// -Gecko uses MS Shell Dlg (actually calls GetStockObject(DEFAULT_GUI_FONT), +// which returns MS Shell Dlg) +// -Safari uses Lucida Grande. +// +// FIXME: The only case where we know we don't match IE is for ANSI encodings. +// IE uses MS Shell Dlg there, which we render incorrectly at certain pixel +// sizes (e.g. 15px). So, for now we just use Arial. +static wchar_t* defaultGUIFont(Document* document) +{ + UScriptCode dominantScript = document->dominantScript(); + const wchar_t* family = NULL; + + // FIXME: Special-casing of Latin/Greeek/Cyrillic should go away once + // GetFontFamilyForScript is enhanced to support GenericFamilyType for + // real. For now, we make sure that we use Arial to match IE for those + // scripts. + if (dominantScript != USCRIPT_LATIN && + dominantScript != USCRIPT_CYRILLIC && + dominantScript != USCRIPT_GREEK && + dominantScript != USCRIPT_INVALID_CODE) { + family = getFontFamilyForScript(dominantScript, FontDescription::NoFamily); + if (family) + return const_cast<wchar_t*>(family); + } + return L"Arial"; +} + +// Converts |points| to pixels. One point is 1/72 of an inch. +static float pointsToPixels(float points) +{ + static float pixelsPerInch = 0.0f; + if (!pixelsPerInch) { + HDC hdc = GetDC(0); // What about printing? Is this the right DC? + if (hdc) { // Can this ever actually be NULL? + pixelsPerInch = GetDeviceCaps(hdc, LOGPIXELSY); + ReleaseDC(0, hdc); + } else { + pixelsPerInch = 96.0f; + } + } + + static const float pointsPerInch = 72.0f; + return points / pointsPerInch * pixelsPerInch; +} + +static void setSizeIfAuto(RenderStyle* style, const IntSize& size) +{ + if (style->width().isIntrinsicOrAuto()) + style->setWidth(Length(size.width(), Fixed)); + if (style->height().isAuto()) + style->setHeight(Length(size.height(), Fixed)); +} + +static double querySystemBlinkInterval(double defaultInterval) +{ + UINT blinkTime = GetCaretBlinkTime(); + if (blinkTime == 0) + return defaultInterval; + if (blinkTime == INFINITE) + return 0; + return blinkTime / 1000.0; +} + +// Implement WebCore::theme() for getting the global RenderTheme. +RenderTheme* theme() +{ + static RenderThemeChromiumWin winTheme; + return &winTheme; +} + +String RenderThemeChromiumWin::extraDefaultStyleSheet() +{ + return String(themeWinUserAgentStyleSheet, sizeof(themeWinUserAgentStyleSheet)); +} + +String RenderThemeChromiumWin::extraQuirksStyleSheet() +{ + return String(themeWinQuirksUserAgentStyleSheet, sizeof(themeWinQuirksUserAgentStyleSheet)); +} + +bool RenderThemeChromiumWin::supportsFocusRing(const RenderStyle* style) const +{ + // Let webkit draw one of its halo rings around any focused element, + // except push buttons. For buttons we use the windows PBS_DEFAULTED + // styling to give it a blue border. + return style->appearance() == ButtonPart + || style->appearance() == PushButtonPart; +} + +Color RenderThemeChromiumWin::platformActiveSelectionBackgroundColor() const +{ + if (ChromiumBridge::layoutTestMode()) + return Color("#0000FF"); // Royal blue. + if (m_findInPageMode) + return Color(255, 150, 50, 200); // Orange. + COLORREF color = GetSysColor(COLOR_HIGHLIGHT); + return Color(GetRValue(color), GetGValue(color), GetBValue(color), 255); +} + +Color RenderThemeChromiumWin::platformInactiveSelectionBackgroundColor() const +{ + if (ChromiumBridge::layoutTestMode()) + return Color("#999999"); // Medium gray. + if (m_findInPageMode) + return Color(255, 150, 50, 200); // Orange. + COLORREF color = GetSysColor(COLOR_GRAYTEXT); + return Color(GetRValue(color), GetGValue(color), GetBValue(color), 255); +} + +Color RenderThemeChromiumWin::platformActiveSelectionForegroundColor() const +{ + if (ChromiumBridge::layoutTestMode()) + return Color("#FFFFCC"); // Pale yellow. + COLORREF color = GetSysColor(COLOR_HIGHLIGHTTEXT); + return Color(GetRValue(color), GetGValue(color), GetBValue(color), 255); +} + +Color RenderThemeChromiumWin::platformInactiveSelectionForegroundColor() const +{ + return Color::white; +} + +Color RenderThemeChromiumWin::platformTextSearchHighlightColor() const +{ + return Color(255, 255, 150); +} + +double RenderThemeChromiumWin::caretBlinkInterval() const +{ + // Disable the blinking caret in layout test mode, as it introduces + // a race condition for the pixel tests. http://b/1198440 + if (ChromiumBridge::layoutTestMode()) + return 0; + + // This involves a system call, so we cache the result. + static double blinkInterval = querySystemBlinkInterval(RenderTheme::caretBlinkInterval()); + return blinkInterval; +} + +void RenderThemeChromiumWin::systemFont(int propId, Document* document, FontDescription& fontDescription) const +{ + // This logic owes much to RenderThemeSafari.cpp. + FontDescription* cachedDesc = NULL; + wchar_t* faceName = 0; + float fontSize = 0; + switch (propId) { + case CSSValueSmallCaption: + cachedDesc = &smallSystemFont; + if (!smallSystemFont.isAbsoluteSize()) { + NONCLIENTMETRICS metrics; + getNonClientMetrics(&metrics); + faceName = metrics.lfSmCaptionFont.lfFaceName; + fontSize = systemFontSize(metrics.lfSmCaptionFont); + } + break; + case CSSValueMenu: + cachedDesc = &menuFont; + if (!menuFont.isAbsoluteSize()) { + NONCLIENTMETRICS metrics; + getNonClientMetrics(&metrics); + faceName = metrics.lfMenuFont.lfFaceName; + fontSize = systemFontSize(metrics.lfMenuFont); + } + break; + case CSSValueStatusBar: + cachedDesc = &labelFont; + if (!labelFont.isAbsoluteSize()) { + NONCLIENTMETRICS metrics; + getNonClientMetrics(&metrics); + faceName = metrics.lfStatusFont.lfFaceName; + fontSize = systemFontSize(metrics.lfStatusFont); + } + break; + case CSSValueWebkitMiniControl: + case CSSValueWebkitSmallControl: + case CSSValueWebkitControl: + faceName = defaultGUIFont(document); + // Why 2 points smaller? Because that's what Gecko does. + fontSize = defaultFontSize - pointsToPixels(2); + break; + default: + faceName = defaultGUIFont(document); + fontSize = defaultFontSize; + break; + } + + if (!cachedDesc) + cachedDesc = &fontDescription; + + if (fontSize) { + ASSERT(faceName); + cachedDesc->firstFamily().setFamily(AtomicString(faceName, + wcslen(faceName))); + cachedDesc->setIsAbsoluteSize(true); + cachedDesc->setGenericFamily(FontDescription::NoFamily); + cachedDesc->setSpecifiedSize(fontSize); + cachedDesc->setWeight(FontWeightNormal); + cachedDesc->setItalic(false); + } + fontDescription = *cachedDesc; +} + +int RenderThemeChromiumWin::minimumMenuListSize(RenderStyle* style) const +{ + return 0; +} + +void RenderThemeChromiumWin::setCheckboxSize(RenderStyle* style) const +{ + // If the width and height are both specified, then we have nothing to do. + if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto()) + return; + + // FIXME: A hard-coded size of 13 is used. This is wrong but necessary + // for now. It matches Firefox. At different DPI settings on Windows, + // querying the theme gives you a larger size that accounts for the higher + // DPI. Until our entire engine honors a DPI setting other than 96, we + // can't rely on the theme's metrics. + const IntSize size(13, 13); + setSizeIfAuto(style, size); +} + +void RenderThemeChromiumWin::setRadioSize(RenderStyle* style) const +{ + // Use same sizing for radio box as checkbox. + setCheckboxSize(style); +} + +bool RenderThemeChromiumWin::paintButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) +{ + const ThemeData& themeData = getThemeData(o); + + WebCore::ThemeHelperWin helper(i.context, r); + ChromiumBridge::paintButton(helper.context(), + themeData.m_part, + themeData.m_state, + themeData.m_classicState, + helper.rect()); + return false; +} + +bool RenderThemeChromiumWin::paintTextField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) +{ + return paintTextFieldInternal(o, i, r, true); +} + +bool RenderThemeChromiumWin::paintSearchField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) +{ + return paintTextField(o, i, r); +} + +void RenderThemeChromiumWin::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +{ + // Height is locked to auto on all browsers. + style->setLineHeight(RenderStyle::initialLineHeight()); +} + +// Used to paint unstyled menulists (i.e. with the default border) +bool RenderThemeChromiumWin::paintMenuList(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) +{ + int borderRight = o->borderRight(); + int borderLeft = o->borderLeft(); + int borderTop = o->borderTop(); + int borderBottom = o->borderBottom(); + + // If all the borders are 0, then tell skia not to paint the border on the + // textfield. FIXME: http://b/1210017 Figure out how to get Windows to not + // draw individual borders and then pass that to skia so we can avoid + // drawing any borders that are set to 0. For non-zero borders, we draw the + // border, but webkit just draws over it. + bool drawEdges = !(borderRight == 0 && borderLeft == 0 && borderTop == 0 && borderBottom == 0); + + paintTextFieldInternal(o, i, r, drawEdges); + + // Take padding and border into account. If the MenuList is smaller than + // the size of a button, make sure to shrink it appropriately and not put + // its x position to the left of the menulist. + const int buttonWidth = GetSystemMetrics(SM_CXVSCROLL); + int spacingLeft = borderLeft + o->paddingLeft(); + int spacingRight = borderRight + o->paddingRight(); + int spacingTop = borderTop + o->paddingTop(); + int spacingBottom = borderBottom + o->paddingBottom(); + + int buttonX; + if (r.right() - r.x() < buttonWidth) + buttonX = r.x(); + else + buttonX = o->style()->direction() == LTR ? r.right() - spacingRight - buttonWidth : r.x() + spacingLeft; + + // Compute the rectangle of the button in the destination image. + IntRect rect(buttonX, + r.y() + spacingTop, + std::min(buttonWidth, r.right() - r.x()), + r.height() - (spacingTop + spacingBottom)); + + // Get the correct theme data for a textfield and paint the menu. + WebCore::ThemeHelperWin helper(i.context, rect); + ChromiumBridge::paintMenuList(helper.context(), + CP_DROPDOWNBUTTON, + determineState(o), + determineClassicState(o), + helper.rect()); + return false; +} + +void RenderThemeChromiumWin::adjustMenuListButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +{ + adjustMenuListStyle(selector, style, e); +} + +// Used to paint styled menulists (i.e. with a non-default border) +bool RenderThemeChromiumWin::paintMenuListButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) +{ + return paintMenuList(o, i, r); +} + +int RenderThemeChromiumWin::popupInternalPaddingLeft(RenderStyle* style) const +{ + return menuListInternalPadding(style, LeftPadding); +} + +int RenderThemeChromiumWin::popupInternalPaddingRight(RenderStyle* style) const +{ + return menuListInternalPadding(style, RightPadding); +} + +int RenderThemeChromiumWin::popupInternalPaddingTop(RenderStyle* style) const +{ + return menuListInternalPadding(style, TopPadding); +} + +int RenderThemeChromiumWin::popupInternalPaddingBottom(RenderStyle* style) const +{ + return menuListInternalPadding(style, BottomPadding); +} + +void RenderThemeChromiumWin::adjustButtonInnerStyle(RenderStyle* style) const +{ + // This inner padding matches Firefox. + style->setPaddingTop(Length(1, Fixed)); + style->setPaddingRight(Length(3, Fixed)); + style->setPaddingBottom(Length(1, Fixed)); + style->setPaddingLeft(Length(3, Fixed)); +} + +// static +void RenderThemeChromiumWin::setDefaultFontSize(int fontSize) { + defaultFontSize = static_cast<float>(fontSize); + + // Reset cached fonts. + smallSystemFont = menuFont = labelFont = FontDescription(); +} + +unsigned RenderThemeChromiumWin::determineState(RenderObject* o) +{ + unsigned result = TS_NORMAL; + ControlPart appearance = o->style()->appearance(); + if (!isEnabled(o)) + result = TS_DISABLED; + else if (isReadOnlyControl(o) && (TextFieldPart == appearance || TextAreaPart == appearance)) + result = ETS_READONLY; // Readonly is supported on textfields. + else if (isPressed(o)) // Active overrides hover and focused. + result = TS_PRESSED; + else if (supportsFocus(appearance) && isFocused(o)) + result = ETS_FOCUSED; + else if (isHovered(o)) + result = TS_HOT; + if (isChecked(o)) + result += 4; // 4 unchecked states, 4 checked states. + return result; +} + +unsigned RenderThemeChromiumWin::determineClassicState(RenderObject* o) +{ + unsigned result = 0; + if (!isEnabled(o)) + result = DFCS_INACTIVE; + else if (isPressed(o)) // Active supersedes hover + result = DFCS_PUSHED; + else if (isHovered(o)) + result = DFCS_HOT; + if (isChecked(o)) + result |= DFCS_CHECKED; + return result; +} + +ThemeData RenderThemeChromiumWin::getThemeData(RenderObject* o) +{ + ThemeData result; + switch (o->style()->appearance()) { + case PushButtonPart: + case ButtonPart: + result.m_part = BP_PUSHBUTTON; + result.m_classicState = DFCS_BUTTONPUSH; + break; + case CheckboxPart: + result.m_part = BP_CHECKBOX; + result.m_classicState = DFCS_BUTTONCHECK; + break; + case RadioPart: + result.m_part = BP_RADIOBUTTON; + result.m_classicState = DFCS_BUTTONRADIO; + break; + case ListboxPart: + case MenulistPart: + case TextFieldPart: + case TextAreaPart: + result.m_part = ETS_NORMAL; + break; + } + + result.m_state = determineState(o); + result.m_classicState |= determineClassicState(o); + + return result; +} + +bool RenderThemeChromiumWin::paintTextFieldInternal(RenderObject* o, + const RenderObject::PaintInfo& i, + const IntRect& r, + bool drawEdges) +{ + // Nasty hack to make us not paint the border on text fields with a + // border-radius. Webkit paints elements with border-radius for us. + // FIXME: Get rid of this if-check once we can properly clip rounded + // borders: http://b/1112604 and http://b/1108635 + // FIXME: make sure we do the right thing if css background-clip is set. + if (o->style()->hasBorderRadius()) + return false; + + const ThemeData& themeData = getThemeData(o); + + WebCore::ThemeHelperWin helper(i.context, r); + ChromiumBridge::paintTextField(helper.context(), + themeData.m_part, + themeData.m_state, + themeData.m_classicState, + helper.rect(), + o->style()->backgroundColor(), + true, + drawEdges); + return false; +} + +int RenderThemeChromiumWin::menuListInternalPadding(RenderStyle* style, int paddingType) const +{ + // This internal padding is in addition to the user-supplied padding. + // Matches the FF behavior. + int padding = styledMenuListInternalPadding[paddingType]; + + // Reserve the space for right arrow here. The rest of the padding is set + // by adjustMenuListStyle, since PopupMenuChromium.cpp uses the padding + // from RenderMenuList to lay out the individual items in the popup. If + // the MenuList actually has appearance "NoAppearance", then that means we + // don't draw a button, so don't reserve space for it. + const int barType = style->direction() == LTR ? RightPadding : LeftPadding; + if (paddingType == barType && style->appearance() != NoControlPart) + padding += ScrollbarTheme::nativeTheme()->scrollbarThickness(); + + return padding; +} + +// static +void RenderThemeChromiumWin::setFindInPageMode(bool enable) { + if (m_findInPageMode == enable) + return; + + m_findInPageMode = enable; + theme()->platformColorsDidChange(); +} + +} // namespace WebCore diff --git a/WebCore/rendering/RenderThemeChromiumWin.h b/WebCore/rendering/RenderThemeChromiumWin.h new file mode 100644 index 0000000..2d335c2 --- /dev/null +++ b/WebCore/rendering/RenderThemeChromiumWin.h @@ -0,0 +1,136 @@ +/* + * This file is part of the WebKit project. + * + * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2008, 2009 Google, Inc. + * + * 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 RenderThemeChromiumWin_h +#define RenderThemeChromiumWin_h + +#include "RenderTheme.h" + +#if WIN32 +typedef void* HANDLE; +typedef struct HINSTANCE__* HINSTANCE; +typedef HINSTANCE HMODULE; +#endif + +namespace WebCore { + + struct ThemeData { + ThemeData() : m_part(0), m_state(0), m_classicState(0) {} + + unsigned m_part; + unsigned m_state; + unsigned m_classicState; + }; + + class RenderThemeChromiumWin : public RenderTheme { + public: + RenderThemeChromiumWin() { } + ~RenderThemeChromiumWin() { } + + virtual String extraDefaultStyleSheet(); + virtual String extraQuirksStyleSheet(); + + // A method asking if the theme's controls actually care about redrawing when hovered. + virtual bool supportsHover(const RenderStyle*) const { return true; } + + // A method asking if the theme is able to draw the focus ring. + virtual bool supportsFocusRing(const RenderStyle*) const; + + // The platform selection color. + virtual Color platformActiveSelectionBackgroundColor() const; + virtual Color platformInactiveSelectionBackgroundColor() const; + virtual Color platformActiveSelectionForegroundColor() const; + virtual Color platformInactiveSelectionForegroundColor() const; + virtual Color platformTextSearchHighlightColor() const; + + virtual double caretBlinkInterval() const; + + // System fonts. + virtual void systemFont(int propId, Document*, FontDescription&) const; + + virtual int minimumMenuListSize(RenderStyle*) const; + + virtual bool paintCheckbox(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) { return paintButton(o, i, r); } + virtual void setCheckboxSize(RenderStyle*) const; + + virtual bool paintRadio(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) { return paintButton(o, i, r); } + virtual void setRadioSize(RenderStyle*) const; + + virtual bool paintButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + virtual bool paintTextField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + virtual bool paintTextArea(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) { return paintTextField(o, i, r); } + + virtual bool paintSearchField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + // MenuList refers to an unstyled menulist (meaning a menulist without + // background-color or border set) and MenuListButton refers to a styled + // menulist (a menulist with background-color or border set). They have + // this distinction to support showing aqua style themes whenever they + // possibly can, which is something we don't want to replicate. + // + // In short, we either go down the MenuList code path or the MenuListButton + // codepath. We never go down both. And in both cases, they render the + // entire menulist. + virtual void adjustMenuListStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual bool paintMenuList(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual void adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual bool paintMenuListButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + // These methods define the padding for the MenuList's inner block. + virtual int popupInternalPaddingLeft(RenderStyle*) const; + virtual int popupInternalPaddingRight(RenderStyle*) const; + virtual int popupInternalPaddingTop(RenderStyle*) const; + virtual int popupInternalPaddingBottom(RenderStyle*) const; + + virtual void adjustButtonInnerStyle(RenderStyle*) const; + + // Provide a way to pass the default font size from the Settings object + // to the render theme. FIXME: http://b/1129186 A cleaner way would be + // to remove the default font size from this object and have callers + // that need the value to get it directly from the appropriate Settings + // object. + static void setDefaultFontSize(int); + + // Enables/Disables FindInPage mode, which (if enabled) overrides the + // selection rect color to be orange. + static void setFindInPageMode(bool); + + private: + unsigned determineState(RenderObject*); + unsigned determineClassicState(RenderObject*); + + ThemeData getThemeData(RenderObject*); + + bool paintTextFieldInternal(RenderObject*, const RenderObject::PaintInfo&, const IntRect&, bool); + + int menuListInternalPadding(RenderStyle*, int paddingType) const; + + // A flag specifying whether we are in Find-in-page mode or not. + static bool m_findInPageMode; + }; + +} // namespace WebCore + +#endif diff --git a/WebCore/rendering/RenderThemeMac.h b/WebCore/rendering/RenderThemeMac.h index 1a49898..0d31603 100644 --- a/WebCore/rendering/RenderThemeMac.h +++ b/WebCore/rendering/RenderThemeMac.h @@ -55,8 +55,11 @@ public: virtual Color platformActiveSelectionBackgroundColor() const; virtual Color platformInactiveSelectionBackgroundColor() const; - virtual Color activeListBoxSelectionBackgroundColor() const; - + virtual Color platformActiveListBoxSelectionBackgroundColor() const; + virtual Color platformActiveListBoxSelectionForegroundColor() const; + virtual Color platformInactiveListBoxSelectionBackgroundColor() const; + virtual Color platformInactiveListBoxSelectionForegroundColor() const; + virtual void platformColorsDidChange(); // System fonts. @@ -76,6 +79,8 @@ public: virtual Color systemColor(int cssValueId) const; protected: + virtual bool supportsSelectionForegroundColors() const { return false; } + virtual bool paintTextField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); virtual void adjustTextFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const; @@ -109,6 +114,7 @@ protected: virtual void adjustSearchFieldResultsButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; virtual bool paintSearchFieldResultsButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); +#if ENABLE(VIDEO) virtual bool paintMediaFullscreenButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); virtual bool paintMediaPlayButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); virtual bool paintMediaMuteButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); @@ -116,10 +122,20 @@ protected: virtual bool paintMediaSeekForwardButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); virtual bool paintMediaSliderTrack(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); virtual bool paintMediaSliderThumb(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual bool paintMediaTimelineContainer(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual bool paintMediaCurrentTime(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual bool paintMediaTimeRemaining(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + // Media controls + virtual bool hitTestMediaControlPart(RenderObject*, const IntPoint& absPoint); + virtual String extraMediaControlsStyleSheet(); +#endif private: IntRect inflateRect(const IntRect&, const IntSize&, const int* margins, float zoomLevel = 1.0f) const; + FloatRect convertToPaintingRect(const RenderObject* inputRenderer, const RenderObject* partRenderer, const FloatRect& inputRect, const IntRect& r) const; + // Get the control size based off the font. Used by some of the controls (like buttons). NSControlSize controlSizeForFont(RenderStyle*) const; NSControlSize controlSizeForSystemFont(RenderStyle*) const; diff --git a/WebCore/rendering/RenderThemeMac.mm b/WebCore/rendering/RenderThemeMac.mm index 699b74a..b2d320a 100644 --- a/WebCore/rendering/RenderThemeMac.mm +++ b/WebCore/rendering/RenderThemeMac.mm @@ -25,7 +25,6 @@ #import "CSSValueKeywords.h" #import "Document.h" #import "Element.h" -#import "FoundationExtras.h" #import "FrameView.h" #import "GraphicsContext.h" #import "HTMLInputElement.h" @@ -33,13 +32,16 @@ #import "HTMLNames.h" #import "Image.h" #import "LocalCurrentGraphicsContext.h" +#import "MediaControlElements.h" #import "RenderSlider.h" #import "RenderView.h" #import "SharedBuffer.h" #import "WebCoreSystemInterface.h" +#import "UserAgentStyleSheets.h" #import <Carbon/Carbon.h> #import <Cocoa/Cocoa.h> #import <wtf/RetainPtr.h> +#import <wtf/StdLibExtras.h> #import <math.h> #ifdef BUILDING_ON_TIGER @@ -73,9 +75,9 @@ using std::min; return self; } -- (void)systemColorsDidChange:(NSNotification *)notification +- (void)systemColorsDidChange:(NSNotification *)unusedNotification { - ASSERT([[notification name] isEqualToString:NSSystemColorsDidChangeNotification]); + ASSERT_UNUSED(unusedNotification, [[unusedNotification name] isEqualToString:NSSystemColorsDidChangeNotification]); _theme->platformColorsDidChange(); } @@ -133,12 +135,27 @@ Color RenderThemeMac::platformInactiveSelectionBackgroundColor() const return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent])); } -Color RenderThemeMac::activeListBoxSelectionBackgroundColor() const +Color RenderThemeMac::platformActiveListBoxSelectionBackgroundColor() const { NSColor* color = [[NSColor alternateSelectedControlColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace]; return Color(static_cast<int>(255.0 * [color redComponent]), static_cast<int>(255.0 * [color greenComponent]), static_cast<int>(255.0 * [color blueComponent])); } +Color RenderThemeMac::platformActiveListBoxSelectionForegroundColor() const +{ + return Color::white; +} + +Color RenderThemeMac::platformInactiveListBoxSelectionForegroundColor() const +{ + return Color::black; +} + +Color RenderThemeMac::platformInactiveListBoxSelectionBackgroundColor() const +{ + return platformInactiveSelectionBackgroundColor(); +} + static FontWeight toFontWeight(NSInteger appKitFontWeight) { ASSERT(appKitFontWeight > 0 && appKitFontWeight < 15); @@ -168,13 +185,13 @@ static FontWeight toFontWeight(NSInteger appKitFontWeight) void RenderThemeMac::systemFont(int cssValueId, FontDescription& fontDescription) const { - static FontDescription systemFont; - static FontDescription smallSystemFont; - static FontDescription menuFont; - static FontDescription labelFont; - static FontDescription miniControlFont; - static FontDescription smallControlFont; - static FontDescription controlFont; + DEFINE_STATIC_LOCAL(FontDescription, systemFont, ()); + DEFINE_STATIC_LOCAL(FontDescription, smallSystemFont, ()); + DEFINE_STATIC_LOCAL(FontDescription, menuFont, ()); + DEFINE_STATIC_LOCAL(FontDescription, labelFont, ()); + DEFINE_STATIC_LOCAL(FontDescription, miniControlFont, ()); + DEFINE_STATIC_LOCAL(FontDescription, smallControlFont, ()); + DEFINE_STATIC_LOCAL(FontDescription, controlFont, ()); FontDescription* cachedDesc; NSFont* font = nil; @@ -229,7 +246,7 @@ void RenderThemeMac::systemFont(int cssValueId, FontDescription& fontDescription static RGBA32 convertNSColorToColor(NSColor *color) { - NSColor *colorInColorSpace = [color colorUsingColorSpaceName:NSCalibratedRGBColorSpace]; + NSColor *colorInColorSpace = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace]; if (colorInColorSpace) { static const double scaleFactor = nextafter(256.0, 0.0); return makeRGB(static_cast<int>(scaleFactor * [colorInColorSpace redComponent]), @@ -249,7 +266,7 @@ static RGBA32 convertNSColorToColor(NSColor *color) samplesPerPixel:4 hasAlpha:YES isPlanar:NO - colorSpaceName:NSCalibratedRGBColorSpace + colorSpaceName:NSDeviceRGBColorSpace bytesPerRow:4 bitsPerPixel:32]; @@ -276,7 +293,7 @@ static RGBA32 menuBackgroundColor() samplesPerPixel:4 hasAlpha:YES isPlanar:NO - colorSpaceName:NSCalibratedRGBColorSpace + colorSpaceName:NSDeviceRGBColorSpace bytesPerRow:4 bitsPerPixel:32]; @@ -416,6 +433,14 @@ bool RenderThemeMac::isControlStyled(const RenderStyle* style, const BorderData& { if (style->appearance() == TextFieldPart || style->appearance() == TextAreaPart || style->appearance() == ListboxPart) return style->border() != border; + + // FIXME: This is horrible, but there is not much else that can be done. Menu lists cannot draw properly when + // scaled. They can't really draw properly when transformed either. We can't detect the transform case at style + // adjustment time so that will just have to stay broken. We can however detect that we're zooming. If zooming + // is in effect we treat it like the control is styled. + if (style->appearance() == MenulistPart && style->effectiveZoom() != 1.0f) + return true; + return RenderTheme::isControlStyled(style, border, background, backgroundColor); } @@ -466,6 +491,28 @@ IntRect RenderThemeMac::inflateRect(const IntRect& r, const IntSize& size, const return result; } +FloatRect RenderThemeMac::convertToPaintingRect(const RenderObject* inputRenderer, const RenderObject* partRenderer, const FloatRect& inputRect, const IntRect& r) const +{ + FloatRect partRect(inputRect); + + // Compute an offset between the part renderer and the input renderer + FloatSize offsetFromInputRenderer; + const RenderObject* renderer = partRenderer; + while (renderer && renderer != inputRenderer) { + RenderObject* containingRenderer = renderer->container(); + offsetFromInputRenderer -= renderer->offsetFromContainer(containingRenderer); + renderer = containingRenderer; + } + // If the input renderer was not a container, something went wrong + ASSERT(renderer == inputRenderer); + // Move the rect into partRenderer's coords + partRect.move(offsetFromInputRenderer); + // Account for the local drawing offset (tx, ty) + partRect.move(r.x(), r.y()); + + return partRect; +} + void RenderThemeMac::updateCheckedState(NSCell* cell, const RenderObject* o) { bool oldIndeterminate = [cell state] == NSMixedState; @@ -577,7 +624,7 @@ void RenderThemeMac::setSizeFromFont(RenderStyle* style, const IntSize* sizes) c style->setHeight(Length(size.height(), Fixed)); } -void RenderThemeMac::setFontFromControlSize(CSSStyleSelector* selector, RenderStyle* style, NSControlSize controlSize) const +void RenderThemeMac::setFontFromControlSize(CSSStyleSelector*, RenderStyle* style, NSControlSize controlSize) const { FontDescription fontDescription; fontDescription.setIsAbsoluteSize(true); @@ -616,7 +663,7 @@ void RenderThemeMac::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle*, Eleme { } -bool RenderThemeMac::paintCapsLockIndicator(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +bool RenderThemeMac::paintCapsLockIndicator(RenderObject*, const RenderObject::PaintInfo& paintInfo, const IntRect& r) { if (paintInfo.context->paintingDisabled()) return true; @@ -717,7 +764,7 @@ const int styledPopupPaddingLeft = 8; const int styledPopupPaddingTop = 1; const int styledPopupPaddingBottom = 2; -static void TopGradientInterpolate(void* info, const CGFloat* inData, CGFloat* outData) +static void TopGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData) { static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.4f }; static float light[4] = { 1.0f, 1.0f, 1.0f, 0.15f }; @@ -727,7 +774,7 @@ static void TopGradientInterpolate(void* info, const CGFloat* inData, CGFloat* o outData[i] = (1.0f - a) * dark[i] + a * light[i]; } -static void BottomGradientInterpolate(void* info, const CGFloat* inData, CGFloat* outData) +static void BottomGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData) { static float dark[4] = { 1.0f, 1.0f, 1.0f, 0.0f }; static float light[4] = { 1.0f, 1.0f, 1.0f, 0.3f }; @@ -737,7 +784,7 @@ static void BottomGradientInterpolate(void* info, const CGFloat* inData, CGFloat outData[i] = (1.0f - a) * dark[i] + a * light[i]; } -static void MainGradientInterpolate(void* info, const CGFloat* inData, CGFloat* outData) +static void MainGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData) { static float dark[4] = { 0.0f, 0.0f, 0.0f, 0.15f }; static float light[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; @@ -747,7 +794,7 @@ static void MainGradientInterpolate(void* info, const CGFloat* inData, CGFloat* outData[i] = (1.0f - a) * dark[i] + a * light[i]; } -static void TrackGradientInterpolate(void* info, const CGFloat* inData, CGFloat* outData) +static void TrackGradientInterpolate(void*, const CGFloat* inData, CGFloat* outData) { static float dark[4] = { 0.0f, 0.0f, 0.0f, 0.678f }; static float light[4] = { 0.0f, 0.0f, 0.0f, 0.13f }; @@ -956,7 +1003,7 @@ int RenderThemeMac::popupInternalPaddingBottom(RenderStyle* style) const return 0; } -void RenderThemeMac::adjustMenuListButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderThemeMac::adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const { float fontScale = style->fontSize() / baseFontSize; @@ -997,7 +1044,7 @@ int RenderThemeMac::minimumMenuListSize(RenderStyle* style) const const int trackWidth = 5; const int trackRadius = 2; -void RenderThemeMac::adjustSliderTrackStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderThemeMac::adjustSliderTrackStyle(CSSStyleSelector*, RenderStyle* style, Element*) const { style->setBoxShadow(0); } @@ -1041,7 +1088,7 @@ bool RenderThemeMac::paintSliderTrack(RenderObject* o, const RenderObject::Paint return false; } -void RenderThemeMac::adjustSliderThumbStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderThemeMac::adjustSliderThumbStyle(CSSStyleSelector*, RenderStyle* style, Element*) const { style->setBoxShadow(0); } @@ -1108,23 +1155,6 @@ bool RenderThemeMac::paintSliderThumb(RenderObject* o, const RenderObject::Paint return false; } -const int sliderThumbWidth = 15; -const int sliderThumbHeight = 15; -const int mediaSliderThumbWidth = 13; -const int mediaSliderThumbHeight = 14; - -void RenderThemeMac::adjustSliderThumbSize(RenderObject* o) const -{ - float zoomLevel = o->style()->effectiveZoom(); - if (o->style()->appearance() == SliderThumbHorizontalPart || o->style()->appearance() == SliderThumbVerticalPart) { - o->style()->setWidth(Length(static_cast<int>(sliderThumbWidth * zoomLevel), Fixed)); - o->style()->setHeight(Length(static_cast<int>(sliderThumbHeight * zoomLevel), Fixed)); - } else if (o->style()->appearance() == MediaSliderThumbPart) { - o->style()->setWidth(Length(mediaSliderThumbWidth, Fixed)); - o->style()->setHeight(Length(mediaSliderThumbHeight, Fixed)); - } -} - bool RenderThemeMac::paintSearchField(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) { NSSearchFieldCell* search = this->search(); @@ -1163,7 +1193,7 @@ bool RenderThemeMac::paintSearchField(RenderObject* o, const RenderObject::Paint return false; } -void RenderThemeMac::setSearchCellState(RenderObject* o, const IntRect& r) +void RenderThemeMac::setSearchCellState(RenderObject* o, const IntRect&) { NSSearchFieldCell* search = this->search(); @@ -1190,7 +1220,7 @@ void RenderThemeMac::setSearchFieldSize(RenderStyle* style) const setSizeFromFont(style, searchFieldSizes()); } -void RenderThemeMac::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderThemeMac::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element*) const { // Override border. style->resetBorder(); @@ -1224,6 +1254,9 @@ void RenderThemeMac::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderSt bool RenderThemeMac::paintSearchFieldCancelButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) { Node* input = o->node()->shadowAncestorNode(); + if (!input->renderer()->isBox()) + return false; + setSearchCellState(input->renderer(), r); NSSearchFieldCell* search = this->search(); @@ -1234,9 +1267,10 @@ bool RenderThemeMac::paintSearchFieldCancelButton(RenderObject* o, const RenderO float zoomLevel = o->style()->effectiveZoom(); - NSRect bounds = [search cancelButtonRectForBounds:NSRect(input->renderer()->absoluteBoundingBoxRect())]; - - IntRect unzoomedRect(bounds); + FloatRect localBounds = [search cancelButtonRectForBounds:NSRect(input->renderBox()->borderBoxRect())]; + localBounds = convertToPaintingRect(input->renderer(), o, localBounds, r); + + FloatRect unzoomedRect(localBounds); if (zoomLevel != 1.0f) { unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel); unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel); @@ -1258,7 +1292,7 @@ const IntSize* RenderThemeMac::cancelButtonSizes() const return sizes; } -void RenderThemeMac::adjustSearchFieldCancelButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderThemeMac::adjustSearchFieldCancelButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const { IntSize size = sizeForSystemFont(style, cancelButtonSizes()); style->setWidth(Length(size.width(), Fixed)); @@ -1273,7 +1307,7 @@ const IntSize* RenderThemeMac::resultsButtonSizes() const } const int emptyResultsOffset = 9; -void RenderThemeMac::adjustSearchFieldDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderThemeMac::adjustSearchFieldDecorationStyle(CSSStyleSelector*, RenderStyle* style, Element*) const { IntSize size = sizeForSystemFont(style, resultsButtonSizes()); style->setWidth(Length(size.width() - emptyResultsOffset, Fixed)); @@ -1281,12 +1315,12 @@ void RenderThemeMac::adjustSearchFieldDecorationStyle(CSSStyleSelector* selector style->setBoxShadow(0); } -bool RenderThemeMac::paintSearchFieldDecoration(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +bool RenderThemeMac::paintSearchFieldDecoration(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return false; } -void RenderThemeMac::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderThemeMac::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector*, RenderStyle* style, Element*) const { IntSize size = sizeForSystemFont(style, resultsButtonSizes()); style->setWidth(Length(size.width(), Fixed)); @@ -1294,9 +1328,12 @@ void RenderThemeMac::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* s style->setBoxShadow(0); } -bool RenderThemeMac::paintSearchFieldResultsDecoration(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +bool RenderThemeMac::paintSearchFieldResultsDecoration(RenderObject* o, const RenderObject::PaintInfo&, const IntRect& r) { Node* input = o->node()->shadowAncestorNode(); + if (!input->renderer()->isBox()) + return false; + setSearchCellState(input->renderer(), r); NSSearchFieldCell* search = this->search(); @@ -1304,14 +1341,16 @@ bool RenderThemeMac::paintSearchFieldResultsDecoration(RenderObject* o, const Re if ([search searchMenuTemplate] != nil) [search setSearchMenuTemplate:nil]; - NSRect bounds = [search searchButtonRectForBounds:NSRect(input->renderer()->absoluteBoundingBoxRect())]; - [[search searchButtonCell] drawWithFrame:bounds inView:o->view()->frameView()->documentView()]; + FloatRect localBounds = [search searchButtonRectForBounds:NSRect(input->renderBox()->borderBoxRect())]; + localBounds = convertToPaintingRect(input->renderer(), o, localBounds, r); + + [[search searchButtonCell] drawWithFrame:localBounds inView:o->view()->frameView()->documentView()]; [[search searchButtonCell] setControlView:nil]; return false; } const int resultsArrowWidth = 5; -void RenderThemeMac::adjustSearchFieldResultsButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderThemeMac::adjustSearchFieldResultsButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const { IntSize size = sizeForSystemFont(style, resultsButtonSizes()); style->setWidth(Length(size.width() + resultsArrowWidth, Fixed)); @@ -1322,6 +1361,9 @@ void RenderThemeMac::adjustSearchFieldResultsButtonStyle(CSSStyleSelector* selec bool RenderThemeMac::paintSearchFieldResultsButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) { Node* input = o->node()->shadowAncestorNode(); + if (!input->renderer()->isBox()) + return false; + setSearchCellState(input->renderer(), r); NSSearchFieldCell* search = this->search(); @@ -1333,9 +1375,10 @@ bool RenderThemeMac::paintSearchFieldResultsButton(RenderObject* o, const Render float zoomLevel = o->style()->effectiveZoom(); - NSRect bounds = [search searchButtonRectForBounds:NSRect(input->renderer()->absoluteBoundingBoxRect())]; + FloatRect localBounds = [search searchButtonRectForBounds:NSRect(input->renderBox()->borderBoxRect())]; + localBounds = convertToPaintingRect(input->renderer(), o, localBounds, r); - IntRect unzoomedRect(bounds); + IntRect unzoomedRect(localBounds); if (zoomLevel != 1.0f) { unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel); unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel); @@ -1352,6 +1395,71 @@ bool RenderThemeMac::paintSearchFieldResultsButton(RenderObject* o, const Render return false; } +#if ENABLE(VIDEO) +typedef enum { + MediaControllerThemeClassic = 1, + MediaControllerThemeQT = 2 +} MediaControllerThemeStyle; + +static int mediaControllerTheme() +{ + static const long minimumQuickTimeVersion = 0x07600000; // 7.6 + static SInt32 quickTimeVersion = 0; + + if (!quickTimeVersion) { + OSErr err; + err = Gestalt(gestaltQuickTime, &quickTimeVersion); + if (err != noErr) + return MediaControllerThemeClassic; + } + if (quickTimeVersion < minimumQuickTimeVersion) + return MediaControllerThemeClassic; + + // keep the feature off for now without an explicit opt-in + Boolean validKey; + Boolean useQTMediaUI = CFPreferencesGetAppBooleanValue(CFSTR("UseQuickTimeMediaUI"), CFSTR("com.apple.WebCore"), &validKey); + if (!validKey || !useQTMediaUI) + return MediaControllerThemeClassic; + + return MediaControllerThemeQT; +} +#endif + +const int sliderThumbWidth = 15; +const int sliderThumbHeight = 15; +const int mediaSliderThumbWidth = 13; +const int mediaSliderThumbHeight = 14; + +void RenderThemeMac::adjustSliderThumbSize(RenderObject* o) const +{ + float zoomLevel = o->style()->effectiveZoom(); + if (o->style()->appearance() == SliderThumbHorizontalPart || o->style()->appearance() == SliderThumbVerticalPart) { + o->style()->setWidth(Length(static_cast<int>(sliderThumbWidth * zoomLevel), Fixed)); + o->style()->setHeight(Length(static_cast<int>(sliderThumbHeight * zoomLevel), Fixed)); + } + +#if ENABLE(VIDEO) + else if (o->style()->appearance() == MediaSliderThumbPart) { + int width = mediaSliderThumbWidth; + int height = mediaSliderThumbHeight; + + if (mediaControllerTheme() == MediaControllerThemeQT) { + CGSize size; + + wkMeasureMediaUIPart(MediaSliderThumb, MediaControllerThemeQT, NULL, &size); + width = size.width; + height = size.height; + } + + o->style()->setWidth(Length(width, Fixed)); + o->style()->setHeight(Length(height, Fixed)); + } +#endif +} + + +#if ENABLE(VIDEO) + bool RenderThemeMac::paintMediaFullscreenButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) { Node* node = o->element(); @@ -1359,7 +1467,7 @@ bool RenderThemeMac::paintMediaFullscreenButton(RenderObject* o, const RenderObj return false; LocalCurrentGraphicsContext localContext(paintInfo.context); - wkDrawMediaFullscreenButton(paintInfo.context->platformContext(), r, node->active()); + wkDrawMediaUIPart(MediaFullscreenButton, mediaControllerTheme(), paintInfo.context->platformContext(), r, node->active()); return false; } @@ -1375,10 +1483,7 @@ bool RenderThemeMac::paintMediaMuteButton(RenderObject* o, const RenderObject::P return false; LocalCurrentGraphicsContext localContext(paintInfo.context); - if (mediaElement->muted()) - wkDrawMediaUnMuteButton(paintInfo.context->platformContext(), r, node->active()); - else - wkDrawMediaMuteButton(paintInfo.context->platformContext(), r, node->active()); + wkDrawMediaUIPart(mediaElement->muted() ? MediaUnMuteButton : MediaMuteButton, mediaControllerTheme(), paintInfo.context->platformContext(), r, node->active()); return false; } @@ -1394,10 +1499,7 @@ bool RenderThemeMac::paintMediaPlayButton(RenderObject* o, const RenderObject::P return false; LocalCurrentGraphicsContext localContext(paintInfo.context); - if (mediaElement->canPlay()) - wkDrawMediaPlayButton(paintInfo.context->platformContext(), r, node->active()); - else - wkDrawMediaPauseButton(paintInfo.context->platformContext(), r, node->active()); + wkDrawMediaUIPart(mediaElement->canPlay() ? MediaPlayButton : MediaPauseButton, mediaControllerTheme(), paintInfo.context->platformContext(), r, node->active()); return false; } @@ -1408,7 +1510,7 @@ bool RenderThemeMac::paintMediaSeekBackButton(RenderObject* o, const RenderObjec return false; LocalCurrentGraphicsContext localContext(paintInfo.context); - wkDrawMediaSeekBackButton(paintInfo.context->platformContext(), r, node->active()); + wkDrawMediaUIPart(MediaSeekBackButton, mediaControllerTheme(), paintInfo.context->platformContext(), r, node->active()); return false; } @@ -1419,7 +1521,7 @@ bool RenderThemeMac::paintMediaSeekForwardButton(RenderObject* o, const RenderOb return false; LocalCurrentGraphicsContext localContext(paintInfo.context); - wkDrawMediaSeekForwardButton(paintInfo.context->platformContext(), r, node->active()); + wkDrawMediaUIPart(MediaSeekForwardButton, mediaControllerTheme(), paintInfo.context->platformContext(), r, node->active()); return false; } @@ -1434,12 +1536,16 @@ bool RenderThemeMac::paintMediaSliderTrack(RenderObject* o, const RenderObject:: if (!mediaElement) return false; - float percentLoaded = 0; - if (MediaPlayer* player = mediaElement->player()) - if (player->duration()) - percentLoaded = player->maxTimeBuffered() / player->duration(); - - wkDrawMediaSliderTrack(paintInfo.context->platformContext(), r, percentLoaded); + float timeLoaded = 0; + float currentTime = 0; + float duration = 0; + if (MediaPlayer* player = mediaElement->player()) { + duration = player->duration(); + timeLoaded = player->maxTimeBuffered(); + currentTime = player->currentTime(); + } + + wkDrawMediaSliderTrack(mediaControllerTheme(), paintInfo.context->platformContext(), r, timeLoaded, currentTime, duration); return false; } @@ -1450,10 +1556,66 @@ bool RenderThemeMac::paintMediaSliderThumb(RenderObject* o, const RenderObject:: return false; LocalCurrentGraphicsContext localContext(paintInfo.context); - wkDrawMediaSliderThumb(paintInfo.context->platformContext(), r, node->active()); + wkDrawMediaUIPart(MediaSliderThumb, mediaControllerTheme(), paintInfo.context->platformContext(), r, node->active()); + return false; +} + +bool RenderThemeMac::paintMediaTimelineContainer(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + Node* node = o->element(); + if (!node) + return false; + + LocalCurrentGraphicsContext localContext(paintInfo.context); + wkDrawMediaUIPart(MediaTimelineContainer, mediaControllerTheme(), paintInfo.context->platformContext(), r, node->active()); + return false; +} + +bool RenderThemeMac::paintMediaCurrentTime(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + Node* node = o->element(); + if (!node) + return false; + + LocalCurrentGraphicsContext localContext(paintInfo.context); + wkDrawMediaUIPart(MediaCurrentTimeDisplay, mediaControllerTheme(), paintInfo.context->platformContext(), r, node->active()); return false; } +bool RenderThemeMac::paintMediaTimeRemaining(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + Node* node = o->element(); + if (!node) + return false; + + LocalCurrentGraphicsContext localContext(paintInfo.context); + wkDrawMediaUIPart(MediaTimeRemainingDisplay, mediaControllerTheme(), paintInfo.context->platformContext(), r, node->active()); + return false; +} + +String RenderThemeMac::extraMediaControlsStyleSheet() +{ + if (mediaControllerTheme() == MediaControllerThemeQT) + return String(mediaControlsQTUserAgentStyleSheet, sizeof(mediaControlsQTUserAgentStyleSheet)); + else + return String(); +} + +bool RenderThemeMac::hitTestMediaControlPart(RenderObject* o, const IntPoint& absPoint) +{ + if (!o->isBox()) + return false; + + if (mediaControllerTheme() == MediaControllerThemeQT) { + ControlPart part = o->style()->appearance(); + FloatPoint localPoint = o->absoluteToLocal(absPoint, false, true); // respect transforms + return wkHitTestMediaUIPart(part - MediaFullscreenButtonPart, MediaControllerThemeQT, CGRect(toRenderBox(o)->borderBoxRect()), CGPoint(localPoint)); + } + else + return RenderTheme::hitTestMediaControlPart(o, absPoint); +} +#endif + NSPopUpButtonCell* RenderThemeMac::popupButton() const { if (!m_popupButton) { diff --git a/WebCore/rendering/RenderThemeSafari.cpp b/WebCore/rendering/RenderThemeSafari.cpp index 31315bc..ef39a3e 100644 --- a/WebCore/rendering/RenderThemeSafari.cpp +++ b/WebCore/rendering/RenderThemeSafari.cpp @@ -272,8 +272,14 @@ IntRect RenderThemeSafari::inflateRect(const IntRect& r, const IntSize& size, co int RenderThemeSafari::baselinePosition(const RenderObject* o) const { - if (o->style()->appearance() == CheckboxPart || o->style()->appearance() == RadioPart) - return o->marginTop() + o->height() - 2; // The baseline is 2px up from the bottom of the checkbox/radio in AppKit. + if (!o->isBox()) + return 0; + + if (o->style()->appearance() == CheckboxPart || o->style()->appearance() == RadioPart) { + const RenderBox* box = toRenderBox(o); + return box->marginTop() + box->height() - 2; // The baseline is 2px up from the bottom of the checkbox/radio in AppKit. + } + return RenderTheme::baselinePosition(o); } diff --git a/WebCore/rendering/RenderThemeWin.cpp b/WebCore/rendering/RenderThemeWin.cpp index 14dcbf1..e4717a1 100644 --- a/WebCore/rendering/RenderThemeWin.cpp +++ b/WebCore/rendering/RenderThemeWin.cpp @@ -21,6 +21,7 @@ #include "config.h" #include "RenderThemeWin.h" +#include "CSSStyleSheet.h" #include "CSSValueKeywords.h" #include "Document.h" #include "GraphicsContext.h" @@ -29,6 +30,7 @@ #include "Icon.h" #include "RenderSlider.h" #include "SoftLinking.h" +#include "UserAgentStyleSheets.h" #include <tchar.h> @@ -81,11 +83,6 @@ #define PBS_DISABLED 4 #define PBS_DEFAULTED 5 -// This is the fixed width IE and Firefox use for buttons on dropdown menus -static const int dropDownButtonWidth = 17; - -static const int shell32MagnifierIconIndex = 22; - SOFT_LINK_LIBRARY(uxtheme) SOFT_LINK(uxtheme, OpenThemeData, HANDLE, WINAPI, (HWND hwnd, LPCWSTR pszClassList), (hwnd, pszClassList)) SOFT_LINK(uxtheme, CloseThemeData, HRESULT, WINAPI, (HANDLE hTheme), (hTheme)) @@ -95,8 +92,26 @@ SOFT_LINK(uxtheme, IsThemeBackgroundPartiallyTransparent, BOOL, WINAPI, (HANDLE static bool haveTheme; +using namespace std; + namespace WebCore { +// This is the fixed width IE and Firefox use for buttons on dropdown menus +static const int dropDownButtonWidth = 17; + +static const int shell32MagnifierIconIndex = 22; + +// Default font size to match Firefox. +static const float defaultControlFontPixelSize = 13; + +static const float defaultCancelButtonSize = 9; +static const float minCancelButtonSize = 5; +static const float maxCancelButtonSize = 21; +static const float defaultSearchFieldResultsDecorationSize = 13; +static const float minSearchFieldResultsDecorationSize = 9; +static const float maxSearchFieldResultsDecorationSize = 30; +static const float defaultSearchFieldResultsButtonWidth = 18; + static bool gWebKitIsBeingUnloaded; void RenderThemeWin::setWebKitIsBeingUnloaded() @@ -178,6 +193,16 @@ void RenderThemeWin::themeChanged() close(); } +String RenderThemeWin::extraDefaultStyleSheet() +{ + return String(themeWinUserAgentStyleSheet, sizeof(themeWinUserAgentStyleSheet)); +} + +String RenderThemeWin::extraQuirksStyleSheet() +{ + return String(themeWinQuirksUserAgentStyleSheet, sizeof(themeWinQuirksUserAgentStyleSheet)); +} + bool RenderThemeWin::supportsHover(const RenderStyle*) const { // The Classic/2k look has no hover effects. @@ -187,39 +212,45 @@ bool RenderThemeWin::supportsHover(const RenderStyle*) const Color RenderThemeWin::platformActiveSelectionBackgroundColor() const { COLORREF color = GetSysColor(COLOR_HIGHLIGHT); - return Color(GetRValue(color), GetGValue(color), GetBValue(color), 255); + return Color(GetRValue(color), GetGValue(color), GetBValue(color)); } Color RenderThemeWin::platformInactiveSelectionBackgroundColor() const { - COLORREF color = GetSysColor(COLOR_GRAYTEXT); - return Color(GetRValue(color), GetGValue(color), GetBValue(color), 255); + // This color matches Firefox. + return Color(176, 176, 176); } Color RenderThemeWin::platformActiveSelectionForegroundColor() const { COLORREF color = GetSysColor(COLOR_HIGHLIGHTTEXT); - return Color(GetRValue(color), GetGValue(color), GetBValue(color), 255); + return Color(GetRValue(color), GetGValue(color), GetBValue(color)); } Color RenderThemeWin::platformInactiveSelectionForegroundColor() const { - return Color::white; + return platformActiveSelectionForegroundColor(); } -static void fillFontDescription(FontDescription& fontDescription, LOGFONT& logFont) +static void fillFontDescription(FontDescription& fontDescription, LOGFONT& logFont, float fontSize) { fontDescription.setIsAbsoluteSize(true); fontDescription.setGenericFamily(FontDescription::NoFamily); fontDescription.firstFamily().setFamily(String(logFont.lfFaceName)); - fontDescription.setSpecifiedSize(abs(logFont.lfHeight)); + fontDescription.setSpecifiedSize(fontSize); fontDescription.setWeight(logFont.lfWeight >= 700 ? FontWeightBold : FontWeightNormal); // FIXME: Use real weight. fontDescription.setItalic(logFont.lfItalic); } +static void fillFontDescription(FontDescription& fontDescription, LOGFONT& logFont) +{ + fillFontDescription(fontDescription, logFont, abs(logFont.lfHeight)); +} + void RenderThemeWin::systemFont(int propId, FontDescription& fontDescription) const { static FontDescription captionFont; + static FontDescription controlFont; static FontDescription smallCaptionFont; static FontDescription menuFont; static FontDescription iconFont; @@ -267,13 +298,23 @@ void RenderThemeWin::systemFont(int propId, FontDescription& fontDescription) co fontDescription = captionFont; break; case CSSValueSmallCaption: - case CSSValueWebkitSmallControl: // Equivalent to small-caption. - case CSSValueWebkitMiniControl: // Just map to small. - case CSSValueWebkitControl: // Just map to small. if (!smallCaptionFont.isAbsoluteSize()) fillFontDescription(smallCaptionFont, ncm.lfSmCaptionFont); fontDescription = smallCaptionFont; break; + case CSSValueWebkitSmallControl: + case CSSValueWebkitMiniControl: // Just map to small. + case CSSValueWebkitControl: // Just map to small. + if (!controlFont.isAbsoluteSize()) { + HGDIOBJ hGDI = ::GetStockObject(DEFAULT_GUI_FONT); + if (hGDI) { + LOGFONT logFont; + if (::GetObject(hGDI, sizeof(logFont), &logFont) > 0) + fillFontDescription(controlFont, logFont, defaultControlFontPixelSize); + } + } + fontDescription = controlFont; + break; default: { // Everything else uses the stock GUI font. if (!systemFont.isAbsoluteSize()) { HGDIOBJ hGDI = ::GetStockObject(DEFAULT_GUI_FONT); @@ -288,22 +329,23 @@ void RenderThemeWin::systemFont(int propId, FontDescription& fontDescription) co } } -bool RenderThemeWin::supportsFocus(ControlPart appearance) +bool RenderThemeWin::supportsFocus(ControlPart appearance) const { switch (appearance) { case PushButtonPart: case ButtonPart: case DefaultButtonPart: - case TextFieldPart: - case TextAreaPart: return true; - case MenulistPart: - return false; default: return false; } } +bool RenderThemeWin::supportsFocusRing(const RenderStyle* style) const +{ + return supportsFocus(style->appearance()); +} + unsigned RenderThemeWin::determineClassicState(RenderObject* o) { unsigned state = 0; @@ -345,7 +387,7 @@ unsigned RenderThemeWin::determineState(RenderObject* o) ControlPart appearance = o->style()->appearance(); if (!isEnabled(o)) result = TS_DISABLED; - else if (isReadOnlyControl(o) && (TextFieldPart == appearance || TextAreaPart == appearance)) + else if (isReadOnlyControl(o) && (TextFieldPart == appearance || TextAreaPart == appearance || SearchFieldPart == appearance)) result = TFS_READONLY; // Readonly is supported on textfields. else if (isPressed(o)) // Active overrides hover and focused. result = TS_ACTIVE; @@ -404,6 +446,7 @@ ThemeData RenderThemeWin::getClassicThemeData(RenderObject* o) result.m_part = DFC_SCROLL; result.m_state = determineClassicState(o); break; + case SearchFieldPart: case TextFieldPart: case TextAreaPart: result.m_part = TFP_TEXTFIELD; @@ -457,6 +500,7 @@ ThemeData RenderThemeWin::getThemeData(RenderObject* o) result.m_part = BP_RADIO; result.m_state = determineState(o); break; + case SearchFieldPart: case TextFieldPart: case TextAreaPart: result.m_part = TFP_TEXTFIELD; @@ -666,7 +710,16 @@ void RenderThemeWin::adjustSliderThumbSize(RenderObject* o) const o->style()->setWidth(Length(sliderThumbWidth, Fixed)); o->style()->setHeight(Length(sliderThumbHeight, Fixed)); } - } +} + +void RenderThemeWin::adjustButtonInnerStyle(RenderStyle* style) const +{ + // This inner padding matches Firefox. + style->setPaddingTop(Length(1, Fixed)); + style->setPaddingRight(Length(3, Fixed)); + style->setPaddingBottom(Length(1, Fixed)); + style->setPaddingLeft(Length(3, Fixed)); +} bool RenderThemeWin::paintSearchField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) { @@ -685,33 +738,36 @@ void RenderThemeWin::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderSt bool RenderThemeWin::paintSearchFieldCancelButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) { - Color buttonColor = (o->element() && o->element()->active()) ? Color(138, 138, 138) : Color(186, 186, 186); - - IntSize cancelSize(10, 10); - IntSize cancelRadius(cancelSize.width() / 2, cancelSize.height() / 2); - int x = r.x() + (r.width() - cancelSize.width()) / 2; - int y = r.y() + (r.height() - cancelSize.height()) / 2 + 1; - IntRect cancelBounds(IntPoint(x, y), cancelSize); - paintInfo.context->save(); - paintInfo.context->addRoundedRectClip(cancelBounds, cancelRadius, cancelRadius, cancelRadius, cancelRadius); - paintInfo.context->fillRect(cancelBounds, buttonColor); - - // Draw the 'x' - IntSize xSize(3, 3); - IntRect xBounds(cancelBounds.location() + IntSize(3, 3), xSize); - paintInfo.context->setStrokeColor(Color::white); - paintInfo.context->drawLine(xBounds.location(), xBounds.location() + xBounds.size()); - paintInfo.context->drawLine(IntPoint(xBounds.right(), xBounds.y()), IntPoint(xBounds.x(), xBounds.bottom())); - - paintInfo.context->restore(); + IntRect bounds = r; + ASSERT(o->parent()); + if (!o->parent() || !o->parent()->isBox()) + return false; + + RenderBox* parentRenderBox = toRenderBox(o->parent()); + + IntRect parentBox = parentRenderBox->absoluteContentBox(); + + // Make sure the scaled button stays square and will fit in its parent's box + bounds.setHeight(min(parentBox.width(), min(parentBox.height(), bounds.height()))); + bounds.setWidth(bounds.height()); + + // Center the button vertically. Round up though, so if it has to be one pixel off-center, it will + // be one pixel closer to the bottom of the field. This tends to look better with the text. + bounds.setY(parentBox.y() + (parentBox.height() - bounds.height() + 1) / 2); + + static Image* cancelImage = Image::loadPlatformResource("searchCancel").releaseRef(); + static Image* cancelPressedImage = Image::loadPlatformResource("searchCancelPressed").releaseRef(); + paintInfo.context->drawImage(isPressed(o) ? cancelPressedImage : cancelImage, bounds); return false; } void RenderThemeWin::adjustSearchFieldCancelButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const { - IntSize cancelSize(13, 11); - style->setWidth(Length(cancelSize.width(), Fixed)); - style->setHeight(Length(cancelSize.height(), Fixed)); + // Scale the button size based on the font size + float fontScale = style->fontSize() / defaultControlFontPixelSize; + int cancelButtonSize = lroundf(min(max(minCancelButtonSize, defaultCancelButtonSize * fontScale), maxCancelButtonSize)); + style->setWidth(Length(cancelButtonSize, Fixed)); + style->setHeight(Length(cancelButtonSize, Fixed)); } void RenderThemeWin::adjustSearchFieldDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const @@ -720,46 +776,73 @@ void RenderThemeWin::adjustSearchFieldDecorationStyle(CSSStyleSelector* selector style->setWidth(Length(emptySize.width(), Fixed)); style->setHeight(Length(emptySize.height(), Fixed)); } - + void RenderThemeWin::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const { - IntSize magnifierSize(15, 11); - style->setWidth(Length(magnifierSize.width(), Fixed)); - style->setHeight(Length(magnifierSize.height(), Fixed)); + // Scale the decoration size based on the font size + float fontScale = style->fontSize() / defaultControlFontPixelSize; + int magnifierSize = lroundf(min(max(minSearchFieldResultsDecorationSize, defaultSearchFieldResultsDecorationSize * fontScale), + maxSearchFieldResultsDecorationSize)); + style->setWidth(Length(magnifierSize, Fixed)); + style->setHeight(Length(magnifierSize, Fixed)); } bool RenderThemeWin::paintSearchFieldResultsDecoration(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) { IntRect bounds = r; + ASSERT(o->parent()); + if (!o->parent() || !o->parent()->isBox()) + return false; + + RenderBox* parentRenderBox = toRenderBox(o->parent()); + IntRect parentBox = parentRenderBox->absoluteContentBox(); + + // Make sure the scaled decoration stays square and will fit in its parent's box + bounds.setHeight(min(parentBox.width(), min(parentBox.height(), bounds.height()))); bounds.setWidth(bounds.height()); - TCHAR buffer[MAX_PATH]; - UINT length = ::GetSystemDirectory(buffer, ARRAYSIZE(buffer)); - if (!length) - return 0; + // Center the decoration vertically. Round up though, so if it has to be one pixel off-center, it will + // be one pixel closer to the bottom of the field. This tends to look better with the text. + bounds.setY(parentBox.y() + (parentBox.height() - bounds.height() + 1) / 2); - if (_tcscat_s(buffer, TEXT("\\shell32.dll"))) - return 0; - - HICON hIcon; - if (!::ExtractIconEx(buffer, shell32MagnifierIconIndex, 0, &hIcon, 1)) - return 0; - - RefPtr<Icon> icon = Icon::create(hIcon); - icon->paint(paintInfo.context, bounds); + static Image* magnifierImage = Image::loadPlatformResource("searchMagnifier").releaseRef(); + paintInfo.context->drawImage(magnifierImage, bounds); return false; } void RenderThemeWin::adjustSearchFieldResultsButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const { - IntSize magnifierSize(15, 11); - style->setWidth(Length(magnifierSize.width(), Fixed)); - style->setHeight(Length(magnifierSize.height(), Fixed)); + // Scale the button size based on the font size + float fontScale = style->fontSize() / defaultControlFontPixelSize; + int magnifierHeight = lroundf(min(max(minSearchFieldResultsDecorationSize, defaultSearchFieldResultsDecorationSize * fontScale), + maxSearchFieldResultsDecorationSize)); + int magnifierWidth = lroundf(magnifierHeight * defaultSearchFieldResultsButtonWidth / defaultSearchFieldResultsDecorationSize); + style->setWidth(Length(magnifierWidth, Fixed)); + style->setHeight(Length(magnifierHeight, Fixed)); } bool RenderThemeWin::paintSearchFieldResultsButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) { - paintSearchFieldResultsDecoration(o, paintInfo, r); + IntRect bounds = r; + ASSERT(o->parent()); + if (!o->parent()) + return false; + if (!o->parent() || !o->parent()->isBox()) + return false; + + RenderBox* parentRenderBox = toRenderBox(o->parent()); + IntRect parentBox = parentRenderBox->absoluteContentBox(); + + // Make sure the scaled decoration will fit in its parent's box + bounds.setHeight(min(parentBox.height(), bounds.height())); + bounds.setWidth(min(parentBox.width(), static_cast<int>(bounds.height() * defaultSearchFieldResultsButtonWidth / defaultSearchFieldResultsDecorationSize))); + + // Center the button vertically. Round up though, so if it has to be one pixel off-center, it will + // be one pixel closer to the bottom of the field. This tends to look better with the text. + bounds.setY(parentBox.y() + (parentBox.height() - bounds.height() + 1) / 2); + + static Image* magnifierImage = Image::loadPlatformResource("searchMagnifierResults").releaseRef(); + paintInfo.context->drawImage(magnifierImage, bounds); return false; } @@ -802,7 +885,9 @@ static int cssValueIdToSysColorIndex(int cssValueId) Color RenderThemeWin::systemColor(int cssValueId) const { int sysColorIndex = cssValueIdToSysColorIndex(cssValueId); - ASSERT(sysColorIndex != -1); + if (sysColorIndex == -1) + return RenderTheme::systemColor(cssValueId); + COLORREF color = GetSysColor(sysColorIndex); return Color(GetRValue(color), GetGValue(color), GetBValue(color)); } diff --git a/WebCore/rendering/RenderThemeWin.h b/WebCore/rendering/RenderThemeWin.h index 513f6b5..5d5bd4b 100644 --- a/WebCore/rendering/RenderThemeWin.h +++ b/WebCore/rendering/RenderThemeWin.h @@ -50,7 +50,10 @@ class RenderThemeWin : public RenderTheme { public: RenderThemeWin(); ~RenderThemeWin(); - + + virtual String extraDefaultStyleSheet(); + virtual String extraQuirksStyleSheet(); + // A method asking if the theme's controls actually care about redrawing when hovered. virtual bool supportsHover(const RenderStyle*) const; @@ -89,6 +92,8 @@ public: virtual bool paintSliderThumb(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r); virtual void adjustSliderThumbSize(RenderObject*) const; + virtual void adjustButtonInnerStyle(RenderStyle*) const; + virtual void adjustSearchFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const; virtual bool paintSearchField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); @@ -112,6 +117,8 @@ public: static void setWebKitIsBeingUnloaded(); + virtual bool supportsFocusRing(const RenderStyle*) const; + private: void addIntrinsicMargins(RenderStyle*) const; void close(); @@ -121,7 +128,7 @@ private: unsigned determineSliderThumbState(RenderObject*); unsigned determineButtonState(RenderObject*); - bool supportsFocus(ControlPart); + bool supportsFocus(ControlPart) const; ThemeData getThemeData(RenderObject*); ThemeData getClassicThemeData(RenderObject* o); diff --git a/WebCore/rendering/RenderTreeAsText.cpp b/WebCore/rendering/RenderTreeAsText.cpp index 346968b..cf7e027 100644 --- a/WebCore/rendering/RenderTreeAsText.cpp +++ b/WebCore/rendering/RenderTreeAsText.cpp @@ -34,6 +34,7 @@ #include "HTMLNames.h" #include "InlineTextBox.h" #include "RenderBR.h" +#include "RenderInline.h" #include "RenderListMarker.h" #include "RenderTableCell.h" #include "RenderView.h" @@ -69,7 +70,7 @@ static void writeIndent(TextStream& ts, int indent) ts << " "; } -static void printBorderStyle(TextStream& ts, const RenderObject& o, const EBorderStyle borderStyle) +static void printBorderStyle(TextStream& ts, const EBorderStyle borderStyle) { switch (borderStyle) { case BNONE: @@ -180,7 +181,37 @@ static TextStream &operator<<(TextStream& ts, const RenderObject& o) } } - IntRect r(o.xPos(), o.yPos(), o.width(), o.height()); + bool adjustForTableCells = o.containingBlock()->isTableCell(); + + IntRect r; + if (o.isText()) { + // FIXME: Would be better to dump the bounding box x and y rather than the first run's x and y, but that would involve updating + // many test results. + const RenderText& text = *toRenderText(&o); + IntRect linesBox = text.linesBoundingBox(); + r = IntRect(text.firstRunX(), text.firstRunY(), linesBox.width(), linesBox.height()); + if (adjustForTableCells && !text.firstTextBox()) + adjustForTableCells = false; + } else if (o.isBox()) { + if (o.isRenderInline()) { + // FIXME: Would be better not to just dump 0, 0 as the x and y here. + const RenderInline& inlineFlow = static_cast<const RenderInline&>(o); + r = IntRect(0, 0, inlineFlow.linesBoundingBox().width(), inlineFlow.linesBoundingBox().height()); + adjustForTableCells = false; + } else if (o.isTableCell()) { + // FIXME: Deliberately dump the "inner" box of table cells, since that is what current results reflect. We'd like + // to clean up the results to dump both the outer box and the intrinsic padding so that both bits of information are + // captured by the results. + const RenderTableCell& cell = static_cast<const RenderTableCell&>(o); + r = IntRect(cell.x(), cell.y() + cell.intrinsicPaddingTop(), cell.width(), cell.height() - cell.intrinsicPaddingTop() - cell.intrinsicPaddingBottom()); + } else + r = toRenderBox(&o)->frameRect(); + } + + // FIXME: Temporary in order to ensure compatibility with existing layout test results. + if (adjustForTableCells) + r.move(0, -static_cast<RenderTableCell*>(o.containingBlock())->intrinsicPaddingTop()); + ts << " " << r; if (!(o.isText() && !o.isBR())) { @@ -206,17 +237,21 @@ static TextStream &operator<<(TextStream& ts, const RenderObject& o) o.style()->textStrokeWidth() > 0) ts << " [textStrokeWidth=" << o.style()->textStrokeWidth() << "]"; - if (o.borderTop() || o.borderRight() || o.borderBottom() || o.borderLeft()) { + if (!o.isBox()) + return ts; + + const RenderBox& box = *toRenderBox(&o); + if (box.borderTop() || box.borderRight() || box.borderBottom() || box.borderLeft()) { ts << " [border:"; BorderValue prevBorder; if (o.style()->borderTop() != prevBorder) { prevBorder = o.style()->borderTop(); - if (!o.borderTop()) + if (!box.borderTop()) ts << " none"; else { - ts << " (" << o.borderTop() << "px "; - printBorderStyle(ts, o, o.style()->borderTopStyle()); + ts << " (" << box.borderTop() << "px "; + printBorderStyle(ts, o.style()->borderTopStyle()); Color col = o.style()->borderTopColor(); if (!col.isValid()) col = o.style()->color(); @@ -226,11 +261,11 @@ static TextStream &operator<<(TextStream& ts, const RenderObject& o) if (o.style()->borderRight() != prevBorder) { prevBorder = o.style()->borderRight(); - if (!o.borderRight()) + if (!box.borderRight()) ts << " none"; else { - ts << " (" << o.borderRight() << "px "; - printBorderStyle(ts, o, o.style()->borderRightStyle()); + ts << " (" << box.borderRight() << "px "; + printBorderStyle(ts, o.style()->borderRightStyle()); Color col = o.style()->borderRightColor(); if (!col.isValid()) col = o.style()->color(); @@ -239,12 +274,12 @@ static TextStream &operator<<(TextStream& ts, const RenderObject& o) } if (o.style()->borderBottom() != prevBorder) { - prevBorder = o.style()->borderBottom(); - if (!o.borderBottom()) + prevBorder = box.style()->borderBottom(); + if (!box.borderBottom()) ts << " none"; else { - ts << " (" << o.borderBottom() << "px "; - printBorderStyle(ts, o, o.style()->borderBottomStyle()); + ts << " (" << box.borderBottom() << "px "; + printBorderStyle(ts, o.style()->borderBottomStyle()); Color col = o.style()->borderBottomColor(); if (!col.isValid()) col = o.style()->color(); @@ -254,11 +289,11 @@ static TextStream &operator<<(TextStream& ts, const RenderObject& o) if (o.style()->borderLeft() != prevBorder) { prevBorder = o.style()->borderLeft(); - if (!o.borderLeft()) + if (!box.borderLeft()) ts << " none"; else { - ts << " (" << o.borderLeft() << "px "; - printBorderStyle(ts, o, o.style()->borderLeftStyle()); + ts << " (" << box.borderLeft() << "px "; + printBorderStyle(ts, o.style()->borderLeftStyle()); Color col = o.style()->borderLeftColor(); if (!col.isValid()) col = o.style()->color(); @@ -304,14 +339,18 @@ static TextStream &operator<<(TextStream& ts, const RenderObject& o) static void writeTextRun(TextStream& ts, const RenderText& o, const InlineTextBox& run) { - ts << "text run at (" << run.m_x << "," << run.m_y << ") width " << run.m_width; + // FIXME: Table cell adjustment is temporary until results can be updated. + int y = run.m_y; + if (o.containingBlock()->isTableCell()) + y -= static_cast<RenderTableCell*>(o.containingBlock())->intrinsicPaddingTop(); + ts << "text run at (" << run.m_x << "," << y << ") width " << run.m_width; if (run.direction() == RTL || run.m_dirOverride) { ts << (run.direction() == RTL ? " RTL" : " LTR"); if (run.m_dirOverride) ts << " override"; } ts << ": " - << quoteAndEscapeNonPrintables(String(o.text()).substring(run.m_start, run.m_len)) + << quoteAndEscapeNonPrintables(String(o.text()).substring(run.start(), run.len())) << "\n"; } @@ -344,7 +383,7 @@ void write(TextStream& ts, const RenderObject& o, int indent) ts << o << "\n"; if (o.isText() && !o.isBR()) { - const RenderText& text = static_cast<const RenderText&>(o); + const RenderText& text = *toRenderText(&o); for (InlineTextBox* box = text.firstTextBox(); box; box = box->nextTextBox()) { writeIndent(ts, indent + 1); writeTextRun(ts, text, *box); @@ -361,7 +400,7 @@ void write(TextStream& ts, const RenderObject& o, int indent) Widget* widget = static_cast<const RenderWidget&>(o).widget(); if (widget && widget->isFrameView()) { FrameView* view = static_cast<FrameView*>(widget); - RenderObject* root = view->frame()->contentRenderer(); + RenderView* root = view->frame()->contentRenderer(); if (root) { view->layout(); RenderLayer* l = root->layer(); @@ -416,7 +455,7 @@ static void writeLayers(TextStream& ts, const RenderLayer* rootLayer, RenderLaye { // Calculate the clip rects we should use. IntRect layerBounds, damageRect, clipRectToApply, outlineRect; - l->calculateRects(rootLayer, paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect); + l->calculateRects(rootLayer, paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect, true); // Ensure our lists are up-to-date. l->updateZOrderLists(); @@ -501,8 +540,8 @@ String externalRepresentation(RenderObject* o) #endif if (o->view()->frameView()) o->view()->frameView()->layout(); - RenderLayer* l = o->layer(); - if (l) { + if (o->hasLayer()) { + RenderLayer* l = toRenderBox(o)->layer(); writeLayers(ts, l, l, IntRect(l->xPos(), l->yPos(), l->width(), l->height())); writeSelection(ts, o); } diff --git a/WebCore/rendering/RenderVideo.cpp b/WebCore/rendering/RenderVideo.cpp index d677725..be75997 100644 --- a/WebCore/rendering/RenderVideo.cpp +++ b/WebCore/rendering/RenderVideo.cpp @@ -68,7 +68,7 @@ void RenderVideo::videoSizeChanged() IntRect RenderVideo::videoBox() const { - IntRect contentRect = contentBox(); + IntRect contentRect = contentBoxRect(); if (intrinsicSize().isEmpty() || contentRect.isEmpty()) return IntRect(); @@ -124,11 +124,11 @@ void RenderVideo::updatePlayer() mediaPlayer->setVisible(false); return; } - int x; - int y; - absolutePosition(x, y); + + // FIXME: This doesn't work correctly with transforms. + FloatPoint absPos = localToAbsolute(); IntRect videoBounds = videoBox(); - videoBounds.move(x, y); + videoBounds.move(absPos.x(), absPos.y()); mediaPlayer->setFrameView(document()->view()); mediaPlayer->setRect(videoBounds); mediaPlayer->setVisible(true); @@ -174,7 +174,7 @@ int RenderVideo::calcReplacedWidth(bool includeMaxWidth) const if (isWidthSpecified()) width = calcReplacedWidthUsing(style()->width()); else - width = calcAspectRatioWidth(); + width = calcAspectRatioWidth() * style()->effectiveZoom(); int minW = calcReplacedWidthUsing(style()->minWidth()); int maxW = !includeMaxWidth || style()->maxWidth().isUndefined() ? width : calcReplacedWidthUsing(style()->maxWidth()); @@ -188,7 +188,7 @@ int RenderVideo::calcReplacedHeight() const if (isHeightSpecified()) height = calcReplacedHeightUsing(style()->height()); else - height = calcAspectRatioHeight(); + height = calcAspectRatioHeight() * style()->effectiveZoom(); int minH = calcReplacedHeightUsing(style()->minHeight()); int maxH = style()->maxHeight().isUndefined() ? height : calcReplacedHeightUsing(style()->maxHeight()); diff --git a/WebCore/rendering/RenderView.cpp b/WebCore/rendering/RenderView.cpp index a447bc8..7ce4998 100644 --- a/WebCore/rendering/RenderView.cpp +++ b/WebCore/rendering/RenderView.cpp @@ -1,8 +1,6 @@ -/** - * This file is part of the HTML widget for KDE. - * +/* * Copyright (C) 1999 Lars Knoll (knoll@kde.org) - * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. + * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -25,6 +23,7 @@ #include "Document.h" #include "Element.h" +#include "FloatQuad.h" #include "Frame.h" #include "FrameView.h" #include "GraphicsContext.h" @@ -54,10 +53,7 @@ RenderView::RenderView(Node* node, FrameView* view) // init RenderObject attributes setInline(false); - - // try to contrain the width to the views width - m_width = 0; - m_height = 0; + m_minPrefWidth = 0; m_maxPrefWidth = 0; @@ -77,20 +73,20 @@ RenderView::~RenderView() void RenderView::calcHeight() { if (!printing() && m_frameView) - m_height = viewHeight(); + setHeight(viewHeight()); } void RenderView::calcWidth() { if (!printing() && m_frameView) - m_width = viewWidth(); + setWidth(viewWidth()); #ifdef ANDROID_LAYOUT const Settings * settings = document()->settings(); ASSERT(settings); if (settings->layoutAlgorithm() == Settings::kLayoutFitColumnToScreen) m_visibleWidth = m_frameView->screenWidth(); - if (settings->useWideViewport() && settings->viewportWidth() == -1 && m_width < minPrefWidth()) - m_width = m_minPrefWidth; + if (settings->useWideViewport() && settings->viewportWidth() == -1 && width() < minPrefWidth()) + setWidth(m_minPrefWidth); #endif m_marginLeft = 0; m_marginRight = 0; @@ -108,10 +104,10 @@ void RenderView::calcPrefWidths() void RenderView::layout() { if (printing()) - m_minPrefWidth = m_maxPrefWidth = m_width; + m_minPrefWidth = m_maxPrefWidth = width(); // Use calcWidth/Height to get the new width/height, since this will take the full page zoom factor into account. - bool relayoutChildren = !printing() && (!m_frameView || m_width != viewWidth() || m_height != viewHeight()); + bool relayoutChildren = !printing() && (!m_frameView || width() != viewWidth() || height() != viewHeight()); if (relayoutChildren) { setChildNeedsLayout(true, false); for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { @@ -130,8 +126,8 @@ void RenderView::layout() RenderBlock::layout(); // Ensure that docWidth() >= width() and docHeight() >= height(). - setOverflowWidth(m_width); - setOverflowHeight(m_height); + setOverflowWidth(width()); + setOverflowHeight(height()); setOverflowWidth(docWidth()); setOverflowHeight(docHeight()); @@ -143,20 +139,39 @@ void RenderView::layout() setNeedsLayout(false); } -bool RenderView::absolutePosition(int& xPos, int& yPos, bool fixed) const +FloatPoint RenderView::localToAbsolute(FloatPoint localPoint, bool fixed, bool) const +{ + // This disables the css position:fixed to the Browser window. Instead + // the fixed element will be always fixed to the top page. +#ifndef ANDROID_DISABLE_POSITION_FIXED + if (fixed && m_frameView) + localPoint += m_frameView->scrollOffset(); +#endif + return localPoint; +} + +FloatPoint RenderView::absoluteToLocal(FloatPoint containerPoint, bool fixed, bool) const { - if (fixed && m_frameView) { -#ifdef ANDROID_DISABLE_POSITION_FIXED - // This disables the css position:fixed to the Browser window. Instead - // the fixed element will be always fixed to the top page. - xPos = yPos = 0; -#else - xPos = m_frameView->scrollX(); - yPos = m_frameView->scrollY(); + // This disables the css position:fixed to the Browser window. Instead + // the fixed element will be always fixed to the top page. +#ifndef ANDROID_DISABLE_POSITION_FIXED + if (fixed && m_frameView) + containerPoint -= m_frameView->scrollOffset(); #endif - } else - xPos = yPos = 0; - return true; + return containerPoint; +} + +FloatQuad RenderView::localToContainerQuad(const FloatQuad& localQuad, RenderBox* repaintContainer, bool fixed) const +{ + // If a container was specified, and was not 0 or the RenderView, + // then we should have found it by now. + ASSERT_UNUSED(repaintContainer, !repaintContainer || repaintContainer == this); + + FloatQuad quad = localQuad; + if (fixed && m_frameView) + quad += m_frameView->scrollOffset(); + + return quad; } void RenderView::paint(PaintInfo& paintInfo, int tx, int ty) @@ -172,7 +187,12 @@ void RenderView::paint(PaintInfo& paintInfo, int tx, int ty) paintObject(paintInfo, tx, ty); } -void RenderView::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty) +static inline bool rendererObscuresBackground(RenderObject* object) +{ + return object && object->style()->visibility() == VISIBLE && object->style()->opacity() == 1 && !object->style()->hasTransform(); +} + +void RenderView::paintBoxDecorations(PaintInfo& paintInfo, int, int) { // Check to see if we are enclosed by a layer that requires complex painting rules. If so, we cannot blit // when scrolling, and we need to use slow repaints. Examples of layers that require this are transparent layers, @@ -188,10 +208,12 @@ void RenderView::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty) } } - if (elt || (firstChild() && firstChild()->style()->visibility() == VISIBLE) || !view()) + // If painting will entirely fill the view, no need to fill the background. + if (elt || rendererObscuresBackground(firstChild()) || !view()) return; - // This code typically only executes if the root element's visibility has been set to hidden. + // This code typically only executes if the root element's visibility has been set to hidden, + // or there is a transform on the <html>. // 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 (view()->isTransparent()) // FIXME: This needs to be dynamic. We should be able to go back to blitting if we ever stop being transparent. @@ -221,7 +243,7 @@ void RenderView::repaintViewRectangle(const IntRect& ur, bool immediate) Element* elt = document()->ownerElement(); if (!elt) m_frameView->repaintContentRectangle(ur, immediate); - else if (RenderObject* obj = elt->renderer()) { + else if (RenderBox* obj = elt->renderBox()) { IntRect vr = viewRect(); IntRect r = intersection(ur, vr); @@ -236,8 +258,12 @@ void RenderView::repaintViewRectangle(const IntRect& ur, bool immediate) } } -void RenderView::computeAbsoluteRepaintRect(IntRect& rect, bool fixed) +void RenderView::computeRectForRepaint(IntRect& rect, RenderBox* repaintContainer, bool fixed) { + // If a container was specified, and was not 0 or the RenderView, + // then we should have found it by now. + ASSERT_UNUSED(repaintContainer, !repaintContainer || repaintContainer == this); + if (printing()) return; @@ -254,7 +280,12 @@ void RenderView::absoluteRects(Vector<IntRect>& rects, int tx, int ty, bool) rects.append(IntRect(tx, ty, m_layer->width(), m_layer->height())); } -RenderObject* rendererAfterPosition(RenderObject* object, unsigned offset) +void RenderView::absoluteQuads(Vector<FloatQuad>& quads, bool) +{ + quads.append(FloatRect(0, 0, m_layer->width(), m_layer->height())); +} + +static RenderObject* rendererAfterPosition(RenderObject* object, unsigned offset) { if (!object) return 0; @@ -263,7 +294,17 @@ RenderObject* rendererAfterPosition(RenderObject* object, unsigned offset) return child ? child : object->nextInPreOrderAfterChildren(); } -IntRect RenderView::selectionRect(bool clipToVisibleContent) const +IntRect RenderView::selectionRect(bool clipToVisibleContent) +{ + // The virtual selectionRect() should never be called on the RenderView. + // We assert because there used to be ambiguity between + // RenderView::selectionRect(bool) and + // virtual RenderObject::selectionRect(bool) const + ASSERT_NOT_REACHED(); + return RenderBlock::selectionRect(clipToVisibleContent); +} + +IntRect RenderView::selectionBounds(bool clipToVisibleContent) const { document()->updateRendering(); @@ -495,7 +536,7 @@ void RenderView::removeWidget(RenderObject* o) IntRect RenderView::viewRect() const { if (printing()) - return IntRect(0, 0, m_width, m_height); + return IntRect(0, 0, width(), height()); if (m_frameView) return m_frameView->visibleContentRect(); return IntRect(); @@ -503,7 +544,7 @@ IntRect RenderView::viewRect() const int RenderView::docHeight() const { - int h = m_height; + int h = height(); int lowestPos = lowestPosition(); if (lowestPos > h) h = lowestPos; @@ -512,7 +553,7 @@ int RenderView::docHeight() const // Instead of this dh computation we should keep the result // when we call RenderBlock::layout. int dh = 0; - for (RenderObject* c = firstChild(); c; c = c->nextSibling()) + for (RenderBox* c = firstChildBox(); c; c = c->nextSiblingBox()) dh += c->height() + c->marginTop() + c->marginBottom(); if (dh > h) @@ -523,12 +564,12 @@ int RenderView::docHeight() const int RenderView::docWidth() const { - int w = m_width; + int w = width(); int rightmostPos = rightmostPosition(); if (rightmostPos > w) w = rightmostPos; - - for (RenderObject *c = firstChild(); c; c = c->nextSibling()) { + + for (RenderBox* c = firstChildBox(); c; c = c->nextSiblingBox()) { int dw = c->width() + c->marginLeft() + c->marginRight(); if (dw > w) w = dw; @@ -540,22 +581,26 @@ int RenderView::docWidth() const int RenderView::viewHeight() const { int height = 0; - if (!printing() && m_frameView) - height = m_frameView->visibleHeight(); + if (!printing() && m_frameView) { + height = m_frameView->layoutHeight(); + height = m_frameView->useFixedLayout() ? ceilf(style()->effectiveZoom() * float(height)) : height; + } return height; } int RenderView::viewWidth() const { int width = 0; - if (!printing() && m_frameView) - width = m_frameView->visibleWidth(); + if (!printing() && m_frameView) { + width = m_frameView->layoutWidth(); + width = m_frameView->useFixedLayout() ? ceilf(style()->effectiveZoom() * float(width)) : width; + } return width; } // The idea here is to take into account what object is moving the pagination point, and // thus choose the best place to chop it. -void RenderView::setBestTruncatedAt(int y, RenderObject* forRenderer, bool forcedBreak) +void RenderView::setBestTruncatedAt(int y, RenderBox* forRenderer, bool forcedBreak) { // Nobody else can set a page break once we have a forced break. if (m_forcedPageBreak) @@ -569,16 +614,15 @@ void RenderView::setBestTruncatedAt(int y, RenderObject* forRenderer, bool force } // prefer the widest object who tries to move the pagination point - int width = forRenderer->width(); - if (width > m_truncatorWidth) { - m_truncatorWidth = width; + if (forRenderer->width() > m_truncatorWidth) { + m_truncatorWidth = forRenderer->width(); m_bestTruncatedAt = y; } } void RenderView::pushLayoutState(RenderObject* root) { - ASSERT(!m_frameView->needsFullRepaint()); + ASSERT(!doingFullRepaint()); ASSERT(m_layoutStateDisableCount == 0); ASSERT(m_layoutState == 0); diff --git a/WebCore/rendering/RenderView.h b/WebCore/rendering/RenderView.h index b437cd1..8e7bf95 100644 --- a/WebCore/rendering/RenderView.h +++ b/WebCore/rendering/RenderView.h @@ -44,12 +44,13 @@ public: virtual void calcWidth(); virtual void calcHeight(); virtual void calcPrefWidths(); - virtual bool absolutePosition(int& xPos, int& yPos, bool fixed = false) const; + virtual FloatPoint localToAbsolute(FloatPoint localPoint = FloatPoint(), bool fixed = false, bool useTransforms = false) const; + virtual FloatPoint absoluteToLocal(FloatPoint containerPoint, bool fixed = false, bool useTransforms = false) const; int docHeight() const; int docWidth() const; - // The same as the FrameView's visibleHeight/visibleWidth but with null check guards. + // The same as the FrameView's layoutHeight/layoutWidth but with null check guards. int viewHeight() const; int viewWidth() const; @@ -59,7 +60,7 @@ public: virtual bool hasOverhangingFloats() { return false; } - virtual void computeAbsoluteRepaintRect(IntRect&, bool fixed = false); + virtual void computeRectForRepaint(IntRect&, RenderBox* repaintContainer, bool fixed = false); virtual void repaintViewRectangle(const IntRect&, bool immediate = false); virtual void paint(PaintInfo&, int tx, int ty); @@ -74,14 +75,15 @@ public: void setPrintImages(bool enable) { m_printImages = enable; } bool printImages() const { return m_printImages; } void setTruncatedAt(int y) { m_truncatedAt = y; m_bestTruncatedAt = m_truncatorWidth = 0; m_forcedPageBreak = false; } - void setBestTruncatedAt(int y, RenderObject *forRenderer, bool forcedBreak = false); + void setBestTruncatedAt(int y, RenderBox* forRenderer, bool forcedBreak = false); int bestTruncatedAt() const { return m_bestTruncatedAt; } int truncatedAt() const { return m_truncatedAt; } virtual void absoluteRects(Vector<IntRect>&, int tx, int ty, bool topLevel = true); + virtual void absoluteQuads(Vector<FloatQuad>&, bool topLevel = true); - IntRect selectionRect(bool clipToVisibleContent = true) const; + IntRect selectionBounds(bool clipToVisibleContent = true) const; void setMaximalOutlineSize(int o) { m_maximalOutlineSize = o; } int maximalOutlineSize() const { return m_maximalOutlineSize; } @@ -98,14 +100,25 @@ public: void removeWidget(RenderObject*); // layoutDelta is used transiently during layout to store how far an object has moved from its - // last layout location, in order to repaint correctly - const IntSize& layoutDelta() const { return m_layoutDelta; } - void addLayoutDelta(const IntSize& delta) { m_layoutDelta += delta; } + // last layout location, in order to repaint correctly. + // If we're doing a full repaint m_layoutState will be 0, but in that case layoutDelta doesn't matter. + IntSize layoutDelta() const + { + return m_layoutState ? m_layoutState->m_layoutDelta : IntSize(); + } + void addLayoutDelta(const IntSize& delta) + { + if (m_layoutState) + m_layoutState->m_layoutDelta += delta; + } + + bool doingFullRepaint() const { return m_frameView->needsFullRepaint(); } void pushLayoutState(RenderBox* renderer, const IntSize& offset) { - if (m_layoutStateDisableCount || m_frameView->needsFullRepaint()) + if (doingFullRepaint()) return; + // We push LayoutState even if layoutState is disabled because it stores layoutDelta too. m_layoutState = new (renderArena()) LayoutState(m_layoutState, renderer, offset); } @@ -113,22 +126,32 @@ public: void popLayoutState() { - if (m_layoutStateDisableCount || m_frameView->needsFullRepaint()) + if (doingFullRepaint()) return; LayoutState* state = m_layoutState; m_layoutState = state->m_next; state->destroy(renderArena()); } - LayoutState* layoutState() const { return m_layoutStateDisableCount ? 0 : m_layoutState; } + // Returns true if layoutState should be used for its cached offset and clip. + bool layoutStateEnabled() const { return m_layoutStateDisableCount == 0 && m_layoutState; } + LayoutState* layoutState() const { return m_layoutState; } // Suspends the LayoutState optimization. Used under transforms that cannot be represented by // LayoutState (common in SVG) and when manipulating the render tree during layout in ways // that can trigger repaint of a non-child (e.g. when a list item moves its list marker around). + // Note that even when disabled, LayoutState is still used to store layoutDelta. void disableLayoutState() { m_layoutStateDisableCount++; } void enableLayoutState() { ASSERT(m_layoutStateDisableCount > 0); m_layoutStateDisableCount--; } protected: + virtual FloatQuad localToContainerQuad(const FloatQuad&, RenderBox* repaintContainer, bool fixed = false) const; + +private: + // selectionRect should never be called on a RenderView + virtual IntRect selectionRect(bool); + +protected: FrameView* m_frameView; RenderObject* m_selectionStart; @@ -151,11 +174,67 @@ private: int m_bestTruncatedAt; int m_truncatorWidth; bool m_forcedPageBreak; - IntSize m_layoutDelta; LayoutState* m_layoutState; unsigned m_layoutStateDisableCount; }; +// Stack-based class to assist with LayoutState push/pop +class LayoutStateMaintainer : Noncopyable { +public: + // ctor to push now + LayoutStateMaintainer(RenderView* view, RenderBox* root, IntSize offset, bool disableState = false) + : m_view(view) + , m_disabled(disableState) + , m_didStart(false) + , m_didEnd(false) + { + push(root, offset); + } + + // ctor to maybe push later + LayoutStateMaintainer(RenderView* view) + : m_view(view) + , m_disabled(false) + , m_didStart(false) + , m_didEnd(false) + { + } + + ~LayoutStateMaintainer() + { + ASSERT(m_didStart == m_didEnd); // if this fires, it means that someone did a push(), but forgot to pop(). + } + + void push(RenderBox* root, IntSize offset) + { + ASSERT(!m_didStart); + // We push state even if disabled, because we still need to store layoutDelta + m_view->pushLayoutState(root, offset); + if (m_disabled) + m_view->disableLayoutState(); + m_didStart = true; + } + + void pop() + { + if (m_didStart) { + ASSERT(!m_didEnd); + m_view->popLayoutState(); + if (m_disabled) + m_view->enableLayoutState(); + m_didEnd = true; + } + } + + bool didPush() const { return m_didStart; } + +private: + RenderView* m_view; + bool m_disabled : 1; // true if the offset and clip part of layoutState is disabled + bool m_didStart : 1; // true if we did a push or disable + bool m_didEnd : 1; // true if we popped or re-enabled +}; + } // namespace WebCore #endif // RenderView_h diff --git a/WebCore/rendering/RenderWidget.cpp b/WebCore/rendering/RenderWidget.cpp index 57b8722..9bf8111 100644 --- a/WebCore/rendering/RenderWidget.cpp +++ b/WebCore/rendering/RenderWidget.cpp @@ -75,9 +75,10 @@ void RenderWidget::destroy() if (RenderView* v = view()) v->removeWidget(this); - if (AXObjectCache::accessibilityEnabled()) + if (AXObjectCache::accessibilityEnabled()) { + document()->axObjectCache()->childrenChanged(this->parent()); document()->axObjectCache()->remove(this); - + } remove(); if (m_widget) { @@ -94,7 +95,7 @@ void RenderWidget::destroy() RenderArena* arena = renderArena(); if (layer) - layer->clearClipRect(); + layer->clearClipRects(); if (style() && (style()->height().isPercent() || style()->minHeight().isPercent() || style()->maxHeight().isPercent())) RenderBlock::removePercentHeightDescendant(this); @@ -172,8 +173,8 @@ void RenderWidget::paint(PaintInfo& paintInfo, int tx, int ty) if (!shouldPaint(paintInfo, tx, ty)) return; - tx += m_x; - ty += m_y; + tx += x(); + ty += y(); if (hasBoxDecorations() && (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection)) paintBoxDecorations(paintInfo, tx, ty); @@ -188,7 +189,7 @@ void RenderWidget::paint(PaintInfo& paintInfo, int tx, int ty) #if PLATFORM(MAC) if (style()->highlight() != nullAtom && !paintInfo.context->paintingDisabled()) - paintCustomHighlight(tx - m_x, ty - m_y, style()->highlight(), true); + paintCustomHighlight(tx - x(), ty - y(), style()->highlight(), true); #endif if (m_widget) { @@ -218,16 +219,14 @@ void RenderWidget::updateWidgetPosition() if (!m_widget) return; - int x; - int y; - absolutePosition(x, y); - x += borderLeft() + paddingLeft(); - y += borderTop() + paddingTop(); + // FIXME: This doesn't work correctly with transforms. + FloatPoint absPos = localToAbsolute(); + absPos.move(borderLeft() + paddingLeft(), borderTop() + paddingTop()); - int width = m_width - borderLeft() - borderRight() - paddingLeft() - paddingRight(); - int height = m_height - borderTop() - borderBottom() - paddingTop() - paddingBottom(); + int w = width() - borderLeft() - borderRight() - paddingLeft() - paddingRight(); + int h = height() - borderTop() - borderBottom() - paddingTop() - paddingBottom(); - IntRect newBounds(x, y, width, height); + IntRect newBounds(absPos.x(), absPos.y(), w, h); IntRect oldBounds(m_widget->frameRect()); if (newBounds != oldBounds) { // The widget changed positions. Update the frame geometry. @@ -273,7 +272,7 @@ bool RenderWidget::nodeAtPoint(const HitTestRequest& request, HitTestResult& res // Check to see if we are really over the widget itself (and not just in the border/padding area). if (inside && !hadResult && result.innerNode() == element()) - result.setIsOverWidget(contentBox().contains(result.localPoint())); + result.setIsOverWidget(contentBoxRect().contains(result.localPoint())); return inside; } diff --git a/WebCore/rendering/RootInlineBox.cpp b/WebCore/rendering/RootInlineBox.cpp index e98d20e..6d42aa7 100644 --- a/WebCore/rendering/RootInlineBox.cpp +++ b/WebCore/rendering/RootInlineBox.cpp @@ -187,7 +187,7 @@ void RootInlineBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty) bool RootInlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty) { - if (m_hasEllipsisBox && object()->style()->visibility() == VISIBLE) { + if (m_hasEllipsisBox && visibleToHitTesting()) { if (ellipsisBox()->nodeAtPoint(request, result, x, y, tx, ty)) { object()->updateHitTestResult(result, IntPoint(x - tx, y - ty)); return true; @@ -240,18 +240,28 @@ GapRects RootInlineBox::fillLineSelectionGap(int selTop, int selHeight, RenderBl lastBox->xPos() + lastBox->width(), selTop, selHeight, rootBlock, blockX, blockY, tx, ty, paintInfo)); + // When dealing with bidi text, a non-contiguous selection region is possible. + // e.g. The logical text aaaAAAbbb (capitals denote RTL text and non-capitals LTR) is layed out + // visually as 3 text runs |aaa|bbb|AAA| if we select 4 characters from the start of the text the + // selection will look like (underline denotes selection): + // |aaa|bbb|AAA| + // ___ _ + // We can see that the |bbb| run is not part of the selection while the runs around it are. if (firstBox && firstBox != lastBox) { // Now fill in any gaps on the line that occurred between two selected elements. int lastX = firstBox->xPos() + firstBox->width(); + bool isPreviousBoxSelected = firstBox->selectionState() != RenderObject::SelectionNone; for (InlineBox* box = firstBox->nextLeafChild(); box; box = box->nextLeafChild()) { if (box->selectionState() != RenderObject::SelectionNone) { - result.uniteCenter(block()->fillHorizontalSelectionGap(box->parent()->object(), - lastX + tx, selTop + ty, - box->xPos() - lastX, selHeight, paintInfo)); + if (isPreviousBoxSelected) // Selection may be non-contiguous, see comment above. + result.uniteCenter(block()->fillHorizontalSelectionGap(box->parent()->object(), + lastX + tx, selTop + ty, + box->xPos() - lastX, selHeight, paintInfo)); lastX = box->xPos() + box->width(); } if (box == lastBox) break; + isPreviousBoxSelected = box->selectionState() != RenderObject::SelectionNone; } } @@ -332,7 +342,7 @@ RenderBlock* RootInlineBox::block() const return static_cast<RenderBlock*>(m_object); } -bool isEditableLeaf(InlineBox* leaf) +static bool isEditableLeaf(InlineBox* leaf) { return leaf && leaf->object() && leaf->object()->element() && leaf->object()->element()->isContentEditable(); } diff --git a/WebCore/rendering/RootInlineBox.h b/WebCore/rendering/RootInlineBox.h index 4724110..a16d1e5 100644 --- a/WebCore/rendering/RootInlineBox.h +++ b/WebCore/rendering/RootInlineBox.h @@ -119,7 +119,7 @@ public: InlineBox* closestLeafChildForXPos(int x, bool onlyEditableLeaves = false); - Vector<RenderObject*>& floats() + Vector<RenderBox*>& floats() { ASSERT(!isDirty()); if (!m_overflow) @@ -127,7 +127,7 @@ public: return m_overflow->floats; } - Vector<RenderObject*>* floatsPtr() { ASSERT(!isDirty()); return m_overflow ? &m_overflow->floats : 0; } + Vector<RenderBox*>* floatsPtr() { ASSERT(!isDirty()); return m_overflow ? &m_overflow->floats : 0; } protected: // Normally we are only as tall as the style on our block dictates, but we might have content @@ -158,7 +158,7 @@ protected: int m_selectionBottom; // Floats hanging off the line are pushed into this vector during layout. It is only // good for as long as the line has not been marked dirty. - Vector<RenderObject*> floats; + Vector<RenderBox*> floats; private: void* operator new(size_t) throw(); }; diff --git a/WebCore/rendering/SVGCharacterLayoutInfo.cpp b/WebCore/rendering/SVGCharacterLayoutInfo.cpp index 287aeac..89bab2d 100644 --- a/WebCore/rendering/SVGCharacterLayoutInfo.cpp +++ b/WebCore/rendering/SVGCharacterLayoutInfo.cpp @@ -512,9 +512,9 @@ bool SVGChar::isHidden() const return pathData && pathData->hidden; } -AffineTransform SVGChar::characterTransform() const +TransformationMatrix SVGChar::characterTransform() const { - AffineTransform ctm; + TransformationMatrix ctm; // Rotate character around angle, and possibly scale. ctm.translate(x, y); diff --git a/WebCore/rendering/SVGCharacterLayoutInfo.h b/WebCore/rendering/SVGCharacterLayoutInfo.h index f3c5209..0188b9d 100644 --- a/WebCore/rendering/SVGCharacterLayoutInfo.h +++ b/WebCore/rendering/SVGCharacterLayoutInfo.h @@ -29,7 +29,7 @@ #include <wtf/HashSet.h> #include <wtf/Vector.h> -#include "AffineTransform.h" +#include "TransformationMatrix.h" #include <wtf/RefCounted.h> #include "SVGRenderStyle.h" #include "SVGTextContentElement.h" @@ -235,7 +235,7 @@ struct SVGChar { // Helper methods bool isHidden() const; - AffineTransform characterTransform() const; + TransformationMatrix characterTransform() const; }; struct SVGInlineBoxCharacterRange { @@ -276,7 +276,7 @@ struct SVGTextChunk { // textLength & lengthAdjust support float textLength; ELengthAdjust lengthAdjust; - AffineTransform ctm; + TransformationMatrix ctm; // status flags bool isVerticalText : 1; @@ -292,7 +292,7 @@ struct SVGTextChunk { struct SVGTextChunkWalkerBase { virtual ~SVGTextChunkWalkerBase() { } - virtual void operator()(SVGInlineTextBox* textBox, int startOffset, const AffineTransform& chunkCtm, + virtual void operator()(SVGInlineTextBox* textBox, int startOffset, const TransformationMatrix& chunkCtm, const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end) = 0; // Followings methods are only used for painting text chunks @@ -308,7 +308,7 @@ struct SVGTextChunkWalker : public SVGTextChunkWalkerBase { public: typedef void (CallbackClass::*SVGTextChunkWalkerCallback)(SVGInlineTextBox* textBox, int startOffset, - const AffineTransform& chunkCtm, + const TransformationMatrix& chunkCtm, const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end); @@ -336,7 +336,7 @@ public: ASSERT(walker); } - virtual void operator()(SVGInlineTextBox* textBox, int startOffset, const AffineTransform& chunkCtm, + virtual void operator()(SVGInlineTextBox* textBox, int startOffset, const TransformationMatrix& chunkCtm, const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end) { (*m_object.*m_walkerCallback)(textBox, startOffset, chunkCtm, start, end); diff --git a/WebCore/rendering/SVGInlineFlowBox.cpp b/WebCore/rendering/SVGInlineFlowBox.cpp index bbd8f4a..2649664 100644 --- a/WebCore/rendering/SVGInlineFlowBox.cpp +++ b/WebCore/rendering/SVGInlineFlowBox.cpp @@ -32,20 +32,21 @@ namespace WebCore { using namespace SVGNames; -void SVGInlineFlowBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty) +void SVGInlineFlowBox::paint(RenderObject::PaintInfo&, int, int) { ASSERT_NOT_REACHED(); } -int SVGInlineFlowBox::placeBoxesHorizontally(int x, int& leftPosition, int& rightPosition, bool& needsWordSpacing) +int SVGInlineFlowBox::placeBoxesHorizontally(int, int&, int&, bool&) { // no-op return 0; } -void SVGInlineFlowBox::verticallyAlignBoxes(int& heightOfBlock) +int SVGInlineFlowBox::verticallyAlignBoxes(int) { // no-op + return 0; } } // namespace WebCore diff --git a/WebCore/rendering/SVGInlineFlowBox.h b/WebCore/rendering/SVGInlineFlowBox.h index 96c5d4a..bb31807 100644 --- a/WebCore/rendering/SVGInlineFlowBox.h +++ b/WebCore/rendering/SVGInlineFlowBox.h @@ -38,7 +38,7 @@ public: virtual void paint(RenderObject::PaintInfo&, int tx, int ty); virtual int placeBoxesHorizontally(int x, int& leftPosition, int& rightPosition, bool& needsWordSpacing); - virtual void verticallyAlignBoxes(int& heightOfBlock); + virtual int verticallyAlignBoxes(int heightOfBlock); }; } // namespace WebCore diff --git a/WebCore/rendering/SVGInlineTextBox.cpp b/WebCore/rendering/SVGInlineTextBox.cpp index ceb7b0e..620aea5 100644 --- a/WebCore/rendering/SVGInlineTextBox.cpp +++ b/WebCore/rendering/SVGInlineTextBox.cpp @@ -80,10 +80,8 @@ float SVGInlineTextBox::calculateGlyphWidth(RenderStyle* style, int offset, int return style->font().floatWidth(svgTextRunForInlineTextBox(textObject()->text()->characters() + offset, 1, style, this, 0), extraCharsAvailable, charsConsumed, glyphName); } -float SVGInlineTextBox::calculateGlyphHeight(RenderStyle* style, int offset, int extraCharsAvailable) const +float SVGInlineTextBox::calculateGlyphHeight(RenderStyle* style, int, int) const { - ASSERT(style); - // This is just a guess, and the only purpose of this function is to centralize this hack. // In real-life top-top-bottom scripts this won't be enough, I fear. return style->font().ascent() + style->font().descent(); @@ -113,7 +111,7 @@ FloatRect SVGInlineTextBox::calculateGlyphBoundaries(RenderStyle* style, int off FloatRect glyphRect(x1, y1, x2 - x1, y2 - y1); // Take per-character transformations into account - AffineTransform ctm = svgChar.characterTransform(); + TransformationMatrix ctm = svgChar.characterTransform(); if (!ctm.isIdentity()) glyphRect = ctm.mapRect(glyphRect); @@ -131,7 +129,7 @@ struct SVGInlineTextBoxClosestCharacterToPositionWalker { { } - void chunkPortionCallback(SVGInlineTextBox* textBox, int startOffset, const AffineTransform& chunkCtm, + void chunkPortionCallback(SVGInlineTextBox* textBox, int startOffset, const TransformationMatrix& chunkCtm, const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end) { RenderStyle* style = textBox->textObject()->style(); @@ -198,7 +196,7 @@ struct SVGInlineTextBoxSelectionRectWalker { { } - void chunkPortionCallback(SVGInlineTextBox* textBox, int startOffset, const AffineTransform& chunkCtm, + void chunkPortionCallback(SVGInlineTextBox* textBox, int startOffset, const TransformationMatrix& chunkCtm, const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end) { RenderStyle* style = textBox->textObject()->style(); @@ -279,21 +277,21 @@ bool SVGInlineTextBox::svgCharacterHitsPosition(int x, int y, int& offset) const return true; } -int SVGInlineTextBox::offsetForPosition(int x, bool includePartialGlyphs) const +int SVGInlineTextBox::offsetForPosition(int, bool) const { // SVG doesn't use the offset <-> position selection system. ASSERT_NOT_REACHED(); return 0; } -int SVGInlineTextBox::positionForOffset(int offset) const +int SVGInlineTextBox::positionForOffset(int) const { // SVG doesn't use the offset <-> position selection system. ASSERT_NOT_REACHED(); return 0; } -bool SVGInlineTextBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty) +bool SVGInlineTextBox::nodeAtPoint(const HitTestRequest&, HitTestResult& result, int x, int y, int tx, int ty) { ASSERT(!isLineBreak()); @@ -348,11 +346,9 @@ void SVGInlineTextBox::paintCharacters(RenderObject::PaintInfo& paintInfo, int t // Set our font RenderStyle* styleToUse = text->style(isFirstLineStyle()); - const Font* font = &styleToUse->font(); - if (*font != paintInfo.context->font()) - paintInfo.context->setFont(*font); + const Font& font = styleToUse->font(); - AffineTransform ctm = svgChar.characterTransform(); + TransformationMatrix ctm = svgChar.characterTransform(); if (!ctm.isIdentity()) paintInfo.context->concatCTM(ctm); @@ -367,8 +363,8 @@ void SVGInlineTextBox::paintCharacters(RenderObject::PaintInfo& paintInfo, int t if (containsComposition && !useCustomUnderlines) paintCompositionBackground(paintInfo.context, tx, ty, styleToUse, font, - text->document()->frame()->editor()->compositionStart(), - text->document()->frame()->editor()->compositionEnd()); + text->document()->frame()->editor()->compositionStart(), + text->document()->frame()->editor()->compositionEnd()); paintDocumentMarkers(paintInfo.context, tx, ty, styleToUse, font, true); @@ -397,7 +393,7 @@ void SVGInlineTextBox::paintCharacters(RenderObject::PaintInfo& paintInfo, int t run.setActivePaintServer(activePaintServer); #endif - paintInfo.context->drawText(run, origin); + paintInfo.context->drawText(font, run, origin); if (paintInfo.phase != PaintPhaseSelection) { paintDocumentMarkers(paintInfo.context, tx, ty, styleToUse, font, false); @@ -436,7 +432,7 @@ void SVGInlineTextBox::paintCharacters(RenderObject::PaintInfo& paintInfo, int t paintInfo.context->concatCTM(ctm.inverse()); } -void SVGInlineTextBox::paintSelection(int boxStartOffset, const SVGChar& svgChar, const UChar* chars, int length, GraphicsContext* p, RenderStyle* style, const Font* f) +void SVGInlineTextBox::paintSelection(int boxStartOffset, const SVGChar& svgChar, const UChar*, int length, GraphicsContext* p, RenderStyle* style, const Font& font) { if (selectionState() == RenderObject::SelectionNone) return; @@ -475,9 +471,9 @@ void SVGInlineTextBox::paintSelection(int boxStartOffset, const SVGChar& svgChar p->save(); int adjust = startPos >= boxStartOffset ? boxStartOffset : 0; - p->drawHighlightForText(svgTextRunForInlineTextBox(textObject()->text()->characters() + start() + boxStartOffset, length, style, this, svgChar.x), - IntPoint((int) svgChar.x, (int) svgChar.y - f->ascent()), - f->ascent() + f->descent(), color, startPos - adjust, endPos - adjust); + p->drawHighlightForText(font, svgTextRunForInlineTextBox(textObject()->text()->characters() + start() + boxStartOffset, length, style, this, svgChar.x), + IntPoint((int) svgChar.x, (int) svgChar.y - font.ascent()), + font.ascent() + font.descent(), color, startPos - adjust, endPos - adjust); p->restore(); } @@ -520,7 +516,7 @@ void SVGInlineTextBox::paintDecoration(ETextDecoration decoration, GraphicsConte context->save(); context->beginPath(); - AffineTransform ctm = svgChar.characterTransform(); + TransformationMatrix ctm = svgChar.characterTransform(); if (!ctm.isIdentity()) context->concatCTM(ctm); diff --git a/WebCore/rendering/SVGInlineTextBox.h b/WebCore/rendering/SVGInlineTextBox.h index 1ddc23a..9882128 100644 --- a/WebCore/rendering/SVGInlineTextBox.h +++ b/WebCore/rendering/SVGInlineTextBox.h @@ -50,7 +50,7 @@ namespace WebCore { void paintCharacters(RenderObject::PaintInfo&, int tx, int ty, const SVGChar&, const UChar* chars, int length, SVGPaintServer*); // SVGs custom paint selection method - void paintSelection(int boxStartOffset, const SVGChar&, const UChar*, int length, GraphicsContext*, RenderStyle*, const Font*); + void paintSelection(int boxStartOffset, const SVGChar&, const UChar*, int length, GraphicsContext*, RenderStyle*, const Font&); // SVGs custom paint decoration method void paintDecoration(ETextDecoration, GraphicsContext*, int tx, int ty, int width, const SVGChar&, const SVGTextDecorationInfo&); diff --git a/WebCore/rendering/SVGRenderSupport.cpp b/WebCore/rendering/SVGRenderSupport.cpp index f3223f1..9ffc533 100644 --- a/WebCore/rendering/SVGRenderSupport.cpp +++ b/WebCore/rendering/SVGRenderSupport.cpp @@ -25,7 +25,7 @@ #if ENABLE(SVG) #include "SVGRenderSupport.h" -#include "AffineTransform.h" +#include "TransformationMatrix.h" #include "ImageBuffer.h" #include "RenderObject.h" #include "RenderSVGContainer.h" @@ -35,11 +35,17 @@ #include "SVGResourceMasker.h" #include "SVGStyledElement.h" #include "SVGURIReference.h" +#include <wtf/UnusedParam.h> namespace WebCore { void prepareToRenderSVGContent(RenderObject* object, RenderObject::PaintInfo& paintInfo, const FloatRect& boundingBox, SVGResourceFilter*& filter, SVGResourceFilter* rootFilter) -{ +{ +#if !ENABLE(SVG_FILTERS) + UNUSED_PARAM(filter); + UNUSED_PARAM(rootFilter); +#endif + SVGElement* svgElement = static_cast<SVGElement*>(object->element()); ASSERT(svgElement && svgElement->document() && svgElement->isStyled()); ASSERT(object); @@ -104,6 +110,12 @@ void prepareToRenderSVGContent(RenderObject* object, RenderObject::PaintInfo& pa void finishRenderSVGContent(RenderObject* object, RenderObject::PaintInfo& paintInfo, const FloatRect& boundingBox, SVGResourceFilter*& filter, GraphicsContext* savedContext) { +#if !ENABLE(SVG_FILTERS) + UNUSED_PARAM(boundingBox); + UNUSED_PARAM(filter); + UNUSED_PARAM(savedContext); +#endif + ASSERT(object); const RenderStyle* style = object->style(); diff --git a/WebCore/rendering/SVGRenderTreeAsText.cpp b/WebCore/rendering/SVGRenderTreeAsText.cpp index d3e029c..74a8af9 100644 --- a/WebCore/rendering/SVGRenderTreeAsText.cpp +++ b/WebCore/rendering/SVGRenderTreeAsText.cpp @@ -88,7 +88,7 @@ TextStream& operator<<(TextStream& ts, const IntRect& r) return ts << "at (" << r.x() << "," << r.y() << ") size " << r.width() << "x" << r.height(); } -bool hasFractions(double val) +static bool hasFractions(double val) { double epsilon = 0.0001; int ival = static_cast<int>(val); @@ -151,7 +151,7 @@ TextStream& operator<<(TextStream& ts, const FloatSize& s) return ts; } -TextStream& operator<<(TextStream& ts, const AffineTransform& transform) +TextStream& operator<<(TextStream& ts, const TransformationMatrix& transform) { if (transform.isIdentity()) ts << "identity"; @@ -233,8 +233,10 @@ static void writeStyle(TextStream& ts, const RenderObject& object) if (!object.localTransform().isIdentity()) ts << " [transform=" << object.localTransform() << "]"; - if (svgStyle->imageRendering() != SVGRenderStyle::initialImageRendering()) - ts << " [image rendering=" << svgStyle->imageRendering() << "]"; + if (svgStyle->imageRendering() != SVGRenderStyle::initialImageRendering()) { + unsigned imageRenderingAsInteger = svgStyle->imageRendering(); + ts << " [image rendering=" << imageRenderingAsInteger << "]"; + } if (style->opacity() != RenderStyle::initialOpacity()) ts << " [opacity=" << style->opacity() << "]"; if (object.isRenderPath()) { @@ -329,7 +331,7 @@ static TextStream& operator<<(TextStream& ts, const RenderSVGText& text) return ts; Vector<SVGTextChunk>& chunks = const_cast<Vector<SVGTextChunk>& >(box->svgTextChunks()); - ts << " at (" << text.xPos() << "," << text.yPos() << ") size " << box->width() << "x" << box->height() << " contains " << chunks.size() << " chunk(s)"; + ts << " at (" << text.x() << "," << text.y() << ") size " << box->width() << "x" << box->height() << " contains " << chunks.size() << " chunk(s)"; if (text.parent() && (text.parent()->style()->color() != text.style()->color())) ts << " [color=" << text.style()->color().name() << "]"; @@ -514,7 +516,9 @@ void write(TextStream& ts, const RenderSVGInlineText& text, int indent) ts << " {" << tagName << "}"; } - ts << " at (" << text.xPos() << "," << text.yPos() << ") size " << text.width() << "x" << text.height() << "\n"; + IntRect linesBox = text.linesBoundingBox(); + + ts << " at (" << text.firstRunX() << "," << text.firstRunY() << ") size " << linesBox.width() << "x" << linesBox.height() << "\n"; writeSVGInlineText(ts, text, indent); } diff --git a/WebCore/rendering/SVGRenderTreeAsText.h b/WebCore/rendering/SVGRenderTreeAsText.h index e23b82c..c4d832d 100644 --- a/WebCore/rendering/SVGRenderTreeAsText.h +++ b/WebCore/rendering/SVGRenderTreeAsText.h @@ -32,7 +32,7 @@ namespace WebCore { - class AffineTransform; + class TransformationMatrix; class Color; class FloatPoint; class FloatRect; @@ -56,7 +56,7 @@ void write(TextStream&, const RenderSVGText&, int ident = 0); void writeRenderResources(TextStream&, Node* parent); // helper operators defined used in various classes to dump the render tree. -TextStream& operator<<(TextStream&, const AffineTransform&); +TextStream& operator<<(TextStream&, const TransformationMatrix&); TextStream& operator<<(TextStream&, const IntRect&); TextStream& operator<<(TextStream&, const Color&); TextStream& operator<<(TextStream&, const IntPoint&); diff --git a/WebCore/rendering/SVGRootInlineBox.cpp b/WebCore/rendering/SVGRootInlineBox.cpp index e5f9fdf..62a8b04 100644 --- a/WebCore/rendering/SVGRootInlineBox.cpp +++ b/WebCore/rendering/SVGRootInlineBox.cpp @@ -30,6 +30,7 @@ #include "Editor.h" #include "Frame.h" #include "GraphicsContext.h" +#include "RenderBlock.h" #include "RenderSVGRoot.h" #include "SVGInlineFlowBox.h" #include "SVGInlineTextBox.h" @@ -481,7 +482,7 @@ struct SVGRootInlineBoxPaintWalker { return false; } - void chunkPortionCallback(SVGInlineTextBox* textBox, int startOffset, const AffineTransform& chunkCtm, + void chunkPortionCallback(SVGInlineTextBox* textBox, int startOffset, const TransformationMatrix& chunkCtm, const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end) { RenderText* text = textBox->textObject(); @@ -611,10 +612,10 @@ int SVGRootInlineBox::placeBoxesHorizontally(int, int& leftPosition, int& rightP return 0; } -void SVGRootInlineBox::verticallyAlignBoxes(int& heightOfBlock) +int SVGRootInlineBox::verticallyAlignBoxes(int) { // height is set by layoutInlineBoxes. - heightOfBlock = height(); + return height(); } float cummulatedWidthOfInlineBoxCharacterRange(SVGInlineBoxCharacterRange& range) @@ -842,7 +843,7 @@ static void applyTextLengthCorrectionToTextChunk(SVGTextChunk& chunk) SVGChar& firstChar = *(chunk.start); // Assure we apply the chunk scaling in the right origin - AffineTransform newChunkCtm; + TransformationMatrix newChunkCtm; newChunkCtm.translate(firstChar.x, firstChar.y); newChunkCtm = chunk.ctm * newChunkCtm; newChunkCtm.translate(-firstChar.x, -firstChar.y); @@ -887,7 +888,7 @@ void SVGRootInlineBox::computePerCharacterLayoutInformation() // Finally the top left position of our box is known. // Propogate this knownledge to our RenderSVGText parent. FloatPoint topLeft = topLeftPositionOfCharacterRange(m_svgChars); - object()->setPos((int) floorf(topLeft.x()), (int) floorf(topLeft.y())); + block()->setLocation((int) floorf(topLeft.x()), (int) floorf(topLeft.y())); // Layout all InlineText/Flow boxes // BEWARE: This requires the root top/left position to be set correctly before! @@ -915,6 +916,9 @@ void SVGRootInlineBox::buildLayoutInformation(InlineFlowBox* start, SVGCharacter ASSERT(curr->isInlineFlowBox()); InlineFlowBox* flowBox = static_cast<InlineFlowBox*>(curr); + if (!flowBox->object()->element()) + continue; // Skip generated content. + bool isAnchor = flowBox->object()->element()->hasTagName(SVGNames::aTag); bool isTextPath = flowBox->object()->element()->hasTagName(SVGNames::textPathTag); @@ -952,7 +956,7 @@ void SVGRootInlineBox::buildLayoutInformation(InlineFlowBox* start, SVGCharacter Vector<SVGTextChunk>::iterator it = tempChunks.begin(); Vector<SVGTextChunk>::iterator end = tempChunks.end(); - AffineTransform ctm; + TransformationMatrix ctm; float computedLength = 0.0f; for (; it != end; ++it) { @@ -1035,10 +1039,10 @@ void SVGRootInlineBox::layoutInlineBoxes(InlineFlowBox* start, Vector<SVGChar>:: int minY = enclosedStringRect.y(); int maxY = minY + enclosedStringRect.height(); - curr->setXPos(minX - object()->xPos()); + curr->setXPos(minX - block()->x()); curr->setWidth(enclosedStringRect.width()); - curr->setYPos(minY - object()->yPos()); + curr->setYPos(minY - block()->y()); curr->setBaseline(font.ascent()); curr->setHeight(enclosedStringRect.height()); @@ -1062,12 +1066,16 @@ void SVGRootInlineBox::layoutInlineBoxes(InlineFlowBox* start, Vector<SVGChar>:: int maxY = INT_MIN; InlineFlowBox* flowBox = static_cast<InlineFlowBox*>(curr); + + if (!flowBox->object()->element()) + continue; // Skip generated content. + layoutInlineBoxes(flowBox, it, minX, maxX, minY, maxY); - curr->setXPos(minX - object()->xPos()); + curr->setXPos(minX - block()->x()); curr->setWidth(maxX - minX); - curr->setYPos(minY - object()->yPos()); + curr->setYPos(minY - block()->y()); curr->setBaseline(font.ascent()); curr->setHeight(maxY - minY); @@ -1086,10 +1094,10 @@ void SVGRootInlineBox::layoutInlineBoxes(InlineFlowBox* start, Vector<SVGChar>:: } if (start->isRootInlineBox()) { - int top = lowY - object()->yPos(); - int bottom = highY - object()->yPos(); + int top = lowY - block()->y(); + int bottom = highY - block()->y(); - start->setXPos(lowX - object()->xPos()); + start->setXPos(lowX - block()->x()); start->setYPos(top); start->setWidth(highX - lowX); @@ -1517,6 +1525,9 @@ void SVGRootInlineBox::buildTextChunks(Vector<SVGChar>& svgChars, InlineFlowBox* ASSERT(curr->isInlineFlowBox()); InlineFlowBox* flowBox = static_cast<InlineFlowBox*>(curr); + if (!flowBox->object()->element()) + continue; // Skip generated content. + bool isTextPath = flowBox->object()->element()->hasTagName(SVGNames::textPathTag); #if DEBUG_CHUNK_BUILDING > 1 diff --git a/WebCore/rendering/SVGRootInlineBox.h b/WebCore/rendering/SVGRootInlineBox.h index 800664b..bfe9889 100644 --- a/WebCore/rendering/SVGRootInlineBox.h +++ b/WebCore/rendering/SVGRootInlineBox.h @@ -55,7 +55,7 @@ public: virtual void paint(RenderObject::PaintInfo&, int tx, int ty); virtual int placeBoxesHorizontally(int x, int& leftPosition, int& rightPosition, bool& needsWordSpacing); - virtual void verticallyAlignBoxes(int& heightOfBlock); + virtual int verticallyAlignBoxes(int heightOfBlock); virtual void computePerCharacterLayoutInformation(); diff --git a/WebCore/rendering/TextControlInnerElements.cpp b/WebCore/rendering/TextControlInnerElements.cpp index f14480f..452333c 100644 --- a/WebCore/rendering/TextControlInnerElements.cpp +++ b/WebCore/rendering/TextControlInnerElements.cpp @@ -32,9 +32,10 @@ #include "EventNames.h" #include "Frame.h" #include "HTMLInputElement.h" +#include "HTMLNames.h" #include "HTMLTextAreaElement.h" #include "MouseEvent.h" -#include "RenderTextControl.h" +#include "RenderTextControlSingleLine.h" namespace WebCore { @@ -47,13 +48,18 @@ public: bool RenderTextControlInnerBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction) { - RenderTextControl* renderer = static_cast<RenderTextControl*>(node()->shadowAncestorNode()->renderer()); - - return RenderBlock::nodeAtPoint(request, result, x, y, tx, ty, renderer->placeholderIsVisible() ? HitTestBlockBackground : hitTestAction); + RenderObject* renderer = node()->shadowAncestorNode()->renderer(); + + bool placeholderIsVisible = false; + if (renderer->isTextField()) + placeholderIsVisible = static_cast<RenderTextControlSingleLine*>(renderer)->placeholderIsVisible(); + + return RenderBlock::nodeAtPoint(request, result, x, y, tx, ty, placeholderIsVisible ? HitTestBlockBackground : hitTestAction); } TextControlInnerElement::TextControlInnerElement(Document* doc, Node* shadowParent) - : HTMLDivElement(doc), m_shadowParent(shadowParent) + : HTMLDivElement(HTMLNames::divTag, doc) + , m_shadowParent(shadowParent) { } @@ -122,10 +128,11 @@ void SearchFieldResultsButtonElement::defaultEventHandler(Event* evt) if (evt->type() == eventNames().mousedownEvent && evt->isMouseEvent() && static_cast<MouseEvent*>(evt)->button() == LeftButton) { input->focus(); input->select(); - if (input && input->renderer() && static_cast<RenderTextControl*>(input->renderer())->popupIsVisible()) - static_cast<RenderTextControl*>(input->renderer())->hidePopup(); + RenderTextControlSingleLine* renderer = static_cast<RenderTextControlSingleLine*>(input->renderer()); + if (renderer->popupIsVisible()) + renderer->hidePopup(); else if (input->maxResults() > 0) - static_cast<RenderTextControl*>(input->renderer())->showPopup(); + renderer->showPopup(); evt->setDefaultHandled(); } if (!evt->defaultHandled()) @@ -146,13 +153,13 @@ void SearchFieldCancelButtonElement::defaultEventHandler(Event* evt) input->focus(); input->select(); evt->setDefaultHandled(); - if (renderer() && renderer()->style()->visibility() == VISIBLE) + if (renderer() && renderer()->visibleToHitTesting()) if (Frame* frame = document()->frame()) { frame->eventHandler()->setCapturingMouseEventsNode(this); m_capturing = true; } } else if (evt->type() == eventNames().mouseupEvent && evt->isMouseEvent() && static_cast<MouseEvent*>(evt)->button() == LeftButton) { - if (m_capturing && renderer() && renderer()->style()->visibility() == VISIBLE) { + if (m_capturing && renderer() && renderer()->visibleToHitTesting()) { if (hovered()) { input->setValue(""); input->onSearch(); diff --git a/WebCore/rendering/bidi.cpp b/WebCore/rendering/bidi.cpp index 93f3b0f..2f05e7f 100644 --- a/WebCore/rendering/bidi.cpp +++ b/WebCore/rendering/bidi.cpp @@ -35,6 +35,7 @@ #include "break_lines.h" #include <wtf/AlwaysInline.h> #include <wtf/RefCountedLeakCounter.h> +#include <wtf/StdLibExtras.h> #include <wtf/Vector.h> #ifdef ANDROID_LAYOUT #include "Frame.h" @@ -94,7 +95,7 @@ static bool betweenMidpoints; static bool isLineEmpty = true; static bool previousLineBrokeCleanly = true; -static int getBorderPaddingMargin(RenderObject* child, bool endOfInline) +static int getBorderPaddingMargin(RenderBox* child, bool endOfInline) { bool leftSide = (child->style()->direction() == LTR) ? !endOfInline : endOfInline; if (leftSide) @@ -107,11 +108,11 @@ static int inlineWidth(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->isBox() && parent->isInline() && !parent->isInlineBlockOrInlineTable() && lineDepth++ < cMaxLineDepth) { if (start && parent->firstChild() == child) - extraWidth += getBorderPaddingMargin(parent, false); + extraWidth += getBorderPaddingMargin(toRenderBox(parent), false); if (end && parent->lastChild() == child) - extraWidth += getBorderPaddingMargin(parent, true); + extraWidth += getBorderPaddingMargin(toRenderBox(parent), true); child = parent; parent = child->parent(); } @@ -180,7 +181,7 @@ static inline RenderObject* bidiNext(RenderBlock* block, RenderObject* current, next = 0; if (!oldEndOfInline && !current->isFloating() && !current->isReplaced() && !current->isPositioned()) { next = current->firstChild(); - if (next && resolver && next->isInlineFlow()) { + if (next && resolver && next->isRenderInline()) { EUnicodeBidi ub = next->style()->unicodeBidi(); if (ub != UBNormal) { TextDirection dir = next->style()->direction(); @@ -193,19 +194,19 @@ static inline RenderObject* bidiNext(RenderBlock* block, RenderObject* current, } if (!next) { - if (!skipInlines && !oldEndOfInline && current->isInlineFlow()) { + if (!skipInlines && !oldEndOfInline && current->isRenderInline()) { next = current; endOfInline = true; break; } while (current && current != block) { - if (resolver && current->isInlineFlow() && current->style()->unicodeBidi() != UBNormal) + if (resolver && current->isRenderInline() && current->style()->unicodeBidi() != UBNormal) resolver->embed(PopDirectionalFormat); next = current->nextSibling(); if (next) { - if (resolver && next->isInlineFlow()) { + if (resolver && next->isRenderInline()) { EUnicodeBidi ub = next->style()->unicodeBidi(); if (ub != UBNormal) { TextDirection dir = next->style()->direction(); @@ -219,7 +220,7 @@ static inline RenderObject* bidiNext(RenderBlock* block, RenderObject* current, } current = current->parent(); - if (!skipInlines && current && current != block && current->isInlineFlow()) { + if (!skipInlines && current && current != block && current->isRenderInline()) { next = current; endOfInline = true; break; @@ -232,7 +233,7 @@ static inline RenderObject* bidiNext(RenderBlock* block, RenderObject* current, if (next->isText() || next->isFloating() || next->isReplaced() || next->isPositioned() || ((!skipInlines || !next->firstChild()) // Always return EMPTY inlines. - && next->isInlineFlow())) + && next->isRenderInline())) break; current = next; } @@ -249,7 +250,7 @@ static RenderObject* bidiFirst(RenderBlock* block, InlineBidiResolver* resolver, return 0; RenderObject* o = block->firstChild(); - if (o->isInlineFlow()) { + if (o->isRenderInline()) { if (resolver) { EUnicodeBidi ub = o->style()->unicodeBidi(); if (ub != UBNormal) { @@ -284,7 +285,7 @@ inline void InlineIterator::increment(InlineBidiResolver* resolver) return; if (obj->isText()) { pos++; - if (pos >= static_cast<RenderText*>(obj)->textLength()) { + if (pos >= toRenderText(obj)->textLength()) { obj = bidiNext(block, obj, resolver); pos = 0; nextBreakablePosition = -1; @@ -312,7 +313,7 @@ inline UChar InlineIterator::current() const if (!obj || !obj->isText()) return 0; - RenderText* text = static_cast<RenderText*>(obj); + RenderText* text = toRenderText(obj); if (pos >= text->textLength()) return 0; @@ -364,12 +365,12 @@ static void checkMidpoints(InlineIterator& lBreak) if (endpoint.obj->style()->collapseWhiteSpace()) { if (endpoint.obj->isText()) { // Don't shave a character off the endpoint if it was from a soft hyphen. - RenderText* textObj = static_cast<RenderText*>(endpoint.obj); + RenderText* textObj = toRenderText(endpoint.obj); if (endpoint.pos + 1 < textObj->textLength()) { if (textObj->characters()[endpoint.pos+1] == softHyphen) return; } else if (startpoint.obj->isText()) { - RenderText *startText = static_cast<RenderText*>(startpoint.obj); + RenderText *startText = toRenderText(startpoint.obj); if (startText->textLength() && startText->characters()[0] == softHyphen) return; } @@ -392,7 +393,7 @@ static void addMidpoint(const InlineIterator& midpoint) static void appendRunsForObject(int start, int end, RenderObject* obj, InlineBidiResolver& resolver) { if (start > end || obj->isFloating() || - (obj->isPositioned() && !obj->hasStaticX() && !obj->hasStaticY() && !obj->container()->isInlineFlow())) + (obj->isPositioned() && !obj->hasStaticX() && !obj->hasStaticY() && !obj->container()->isRenderInline())) return; bool haveNextMidpoint = (sCurrMidpoint < sNumMidpoints); @@ -470,7 +471,7 @@ InlineFlowBox* RenderBlock::createLineBoxes(RenderObject* obj) InlineFlowBox* parentBox = 0; InlineFlowBox* result = 0; do { - ASSERT(obj->isInlineFlow() || obj == this); + ASSERT(obj->isRenderInline() || obj == this); RenderFlow* flow = static_cast<RenderFlow*>(obj); // Get the last box we made for this render object. @@ -572,7 +573,7 @@ RootInlineBox* RenderBlock::constructLine(unsigned runCount, BidiRun* firstRun, void RenderBlock::computeHorizontalPositionsForLine(RootInlineBox* lineBox, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd) { // First determine our total width. - int availableWidth = lineWidth(m_height); + int availableWidth = lineWidth(height()); int totWidth = lineBox->getFlowSpacingWidth(); bool needsWordSpacing = false; unsigned numSpaces = 0; @@ -584,7 +585,7 @@ void RenderBlock::computeHorizontalPositionsForLine(RootInlineBox* lineBox, Bidi // correct static x position. They have no effect on the width. // Similarly, line break boxes have no effect on the width. if (r->m_object->isText()) { - RenderText* rt = static_cast<RenderText*>(r->m_object); + RenderText* rt = toRenderText(r->m_object); if (textAlign == JUSTIFY && r != trailingSpaceRun) { const UChar* characters = rt->characters(); @@ -596,28 +597,26 @@ void RenderBlock::computeHorizontalPositionsForLine(RootInlineBox* lineBox, Bidi } if (int length = rt->textLength()) { - if (!r->m_compact && !r->m_start && needsWordSpacing && isSpaceOrNewline(rt->characters()[r->m_start])) + if (!r->m_start && needsWordSpacing && isSpaceOrNewline(rt->characters()[r->m_start])) totWidth += rt->style(m_firstLine)->font().wordSpacing(); needsWordSpacing = !isSpaceOrNewline(rt->characters()[r->m_stop - 1]) && r->m_stop == length; } r->m_box->setWidth(rt->width(r->m_start, r->m_stop - r->m_start, totWidth, m_firstLine)); - } else if (!r->m_object->isInlineFlow()) { - r->m_object->calcWidth(); - r->m_box->setWidth(r->m_object->width()); - if (!r->m_compact) - totWidth += r->m_object->marginLeft() + r->m_object->marginRight(); + } else if (!r->m_object->isRenderInline()) { + RenderBox* renderBox = toRenderBox(r->m_object); + renderBox->calcWidth(); + r->m_box->setWidth(renderBox->width()); + totWidth += renderBox->marginLeft() + renderBox->marginRight(); } - // Compacts don't contribute to the width of the line, since they are placed in the margin. - if (!r->m_compact) - totWidth += r->m_box->width(); + totWidth += r->m_box->width(); } // Armed with the total width of the line (without justification), // we now examine our text-align property in order to determine where to position the // objects horizontally. The total width of the line can be increased if we end up // justifying text. - int x = leftOffset(m_height); + int x = leftOffset(height()); switch(textAlign) { case LEFT: case WEBKIT_LEFT: @@ -691,9 +690,9 @@ void RenderBlock::computeHorizontalPositionsForLine(RootInlineBox* lineBox, Bidi continue; int spaceAdd = 0; - if (r->m_object->isText() && !r->m_compact) { + if (r->m_object->isText()) { unsigned spaces = 0; - const UChar* characters = static_cast<RenderText*>(r->m_object)->characters(); + const UChar* characters = toRenderText(r->m_object)->characters(); for (int i = r->m_start; i < r->m_stop; i++) { UChar c = characters[i]; if (c == ' ' || c == '\n' || c == '\t') @@ -726,12 +725,12 @@ void RenderBlock::computeHorizontalPositionsForLine(RootInlineBox* lineBox, Bidi void RenderBlock::computeVerticalPositionsForLine(RootInlineBox* lineBox, BidiRun* firstRun) { - lineBox->verticallyAlignBoxes(m_height); - lineBox->setBlockHeight(m_height); + setHeight(lineBox->verticallyAlignBoxes(height())); + lineBox->setBlockHeight(height()); // See if the line spilled out. If so set overflow height accordingly. int bottomOfLine = lineBox->bottomOverflow(); - if (bottomOfLine > m_height && bottomOfLine > m_overflowHeight) + if (bottomOfLine > height() && bottomOfLine > m_overflowHeight) m_overflowHeight = bottomOfLine; // Now make sure we place replaced render objects correctly. @@ -742,7 +741,7 @@ void RenderBlock::computeVerticalPositionsForLine(RootInlineBox* lineBox, BidiRu // Align positioned boxes with the top of the line box. This is // a reasonable approximation of an appropriate y position. if (r->m_object->isPositioned()) - r->m_box->setYPos(m_height); + r->m_box->setYPos(height()); // Position is used to properly position both replaced elements and // to update the static normal flow x/y of positioned elements. @@ -759,34 +758,6 @@ void RenderBlock::bidiReorderLine(InlineBidiResolver& resolver, const InlineIter resolver.createBidiRunsForLine(end, style()->visuallyOrdered(), previousLineBrokeCleanly); } -static void buildCompactRuns(RenderObject* compactObj, InlineBidiResolver& resolver) -{ - ASSERT(compactObj->isRenderBlock()); - ASSERT(!resolver.firstRun()); - - // Format the compact like it is its own single line. We build up all the runs for - // the little compact and then reorder them for bidi. - RenderBlock* compactBlock = static_cast<RenderBlock*>(compactObj); - - InlineIterator start(compactBlock, bidiFirst(compactBlock, &resolver), 0); - resolver.setPosition(start); - - betweenMidpoints = false; - isLineEmpty = true; - previousLineBrokeCleanly = true; - - InlineIterator end = compactBlock->findNextLineBreak(resolver); - if (!isLineEmpty) - compactBlock->bidiReorderLine(resolver, end); - - for (BidiRun* run = resolver.firstRun(); run; run = run->next()) - run->m_compact = true; - - sNumMidpoints = 0; - sCurrMidpoint = 0; - betweenMidpoints = false; -} - static inline bool isCollapsibleSpace(UChar character, RenderText* renderer) { if (character == ' ' || character == '\t' || character == softHyphen) @@ -806,7 +777,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i m_overflowHeight = 0; - m_height = borderTop() + paddingTop(); + setHeight(borderTop() + paddingTop()); int toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight(); // Figure out if we should clear out our line boxes. @@ -853,6 +824,8 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i while (o) { o->invalidateVerticalPosition(); if (o->isReplaced() || o->isFloating() || o->isPositioned()) { + RenderBox* box = toRenderBox(o); + if (relayoutChildren || o->style()->width().isPercent() || o->style()->height().isPercent()) o->setChildNeedsLayout(true, false); @@ -861,7 +834,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i o->setPrefWidthsDirty(true, false); if (o->isPositioned()) - o->containingBlock()->insertPositionedObject(o); + o->containingBlock()->insertPositionedObject(box); else { #ifdef ANDROID_LAYOUT // ignore text wrap for textField or menuList @@ -869,18 +842,18 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i doTextWrap = false; #endif if (o->isFloating()) - floats.append(FloatWithRect(o)); + floats.append(FloatWithRect(box)); else if (fullLayout || o->needsLayout()) // Replaced elements o->dirtyLineBoxes(fullLayout); o->layoutIfNeeded(); } - } else if (o->isText() || (o->isInlineFlow() && !endOfInline)) { + } else if (o->isText() || (o->isRenderInline() && !endOfInline)) { if (fullLayout || o->selfNeedsLayout()) o->dirtyLineBoxes(fullLayout); // Calculate margins of inline flows so that they can be used later by line layout. - if (o->isInlineFlow()) + if (o->isRenderInline()) static_cast<RenderFlow*>(o)->calcMargins(containerWidth); o->setNeedsLayout(false); #ifdef ANDROID_LAYOUT @@ -928,7 +901,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i if (!isConstrained) { int maxWidth = view()->frameView()->screenWidth() - 2 * ANDROID_FCTS_MARGIN_PADDING; if (maxWidth > 0) { - m_width = min(m_width, maxWidth); + setWidth(min(width(), maxWidth)); m_minPrefWidth = min(m_minPrefWidth, maxWidth); m_maxPrefWidth = min(m_maxPrefWidth, maxWidth); m_overflowWidth = min(m_overflowWidth, maxWidth); @@ -944,14 +917,13 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i if (fullLayout && !selfNeedsLayout()) { setNeedsLayout(true, false); // Mark ourselves as needing a full layout. This way we'll repaint like // we're supposed to. - if (!document()->view()->needsFullRepaint() && m_layer) { + RenderView* v = view(); + if (v && !v->doingFullRepaint() && m_layer) { // Because we waited until we were already inside layout to discover // that the block really needed a full layout, we missed our chance to repaint the layer // before layout started. Luckily the layer has cached the repaint rect for its original // position and size, and so we can use that to make a repaint happen now. - RenderView* c = view(); - if (c && !c->printing()) - c->repaintViewRectangle(m_layer->repaintRect()); + v->repaintViewRectangle(m_layer->repaintRect()); } } @@ -973,8 +945,8 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i if (startLine) { useRepaintBounds = true; - repaintTop = m_height; - repaintBottom = m_height; + repaintTop = height(); + repaintBottom = height(); RenderArena* arena = renderArena(); RootInlineBox* box = startLine; while (box) { @@ -1007,7 +979,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i bool endLineMatched = false; bool checkForEndLineMatch = endLine; bool checkForFloatsFromLastLine = false; - int lastHeight = m_height; + int lastHeight = height(); while (!end.atEnd()) { // FIXME: Is this check necessary before the first iteration or can it be moved to the end? @@ -1016,10 +988,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i betweenMidpoints = false; isLineEmpty = true; - if (m_firstLine && firstChild()->isCompact() && firstChild()->isRenderBlock()) { - buildCompactRuns(firstChild(), resolver); - resolver.setPosition(InlineIterator(this, firstChild()->nextSibling(), 0)); - } + EClear clear = CNONE; end = findNextLineBreak(resolver, &clear); if (resolver.position().atEnd()) { @@ -1038,7 +1007,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i trailingSpaceRun = resolver.logicallyLastRun(); RenderObject* lastObject = trailingSpaceRun->m_object; if (lastObject->isText()) { - RenderText* lastText = static_cast<RenderText*>(lastObject); + RenderText* lastText = toRenderText(lastObject); const UChar* characters = lastText->characters(); int firstSpace = trailingSpaceRun->stop(); while (firstSpace > trailingSpaceRun->start()) { @@ -1150,7 +1119,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i lastFloat = m_floatingObjects->last(); } - lastHeight = m_height; + lastHeight = height(); sNumMidpoints = 0; sCurrMidpoint = 0; resolver.setPosition(end); @@ -1159,7 +1128,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i if (endLine) { if (endLineMatched) { // Attach all the remaining lines, and then adjust their y-positions as needed. - int delta = m_height - endLineYPos; + int delta = height() - endLineYPos; for (RootInlineBox* line = endLine; line; line = line->nextRootBox()) { line->attachLine(); if (delta) { @@ -1167,17 +1136,17 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i repaintBottom = max(repaintBottom, line->bottomOverflow() + max(delta, 0)); line->adjustPosition(0, delta); } - if (Vector<RenderObject*>* cleanLineFloats = line->floatsPtr()) { - Vector<RenderObject*>::iterator end = cleanLineFloats->end(); - for (Vector<RenderObject*>::iterator f = cleanLineFloats->begin(); f != end; ++f) { - int floatTop = (*f)->yPos() - (*f)->marginTop(); + if (Vector<RenderBox*>* cleanLineFloats = line->floatsPtr()) { + Vector<RenderBox*>::iterator end = cleanLineFloats->end(); + for (Vector<RenderBox*>::iterator f = cleanLineFloats->begin(); f != end; ++f) { + int floatTop = (*f)->y() - (*f)->marginTop(); insertFloatingObject(*f); - m_height = floatTop + delta; + setHeight(floatTop + delta); positionNewFloats(); } } } - m_height = lastRootBox()->blockHeight(); + setHeight(lastRootBox()->blockHeight()); } else { // Delete all the remaining lines. InlineRunBox* line = endLine; @@ -1213,16 +1182,16 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i sCurrMidpoint = 0; // Now add in the bottom border/padding. - m_height += toAdd; + setHeight(height() + toAdd); // Always make sure this is at least our height. - m_overflowHeight = max(m_height, m_overflowHeight); + m_overflowHeight = max(height(), m_overflowHeight); // See if any lines spill out of the block. If so, we need to update our overflow width. checkLinesForOverflow(); if (!firstLineBox() && hasLineIfEmpty()) - m_height += lineHeight(true, true); + setHeight(height() + lineHeight(true, true)); // See if we have any lines that spill out of our block. If we do, then we will possibly need to // truncate text. @@ -1239,10 +1208,10 @@ RootInlineBox* RenderBlock::determineStartPosition(bool& fullLayout, InlineBidiR if (!fullLayout) { size_t floatIndex = 0; for (curr = firstRootBox(); curr && !curr->isDirty(); curr = curr->nextRootBox()) { - if (Vector<RenderObject*>* cleanLineFloats = curr->floatsPtr()) { - Vector<RenderObject*>::iterator end = cleanLineFloats->end(); - for (Vector<RenderObject*>::iterator o = cleanLineFloats->begin(); o != end; ++o) { - RenderObject* f = *o; + if (Vector<RenderBox*>* cleanLineFloats = curr->floatsPtr()) { + Vector<RenderBox*>::iterator end = cleanLineFloats->end(); + for (Vector<RenderBox*>::iterator o = cleanLineFloats->begin(); o != end; ++o) { + RenderBox* f = *o; IntSize newSize(f->width() + f->marginLeft() +f->marginRight(), f->height() + f->marginTop() + f->marginBottom()); ASSERT(floatIndex < floats.size()); if (floats[floatIndex].object != f) { @@ -1286,7 +1255,7 @@ RootInlineBox* RenderBlock::determineStartPosition(bool& fullLayout, InlineBidiR // We have a dirty line. if (RootInlineBox* prevRootBox = curr->prevRootBox()) { // We have a previous line. - if (!dirtiedByFloat && (!prevRootBox->endsWithBreak() || prevRootBox->lineBreakObj()->isText() && prevRootBox->lineBreakPos() >= static_cast<RenderText*>(prevRootBox->lineBreakObj())->textLength())) + if (!dirtiedByFloat && (!prevRootBox->endsWithBreak() || prevRootBox->lineBreakObj()->isText() && prevRootBox->lineBreakPos() >= toRenderText(prevRootBox->lineBreakObj())->textLength())) // The previous line didn't break cleanly or broke at a newline // that has been deleted, so treat it as dirty too. curr = prevRootBox; @@ -1304,15 +1273,15 @@ RootInlineBox* RenderBlock::determineStartPosition(bool& fullLayout, InlineBidiR numCleanFloats = 0; if (!floats.isEmpty()) { - int savedHeight = m_height; + int savedHeight = height(); // Restore floats from clean lines. RootInlineBox* line = firstRootBox(); while (line != curr) { - if (Vector<RenderObject*>* cleanLineFloats = line->floatsPtr()) { - Vector<RenderObject*>::iterator end = cleanLineFloats->end(); - for (Vector<RenderObject*>::iterator f = cleanLineFloats->begin(); f != end; ++f) { + if (Vector<RenderBox*>* cleanLineFloats = line->floatsPtr()) { + Vector<RenderBox*>::iterator end = cleanLineFloats->end(); + for (Vector<RenderBox*>::iterator f = cleanLineFloats->begin(); f != end; ++f) { insertFloatingObject(*f); - m_height = (*f)->yPos() - (*f)->marginTop(); + setHeight((*f)->y() - (*f)->marginTop()); positionNewFloats(); ASSERT(floats[numCleanFloats].object == *f); numCleanFloats++; @@ -1320,7 +1289,7 @@ RootInlineBox* RenderBlock::determineStartPosition(bool& fullLayout, InlineBidiR } line = line->nextRootBox(); } - m_height = savedHeight; + setHeight(savedHeight); } m_firstLine = !last; @@ -1329,7 +1298,7 @@ RootInlineBox* RenderBlock::determineStartPosition(bool& fullLayout, InlineBidiR RenderObject* startObj; int pos = 0; if (last) { - m_height = last->blockHeight(); + setHeight(last->blockHeight()); startObj = last->lineBreakObj(); pos = last->lineBreakPos(); resolver.setStatus(last->lineBreakBidiStatus()); @@ -1389,12 +1358,12 @@ bool RenderBlock::matchedEndLine(const InlineBidiResolver& resolver, const Inlin if (resolver.status() != endLineStatus) return false; - int delta = m_height - endYPos; + int delta = height() - endYPos; if (!delta || !m_floatingObjects) return true; // See if any floats end in the range along which we want to shift the lines vertically. - int top = min(m_height, endYPos); + int top = min(height(), endYPos); RootInlineBox* lastLine = endLine; while (RootInlineBox* nextLine = lastLine->nextRootBox()) @@ -1425,10 +1394,10 @@ bool RenderBlock::matchedEndLine(const InlineBidiResolver& resolver, const Inlin if (result) endYPos = line->blockHeight(); - int delta = m_height - endYPos; + int delta = height() - endYPos; if (delta && m_floatingObjects) { // See if any floats end in the range along which we want to shift the lines vertically. - int top = min(m_height, endYPos); + int top = min(height(), endYPos); RootInlineBox* lastLine = endLine; while (RootInlineBox* nextLine = lastLine->nextRootBox()) @@ -1492,12 +1461,12 @@ static inline bool shouldPreserveNewline(RenderObject* object) return object->style()->preserveNewline(); } -static bool inlineFlowRequiresLineBox(RenderObject* flow) +static bool inlineFlowRequiresLineBox(RenderBox* flow) { // FIXME: Right now, we only allow line boxes for inlines that are truly empty. // We need to fix this, though, because at the very least, inlines containing only // ignorable whitespace should should also have line boxes. - return flow->isInlineFlow() && !flow->firstChild() && flow->hasHorizontalBordersPaddingOrMargin(); + return flow->isRenderInline() && !flow->firstChild() && flow->hasHorizontalBordersPaddingOrMargin(); } static inline bool requiresLineBox(const InlineIterator& it) @@ -1505,7 +1474,7 @@ static inline bool requiresLineBox(const InlineIterator& it) if (it.obj->isFloatingOrPositioned()) return false; - if (it.obj->isInlineFlow() && !inlineFlowRequiresLineBox(it.obj)) + if (it.obj->isRenderInline() && !inlineFlowRequiresLineBox(toRenderBox(it.obj))) return false; if (!shouldCollapseWhiteSpace(it.obj->style()) || it.obj->isBR()) @@ -1537,28 +1506,28 @@ void RenderBlock::skipTrailingWhitespace(InlineIterator& iterator) while (!iterator.atEnd() && !requiresLineBox(iterator)) { RenderObject* object = iterator.obj; if (object->isFloating()) { - insertFloatingObject(object); + insertFloatingObject(toRenderBox(object)); } else if (object->isPositioned()) { // FIXME: The math here is actually not really right. It's a best-guess approximation that // will work for the common cases RenderObject* c = object->container(); - if (c->isInlineFlow()) { + if (c->isRenderInline()) { // A relative positioned inline encloses us. In this case, we also have to determine our // position as though we were an inline. Set |staticX| and |staticY| on the relative positioned // inline so that we can obtain the value later. - c->setStaticX(style()->direction() == LTR ? leftOffset(m_height) : rightOffset(m_height)); - c->setStaticY(m_height); + c->setStaticX(style()->direction() == LTR ? leftOffset(height()) : rightOffset(height())); + c->setStaticY(height()); } if (object->hasStaticX()) { if (object->style()->isOriginalDisplayInlineType()) - object->setStaticX(style()->direction() == LTR ? leftOffset(m_height) : width() - rightOffset(m_height)); + object->setStaticX(style()->direction() == LTR ? leftOffset(height()) : width() - rightOffset(height())); else object->setStaticX(style()->direction() == LTR ? borderLeft() + paddingLeft() : borderRight() + paddingRight()); } if (object->hasStaticY()) - object->setStaticY(m_height); + object->setStaticY(height()); } iterator.increment(); } @@ -1566,34 +1535,34 @@ void RenderBlock::skipTrailingWhitespace(InlineIterator& iterator) int RenderBlock::skipLeadingWhitespace(InlineBidiResolver& resolver) { - int availableWidth = lineWidth(m_height); + int availableWidth = lineWidth(height()); while (!resolver.position().atEnd() && !requiresLineBox(resolver.position())) { RenderObject* object = resolver.position().obj; if (object->isFloating()) { - insertFloatingObject(object); + insertFloatingObject(toRenderBox(object)); positionNewFloats(); - availableWidth = lineWidth(m_height); + availableWidth = lineWidth(height()); } else if (object->isPositioned()) { // FIXME: The math here is actually not really right. It's a best-guess approximation that // will work for the common cases RenderObject* c = object->container(); - if (c->isInlineFlow()) { + if (c->isRenderInline()) { // A relative positioned inline encloses us. In this case, we also have to determine our // position as though we were an inline. Set |staticX| and |staticY| on the relative positioned // inline so that we can obtain the value later. - c->setStaticX(style()->direction() == LTR ? leftOffset(m_height) : rightOffset(m_height)); - c->setStaticY(m_height); + c->setStaticX(style()->direction() == LTR ? leftOffset(height()) : rightOffset(height())); + c->setStaticY(height()); } if (object->hasStaticX()) { if (object->style()->isOriginalDisplayInlineType()) - object->setStaticX(style()->direction() == LTR ? leftOffset(m_height) : width() - rightOffset(m_height)); + object->setStaticX(style()->direction() == LTR ? leftOffset(height()) : width() - rightOffset(height())); else object->setStaticX(style()->direction() == LTR ? borderLeft() + paddingLeft() : borderRight() + paddingRight()); } if (object->hasStaticY()) - object->setStaticY(m_height); + object->setStaticY(height()); } resolver.increment(); } @@ -1606,8 +1575,8 @@ int RenderBlock::skipLeadingWhitespace(InlineBidiResolver& resolver) static bool shouldSkipWhitespaceAfterStartObject(RenderBlock* block, RenderObject* o) { RenderObject* next = bidiNext(block, o); - if (next && !next->isBR() && next->isText() && static_cast<RenderText*>(next)->textLength() > 0) { - RenderText* nextText = static_cast<RenderText*>(next); + if (next && !next->isBR() && next->isText() && toRenderText(next)->textLength() > 0) { + RenderText* nextText = toRenderText(next); UChar nextChar = nextText->characters()[0]; if (nextText->style()->isCollapsibleWhiteSpace(nextChar)) { addMidpoint(InlineIterator(0, o, 0)); @@ -1623,7 +1592,7 @@ void RenderBlock::fitBelowFloats(int widthToFit, int& availableWidth) ASSERT(widthToFit > availableWidth); int floatBottom; - int lastFloatBottom = m_height; + int lastFloatBottom = height(); int newLineWidth = availableWidth; while (true) { floatBottom = nextFloatBottomBelow(lastFloatBottom); @@ -1637,7 +1606,7 @@ void RenderBlock::fitBelowFloats(int widthToFit, int& availableWidth) } if (newLineWidth > availableWidth) { - m_height = lastFloatBottom; + setHeight(lastFloatBottom); availableWidth = newLineWidth; } } @@ -1730,13 +1699,14 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, ECle if (o->isFloatingOrPositioned()) { // add to special objects... if (o->isFloating()) { - insertFloatingObject(o); + RenderBox* floatBox = toRenderBox(o); + insertFloatingObject(floatBox); // 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 && o->width() + o->marginLeft() + o->marginRight() + w + tmpW <= width) { + if (floatsFitOnLine && floatBox->width() + floatBox->marginLeft() + floatBox->marginRight() + w + tmpW <= width) { positionNewFloats(); - width = lineWidth(m_height); + width = lineWidth(height()); } else floatsFitOnLine = false; } else if (o->isPositioned()) { @@ -1755,13 +1725,13 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, ECle // and determine our static y position now. bool needToSetStaticY = o->hasStaticY(); if (o->hasStaticY() && isInlineType) { - o->setStaticY(m_height); + o->setStaticY(height()); needToSetStaticY = false; } bool needToCreateLineBox = needToSetStaticX || needToSetStaticY; RenderObject* c = o->container(); - if (c->isInlineFlow() && (!needToSetStaticX || !needToSetStaticY)) + if (c->isRenderInline() && (!needToSetStaticX || !needToSetStaticY)) needToCreateLineBox = true; // If we're ignoring spaces, we have to stop and include this object and @@ -1777,15 +1747,17 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, ECle } } - } else if (o->isInlineFlow()) { + } else if (o->isRenderInline()) { // Right now, we should only encounter empty inlines here. ASSERT(!o->firstChild()); + RenderBox* flowBox = toRenderBox(o); + // Now that some inline flows have line boxes, if we are already ignoring spaces, we need // to make sure that we stop to include this object and then start ignoring spaces again. // If this object is at the start of the line, we need to behave like list markers and // start ignoring spaces. - if (inlineFlowRequiresLineBox(o)) { + if (inlineFlowRequiresLineBox(flowBox)) { isLineEmpty = false; if (ignoringSpaces) { trailingSpaceObject = 0; @@ -1801,9 +1773,11 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, ECle } } - tmpW += o->marginLeft() + o->borderLeft() + o->paddingLeft() + - o->marginRight() + o->borderRight() + o->paddingRight(); + tmpW += flowBox->marginLeft() + flowBox->borderLeft() + flowBox->paddingLeft() + + flowBox->marginRight() + flowBox->borderRight() + flowBox->paddingRight(); } 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; @@ -1833,12 +1807,12 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, ECle ignoringSpaces = true; } } else - tmpW += o->width() + o->marginLeft() + o->marginRight() + inlineWidth(o); + tmpW += replacedBox->width() + replacedBox->marginLeft() + replacedBox->marginRight() + inlineWidth(o); } else if (o->isText()) { if (!pos) appliedStartWidth = false; - RenderText* t = static_cast<RenderText*>(o); + RenderText* t = toRenderText(o); int strlen = t->textLength(); int len = strlen - pos; @@ -1885,7 +1859,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, ECle if (pos) beforeSoftHyphen = InlineIterator(0, o, pos - 1); else - beforeSoftHyphen = InlineIterator(0, last, last->isText() ? static_cast<RenderText*>(last)->textLength() - 1 : 0); + beforeSoftHyphen = InlineIterator(0, last, last->isText() ? toRenderText(last)->textLength() - 1 : 0); // Two consecutive soft hyphens. Avoid overlapping midpoints. if (sNumMidpoints && smidpoints->at(sNumMidpoints - 1).obj == o && smidpoints->at(sNumMidpoints - 1).pos == pos) sNumMidpoints--; @@ -1975,7 +1949,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, ECle } } if (lineWasTooWide || w + tmpW > width) { - if (lBreak.obj && shouldPreserveNewline(lBreak.obj) && lBreak.obj->isText() && !static_cast<RenderText*>(lBreak.obj)->isWordBreak() && static_cast<RenderText*>(lBreak.obj)->characters()[lBreak.pos] == '\n') { + if (lBreak.obj && shouldPreserveNewline(lBreak.obj) && lBreak.obj->isText() && !toRenderText(lBreak.obj)->isWordBreak() && toRenderText(lBreak.obj)->characters()[lBreak.pos] == '\n') { if (!stoppedIgnoringSpaces && pos > 0) { // We need to stop right before the newline and then start up again. addMidpoint(InlineIterator(0, o, pos - 1)); // Stop @@ -2096,7 +2070,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, ECle checkForBreak = true; else { checkForBreak = false; - RenderText* nextText = static_cast<RenderText*>(next); + RenderText* nextText = toRenderText(next); if (nextText->textLength()) { UChar c = nextText->characters()[0]; if (c == ' ' || c == '\t' || (c == '\n' && !shouldPreserveNewline(next))) @@ -2220,7 +2194,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, ECle // lBreak.pos--; else if (lBreak.obj == 0 && trailingSpaceObject->isText()) { // Add a new end midpoint that stops right at the very end. - RenderText* text = static_cast<RenderText *>(trailingSpaceObject); + RenderText* text = toRenderText(trailingSpaceObject); unsigned length = text->textLength(); unsigned pos = length >= 2 ? length - 2 : UINT_MAX; InlineIterator endMid(0, trailingSpaceObject, pos); @@ -2240,7 +2214,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, ECle if (lBreak.obj && lBreak.pos >= 2 && lBreak.obj->isText()) { // For soft hyphens on line breaks, we have to chop out the midpoints that made us // ignore the hyphen so that it will render at the end of the line. - UChar c = static_cast<RenderText*>(lBreak.obj)->characters()[lBreak.pos-1]; + UChar c = toRenderText(lBreak.obj)->characters()[lBreak.pos-1]; if (c == softHyphen) chopMidpointsAt(lBreak.obj, lBreak.pos-2); } @@ -2250,7 +2224,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, ECle void RenderBlock::checkLinesForOverflow() { - m_overflowWidth = m_width; + m_overflowWidth = width(); for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) { m_overflowLeft = min(curr->leftOverflow(), m_overflowLeft); m_overflowTop = min(curr->topOverflow(), m_overflowTop); @@ -2270,7 +2244,7 @@ void RenderBlock::checkLinesForTextOverflow() // Determine the width of the ellipsis using the current font. // FIXME: CSS3 says this is configurable, also need to use 0x002E (FULL STOP) if horizontal ellipsis is "not renderable" TextRun ellipsisRun(&horizontalEllipsis, 1); - static AtomicString ellipsisStr(&horizontalEllipsis, 1); + DEFINE_STATIC_LOCAL(AtomicString, ellipsisStr, (&horizontalEllipsis, 1)); const Font& firstLineFont = firstLineStyle()->font(); const Font& font = style()->font(); int firstLineEllipsisWidth = firstLineFont.width(ellipsisRun); diff --git a/WebCore/rendering/bidi.h b/WebCore/rendering/bidi.h index fc6de5b..9058eeb 100644 --- a/WebCore/rendering/bidi.h +++ b/WebCore/rendering/bidi.h @@ -38,7 +38,6 @@ struct BidiRun : BidiCharacterRun { : BidiCharacterRun(start, stop, context, dir) , m_object(object) , m_box(0) - , m_compact(false) { } @@ -59,7 +58,6 @@ private: public: RenderObject* m_object; InlineBox* m_box; - bool m_compact; }; } // namespace WebCore diff --git a/WebCore/rendering/style/Animation.cpp b/WebCore/rendering/style/Animation.cpp deleted file mode 100644 index ed3a7e7..0000000 --- a/WebCore/rendering/style/Animation.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org) - * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#include "config.h" -#include "Animation.h" - -#include "RenderStyle.h" - -namespace WebCore { - -Animation::Animation() - : m_delay(RenderStyle::initialAnimationDelay()) - , m_direction(RenderStyle::initialAnimationDirection()) - , m_duration(RenderStyle::initialAnimationDuration()) - , m_iterationCount(RenderStyle::initialAnimationIterationCount()) - , m_name(RenderStyle::initialAnimationName()) - , m_property(RenderStyle::initialAnimationProperty()) - , m_timingFunction(RenderStyle::initialAnimationTimingFunction()) - , m_playState(RenderStyle::initialAnimationPlayState()) - , m_delaySet(false) - , m_directionSet(false) - , m_durationSet(false) - , m_iterationCountSet(false) - , m_nameSet(false) - , m_playStateSet(false) - , m_propertySet(false) - , m_timingFunctionSet(false) - , m_isNone(false) -{ -} - -Animation::Animation(const Animation& o) - : RefCounted<Animation>() - , m_delay(o.m_delay) - , m_direction(o.m_direction) - , m_duration(o.m_duration) - , m_iterationCount(o.m_iterationCount) - , m_name(o.m_name) - , m_property(o.m_property) - , m_timingFunction(o.m_timingFunction) - , m_playState(o.m_playState) - , m_delaySet(o.m_delaySet) - , m_directionSet(o.m_directionSet) - , m_durationSet(o.m_durationSet) - , m_iterationCountSet(o.m_iterationCountSet) - , m_nameSet(o.m_nameSet) - , m_playStateSet(o.m_playStateSet) - , m_propertySet(o.m_propertySet) - , m_timingFunctionSet(o.m_timingFunctionSet) - , m_isNone(o.m_isNone) -{ -} - -Animation& Animation::operator=(const Animation& o) -{ - m_delay = o.m_delay; - m_direction = o.m_direction; - m_duration = o.m_duration; - m_iterationCount = o.m_iterationCount; - m_name = o.m_name; - m_playState = o.m_playState; - m_property = o.m_property; - m_timingFunction = o.m_timingFunction; - - m_delaySet = o.m_delaySet; - m_directionSet = o.m_directionSet; - m_durationSet = o.m_durationSet; - m_iterationCountSet = o.m_iterationCountSet; - m_nameSet = o.m_nameSet; - m_playStateSet = o.m_playStateSet; - m_propertySet = o.m_propertySet; - m_timingFunctionSet = o.m_timingFunctionSet; - - m_isNone = o.m_isNone; - - return *this; -} - -Animation::~Animation() -{ -} - -bool Animation::animationsMatch(const Animation* o, bool matchPlayStates) const -{ - if (!o) - return false; - - bool result = m_delay == o->m_delay && - m_direction == o->m_direction && - m_duration == o->m_duration && - m_iterationCount == o->m_iterationCount && - m_name == o->m_name && - m_property == o->m_property && - m_timingFunction == o->m_timingFunction && - m_delaySet == o->m_delaySet && - m_directionSet == o->m_directionSet && - m_durationSet == o->m_durationSet && - m_iterationCountSet == o->m_iterationCountSet && - m_nameSet == o->m_nameSet && - m_propertySet == o->m_propertySet && - m_timingFunctionSet == o->m_timingFunctionSet && - m_isNone == o->m_isNone; - - if (!result) - return false; - - return !matchPlayStates || (m_playState == o->m_playState && m_playStateSet == o->m_playStateSet); -} - -} // namespace WebCore diff --git a/WebCore/rendering/style/Animation.h b/WebCore/rendering/style/Animation.h deleted file mode 100644 index 8930e30..0000000 --- a/WebCore/rendering/style/Animation.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (C) 2000 Lars Knoll (knoll@kde.org) - * (C) 2000 Antti Koivisto (koivisto@kde.org) - * (C) 2000 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com) - * - * 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 Animation_h -#define Animation_h - -#include "PlatformString.h" -#include "TimingFunction.h" -#include <wtf/PassRefPtr.h> -#include <wtf/RefCounted.h> - -namespace WebCore { - -class Animation : public RefCounted<Animation> { -public: - ~Animation(); - - static PassRefPtr<Animation> create() { return adoptRef(new Animation); }; - - bool isDelaySet() const { return m_delaySet; } - bool isDirectionSet() const { return m_directionSet; } - bool isDurationSet() const { return m_durationSet; } - bool isIterationCountSet() const { return m_iterationCountSet; } - bool isNameSet() const { return m_nameSet; } - bool isPlayStateSet() const { return m_playStateSet; } - bool isPropertySet() const { return m_propertySet; } - bool isTimingFunctionSet() const { return m_timingFunctionSet; } - - // Flags this to be the special "none" animation (animation-name: none) - bool isNoneAnimation() const { return m_isNone; } - // We can make placeholder Animation objects to keep the comma-separated lists - // of properties in sync. isValidAnimation means this is not a placeholder. - bool isValidAnimation() const { return !m_isNone && !m_name.isEmpty(); } - - bool isEmpty() const - { - return (!m_directionSet && !m_durationSet && !m_nameSet && !m_playStateSet && - !m_iterationCountSet && !m_delaySet && !m_timingFunctionSet && !m_propertySet); - } - - bool isEmptyOrZeroDuration() const - { - return isEmpty() || (m_duration == 0 && m_delay <= 0); - } - - void clearDelay() { m_delaySet = false; } - void clearDirection() { m_directionSet = false; } - void clearDuration() { m_durationSet = false; } - void clearIterationCount() { m_iterationCountSet = false; } - void clearName() { m_nameSet = false; } - void clearPlayState() { m_playStateSet = AnimPlayStatePlaying; } - void clearProperty() { m_propertySet = false; } - void clearTimingFunction() { m_timingFunctionSet = false; } - - double delay() const { return m_delay; } - bool direction() const { return m_direction; } - double duration() const { return m_duration; } - int iterationCount() const { return m_iterationCount; } - const String& name() const { return m_name; } - unsigned playState() const { return m_playState; } - int property() const { return m_property; } - const TimingFunction& timingFunction() const { return m_timingFunction; } - - void setDelay(double c) { m_delay = c; m_delaySet = true; } - void setDirection(bool d) { m_direction = d; m_directionSet = true; } - void setDuration(double d) { ASSERT(d >= 0); m_duration = d; m_durationSet = true; } - void setIterationCount(int c) { m_iterationCount = c; m_iterationCountSet = true; } - void setName(const String& n) { m_name = n; m_nameSet = true; } - void setPlayState(unsigned d) { m_playState = d; m_playStateSet = true; } - void setProperty(int t) { m_property = t; m_propertySet = true; } - void setTimingFunction(const TimingFunction& f) { m_timingFunction = f; m_timingFunctionSet = true; } - - void setIsNoneAnimation(bool n) { m_isNone = n; } - - Animation& operator=(const Animation& o); - - // return true if all members of this class match (excluding m_next) - bool animationsMatch(const Animation*, bool matchPlayStates = true) const; - - // return true every Animation in the chain (defined by m_next) match - bool operator==(const Animation& o) const { return animationsMatch(&o); } - bool operator!=(const Animation& o) const { return !(*this == o); } - -private: - Animation(); - Animation(const Animation& o); - - double m_delay; - bool m_direction; - double m_duration; - int m_iterationCount; - String m_name; - int m_property; - TimingFunction m_timingFunction; - - unsigned m_playState : 2; - - bool m_delaySet : 1; - bool m_directionSet : 1; - bool m_durationSet : 1; - bool m_iterationCountSet : 1; - bool m_nameSet : 1; - bool m_playStateSet : 1; - bool m_propertySet : 1; - bool m_timingFunctionSet : 1; - - bool m_isNone : 1; -}; - -} // namespace WebCore - -#endif // Animation_h diff --git a/WebCore/rendering/style/AnimationList.cpp b/WebCore/rendering/style/AnimationList.cpp deleted file mode 100644 index 804dede..0000000 --- a/WebCore/rendering/style/AnimationList.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org) - * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#include "config.h" -#include "AnimationList.h" - -namespace WebCore { - -#define FILL_UNSET_PROPERTY(test, propGet, propSet) \ -for (i = 0; i < size() && animation(i)->test(); ++i) { } \ -if (i < size() && i != 0) { \ - for (size_t j = 0; i < size(); ++i, ++j) \ - animation(i)->propSet(animation(j)->propGet()); \ -} - -void AnimationList::fillUnsetProperties() -{ - size_t i; - FILL_UNSET_PROPERTY(isDelaySet, delay, setDelay); - FILL_UNSET_PROPERTY(isDirectionSet, direction, setDirection); - FILL_UNSET_PROPERTY(isDurationSet, duration, setDuration); - FILL_UNSET_PROPERTY(isIterationCountSet, iterationCount, setIterationCount); - FILL_UNSET_PROPERTY(isPlayStateSet, playState, setPlayState); - FILL_UNSET_PROPERTY(isNameSet, name, setName); - FILL_UNSET_PROPERTY(isTimingFunctionSet, timingFunction, setTimingFunction); - FILL_UNSET_PROPERTY(isPropertySet, property, setProperty); -} - -bool AnimationList::operator==(const AnimationList& o) const -{ - if (size() != o.size()) - return false; - for (size_t i = 0; i < size(); ++i) - if (*animation(i) != *o.animation(i)) - return false; - return true; -} - -} // namespace WebCore diff --git a/WebCore/rendering/style/AnimationList.h b/WebCore/rendering/style/AnimationList.h deleted file mode 100644 index 9901424..0000000 --- a/WebCore/rendering/style/AnimationList.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2000 Lars Knoll (knoll@kde.org) - * (C) 2000 Antti Koivisto (koivisto@kde.org) - * (C) 2000 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com) - * - * 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 AnimationList_h -#define AnimationList_h - -#include "Animation.h" -#include <wtf/RefPtr.h> -#include <wtf/Vector.h> - -namespace WebCore { - -class AnimationList { -public: - void fillUnsetProperties(); - bool operator==(const AnimationList& o) const; - bool operator!=(const AnimationList& o) const - { - return !(*this == o); - } - - size_t size() const { return m_animations.size(); } - bool isEmpty() const { return m_animations.isEmpty(); } - - void resize(size_t n) { m_animations.resize(n); } - void remove(size_t i) { m_animations.remove(i); } - void append(PassRefPtr<Animation> anim) { m_animations.append(anim); } - - Animation* animation(size_t i) { return m_animations[i].get(); } - const Animation* animation(size_t i) const { return m_animations[i].get(); } - -private: - Vector<RefPtr<Animation> > m_animations; -}; - - -} // namespace WebCore - -#endif // AnimationList_h diff --git a/WebCore/rendering/style/FillLayer.h b/WebCore/rendering/style/FillLayer.h index 8f0ad94..2dc5871 100644 --- a/WebCore/rendering/style/FillLayer.h +++ b/WebCore/rendering/style/FillLayer.h @@ -120,8 +120,8 @@ public: static EFillRepeat initialFillRepeat(EFillLayerType) { return RepeatFill; } static CompositeOperator initialFillComposite(EFillLayerType) { return CompositeSourceOver; } static LengthSize initialFillSize(EFillLayerType) { return LengthSize(); } - static Length initialFillXPosition(EFillLayerType type) { return Length(0.0, Percent); } - static Length initialFillYPosition(EFillLayerType type) { return Length(0.0, Percent); } + static Length initialFillXPosition(EFillLayerType) { return Length(0.0, Percent); } + static Length initialFillYPosition(EFillLayerType) { return Length(0.0, Percent); } static StyleImage* initialFillImage(EFillLayerType) { return 0; } private: diff --git a/WebCore/rendering/style/IdentityTransformOperation.h b/WebCore/rendering/style/IdentityTransformOperation.h deleted file mode 100644 index 54c49a3..0000000 --- a/WebCore/rendering/style/IdentityTransformOperation.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2000 Lars Knoll (knoll@kde.org) - * (C) 2000 Antti Koivisto (koivisto@kde.org) - * (C) 2000 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com) - * - * 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 IdentityTransformOperation_h -#define IdentityTransformOperation_h - -#include "TransformOperation.h" - -namespace WebCore { - -class IdentityTransformOperation : public TransformOperation { -public: - static PassRefPtr<IdentityTransformOperation> create() - { - return adoptRef(new IdentityTransformOperation()); - } - - virtual bool isIdentity() const { return true; } - virtual OperationType getOperationType() const { return IDENTITY; } - virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == IDENTITY; } - - virtual bool operator==(const TransformOperation& o) const - { - return isSameType(o); - } - - virtual bool apply(AffineTransform& transform, const IntSize& borderBoxSize) const - { - return false; - } - - virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false) - { - return this; - } - -private: - IdentityTransformOperation() - { - } - -}; - -} // namespace WebCore - -#endif // IdentityTransformOperation_h diff --git a/WebCore/rendering/style/MatrixTransformOperation.cpp b/WebCore/rendering/style/MatrixTransformOperation.cpp deleted file mode 100644 index c41ae3e..0000000 --- a/WebCore/rendering/style/MatrixTransformOperation.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org) - * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#include "config.h" -#include "MatrixTransformOperation.h" - -#include <algorithm> - -namespace WebCore { - -PassRefPtr<TransformOperation> MatrixTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity) -{ - if (from && !from->isSameType(*this)) - return this; - - // convert the TransformOperations into matrices - IntSize size; - AffineTransform fromT; - AffineTransform toT(m_a, m_b, m_c, m_d, m_e, m_f); - if (from) { - const MatrixTransformOperation* m = static_cast<const MatrixTransformOperation*>(from); - fromT.setMatrix(m->m_a, m->m_b, m->m_c, m->m_d, m->m_e, m->m_f); - } - - if (blendToIdentity) - std::swap(fromT, toT); - - toT.blend(fromT, progress); - return MatrixTransformOperation::create(toT.a(), toT.b(), toT.c(), toT.d(), toT.e(), toT.f()); -} - -} // namespace WebCore diff --git a/WebCore/rendering/style/MatrixTransformOperation.h b/WebCore/rendering/style/MatrixTransformOperation.h deleted file mode 100644 index 574f2a8..0000000 --- a/WebCore/rendering/style/MatrixTransformOperation.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2000 Lars Knoll (knoll@kde.org) - * (C) 2000 Antti Koivisto (koivisto@kde.org) - * (C) 2000 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com) - * - * 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 MatrixTransformOperation_h -#define MatrixTransformOperation_h - -#include "TransformOperation.h" - -namespace WebCore { - -class MatrixTransformOperation : public TransformOperation { -public: - static PassRefPtr<MatrixTransformOperation> create(double a, double b, double c, double d, double e, double f) - { - return adoptRef(new MatrixTransformOperation(a, b, c, d, e, f)); - } - - virtual bool isIdentity() const { return m_a == 1 && m_b == 0 && m_c == 0 && m_d == 1 && m_e == 0 && m_f == 0; } - virtual OperationType getOperationType() const { return MATRIX; } - virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == MATRIX; } - - virtual bool operator==(const TransformOperation& o) const - { - if (!isSameType(o)) - return false; - - const MatrixTransformOperation* m = static_cast<const MatrixTransformOperation*>(&o); - return m_a == m->m_a && m_b == m->m_b && m_c == m->m_c && m_d == m->m_d && m_e == m->m_e && m_f == m->m_f; - } - - virtual bool apply(AffineTransform& transform, const IntSize& borderBoxSize) const - { - AffineTransform matrix(m_a, m_b, m_c, m_d, m_e, m_f); - transform = matrix * transform; - return false; - } - - virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false); - -private: - MatrixTransformOperation(double a, double b, double c, double d, double e, double f) - : m_a(a) - , m_b(b) - , m_c(c) - , m_d(d) - , m_e(e) - , m_f(f) - { - } - - double m_a; - double m_b; - double m_c; - double m_d; - double m_e; - double m_f; -}; - -} // namespace WebCore - -#endif // MatrixTransformOperation_h diff --git a/WebCore/rendering/style/RenderStyle.cpp b/WebCore/rendering/style/RenderStyle.cpp index 5088c33..09445b9 100644 --- a/WebCore/rendering/style/RenderStyle.cpp +++ b/WebCore/rendering/style/RenderStyle.cpp @@ -29,6 +29,7 @@ #include "RenderArena.h" #include "RenderObject.h" #include "StyleImage.h" +#include <wtf/StdLibExtras.h> #include <algorithm> namespace WebCore { @@ -232,7 +233,7 @@ bool RenderStyle::inheritedNotEqual(RenderStyle* other) const rareInheritedData != other->rareInheritedData; } -bool positionedObjectMoved(const LengthBox& a, const LengthBox& b) +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. @@ -498,7 +499,8 @@ void RenderStyle::setCursorList(PassRefPtr<CursorList> other) void RenderStyle::clearCursorList() { - inherited.access()->cursorData = CursorList::create(); + if (inherited->cursorData) + inherited.access()->cursorData = 0; } bool RenderStyle::contentDataEquivalent(const RenderStyle* otherStyle) const @@ -635,7 +637,7 @@ void RenderStyle::setContent(CounterContent* c, bool add) newContentData->m_type = CONTENT_COUNTER; } -void RenderStyle::applyTransform(AffineTransform& transform, const IntSize& borderBoxSize, bool includeTransformOrigin) const +void RenderStyle::applyTransform(TransformationMatrix& transform, const IntSize& borderBoxSize, bool includeTransformOrigin) const { // transform-origin brackets the transform with translate operations. // Optimize for the case where the only transform is a translation, since the transform-origin is irrelevant @@ -720,13 +722,13 @@ CounterDirectiveMap& RenderStyle::accessCounterDirectives() #if ENABLE(DASHBOARD_SUPPORT) const Vector<StyleDashboardRegion>& RenderStyle::initialDashboardRegions() { - static Vector<StyleDashboardRegion> emptyList; + DEFINE_STATIC_LOCAL(Vector<StyleDashboardRegion>, emptyList, ()); return emptyList; } const Vector<StyleDashboardRegion>& RenderStyle::noneDashboardRegions() { - static Vector<StyleDashboardRegion> noneList; + DEFINE_STATIC_LOCAL(Vector<StyleDashboardRegion>, noneList, ()); static bool noneListInitialized = false; if (!noneListInitialized) { @@ -750,7 +752,7 @@ void RenderStyle::adjustAnimations() if (!animationList) return; - // get rid of empty transitions and anything beyond them + // Get rid of empty animations and anything beyond them for (size_t i = 0; i < animationList->size(); ++i) { if (animationList->animation(i)->isEmpty()) { animationList->resize(i); @@ -773,7 +775,7 @@ void RenderStyle::adjustTransitions() if (!transitionList) return; - // get rid of empty transitions and anything beyond them + // Get rid of empty transitions and anything beyond them for (size_t i = 0; i < transitionList->size(); ++i) { if (transitionList->animation(i)->isEmpty()) { transitionList->resize(i); diff --git a/WebCore/rendering/style/RenderStyle.h b/WebCore/rendering/style/RenderStyle.h index 084bdc8..fed3057 100644 --- a/WebCore/rendering/style/RenderStyle.h +++ b/WebCore/rendering/style/RenderStyle.h @@ -25,7 +25,7 @@ #ifndef RenderStyle_h #define RenderStyle_h -#include "AffineTransform.h" +#include "TransformationMatrix.h" #include "AnimationList.h" #include "BorderData.h" #include "BorderValue.h" @@ -72,6 +72,7 @@ #include "TransformOperations.h" #include <wtf/OwnPtr.h> #include <wtf/RefCounted.h> +#include <wtf/StdLibExtras.h> #include <wtf/Vector.h> #if ENABLE(DASHBOARD_SUPPORT) @@ -110,8 +111,9 @@ public: // static pseudo styles. Dynamic ones are produced on the fly. enum PseudoId { NOPSEUDO, FIRST_LINE, FIRST_LETTER, BEFORE, AFTER, SELECTION, FIRST_LINE_INHERITED, SCROLLBAR, FILE_UPLOAD_BUTTON, INPUT_PLACEHOLDER, SLIDER_THUMB, SEARCH_CANCEL_BUTTON, SEARCH_DECORATION, SEARCH_RESULTS_DECORATION, SEARCH_RESULTS_BUTTON, MEDIA_CONTROLS_PANEL, - MEDIA_CONTROLS_PLAY_BUTTON, MEDIA_CONTROLS_MUTE_BUTTON, MEDIA_CONTROLS_TIMELINE, MEDIA_CONTROLS_TIME_DISPLAY, - MEDIA_CONTROLS_SEEK_BACK_BUTTON, MEDIA_CONTROLS_SEEK_FORWARD_BUTTON , MEDIA_CONTROLS_FULLSCREEN_BUTTON, + MEDIA_CONTROLS_PLAY_BUTTON, MEDIA_CONTROLS_MUTE_BUTTON, MEDIA_CONTROLS_TIMELINE, MEDIA_CONTROLS_TIMELINE_CONTAINER, + MEDIA_CONTROLS_CURRENT_TIME_DISPLAY, MEDIA_CONTROLS_TIME_REMAINING_DISPLAY, MEDIA_CONTROLS_SEEK_BACK_BUTTON, + MEDIA_CONTROLS_SEEK_FORWARD_BUTTON, MEDIA_CONTROLS_FULLSCREEN_BUTTON, SCROLLBAR_THUMB, SCROLLBAR_BUTTON, SCROLLBAR_TRACK, SCROLLBAR_TRACK_PIECE, SCROLLBAR_CORNER, RESIZER }; static const int FIRST_INTERNAL_PSEUDOID = FILE_UPLOAD_BUTTON; @@ -139,7 +141,8 @@ protected: (_box_direction == other._box_direction) && (_visuallyOrdered == other._visuallyOrdered) && (_htmlHacks == other._htmlHacks) && - (_force_backgrounds_to_white == other._force_backgrounds_to_white); + (_force_backgrounds_to_white == other._force_backgrounds_to_white) && + (_pointerEvents == other._pointerEvents); } bool operator!=(const InheritedFlags& other) const { return !(*this == other); } @@ -162,6 +165,7 @@ protected: bool _visuallyOrdered : 1; bool _htmlHacks :1; bool _force_backgrounds_to_white : 1; + unsigned _pointerEvents : 4; // EPointerEvents } inherited_flags; // don't inherit @@ -268,6 +272,7 @@ protected: inherited_flags._htmlHacks=false; inherited_flags._box_direction = initialBoxDirection(); inherited_flags._force_backgrounds_to_white = false; + inherited_flags._pointerEvents = initialPointerEvents(); noninherited_flags._effectiveDisplay = noninherited_flags._originalDisplay = initialDisplay(); noninherited_flags._overflowX = initialOverflowX(); @@ -624,11 +629,12 @@ public: Length transformOriginX() const { return rareNonInheritedData->m_transform->m_x; } Length transformOriginY() const { return rareNonInheritedData->m_transform->m_y; } bool hasTransform() const { return !rareNonInheritedData->m_transform->m_operations.operations().isEmpty(); } - void applyTransform(AffineTransform&, const IntSize& borderBoxSize, bool includeTransformOrigin = true) const; + void applyTransform(TransformationMatrix&, const IntSize& borderBoxSize, bool includeTransformOrigin = true) const; bool hasMask() const { return rareNonInheritedData->m_mask.hasImage() || rareNonInheritedData->m_maskBoxImage.hasImage(); } // End CSS3 Getters // Apple-specific property getter methods + EPointerEvents pointerEvents() const { return static_cast<EPointerEvents>(inherited_flags._pointerEvents); } const AnimationList* animations() const { return rareNonInheritedData->m_animations.get(); } const AnimationList* transitions() const { return rareNonInheritedData->m_transitions.get(); } @@ -923,6 +929,8 @@ public: // End CSS3 Setters // Apple-specific property setters + void setPointerEvents(EPointerEvents p) { inherited_flags._pointerEvents = p; } + void clearAnimations() { rareNonInheritedData.access()->m_animations.clear(); @@ -1107,19 +1115,12 @@ public: static bool initialVisuallyOrdered() { return false; } static float initialTextStrokeWidth() { return 0; } static unsigned short initialColumnCount() { return 1; } - static const TransformOperations& initialTransform() { static TransformOperations ops; return ops; } + static const TransformOperations& initialTransform() { DEFINE_STATIC_LOCAL(TransformOperations, ops, ()); return ops; } static Length initialTransformOriginX() { return Length(50.0, Percent); } static Length initialTransformOriginY() { return Length(50.0, Percent); } + static EPointerEvents initialPointerEvents() { return PE_AUTO; } // Keep these at the end. - static float initialAnimationDelay() { return 0; } - static bool initialAnimationDirection() { return false; } - static double initialAnimationDuration() { return 0; } - static int initialAnimationIterationCount() { return 1; } - static String initialAnimationName() { return String(); } - static unsigned initialAnimationPlayState() { return AnimPlayStatePlaying; } - static int initialAnimationProperty() { return cAnimateAll; } - static TimingFunction initialAnimationTimingFunction() { return TimingFunction(); } static int initialLineClamp() { return -1; } static bool initialTextSizeAdjust() { return true; } static ETextSecurity initialTextSecurity() { return TSNONE; } diff --git a/WebCore/rendering/style/RenderStyleConstants.h b/WebCore/rendering/style/RenderStyleConstants.h index 37fbc1e..40ad3cc 100644 --- a/WebCore/rendering/style/RenderStyleConstants.h +++ b/WebCore/rendering/style/RenderStyleConstants.h @@ -258,6 +258,11 @@ enum EDisplay { TABLE_CAPTION, BOX, INLINE_BOX, NONE }; +enum EPointerEvents { + PE_NONE, PE_AUTO, PE_STROKE, PE_FILL, PE_PAINTED, PE_VISIBLE, + PE_VISIBLE_STROKE, PE_VISIBLE_FILL, PE_VISIBLE_PAINTED, PE_ALL +}; + } // namespace WebCore #endif // RenderStyleConstants_h diff --git a/WebCore/rendering/style/RotateTransformOperation.cpp b/WebCore/rendering/style/RotateTransformOperation.cpp deleted file mode 100644 index 4887cee..0000000 --- a/WebCore/rendering/style/RotateTransformOperation.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org) - * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#include "config.h" -#include "RotateTransformOperation.h" - -namespace WebCore { - -PassRefPtr<TransformOperation> RotateTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity) -{ - if (from && !from->isSameType(*this)) - return this; - - if (blendToIdentity) - return RotateTransformOperation::create(m_angle - m_angle * progress, m_type); - - const RotateTransformOperation* fromOp = static_cast<const RotateTransformOperation*>(from); - double fromAngle = fromOp ? fromOp->m_angle : 0; - return RotateTransformOperation::create(fromAngle + (m_angle - fromAngle) * progress, m_type); -} - -} // namespace WebCore diff --git a/WebCore/rendering/style/RotateTransformOperation.h b/WebCore/rendering/style/RotateTransformOperation.h deleted file mode 100644 index 9cfc9c8..0000000 --- a/WebCore/rendering/style/RotateTransformOperation.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2000 Lars Knoll (knoll@kde.org) - * (C) 2000 Antti Koivisto (koivisto@kde.org) - * (C) 2000 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com) - * - * 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 RotateTransformOperation_h -#define RotateTransformOperation_h - -#include "TransformOperation.h" - -namespace WebCore { - -class RotateTransformOperation : public TransformOperation { -public: - static PassRefPtr<RotateTransformOperation> create(double angle, OperationType type) - { - return adoptRef(new RotateTransformOperation(angle, type)); - } - - virtual bool isIdentity() const { return m_angle == 0; } - virtual OperationType getOperationType() const { return m_type; } - virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == m_type; } - - virtual bool operator==(const TransformOperation& o) const - { - if (!isSameType(o)) - return false; - const RotateTransformOperation* r = static_cast<const RotateTransformOperation*>(&o); - return m_angle == r->m_angle; - } - - virtual bool apply(AffineTransform& transform, const IntSize& borderBoxSize) const - { - transform.rotate(m_angle); - return false; - } - - virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false); - - double angle() const { return m_angle; } - -private: - RotateTransformOperation(double angle, OperationType type) - : m_angle(angle) - , m_type(type) - { - } - - double m_angle; - OperationType m_type; -}; - -} // namespace WebCore - -#endif // RotateTransformOperation_h diff --git a/WebCore/rendering/style/SVGRenderStyle.h b/WebCore/rendering/style/SVGRenderStyle.h index 5724621..0e9dae4 100644 --- a/WebCore/rendering/style/SVGRenderStyle.h +++ b/WebCore/rendering/style/SVGRenderStyle.h @@ -63,7 +63,6 @@ namespace WebCore { SVG_RS_DEFINE_ATTRIBUTE_INHERITED(WindRule, FillRule, fillRule, RULE_NONZERO) SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EImageRendering, ImageRendering, imageRendering, IR_AUTO) SVG_RS_DEFINE_ATTRIBUTE_INHERITED(LineJoin, JoinStyle, joinStyle, MiterJoin) - SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EPointerEvents, PointerEvents, pointerEvents, PE_VISIBLE_PAINTED) SVG_RS_DEFINE_ATTRIBUTE_INHERITED(EShapeRendering, ShapeRendering, shapeRendering, SR_AUTO) SVG_RS_DEFINE_ATTRIBUTE_INHERITED(ETextAnchor, TextAnchor, textAnchor, TA_START) SVG_RS_DEFINE_ATTRIBUTE_INHERITED(ETextRendering, TextRendering, textRendering, TR_AUTO) @@ -122,7 +121,6 @@ namespace WebCore { (_textAnchor == other._textAnchor) && (_colorInterpolation == other._colorInterpolation) && (_colorInterpolationFilters == other._colorInterpolationFilters) && - (_pointerEvents == other._pointerEvents) && (_writingMode == other._writingMode) && (_glyphOrientationHorizontal == other._glyphOrientationHorizontal) && (_glyphOrientationVertical == other._glyphOrientationVertical); @@ -144,7 +142,6 @@ namespace WebCore { unsigned _textAnchor : 2; // ETextAnchor unsigned _colorInterpolation : 2; // EColorInterpolation unsigned _colorInterpolationFilters : 2; // EColorInterpolation - unsigned _pointerEvents : 4; // EPointerEvents unsigned _writingMode : 3; // EWritingMode unsigned _glyphOrientationHorizontal : 3; // EGlyphOrientation unsigned _glyphOrientationVertical : 3; // EGlyphOrientation @@ -199,7 +196,6 @@ namespace WebCore { svg_inherited_flags._joinStyle = initialJoinStyle(); svg_inherited_flags._colorInterpolation = initialColorInterpolation(); svg_inherited_flags._colorInterpolationFilters = initialColorInterpolationFilters(); - svg_inherited_flags._pointerEvents = initialPointerEvents(); svg_inherited_flags._writingMode = initialWritingMode(); svg_inherited_flags._glyphOrientationHorizontal = initialGlyphOrientationHorizontal(); svg_inherited_flags._glyphOrientationVertical = initialGlyphOrientationVertical(); diff --git a/WebCore/rendering/style/SVGRenderStyleDefs.h b/WebCore/rendering/style/SVGRenderStyleDefs.h index 12a70d3..cb504d2 100644 --- a/WebCore/rendering/style/SVGRenderStyleDefs.h +++ b/WebCore/rendering/style/SVGRenderStyleDefs.h @@ -119,11 +119,6 @@ namespace WebCore { DB_CENTRAL, DB_MIDDLE, DB_TEXT_AFTER_EDGE, DB_TEXT_BEFORE_EDGE }; - enum EPointerEvents { - PE_NONE, PE_STROKE, PE_FILL, PE_PAINTED, PE_VISIBLE, - PE_VISIBLE_STROKE, PE_VISIBLE_FILL, PE_VISIBLE_PAINTED, PE_ALL - }; - class CSSValue; class CSSValueList; class SVGPaint; diff --git a/WebCore/rendering/style/ScaleTransformOperation.cpp b/WebCore/rendering/style/ScaleTransformOperation.cpp deleted file mode 100644 index 49a8fd8..0000000 --- a/WebCore/rendering/style/ScaleTransformOperation.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org) - * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#include "config.h" -#include "ScaleTransformOperation.h" - -namespace WebCore { - -PassRefPtr<TransformOperation> ScaleTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity) -{ - if (from && !from->isSameType(*this)) - return this; - - if (blendToIdentity) - return ScaleTransformOperation::create(m_x + (1. - m_x) * progress, m_y + (1. - m_y) * progress, m_type); - - const ScaleTransformOperation* fromOp = static_cast<const ScaleTransformOperation*>(from); - double fromX = fromOp ? fromOp->m_x : 1.; - double fromY = fromOp ? fromOp->m_y : 1.; - return ScaleTransformOperation::create(fromX + (m_x - fromX) * progress, fromY + (m_y - fromY) * progress, m_type); -} - -} // namespace WebCore diff --git a/WebCore/rendering/style/ScaleTransformOperation.h b/WebCore/rendering/style/ScaleTransformOperation.h deleted file mode 100644 index 787f067..0000000 --- a/WebCore/rendering/style/ScaleTransformOperation.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2000 Lars Knoll (knoll@kde.org) - * (C) 2000 Antti Koivisto (koivisto@kde.org) - * (C) 2000 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com) - * - * 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 ScaleTransformOperation_h -#define ScaleTransformOperation_h - -#include "TransformOperation.h" - -namespace WebCore { - -class ScaleTransformOperation : public TransformOperation { -public: - static PassRefPtr<ScaleTransformOperation> create(double sx, double sy, OperationType type) - { - return adoptRef(new ScaleTransformOperation(sx, sy, type)); - } - - virtual bool isIdentity() const { return m_x == 1 && m_y == 1; } - virtual OperationType getOperationType() const { return m_type; } - virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == m_type; } - - virtual bool operator==(const TransformOperation& o) const - { - if (!isSameType(o)) - return false; - const ScaleTransformOperation* s = static_cast<const ScaleTransformOperation*>(&o); - return m_x == s->m_x && m_y == s->m_y; - } - - virtual bool apply(AffineTransform& transform, const IntSize& borderBoxSize) const - { - transform.scale(m_x, m_y); - return false; - } - - virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false); - -private: - ScaleTransformOperation(double sx, double sy, OperationType type) - : m_x(sx) - , m_y(sy) - , m_type(type) - { - } - - double m_x; - double m_y; - OperationType m_type; -}; - -} // namespace WebCore - -#endif // ScaleTransformOperation_h diff --git a/WebCore/rendering/style/SkewTransformOperation.cpp b/WebCore/rendering/style/SkewTransformOperation.cpp deleted file mode 100644 index 2a430e9..0000000 --- a/WebCore/rendering/style/SkewTransformOperation.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org) - * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#include "config.h" -#include "SkewTransformOperation.h" - -namespace WebCore { - -PassRefPtr<TransformOperation> SkewTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity) -{ - if (from && !from->isSameType(*this)) - return this; - - if (blendToIdentity) - return SkewTransformOperation::create(m_angleX - m_angleX * progress, m_angleY - m_angleY * progress, m_type); - - const SkewTransformOperation* fromOp = static_cast<const SkewTransformOperation*>(from); - double fromAngleX = fromOp ? fromOp->m_angleX : 0; - double fromAngleY = fromOp ? fromOp->m_angleY : 0; - return SkewTransformOperation::create(fromAngleX + (m_angleX - fromAngleX) * progress, fromAngleY + (m_angleY - fromAngleY) * progress, m_type); -} - -} // namespace WebCore diff --git a/WebCore/rendering/style/SkewTransformOperation.h b/WebCore/rendering/style/SkewTransformOperation.h deleted file mode 100644 index a7879e8..0000000 --- a/WebCore/rendering/style/SkewTransformOperation.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2000 Lars Knoll (knoll@kde.org) - * (C) 2000 Antti Koivisto (koivisto@kde.org) - * (C) 2000 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com) - * - * 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 SkewTransformOperation_h -#define SkewTransformOperation_h - -#include "TransformOperation.h" - -namespace WebCore { - -class SkewTransformOperation : public TransformOperation { -public: - static PassRefPtr<SkewTransformOperation> create(double angleX, double angleY, OperationType type) - { - return adoptRef(new SkewTransformOperation(angleX, angleY, type)); - } - - virtual bool isIdentity() const { return m_angleX == 0 && m_angleY == 0; } - virtual OperationType getOperationType() const { return m_type; } - virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == m_type; } - - virtual bool operator==(const TransformOperation& o) const - { - if (!isSameType(o)) - return false; - const SkewTransformOperation* s = static_cast<const SkewTransformOperation*>(&o); - return m_angleX == s->m_angleX && m_angleY == s->m_angleY; - } - - virtual bool apply(AffineTransform& transform, const IntSize& borderBoxSize) const - { - transform.skew(m_angleX, m_angleY); - return false; - } - - virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false); - -private: - SkewTransformOperation(double angleX, double angleY, OperationType type) - : m_angleX(angleX) - , m_angleY(angleY) - , m_type(type) - { - } - - double m_angleX; - double m_angleY; - OperationType m_type; -}; - -} // namespace WebCore - -#endif // SkewTransformOperation_h diff --git a/WebCore/rendering/style/StyleCachedImage.cpp b/WebCore/rendering/style/StyleCachedImage.cpp index 17ebce9..b55c5b9 100644 --- a/WebCore/rendering/style/StyleCachedImage.cpp +++ b/WebCore/rendering/style/StyleCachedImage.cpp @@ -84,7 +84,7 @@ void StyleCachedImage::removeClient(RenderObject* renderer) return m_image->removeClient(renderer); } -Image* StyleCachedImage::image(RenderObject* renderer, const IntSize&) const +Image* StyleCachedImage::image(RenderObject*, const IntSize&) const { return m_image->image(); } diff --git a/WebCore/rendering/style/StyleImage.h b/WebCore/rendering/style/StyleImage.h index 4bdba6e..cb90288 100644 --- a/WebCore/rendering/style/StyleImage.h +++ b/WebCore/rendering/style/StyleImage.h @@ -48,7 +48,7 @@ public: virtual PassRefPtr<CSSValue> cssValue() = 0; - virtual bool canRender(float multiplier) const { return true; } + virtual bool canRender(float /*multiplier*/) const { return true; } virtual bool isLoaded() const { return true; } virtual bool errorOccurred() const { return false; } virtual IntSize imageSize(const RenderObject*, float multiplier) const = 0; diff --git a/WebCore/rendering/style/TimingFunction.h b/WebCore/rendering/style/TimingFunction.h deleted file mode 100644 index f114596..0000000 --- a/WebCore/rendering/style/TimingFunction.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2000 Lars Knoll (knoll@kde.org) - * (C) 2000 Antti Koivisto (koivisto@kde.org) - * (C) 2000 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com) - * - * 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 TimingFunction_h -#define TimingFunction_h - -#include "RenderStyleConstants.h" - -namespace WebCore { - -struct TimingFunction { - TimingFunction() - : m_type(CubicBezierTimingFunction) - , m_x1(0.25) - , m_y1(0.1) - , m_x2(0.25) - , m_y2(1.0) - { - } - - TimingFunction(ETimingFunctionType timingFunction, double x1 = 0.0, double y1 = 0.0, double x2 = 1.0, double y2 = 1.0) - : m_type(timingFunction) - , m_x1(x1) - , m_y1(y1) - , m_x2(x2) - , m_y2(y2) - { - } - - bool operator==(const TimingFunction& o) const - { - return m_type == o.m_type && m_x1 == o.m_x1 && m_y1 == o.m_y1 && m_x2 == o.m_x2 && m_y2 == o.m_y2; - } - - double x1() const { return m_x1; } - double y1() const { return m_y1; } - double x2() const { return m_x2; } - double y2() const { return m_y2; } - - ETimingFunctionType type() const { return m_type; } - -private: - ETimingFunctionType m_type; - - double m_x1; - double m_y1; - double m_x2; - double m_y2; -}; - -} // namespace WebCore - -#endif // TimingFunction_h diff --git a/WebCore/rendering/style/TransformOperation.h b/WebCore/rendering/style/TransformOperation.h deleted file mode 100644 index 1baa67d..0000000 --- a/WebCore/rendering/style/TransformOperation.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2000 Lars Knoll (knoll@kde.org) - * (C) 2000 Antti Koivisto (koivisto@kde.org) - * (C) 2000 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com) - * - * 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 TransformOperation_h -#define TransformOperation_h - -#include "AffineTransform.h" -#include "IntSize.h" -#include <wtf/PassRefPtr.h> -#include <wtf/RefCounted.h> - -namespace WebCore { - -// CSS Transforms (may become part of CSS3) - -class TransformOperation : public RefCounted<TransformOperation> { -public: - enum OperationType { - SCALE_X, SCALE_Y, SCALE, - TRANSLATE_X, TRANSLATE_Y, TRANSLATE, - ROTATE, - SKEW_X, SKEW_Y, SKEW, - MATRIX, IDENTITY, NONE - }; - - virtual ~TransformOperation() { } - - virtual bool operator==(const TransformOperation&) const = 0; - bool operator!=(const TransformOperation& o) const { return !(*this == o); } - - virtual bool isIdentity() const = 0; - - virtual bool apply(AffineTransform&, const IntSize& borderBoxSize) const = 0; - - virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false) = 0; - - virtual OperationType getOperationType() const = 0; - virtual bool isSameType(const TransformOperation& o) const { return false; } -}; - -} // namespace WebCore - -#endif // TransformOperation_h diff --git a/WebCore/rendering/style/TransformOperations.cpp b/WebCore/rendering/style/TransformOperations.cpp deleted file mode 100644 index 3d71480..0000000 --- a/WebCore/rendering/style/TransformOperations.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org) - * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#include "config.h" -#include "TransformOperations.h" - -#include "IdentityTransformOperation.h" - -namespace WebCore { - -TransformOperations::TransformOperations(bool makeIdentity) -{ - if (makeIdentity) - m_operations.append(IdentityTransformOperation::create()); -} - -bool TransformOperations::operator==(const TransformOperations& o) const -{ - if (m_operations.size() != o.m_operations.size()) - return false; - - unsigned s = m_operations.size(); - for (unsigned i = 0; i < s; i++) { - if (*m_operations[i] != *o.m_operations[i]) - return false; - } - - return true; -} - -} // namespace WebCore diff --git a/WebCore/rendering/style/TransformOperations.h b/WebCore/rendering/style/TransformOperations.h deleted file mode 100644 index d558a4e..0000000 --- a/WebCore/rendering/style/TransformOperations.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2000 Lars Knoll (knoll@kde.org) - * (C) 2000 Antti Koivisto (koivisto@kde.org) - * (C) 2000 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com) - * - * 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 TransformOperations_h -#define TransformOperations_h - -#include "TransformOperation.h" -#include <wtf/RefPtr.h> -#include <wtf/Vector.h> - -namespace WebCore { - -class TransformOperations { -public: - TransformOperations(bool makeIdentity = false); - - bool operator==(const TransformOperations& o) const; - bool operator!=(const TransformOperations& o) const - { - return !(*this == o); - } - - void apply(const IntSize& sz, AffineTransform& t) const - { - for (unsigned i = 0; i < m_operations.size(); ++i) - m_operations[i]->apply(t, sz); - } - - Vector<RefPtr<TransformOperation> >& operations() { return m_operations; } - const Vector<RefPtr<TransformOperation> >& operations() const { return m_operations; } - -private: - Vector<RefPtr<TransformOperation> > m_operations; -}; - -} // namespace WebCore - -#endif // TransformOperations_h diff --git a/WebCore/rendering/style/TranslateTransformOperation.cpp b/WebCore/rendering/style/TranslateTransformOperation.cpp deleted file mode 100644 index 47471c4..0000000 --- a/WebCore/rendering/style/TranslateTransformOperation.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org) - * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#include "config.h" -#include "TranslateTransformOperation.h" - -namespace WebCore { - -PassRefPtr<TransformOperation> TranslateTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity) -{ - if (from && !from->isSameType(*this)) - return this; - - if (blendToIdentity) - return TranslateTransformOperation::create(Length(m_x.type()).blend(m_x, progress), Length(m_y.type()).blend(m_y, progress), m_type); - - const TranslateTransformOperation* fromOp = static_cast<const TranslateTransformOperation*>(from); - Length fromX = fromOp ? fromOp->m_x : Length(m_x.type()); - Length fromY = fromOp ? fromOp->m_y : Length(m_y.type()); - return TranslateTransformOperation::create(m_x.blend(fromX, progress), m_y.blend(fromY, progress), m_type); -} - -} // namespace WebCore diff --git a/WebCore/rendering/style/TranslateTransformOperation.h b/WebCore/rendering/style/TranslateTransformOperation.h deleted file mode 100644 index c292ae7..0000000 --- a/WebCore/rendering/style/TranslateTransformOperation.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2000 Lars Knoll (knoll@kde.org) - * (C) 2000 Antti Koivisto (koivisto@kde.org) - * (C) 2000 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com) - * - * 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 TranslateTransformOperation_h -#define TranslateTransformOperation_h - -#include "Length.h" -#include "TransformOperation.h" - -namespace WebCore { - -class TranslateTransformOperation : public TransformOperation { -public: - static PassRefPtr<TranslateTransformOperation> create(const Length& tx, const Length& ty, OperationType type) - { - return adoptRef(new TranslateTransformOperation(tx, ty, type)); - } - - virtual bool isIdentity() const { return m_x.calcFloatValue(1) == 0 && m_y.calcFloatValue(1) == 0; } - virtual OperationType getOperationType() const { return m_type; } - virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == m_type; } - - virtual bool operator==(const TransformOperation& o) const - { - if (!isSameType(o)) - return false; - const TranslateTransformOperation* t = static_cast<const TranslateTransformOperation*>(&o); - return m_x == t->m_x && m_y == t->m_y; - } - - virtual bool apply(AffineTransform& transform, const IntSize& borderBoxSize) const - { - transform.translate(m_x.calcFloatValue(borderBoxSize.width()), m_y.calcFloatValue(borderBoxSize.height())); - return m_x.type() == Percent || m_y.type() == Percent; - } - - virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false); - -private: - TranslateTransformOperation(const Length& tx, const Length& ty, OperationType type) - : m_x(tx) - , m_y(ty) - , m_type(type) - { - } - - Length m_x; - Length m_y; - OperationType m_type; -}; - -} // namespace WebCore - -#endif // TranslateTransformOperation_h |