diff options
Diffstat (limited to 'WebCore/rendering')
158 files changed, 6214 insertions, 3500 deletions
diff --git a/WebCore/rendering/AutoTableLayout.cpp b/WebCore/rendering/AutoTableLayout.cpp index 43c66cd..c37fba4 100644 --- a/WebCore/rendering/AutoTableLayout.cpp +++ b/WebCore/rendering/AutoTableLayout.cpp @@ -59,8 +59,10 @@ void AutoTableLayout::recalcColumn(int effCol) RenderTableCell* maxContributor = 0; while (child) { - if (child->isTableSection()) { - RenderTableSection* section = static_cast<RenderTableSection*>(child); + if (child->isTableCol()) + toRenderTableCol(child)->calcPrefWidths(); + else if (child->isTableSection()) { + RenderTableSection* section = toRenderTableSection(child); int numRows = section->numRows(); RenderTableCell* last = 0; for (int i = 0; i < numRows; i++) { @@ -92,7 +94,7 @@ void AutoTableLayout::recalcColumn(int effCol) w.setRawValue(32760); if (w.isNegative()) w.setValue(0); - switch(w.type()) { + switch (w.type()) { case Fixed: // ignore width=0 if (w.value() > 0 && (int)l.width.type() != Percent) { @@ -167,7 +169,7 @@ void AutoTableLayout::fullRecalc() int cCol = 0; while (child) { if (child->isTableCol()) { - RenderTableCol *col = static_cast<RenderTableCol*>(child); + RenderTableCol *col = toRenderTableCol(child); int span = col->span(); if (col->firstChild()) { grpWidth = col->style()->width(); @@ -225,7 +227,7 @@ static bool shouldScaleColumns(RenderTable* table) if (tw.isPercent()) scale = false; else { - RenderTableCell* cell = static_cast<RenderTableCell*>(cb); + RenderTableCell* cell = toRenderTableCell(cb); if (cell->colSpan() > 1 || cell->table()->style()->width().isAuto()) scale = false; else @@ -575,7 +577,7 @@ void AutoTableLayout::layout() int reduction = min(w, excess); // the lines below might look inconsistent, but that's the way it's handled in mozilla excess -= reduction; - int newWidth = max(int (m_layoutStruct[i].effMinWidth), w - reduction); + int newWidth = max(static_cast<int>(m_layoutStruct[i].effMinWidth), w - reduction); available += w - newWidth; m_layoutStruct[i].calcWidth = newWidth; } diff --git a/WebCore/rendering/CounterNode.h b/WebCore/rendering/CounterNode.h index 57f9563..b432e1d 100644 --- a/WebCore/rendering/CounterNode.h +++ b/WebCore/rendering/CounterNode.h @@ -37,7 +37,7 @@ namespace WebCore { class RenderObject; -class CounterNode : Noncopyable { +class CounterNode : public Noncopyable { public: CounterNode(RenderObject*, bool isReset, int value); diff --git a/WebCore/rendering/FixedTableLayout.cpp b/WebCore/rendering/FixedTableLayout.cpp index f995fbf..ee3e75a 100644 --- a/WebCore/rendering/FixedTableLayout.cpp +++ b/WebCore/rendering/FixedTableLayout.cpp @@ -93,7 +93,7 @@ int FixedTableLayout::calcWidthArray(int) Length grpWidth; while (child) { if (child->isTableCol()) { - RenderTableCol* col = static_cast<RenderTableCol*>(child); + RenderTableCol* col = toRenderTableCol(child); if (col->firstChild()) grpWidth = col->style()->width(); else { @@ -128,6 +128,7 @@ int FixedTableLayout::calcWidthArray(int) currentEffectiveColumn++; } } + toRenderTableCol(child)->calcPrefWidths(); } else break; @@ -155,7 +156,7 @@ int FixedTableLayout::calcWidthArray(int) child = firstRow->firstChild(); while (child) { if (child->isTableCell()) { - RenderTableCell* cell = static_cast<RenderTableCell*>(child); + RenderTableCell* cell = toRenderTableCell(child); if (cell->prefWidthsDirty()) cell->calcPrefWidths(); diff --git a/WebCore/rendering/HitTestResult.cpp b/WebCore/rendering/HitTestResult.cpp index f2ed7db..b7de46b 100644 --- a/WebCore/rendering/HitTestResult.cpp +++ b/WebCore/rendering/HitTestResult.cpp @@ -26,6 +26,7 @@ #include "HTMLAnchorElement.h" #include "HTMLImageElement.h" #include "HTMLInputElement.h" +#include "HTMLMediaElement.h" #include "HTMLNames.h" #include "RenderImage.h" #include "Scrollbar.h" @@ -145,17 +146,20 @@ bool HitTestResult::isSelected() const return frame->selection()->contains(m_point); } -String HitTestResult::spellingToolTip() const +String HitTestResult::spellingToolTip(TextDirection& dir) const { + dir = LTR; // Return the tool tip string associated with this point, if any. Only markers associated with bad grammar // currently supply strings, but maybe someday markers associated with misspelled words will also. if (!m_innerNonSharedNode) return String(); - DocumentMarker* marker = m_innerNonSharedNode->document()->markerContainingPoint(m_point, DocumentMarker::Grammar); + DocumentMarker* marker = m_innerNonSharedNode->document()->markerContainingPoint(m_point, DocumentMarker::Grammar); if (!marker) return String(); + if (RenderObject* renderer = m_innerNonSharedNode->renderer()) + dir = renderer->style()->direction(); return marker->description; } @@ -173,15 +177,19 @@ String HitTestResult::replacedString() const return marker->description; } -String HitTestResult::title() const +String HitTestResult::title(TextDirection& dir) const { + dir = LTR; // Find the title in the nearest enclosing DOM node. // For <area> tags in image maps, walk the tree for the <area>, not the <img> using it. for (Node* titleNode = m_innerNode.get(); titleNode; titleNode = titleNode->parentNode()) { if (titleNode->isElementNode()) { String title = static_cast<Element*>(titleNode)->title(); - if (!title.isEmpty()) + if (!title.isEmpty()) { + if (RenderObject* renderer = titleNode->renderer()) + dir = renderer->style()->direction(); return title; + } } } return String(); @@ -208,7 +216,7 @@ String HitTestResult::altDisplayString() const HTMLInputElement* input = static_cast<HTMLInputElement*>(m_innerNonSharedNode.get()); return displayString(input->alt(), m_innerNonSharedNode.get()); } - + #if ENABLE(WML) if (m_innerNonSharedNode->hasTagName(WMLNames::imgTag)) { WMLImageElement* image = static_cast<WMLImageElement*>(m_innerNonSharedNode.get()); @@ -266,7 +274,29 @@ KURL HitTestResult::absoluteImageURL() const } else return KURL(); - return m_innerNonSharedNode->document()->completeURL(parseURL(urlString)); + return m_innerNonSharedNode->document()->completeURL(deprecatedParseURL(urlString)); +} + +KURL HitTestResult::absoluteMediaURL() const +{ +#if ENABLE(VIDEO) + if (!(m_innerNonSharedNode && m_innerNonSharedNode->document())) + return KURL(); + + if (!(m_innerNonSharedNode->renderer() && m_innerNonSharedNode->renderer()->isMedia())) + return KURL(); + + AtomicString urlString; + if (m_innerNonSharedNode->hasTagName(HTMLNames::videoTag) || m_innerNonSharedNode->hasTagName(HTMLNames::audioTag)) { + HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(m_innerNonSharedNode.get()); + urlString = mediaElement->currentSrc(); + } else + return KURL(); + + return m_innerNonSharedNode->document()->completeURL(deprecatedParseURL(urlString)); +#else + return KURL(); +#endif } KURL HitTestResult::absoluteLinkURL() const @@ -288,7 +318,7 @@ KURL HitTestResult::absoluteLinkURL() const else return KURL(); - return m_innerURLElement->document()->completeURL(parseURL(urlString)); + return m_innerURLElement->document()->completeURL(deprecatedParseURL(urlString)); } bool HitTestResult::isLiveLink() const diff --git a/WebCore/rendering/HitTestResult.h b/WebCore/rendering/HitTestResult.h index 4f0383f..f29ca41 100644 --- a/WebCore/rendering/HitTestResult.h +++ b/WebCore/rendering/HitTestResult.h @@ -23,6 +23,7 @@ #define HitTestResult_h #include "IntPoint.h" +#include "TextDirection.h" #include <wtf/RefPtr.h> namespace WebCore { @@ -30,8 +31,8 @@ namespace WebCore { class Element; class Frame; class Image; -class KURL; class IntRect; +class KURL; class Node; class Scrollbar; class String; @@ -64,14 +65,15 @@ public: Frame* targetFrame() const; IntRect boundingBox() const; bool isSelected() const; - String spellingToolTip() const; + String spellingToolTip(TextDirection&) const; String replacedString() const; - String title() const; + String title(TextDirection&) const; String altDisplayString() const; String titleDisplayString() const; Image* image() const; IntRect imageRect() const; KURL absoluteImageURL() const; + KURL absoluteMediaURL() const; KURL absoluteLinkURL() const; String textContent() const; bool isLiveLink() const; diff --git a/WebCore/rendering/InlineBox.cpp b/WebCore/rendering/InlineBox.cpp index 2d956a8..bbf11b3 100644 --- a/WebCore/rendering/InlineBox.cpp +++ b/WebCore/rendering/InlineBox.cpp @@ -88,10 +88,10 @@ void InlineBox::showTreeForThis() const int InlineBox::height() const { #if ENABLE(SVG) - if (isSVG()) - return svgBoxHeight(); + if (hasVirtualHeight()) + return virtualHeight(); #endif - + if (renderer()->isText()) return m_isText ? renderer()->style(m_firstLine)->font().height() : 0; if (renderer()->isBox() && parent()) @@ -244,26 +244,26 @@ bool InlineBox::prevOnLineExists() const return m_prevOnLineExists; } -InlineBox* InlineBox::firstLeafChild() -{ - return this; -} - -InlineBox* InlineBox::lastLeafChild() -{ - return this; -} - -InlineBox* InlineBox::nextLeafChild() +InlineBox* InlineBox::nextLeafChild() const { - return parent() ? parent()->firstLeafChildAfterBox(this) : 0; + InlineBox* leaf = 0; + for (InlineBox* box = nextOnLine(); box && !leaf; box = box->nextOnLine()) + leaf = box->isLeaf() ? box : static_cast<InlineFlowBox*>(box)->firstLeafChild(); + if (!leaf && parent()) + leaf = parent()->nextLeafChild(); + return leaf; } - -InlineBox* InlineBox::prevLeafChild() + +InlineBox* InlineBox::prevLeafChild() const { - return parent() ? parent()->lastLeafChildBeforeBox(this) : 0; + InlineBox* leaf = 0; + for (InlineBox* box = prevOnLine(); box && !leaf; box = box->prevOnLine()) + leaf = box->isLeaf() ? box : static_cast<InlineFlowBox*>(box)->lastLeafChild(); + if (!leaf && parent()) + leaf = parent()->prevLeafChild(); + return leaf; } - + RenderObject::SelectionState InlineBox::selectionState() { return renderer()->selectionState(); diff --git a/WebCore/rendering/InlineBox.h b/WebCore/rendering/InlineBox.h index 9585278..c03758d 100644 --- a/WebCore/rendering/InlineBox.h +++ b/WebCore/rendering/InlineBox.h @@ -49,7 +49,7 @@ public: , m_dirty(false) , m_extracted(false) #if ENABLE(SVG) - , m_isSVG(false) + , m_hasVirtualHeight(false) #endif , m_endsWithBreak(false) , m_hasSelectedChildren(false) @@ -82,7 +82,7 @@ public: , m_dirty(dirty) , m_extracted(extracted) #if ENABLE(SVG) - , m_isSVG(false) + , m_hasVirtualHeight(false) #endif , m_endsWithBreak(false) , m_hasSelectedChildren(false) @@ -129,18 +129,22 @@ public: #ifndef NDEBUG void showTreeForThis() const; #endif + + bool isText() const { return m_isText; } + void setIsText(bool b) { m_isText = b; } + virtual bool isInlineBox() { return false; } virtual bool isInlineFlowBox() const { return false; } virtual bool isInlineTextBox() { return false; } virtual bool isRootInlineBox() const { return false; } #if ENABLE(SVG) virtual bool isSVGRootInlineBox() { return false; } - bool isSVG() const { return m_isSVG; } - void setIsSVG(bool b) { m_isSVG = b; } -#endif - bool isText() const { return m_isText; } - void setIsText(bool b) { m_isText = b; } + bool hasVirtualHeight() const { return m_hasVirtualHeight; } + void setHasVirtualHeight() { m_hasVirtualHeight = true; } + virtual int virtualHeight() const { ASSERT_NOT_REACHED(); return 0; } +#endif + bool isConstructed() { return m_constructed; } virtual void setConstructed() { @@ -171,10 +175,10 @@ public: bool nextOnLineExists() const; bool prevOnLineExists() const; - virtual InlineBox* firstLeafChild(); - virtual InlineBox* lastLeafChild(); - InlineBox* nextLeafChild(); - InlineBox* prevLeafChild(); + virtual bool isLeaf() const { return true; } + + InlineBox* nextLeafChild() const; + InlineBox* prevLeafChild() const; RenderObject* renderer() const { return m_renderer; } @@ -201,6 +205,9 @@ public: int height() const; + inline int baselinePosition(bool isRootLineBox) const { return renderer()->baselinePosition(m_firstLine, isRootLineBox); } + inline int lineHeight(bool isRootLineBox) const { return renderer()->lineHeight(m_firstLine, isRootLineBox); } + virtual int topOverflow() const { return y(); } virtual int bottomOverflow() const { return y() + height(); } virtual int leftOverflow() const { return x(); } @@ -239,15 +246,10 @@ public: RenderBoxModelObject* boxModelObject() const { if (!m_renderer->isText()) - return static_cast<RenderBoxModelObject*>(m_renderer); + return toRenderBoxModelObject(m_renderer); return 0; } -protected: -#if ENABLE(SVG) - virtual int svgBoxHeight() const { return 0; } -#endif - private: InlineBox* m_next; // The next element on the same line as us. InlineBox* m_prev; // The previous element on the same line as us. @@ -272,10 +274,7 @@ private: protected: bool m_dirty : 1; bool m_extracted : 1; - -#if ENABLE(SVG) - bool m_isSVG : 1; -#endif + bool m_hasVirtualHeight : 1; // for RootInlineBox bool m_endsWithBreak : 1; // Whether the line ends with a <br>. diff --git a/WebCore/rendering/InlineFlowBox.cpp b/WebCore/rendering/InlineFlowBox.cpp index 0432a4c..543c190 100644 --- a/WebCore/rendering/InlineFlowBox.cpp +++ b/WebCore/rendering/InlineFlowBox.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003, 2004, 2005, 2006, 2007 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 @@ -253,12 +253,10 @@ int InlineFlowBox::placeBoxesHorizontally(int xPos, int& leftPosition, int& righ // Set our x position. setX(xPos); - int boxShadowLeft = 0; - int boxShadowRight = 0; - for (ShadowData* boxShadow = renderer()->style(m_firstLine)->boxShadow(); boxShadow; boxShadow = boxShadow->next) { - boxShadowLeft = min(boxShadow->x - boxShadow->blur, boxShadowLeft); - boxShadowRight = max(boxShadow->x + boxShadow->blur, boxShadowRight); - } + int boxShadowLeft; + int boxShadowRight; + renderer()->style(m_firstLine)->getBoxShadowHorizontalExtent(boxShadowLeft, boxShadowRight); + leftPosition = min(xPos + boxShadowLeft, leftPosition); int startX = xPos; @@ -311,7 +309,7 @@ int InlineFlowBox::placeBoxesHorizontally(int xPos, int& leftPosition, int& righ xPos += flow->marginLeft(); xPos = flow->placeBoxesHorizontally(xPos, leftPosition, rightPosition, needsWordSpacing); xPos += flow->marginRight(); - } else if (!curr->renderer()->isListMarker() || static_cast<RenderListMarker*>(curr->renderer())->isInside()) { + } else if (!curr->renderer()->isListMarker() || toRenderListMarker(curr->renderer())->isInside()) { xPos += curr->boxModelObject()->marginLeft(); curr->setX(xPos); leftPosition = min(xPos + toRenderBox(curr->renderer())->overflowLeft(false), leftPosition); @@ -371,7 +369,7 @@ void InlineFlowBox::adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent, if (curr->renderer()->isPositioned()) continue; // Positioned placeholders don't affect calculations. if (curr->y() == PositionTop || curr->y() == PositionBottom) { - int lineHeight = curr->renderer()->lineHeight(m_firstLine); + int lineHeight = curr->lineHeight(false); if (curr->y() == PositionTop) { if (maxAscent + maxDescent < lineHeight) maxDescent = lineHeight - maxAscent; @@ -404,11 +402,11 @@ void InlineFlowBox::computeLogicalBoxHeights(int& maxPositionTop, int& maxPositi { if (isRootInlineBox()) { // Examine our root box. - int lineHeight = renderer()->lineHeight(m_firstLine, true); - int baseline = renderer()->baselinePosition(m_firstLine, true); + int height = lineHeight(true); + int baseline = baselinePosition(true); if (hasTextChildren() || strictMode) { int ascent = baseline; - int descent = lineHeight - ascent; + int descent = height - ascent; if (maxAscent < ascent) maxAscent = ascent; if (maxDescent < descent) @@ -456,8 +454,8 @@ void InlineFlowBox::computeLogicalBoxHeights(int& maxPositionTop, int& maxPositi } } } else { - lineHeight = curr->renderer()->lineHeight(m_firstLine); - baseline = curr->renderer()->baselinePosition(m_firstLine); + lineHeight = curr->lineHeight(false); + baseline = curr->baselinePosition(false); } curr->setY(verticalPositionForBox(curr, m_firstLine)); @@ -485,8 +483,8 @@ void InlineFlowBox::placeBoxesVertically(int yPos, int maxHeight, int maxAscent, int& topPosition, int& bottomPosition, int& selectionTop, int& selectionBottom) { if (isRootInlineBox()) - setY(yPos + max(0, maxAscent - renderer()->baselinePosition(m_firstLine, true))); // Place our root box. - + setY(yPos + max(0, maxAscent - baselinePosition(true))); // Place our root box. + for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { if (curr->renderer()->isPositioned()) continue; // Positioned placeholders don't affect calculations. @@ -501,11 +499,11 @@ void InlineFlowBox::placeBoxesVertically(int yPos, int maxHeight, int maxAscent, if (curr->y() == PositionTop) curr->setY(yPos); else if (curr->y() == PositionBottom) - curr->setY(yPos + maxHeight - curr->renderer()->lineHeight(m_firstLine)); + curr->setY(yPos + maxHeight - curr->lineHeight(false)); else { if ((isInlineFlow && !static_cast<InlineFlowBox*>(curr)->hasTextChildren()) && !curr->boxModelObject()->hasHorizontalBordersOrPadding() && !strictMode) childAffectsTopBottomPos = false; - int posAdjust = maxAscent - curr->renderer()->baselinePosition(m_firstLine); + int posAdjust = maxAscent - curr->baselinePosition(false); if (!childAffectsTopBottomPos) posAdjust = max(0, posAdjust); curr->setY(curr->y() + yPos + posAdjust); @@ -521,16 +519,9 @@ void InlineFlowBox::placeBoxesVertically(int yPos, int maxHeight, int maxAscent, int overflowBottom = 0; if (curr->isText() || curr->isInlineFlowBox()) { const Font& font = curr->renderer()->style(m_firstLine)->font(); - newY += curr->renderer()->baselinePosition(m_firstLine) - font.ascent(); - for (ShadowData* shadow = curr->renderer()->style()->textShadow(); shadow; shadow = shadow->next) { - overflowTop = min(overflowTop, shadow->y - shadow->blur); - overflowBottom = max(overflowBottom, shadow->y + shadow->blur); - } + newY += curr->baselinePosition(false) - font.ascent(); - for (ShadowData* boxShadow = curr->renderer()->style(m_firstLine)->boxShadow(); boxShadow; boxShadow = boxShadow->next) { - overflowTop = min(overflowTop, boxShadow->y - boxShadow->blur); - overflowBottom = max(overflowBottom, boxShadow->y + boxShadow->blur); - } + curr->renderer()->style(m_firstLine)->getBoxShadowVerticalExtent(overflowTop, overflowBottom); for (ShadowData* textShadow = curr->renderer()->style(m_firstLine)->textShadow(); textShadow; textShadow = textShadow->next) { overflowTop = min(overflowTop, textShadow->y - textShadow->blur); @@ -565,7 +556,7 @@ void InlineFlowBox::placeBoxesVertically(int yPos, int maxHeight, int maxAscent, if (isRootInlineBox()) { const Font& font = renderer()->style(m_firstLine)->font(); - setY(y() + renderer()->baselinePosition(m_firstLine, true) - font.ascent()); + setY(y() + baselinePosition(true) - font.ascent()); if (hasTextChildren() || strictMode) { selectionTop = min(selectionTop, y()); selectionBottom = max(selectionBottom, y() + height()); @@ -597,16 +588,16 @@ void InlineFlowBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty) { int xPos = tx + m_x - renderer()->maximalOutlineSize(paintInfo.phase); int w = width() + 2 * renderer()->maximalOutlineSize(paintInfo.phase); - int shadowLeft = 0; - int shadowRight = 0; - for (ShadowData* boxShadow = renderer()->style(m_firstLine)->boxShadow(); boxShadow; boxShadow = boxShadow->next) { - shadowLeft = min(boxShadow->x - boxShadow->blur, shadowLeft); - shadowRight = max(boxShadow->x + boxShadow->blur, shadowRight); - } + int shadowLeft; + int shadowRight; + + renderer()->style(m_firstLine)->getBoxShadowHorizontalExtent(shadowLeft, shadowRight); + for (ShadowData* textShadow = renderer()->style(m_firstLine)->textShadow(); textShadow; textShadow = textShadow->next) { shadowLeft = min(textShadow->x - textShadow->blur, shadowLeft); shadowRight = max(textShadow->x + textShadow->blur, shadowRight); } + xPos += shadowLeft; w += -shadowLeft + shadowRight; bool intersectsDamageRect = xPos < paintInfo.rect.right() && xPos + w > paintInfo.rect.x(); @@ -658,22 +649,20 @@ void InlineFlowBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty) paintTextDecorations(paintInfo, tx, ty, true); } -void InlineFlowBox::paintFillLayers(const RenderObject::PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, - int my, int mh, int _tx, int _ty, int w, int h, CompositeOperator op) +void InlineFlowBox::paintFillLayers(const RenderObject::PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, int _tx, int _ty, int w, int h, CompositeOperator op) { if (!fillLayer) return; - paintFillLayers(paintInfo, c, fillLayer->next(), my, mh, _tx, _ty, w, h, op); - paintFillLayer(paintInfo, c, fillLayer, my, mh, _tx, _ty, w, h, op); + paintFillLayers(paintInfo, c, fillLayer->next(), _tx, _ty, w, h, op); + paintFillLayer(paintInfo, c, fillLayer, _tx, _ty, w, h, op); } -void InlineFlowBox::paintFillLayer(const RenderObject::PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, - int my, int mh, int tx, int ty, int w, int h, CompositeOperator op) +void InlineFlowBox::paintFillLayer(const RenderObject::PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, int tx, int ty, int w, int h, CompositeOperator op) { StyleImage* img = fillLayer->image(); bool hasFillImage = img && img->canRender(renderer()->style()->effectiveZoom()); if ((!hasFillImage && !renderer()->style()->hasBorderRadius()) || (!prevLineBox() && !nextLineBox()) || !parent()) - boxModelObject()->paintFillLayerExtended(paintInfo, c, fillLayer, my, mh, tx, ty, w, h, this, op); + boxModelObject()->paintFillLayerExtended(paintInfo, c, fillLayer, tx, ty, w, h, this, op); else { // We have a fill image that spans multiple lines. // We need to adjust _tx and _ty by the width of all previous lines. @@ -692,19 +681,19 @@ void InlineFlowBox::paintFillLayer(const RenderObject::PaintInfo& paintInfo, con totalWidth += curr->width(); paintInfo.context->save(); paintInfo.context->clip(IntRect(tx, ty, width(), height())); - boxModelObject()->paintFillLayerExtended(paintInfo, c, fillLayer, my, mh, startX, ty, totalWidth, h, this, op); + boxModelObject()->paintFillLayerExtended(paintInfo, c, fillLayer, startX, ty, totalWidth, h, this, op); paintInfo.context->restore(); } } -void InlineFlowBox::paintBoxShadow(GraphicsContext* context, RenderStyle* s, int tx, int ty, int w, int h) +void InlineFlowBox::paintBoxShadow(GraphicsContext* context, RenderStyle* s, ShadowStyle shadowStyle, int tx, int ty, int w, int h) { if ((!prevLineBox() && !nextLineBox()) || !parent()) - boxModelObject()->paintBoxShadow(context, tx, ty, w, h, s); + boxModelObject()->paintBoxShadow(context, tx, ty, w, h, s, shadowStyle); else { // FIXME: We can do better here in the multi-line case. We want to push a clip so that the shadow doesn't // protrude incorrectly at the edges, and we want to possibly include shadows cast from the previous/following lines - boxModelObject()->paintBoxShadow(context, tx, ty, w, h, s, includeLeftEdge(), includeRightEdge()); + boxModelObject()->paintBoxShadow(context, tx, ty, w, h, s, shadowStyle, includeLeftEdge(), includeRightEdge()); } } @@ -720,13 +709,6 @@ void InlineFlowBox::paintBoxDecorations(RenderObject::PaintInfo& paintInfo, int int w = width(); int h = height(); - int my = max(ty, paintInfo.rect.y()); - int mh; - if (ty < paintInfo.rect.y()) - mh = max(0, h - (paintInfo.rect.y() - ty)); - else - mh = min(paintInfo.rect.height(), h); - GraphicsContext* context = paintInfo.context; // You can use p::first-line to specify a background. If so, the root line boxes for @@ -735,10 +717,13 @@ void InlineFlowBox::paintBoxDecorations(RenderObject::PaintInfo& paintInfo, int if ((!parent() && m_firstLine && styleToUse != renderer()->style()) || (parent() && renderer()->hasBoxDecorations())) { // Shadow comes first and is behind the background and border. if (styleToUse->boxShadow()) - paintBoxShadow(context, styleToUse, tx, ty, w, h); + paintBoxShadow(context, styleToUse, Normal, tx, ty, w, h); Color c = styleToUse->backgroundColor(); - paintFillLayers(paintInfo, c, styleToUse->backgroundLayers(), my, mh, tx, ty, w, h); + paintFillLayers(paintInfo, c, styleToUse->backgroundLayers(), tx, ty, w, h); + + if (styleToUse->boxShadow()) + paintBoxShadow(context, styleToUse, Inset, tx, ty, w, h); // :first-line cannot be used to put borders on a line. Always paint borders with our // non-first-line style. @@ -789,14 +774,6 @@ void InlineFlowBox::paintMask(RenderObject::PaintInfo& paintInfo, int tx, int ty int w = width(); int h = height(); - int my = max(ty, paintInfo.rect.y()); - int mh; - if (ty < paintInfo.rect.y()) - mh = max(0, h - (paintInfo.rect.y() - ty)); - else - mh = min(paintInfo.rect.height(), h); - - // Figure out if we need to push a transparency layer to render our mask. bool pushTransparencyLayer = false; const NinePieceImage& maskNinePieceImage = renderer()->style()->maskBoxImage(); @@ -811,7 +788,7 @@ void InlineFlowBox::paintMask(RenderObject::PaintInfo& paintInfo, int tx, int ty compositeOp = CompositeSourceOver; } - paintFillLayers(paintInfo, Color(), renderer()->style()->maskLayers(), my, mh, tx, ty, w, h, compositeOp); + paintFillLayers(paintInfo, Color(), renderer()->style()->maskLayers(), tx, ty, w, h, compositeOp); bool hasBoxImage = maskBoxImage && maskBoxImage->canRender(renderer()->style()->effectiveZoom()); if (!hasBoxImage || !maskBoxImage->isLoaded()) @@ -997,33 +974,19 @@ void InlineFlowBox::paintTextDecorations(RenderObject::PaintInfo& paintInfo, int } } -InlineBox* InlineFlowBox::firstLeafChild() -{ - return firstLeafChildAfterBox(); -} - -InlineBox* InlineFlowBox::lastLeafChild() -{ - return lastLeafChildBeforeBox(); -} - -InlineBox* InlineFlowBox::firstLeafChildAfterBox(InlineBox* start) +InlineBox* InlineFlowBox::firstLeafChild() const { InlineBox* leaf = 0; - for (InlineBox* box = start ? start->nextOnLine() : firstChild(); box && !leaf; box = box->nextOnLine()) - leaf = box->firstLeafChild(); - if (start && !leaf && parent()) - return parent()->firstLeafChildAfterBox(this); + for (InlineBox* child = firstChild(); child && !leaf; child = child->nextOnLine()) + leaf = child->isLeaf() ? child : static_cast<InlineFlowBox*>(child)->firstLeafChild(); return leaf; } -InlineBox* InlineFlowBox::lastLeafChildBeforeBox(InlineBox* start) +InlineBox* InlineFlowBox::lastLeafChild() const { InlineBox* leaf = 0; - for (InlineBox* box = start ? start->prevOnLine() : lastChild(); box && !leaf; box = box->prevOnLine()) - leaf = box->lastLeafChild(); - if (start && !leaf && parent()) - return parent()->lastLeafChildBeforeBox(this); + for (InlineBox* child = lastChild(); child && !leaf; child = child->prevOnLine()) + leaf = child->isLeaf() ? child : static_cast<InlineFlowBox*>(child)->lastLeafChild(); return leaf; } @@ -1054,7 +1017,7 @@ int InlineFlowBox::placeEllipsisBox(bool ltr, int blockLeftEdge, int blockRightE int visibleLeftEdge = blockLeftEdge; int visibleRightEdge = blockRightEdge; - while(box) { + while (box) { int currResult = box->placeEllipsisBox(ltr, visibleLeftEdge, visibleRightEdge, ellipsisWidth, foundBox); if (currResult != -1 && result == -1) result = currResult; diff --git a/WebCore/rendering/InlineFlowBox.h b/WebCore/rendering/InlineFlowBox.h index 2462eba..809fd54 100644 --- a/WebCore/rendering/InlineFlowBox.h +++ b/WebCore/rendering/InlineFlowBox.h @@ -58,13 +58,13 @@ public: InlineFlowBox* prevFlowBox() const { return static_cast<InlineFlowBox*>(m_prevLine); } InlineFlowBox* nextFlowBox() const { return static_cast<InlineFlowBox*>(m_nextLine); } - InlineBox* firstChild() { checkConsistency(); return m_firstChild; } - InlineBox* lastChild() { checkConsistency(); return m_lastChild; } + InlineBox* firstChild() const { checkConsistency(); return m_firstChild; } + InlineBox* lastChild() const { checkConsistency(); return m_lastChild; } - virtual InlineBox* firstLeafChild(); - virtual InlineBox* lastLeafChild(); - InlineBox* firstLeafChildAfterBox(InlineBox* start = 0); - InlineBox* lastLeafChildBeforeBox(InlineBox* start = 0); + virtual bool isLeaf() const { return false; } + + InlineBox* firstLeafChild() const; + InlineBox* lastLeafChild() const; virtual void setConstructed() { @@ -87,11 +87,9 @@ public: virtual void paintBoxDecorations(RenderObject::PaintInfo&, int tx, int ty); virtual void paintMask(RenderObject::PaintInfo&, int tx, int ty); - void paintFillLayers(const RenderObject::PaintInfo&, const Color&, const FillLayer*, - int my, int mh, int tx, int ty, int w, int h, CompositeOperator = CompositeSourceOver); - void paintFillLayer(const RenderObject::PaintInfo&, const Color&, const FillLayer*, - int my, int mh, int tx, int ty, int w, int h, CompositeOperator = CompositeSourceOver); - void paintBoxShadow(GraphicsContext*, RenderStyle*, int tx, int ty, int w, int h); + void paintFillLayers(const RenderObject::PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int w, int h, CompositeOperator = CompositeSourceOver); + void paintFillLayer(const RenderObject::PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int w, int h, CompositeOperator = CompositeSourceOver); + void paintBoxShadow(GraphicsContext*, RenderStyle*, ShadowStyle, int tx, int ty, int w, int h); virtual void paintTextDecorations(RenderObject::PaintInfo&, int tx, int ty, bool paintedChildren = false); virtual void paint(RenderObject::PaintInfo&, int tx, int ty); virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty); diff --git a/WebCore/rendering/InlineTextBox.cpp b/WebCore/rendering/InlineTextBox.cpp index 418be15..619fb95 100644 --- a/WebCore/rendering/InlineTextBox.cpp +++ b/WebCore/rendering/InlineTextBox.cpp @@ -256,6 +256,11 @@ bool InlineTextBox::nodeAtPoint(const HitTestRequest&, HitTestResult& result, in 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) { + Color fillColor = context->fillColor(); + bool opaque = fillColor.alpha() == 255; + if (!opaque) + context->setFillColor(Color::black); + do { IntSize extraOffset; @@ -264,7 +269,7 @@ static void paintTextWithShadows(GraphicsContext* context, const Font& font, con int shadowBlur = shadow->blur; const Color& shadowColor = shadow->color; - if (shadow->next || stroked) { + if (shadow->next || stroked || !opaque) { IntRect shadowRect(x, y, w, h); shadowRect.inflate(shadowBlur); shadowRect.move(shadowOffset); @@ -275,7 +280,8 @@ static void paintTextWithShadows(GraphicsContext* context, const Font& font, con shadowOffset -= extraOffset; } context->setShadow(shadowOffset, shadowBlur, shadowColor); - } + } else if (!opaque) + context->setFillColor(fillColor); if (startOffset <= endOffset) context->drawText(font, textRun, textOrigin + extraOffset, startOffset, endOffset); @@ -289,13 +295,13 @@ static void paintTextWithShadows(GraphicsContext* context, const Font& font, con if (!shadow) break; - if (shadow->next || stroked) + if (shadow->next || stroked || !opaque) context->restore(); else context->clearShadow(); shadow = shadow->next; - } while (shadow || stroked); + } while (shadow || stroked || !opaque); } void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty) @@ -753,8 +759,8 @@ void InlineTextBox::paintSpellingOrGrammarMarker(GraphicsContext* pt, int tx, in 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. + // 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. int y = selectionTop(); int h = selectionHeight(); @@ -770,8 +776,8 @@ void InlineTextBox::paintTextMatchMarker(GraphicsContext* pt, int tx, int ty, Do // Optionally highlight the text if (renderer()->document()->frame()->markedTextMatchesAreHighlighted()) { Color color = marker.activeMatch ? - theme()->platformActiveTextSearchHighlightColor() : - theme()->platformInactiveTextSearchHighlightColor(); + renderer()->theme()->platformActiveTextSearchHighlightColor() : + renderer()->theme()->platformInactiveTextSearchHighlightColor(); pt->save(); updateGraphicsContext(pt, color, color, 0); // Don't draw text at all! pt->clip(IntRect(tx + m_x, ty + y, m_width, h)); diff --git a/WebCore/rendering/LayoutState.h b/WebCore/rendering/LayoutState.h index afa2952..2f040c8 100644 --- a/WebCore/rendering/LayoutState.h +++ b/WebCore/rendering/LayoutState.h @@ -36,7 +36,7 @@ class RenderArena; class RenderBox; class RenderObject; -class LayoutState : Noncopyable { +class LayoutState : public Noncopyable { public: LayoutState() : m_clipped(false) diff --git a/WebCore/rendering/MediaControlElements.cpp b/WebCore/rendering/MediaControlElements.cpp index 5cd9363..352f270 100644 --- a/WebCore/rendering/MediaControlElements.cpp +++ b/WebCore/rendering/MediaControlElements.cpp @@ -32,6 +32,7 @@ #include "MediaControlElements.h" +#include "LocalizedStrings.h" #include "EventNames.h" #include "FloatConversion.h" #include "Frame.h" @@ -40,6 +41,7 @@ #include "RenderMedia.h" #include "RenderSlider.h" #include "RenderTheme.h" +#include "CString.h" namespace WebCore { @@ -74,50 +76,165 @@ void MediaControlShadowRootElement::updateStyle() } // ---------------------------- + -MediaTextDisplayElement::MediaTextDisplayElement(Document* doc, PseudoId pseudo, HTMLMediaElement* mediaElement) +MediaControlElement::MediaControlElement(Document* doc, PseudoId pseudo, HTMLMediaElement* mediaElement) : HTMLDivElement(divTag, doc) , m_mediaElement(mediaElement) , m_pseudoStyleId(pseudo) { - RenderStyle* style = m_mediaElement->renderer()->getCachedPseudoStyle(m_pseudoStyleId); - RenderObject* renderer = createRenderer(m_mediaElement->renderer()->renderArena(), style); - if (renderer) { - setRenderer(renderer); - renderer->setStyle(style); - } - setAttached(); setInDocument(true); } -void MediaTextDisplayElement::attachToParent(Element* parent) +void MediaControlElement::attachToParent(Element* parent) { parent->addChild(this); - if (renderer()) - parent->renderer()->addChild(renderer()); } -void MediaTextDisplayElement::update() +void MediaControlElement::update() { if (renderer()) renderer()->updateFromElement(); + updateStyle(); +} + +PassRefPtr<RenderStyle> MediaControlElement::styleForElement() +{ + RenderStyle* style = m_mediaElement->renderer()->getCachedPseudoStyle(m_pseudoStyleId); + if (!style) + return 0; + + // text-decoration can't be overrided from CSS. So we do it here. + // See https://bugs.webkit.org/show_bug.cgi?id=27015 + style->setTextDecoration(TDNONE); + style->setTextDecorationsInEffect(TDNONE); + + return style; } -void MediaTextDisplayElement::updateStyle() +bool MediaControlElement::rendererIsNeeded(RenderStyle* style) { - if (renderer() && m_mediaElement->renderer()) { - RenderStyle* style = m_mediaElement->renderer()->getCachedPseudoStyle(m_pseudoStyleId); - renderer()->setStyle(style); + return HTMLDivElement::rendererIsNeeded(style) && parent() && parent()->renderer(); +} + +void MediaControlElement::attach() +{ + RefPtr<RenderStyle> style = styleForElement(); + if (!style) + return; + bool needsRenderer = rendererIsNeeded(style.get()); + if (!needsRenderer) + return; + RenderObject* renderer = createRenderer(m_mediaElement->renderer()->renderArena(), style.get()); + if (!renderer) + return; + renderer->setStyle(style.get()); + setRenderer(renderer); + if (parent() && parent()->renderer()) { + // Find next sibling with a renderer to determine where to insert. + Node* sibling = nextSibling(); + while (sibling && !sibling->renderer()) + sibling = sibling->nextSibling(); + parent()->renderer()->addChild(renderer, sibling ? sibling->renderer() : 0); } + ContainerNode::attach(); } -MediaTimeDisplayElement::MediaTimeDisplayElement(Document* doc, HTMLMediaElement* element, bool currentTime) - : MediaTextDisplayElement(doc, currentTime ? MEDIA_CONTROLS_CURRENT_TIME_DISPLAY : MEDIA_CONTROLS_TIME_REMAINING_DISPLAY, element) +void MediaControlElement::updateStyle() { + if (!m_mediaElement || !m_mediaElement->renderer()) + return; + + RefPtr<RenderStyle> style = styleForElement(); + if (!style) + return; + + bool needsRenderer = rendererIsNeeded(style.get()) && parent() && parent()->renderer(); + if (renderer() && !needsRenderer) + detach(); + else if (!renderer() && needsRenderer) + attach(); + else if (renderer()) { + renderer()->setStyle(style.get()); + + // Make sure that if there is any innerText renderer, it is updated as well. + if (firstChild() && firstChild()->renderer()) + firstChild()->renderer()->setStyle(style.get()); + } } // ---------------------------- +MediaControlTimelineContainerElement::MediaControlTimelineContainerElement(Document* doc, HTMLMediaElement* element) +: MediaControlElement(doc, MEDIA_CONTROLS_TIMELINE_CONTAINER, element) +{ +} + +bool MediaControlTimelineContainerElement::rendererIsNeeded(RenderStyle* style) +{ + if (!MediaControlElement::rendererIsNeeded(style)) + return false; + + // This is for MediaControllerThemeClassic: + // If there is no style for MediaControlStatusDisplayElement style, don't hide + // the timeline. + if (!m_mediaElement->renderer()->getCachedPseudoStyle(MEDIA_CONTROLS_STATUS_DISPLAY)) + return true; + + float duration = m_mediaElement->duration(); + return !isnan(duration) && !isinf(duration); +} + + +// ---------------------------- + +MediaControlStatusDisplayElement::MediaControlStatusDisplayElement(Document* doc, HTMLMediaElement* element) +: MediaControlElement(doc, MEDIA_CONTROLS_STATUS_DISPLAY, element) +, m_stateBeingDisplayed(Nothing) +{ +} + +void MediaControlStatusDisplayElement::update() +{ + MediaControlElement::update(); + + // Get the new state that we'll have to display. + StateBeingDisplayed newStateToDisplay = Nothing; + + if (m_mediaElement->readyState() != HTMLMediaElement::HAVE_ENOUGH_DATA && !m_mediaElement->currentSrc().isEmpty()) + newStateToDisplay = Loading; + else if (m_mediaElement->movieLoadType() == MediaPlayer::LiveStream) + newStateToDisplay = LiveBroadcast; + + // Propagate only if needed. + if (newStateToDisplay == m_stateBeingDisplayed) + return; + m_stateBeingDisplayed = newStateToDisplay; + + ExceptionCode e; + switch (m_stateBeingDisplayed) { + case Nothing: + setInnerText("", e); + break; + case Loading: + setInnerText(mediaElementLoadingStateText(), e); + break; + case LiveBroadcast: + setInnerText(mediaElementLiveBroadcastStateText(), e); + break; + } +} + +bool MediaControlStatusDisplayElement::rendererIsNeeded(RenderStyle* style) +{ + if (!MediaControlElement::rendererIsNeeded(style)) + return false; + float duration = m_mediaElement->duration(); + return (isnan(duration) || isinf(duration)); +} + +// ---------------------------- + MediaControlInputElement::MediaControlInputElement(Document* doc, PseudoId pseudo, const String& type, HTMLMediaElement* mediaElement, MediaControlElementType displayType) : HTMLInputElement(inputTag, doc) , m_mediaElement(mediaElement) @@ -125,20 +242,12 @@ MediaControlInputElement::MediaControlInputElement(Document* doc, PseudoId pseud , m_displayType(displayType) { setInputType(type); - RenderStyle* style = m_mediaElement->renderer()->getCachedPseudoStyle(m_pseudoStyleId); - RenderObject* renderer = createRenderer(m_mediaElement->renderer()->renderArena(), style); - if (renderer) { - setRenderer(renderer); - renderer->setStyle(style); - } - setAttached(); setInDocument(true); } void MediaControlInputElement::attachToParent(Element* parent) { parent->addChild(this); - parent->renderer()->addChild(renderer()); } void MediaControlInputElement::update() @@ -146,20 +255,65 @@ void MediaControlInputElement::update() updateDisplayType(); if (renderer()) renderer()->updateFromElement(); + updateStyle(); } -void MediaControlInputElement::updateStyle() +PassRefPtr<RenderStyle> MediaControlInputElement::styleForElement() { - if (renderer() && m_mediaElement->renderer()) { - RenderStyle* style = m_mediaElement->renderer()->getCachedPseudoStyle(m_pseudoStyleId); - renderer()->setStyle(style); - } + return m_mediaElement->renderer()->getCachedPseudoStyle(m_pseudoStyleId); +} + +bool MediaControlInputElement::rendererIsNeeded(RenderStyle* style) +{ + return HTMLInputElement::rendererIsNeeded(style) && parent() && parent()->renderer(); } +void MediaControlInputElement::attach() +{ + RefPtr<RenderStyle> style = styleForElement(); + if (!style) + return; + + bool needsRenderer = rendererIsNeeded(style.get()); + if (!needsRenderer) + return; + RenderObject* renderer = createRenderer(m_mediaElement->renderer()->renderArena(), style.get()); + if (!renderer) + return; + renderer->setStyle(style.get()); + setRenderer(renderer); + if (parent() && parent()->renderer()) { + // Find next sibling with a renderer to determine where to insert. + Node* sibling = nextSibling(); + while (sibling && !sibling->renderer()) + sibling = sibling->nextSibling(); + parent()->renderer()->addChild(renderer, sibling ? sibling->renderer() : 0); + } + ContainerNode::attach(); +} + +void MediaControlInputElement::updateStyle() +{ + if (!m_mediaElement || !m_mediaElement->renderer()) + return; + + RefPtr<RenderStyle> style = styleForElement(); + if (!style) + return; + + bool needsRenderer = rendererIsNeeded(style.get()) && parent() && parent()->renderer(); + if (renderer() && !needsRenderer) + detach(); + else if (!renderer() && needsRenderer) + attach(); + else if (renderer()) + renderer()->setStyle(style.get()); +} + bool MediaControlInputElement::hitTest(const IntPoint& absPoint) { if (renderer() && renderer()->style()->hasAppearance()) - return theme()->hitTestMediaControlPart(renderer(), absPoint); + return renderer()->theme()->hitTestMediaControlPart(renderer(), absPoint); return false; } @@ -266,6 +420,59 @@ void MediaControlSeekButtonElement::seekTimerFired(Timer<MediaControlSeekButtonE m_mediaElement->setCurrentTime(m_mediaElement->currentTime() + seekTime, ec); } +void MediaControlSeekButtonElement::detach() +{ + if (m_capturing) { + if (Frame* frame = document()->frame()) + frame->eventHandler()->setCapturingMouseEventsNode(0); + } + MediaControlInputElement::detach(); +} + + +// ---------------------------- + +MediaControlRewindButtonElement::MediaControlRewindButtonElement(Document* doc, HTMLMediaElement* element) +: MediaControlInputElement(doc, MEDIA_CONTROLS_REWIND_BUTTON, "button", element, MediaRewindButton) +{ +} + +void MediaControlRewindButtonElement::defaultEventHandler(Event* event) +{ + if (event->type() == eventNames().clickEvent) { + m_mediaElement->rewind(30); + event->setDefaultHandled(); + } + HTMLInputElement::defaultEventHandler(event); +} + +bool MediaControlRewindButtonElement::rendererIsNeeded(RenderStyle* style) +{ + return MediaControlInputElement::rendererIsNeeded(style) && m_mediaElement->movieLoadType() != MediaPlayer::LiveStream; +} + + +// ---------------------------- + +MediaControlReturnToRealtimeButtonElement::MediaControlReturnToRealtimeButtonElement(Document* doc, HTMLMediaElement* element) +: MediaControlInputElement(doc, MEDIA_CONTROLS_RETURN_TO_REALTIME_BUTTON, "button", element, MediaReturnToRealtimeButton) +{ +} + +void MediaControlReturnToRealtimeButtonElement::defaultEventHandler(Event* event) +{ + if (event->type() == eventNames().clickEvent) { + m_mediaElement->returnToRealtime(); + event->setDefaultHandled(); + } + HTMLInputElement::defaultEventHandler(event); +} + +bool MediaControlReturnToRealtimeButtonElement::rendererIsNeeded(RenderStyle* style) +{ + return MediaControlInputElement::rendererIsNeeded(style) && m_mediaElement->movieLoadType() == MediaPlayer::LiveStream; +} + // ---------------------------- MediaControlTimelineElement::MediaControlTimelineElement(Document* document, HTMLMediaElement* element) @@ -275,14 +482,17 @@ MediaControlTimelineElement::MediaControlTimelineElement(Document* document, HTM void MediaControlTimelineElement::defaultEventHandler(Event* event) { + // Left button is 0. Accepts only if mouse event is from left button. + if (!event->isMouseEvent() || static_cast<MouseEvent*>(event)->button()) + return; + if (event->type() == eventNames().mousedownEvent) m_mediaElement->beginScrubbing(); - HTMLInputElement::defaultEventHandler(event); + MediaControlInputElement::defaultEventHandler(event); - if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent ) { + if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent) return; - } float time = narrowPrecisionToFloat(value().toDouble()); if (time != m_mediaElement->currentTime()) { @@ -290,9 +500,9 @@ void MediaControlTimelineElement::defaultEventHandler(Event* event) m_mediaElement->setCurrentTime(time, ec); } - RenderSlider* slider = static_cast<RenderSlider*>(renderer()); + RenderSlider* slider = toRenderSlider(renderer()); if (slider && slider->inDragMode()) - static_cast<RenderMedia*>(m_mediaElement->renderer())->updateTimeDisplay(); + toRenderMedia(m_mediaElement->renderer())->updateTimeDisplay(); if (event->type() == eventNames().mouseupEvent) m_mediaElement->endScrubbing(); @@ -305,6 +515,7 @@ void MediaControlTimelineElement::update(bool updateDuration) setAttribute(maxAttr, String::number(isfinite(dur) ? dur : 0)); } setValue(String::number(m_mediaElement->currentTime())); + MediaControlInputElement::update(); } // ---------------------------- @@ -322,7 +533,45 @@ void MediaControlFullscreenButtonElement::defaultEventHandler(Event* event) HTMLInputElement::defaultEventHandler(event); } +bool MediaControlFullscreenButtonElement::rendererIsNeeded(RenderStyle* style) +{ + return MediaControlInputElement::rendererIsNeeded(style) && m_mediaElement->supportsFullscreen(); +} + + // ---------------------------- +MediaControlTimeDisplayElement::MediaControlTimeDisplayElement(Document* doc, PseudoId pseudo, HTMLMediaElement* element) + : MediaControlElement(doc, pseudo, element) + , m_isVisible(true) +{ +} + +PassRefPtr<RenderStyle> MediaControlTimeDisplayElement::styleForElement() +{ + RefPtr<RenderStyle> style = MediaControlElement::styleForElement(); + if (!m_isVisible) { + style = RenderStyle::clone(style.get()); + style->setWidth(Length(0, Fixed)); + } + return style; +} + +void MediaControlTimeDisplayElement::setVisible(bool visible) +{ + if (visible == m_isVisible) + return; + m_isVisible = visible; + + // This function is used during the RenderMedia::layout() + // call, where we cannot change the renderer at this time. + if (!renderer() || !renderer()->style()) + return; + + RefPtr<RenderStyle> style = styleForElement(); + renderer()->setStyle(style.get()); +} + + } //namespace WebCore #endif // enable(video) diff --git a/WebCore/rendering/MediaControlElements.h b/WebCore/rendering/MediaControlElements.h index d52d4bc..d5fa5d2 100644 --- a/WebCore/rendering/MediaControlElements.h +++ b/WebCore/rendering/MediaControlElements.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -43,11 +43,24 @@ namespace WebCore { class Event; class Frame; +// Must match WebKitSystemInterface.h enum MediaControlElementType { - MediaFullscreenButton, MediaMuteButton, MediaPlayButton, - MediaSeekBackButton, MediaSeekForwardButton, MediaSlider, MediaSliderThumb, - MediaUnMuteButton, MediaPauseButton, MediaTimelineContainer, MediaCurrentTimeDisplay, - MediaTimeRemainingDisplay, MediaControlsPanel + MediaFullscreenButton = 0, + MediaMuteButton, + MediaPlayButton, + MediaSeekBackButton, + MediaSeekForwardButton, + MediaSlider, + MediaSliderThumb, + MediaRewindButton, + MediaReturnToRealtimeButton, + MediaUnMuteButton, + MediaPauseButton, + MediaTimelineContainer, + MediaCurrentTimeDisplay, + MediaTimeRemainingDisplay, + MediaStatusDisplay, + MediaControlsPanel }; class MediaControlShadowRootElement : public HTMLDivElement { @@ -63,15 +76,19 @@ private: HTMLMediaElement* m_mediaElement; }; - // ---------------------------- - -class MediaTextDisplayElement : public HTMLDivElement -{ +// ---------------------------- + +class MediaControlElement : public HTMLDivElement { public: - MediaTextDisplayElement(Document*, PseudoId, HTMLMediaElement*); + MediaControlElement(Document*, PseudoId, HTMLMediaElement*); + virtual void attach(); + virtual bool rendererIsNeeded(RenderStyle*); + + virtual PassRefPtr<RenderStyle> styleForElement(); void attachToParent(Element*); void update(); - void updateStyle(); + virtual void updateStyle(); + protected: HTMLMediaElement* m_mediaElement; PseudoId m_pseudoStyleId; @@ -79,9 +96,22 @@ protected: // ---------------------------- -class MediaTimeDisplayElement : public MediaTextDisplayElement { +class MediaControlTimelineContainerElement : public MediaControlElement { public: - MediaTimeDisplayElement(Document*, HTMLMediaElement*, bool currentTime); + MediaControlTimelineContainerElement(Document*, HTMLMediaElement*); + virtual bool rendererIsNeeded(RenderStyle*); +}; + +// ---------------------------- + +class MediaControlStatusDisplayElement : public MediaControlElement { +public: + MediaControlStatusDisplayElement(Document*, HTMLMediaElement*); + virtual void update(); + virtual bool rendererIsNeeded(RenderStyle*); +private: + enum StateBeingDisplayed { Nothing, Loading, LiveBroadcast }; + StateBeingDisplayed m_stateBeingDisplayed; }; // ---------------------------- @@ -89,10 +119,16 @@ public: class MediaControlInputElement : public HTMLInputElement { public: MediaControlInputElement(Document*, PseudoId, const String& type, HTMLMediaElement*, MediaControlElementType); + virtual void attach(); + virtual bool rendererIsNeeded(RenderStyle*); + + virtual PassRefPtr<RenderStyle> styleForElement(); void attachToParent(Element*); void update(); void updateStyle(); + bool hitTest(const IntPoint& absPoint); + MediaControlElementType displayType() const { return m_displayType; } protected: virtual void updateDisplayType() { } @@ -127,6 +163,7 @@ class MediaControlSeekButtonElement : public MediaControlInputElement { public: MediaControlSeekButtonElement(Document*, HTMLMediaElement*, bool forward); virtual void defaultEventHandler(Event*); + virtual void detach(); void seekTimerFired(Timer<MediaControlSeekButtonElement>*); private: @@ -135,6 +172,24 @@ private: bool m_capturing; Timer<MediaControlSeekButtonElement> m_seekTimer; }; + +// ---------------------------- + +class MediaControlRewindButtonElement : public MediaControlInputElement { +public: + MediaControlRewindButtonElement(Document*, HTMLMediaElement*); + virtual void defaultEventHandler(Event*); + virtual bool rendererIsNeeded(RenderStyle*); +}; + +// ---------------------------- + +class MediaControlReturnToRealtimeButtonElement : public MediaControlInputElement { +public: + MediaControlReturnToRealtimeButtonElement(Document*, HTMLMediaElement*); + virtual void defaultEventHandler(Event*); + virtual bool rendererIsNeeded(RenderStyle*); +}; // ---------------------------- @@ -151,6 +206,19 @@ class MediaControlFullscreenButtonElement : public MediaControlInputElement { public: MediaControlFullscreenButtonElement(Document*, HTMLMediaElement*); virtual void defaultEventHandler(Event*); + virtual bool rendererIsNeeded(RenderStyle*); +}; + +// ---------------------------- + +class MediaControlTimeDisplayElement : public MediaControlElement { +public: + MediaControlTimeDisplayElement(Document*, PseudoId, HTMLMediaElement*); + void setVisible(bool); + virtual PassRefPtr<RenderStyle> styleForElement(); + +private: + bool m_isVisible; }; // ---------------------------- @@ -160,9 +228,10 @@ public: RenderMediaControlShadowRoot(Element* e) : RenderBlock(e) { } void setParent(RenderObject* p) { RenderObject::setParent(p); } }; - + // ---------------------------- + } //namespace WebCore #endif // enable(video) #endif // MediaControlElements_h diff --git a/WebCore/rendering/RenderApplet.cpp b/WebCore/rendering/RenderApplet.cpp index a989d6f..062641e 100644 --- a/WebCore/rendering/RenderApplet.cpp +++ b/WebCore/rendering/RenderApplet.cpp @@ -26,6 +26,7 @@ #include "HTMLAppletElement.h" #include "HTMLNames.h" #include "HTMLParamElement.h" +#include "Widget.h" namespace WebCore { diff --git a/WebCore/rendering/RenderApplet.h b/WebCore/rendering/RenderApplet.h index b481d87..343421e 100644 --- a/WebCore/rendering/RenderApplet.h +++ b/WebCore/rendering/RenderApplet.h @@ -46,6 +46,15 @@ namespace WebCore { HashMap<String, String> m_args; }; + inline RenderApplet* toRenderApplet(RenderObject* object) + { + ASSERT(!object || object->isApplet()); + return static_cast<RenderApplet*>(object); + } + + // This will catch anyone doing an unnecessary cast. + void toRenderApplet(const RenderApplet*); + } // namespace WebCore #endif // RenderApplet_h diff --git a/WebCore/rendering/RenderArena.cpp b/WebCore/rendering/RenderArena.cpp index c490d2b..3ab4dff 100644 --- a/WebCore/rendering/RenderArena.cpp +++ b/WebCore/rendering/RenderArena.cpp @@ -39,7 +39,7 @@ #include <string.h> #include <wtf/Assertions.h> -#define ROUNDUP(x,y) ((((x)+((y)-1))/(y))*(y)) +#define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y)) namespace WebCore { diff --git a/WebCore/rendering/RenderBlock.cpp b/WebCore/rendering/RenderBlock.cpp index ded093f..e10c331 100644 --- a/WebCore/rendering/RenderBlock.cpp +++ b/WebCore/rendering/RenderBlock.cpp @@ -88,6 +88,10 @@ static PercentHeightContainerMap* gPercentHeightContainerMap = 0; typedef WTF::HashMap<RenderBlock*, ListHashSet<RenderInline*>*> ContinuationOutlineTableMap; +typedef WTF::HashSet<RenderBlock*> DelayedUpdateScrollInfoSet; +static int gDelayUpdateScrollInfo = 0; +static DelayedUpdateScrollInfoSet* gDelayedUpdateScrollInfoSet = 0; + // Our MarginInfo state used when laying out block children. RenderBlock::MarginInfo::MarginInfo(RenderBlock* block, int top, int bottom) { @@ -393,14 +397,14 @@ void RenderBlock::deleteLineBoxTree() m_lineBoxes.deleteLineBoxTree(renderArena()); } -RootInlineBox* RenderBlock::createRootBox() +RootInlineBox* RenderBlock::createRootInlineBox() { return new (renderArena()) RootInlineBox(this); } -RootInlineBox* RenderBlock::createRootInlineBox() +RootInlineBox* RenderBlock::createAndAppendRootInlineBox() { - RootInlineBox* rootBox = createRootBox(); + RootInlineBox* rootBox = createRootInlineBox(); m_lineBoxes.appendLineBox(rootBox); return rootBox; } @@ -553,10 +557,11 @@ void RenderBlock::removeChild(RenderObject* oldChild) int RenderBlock::overflowHeight(bool includeInterior) const { if (!includeInterior && hasOverflowClip()) { - int shadowHeight = 0; - for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next) - shadowHeight = max(boxShadow->y + boxShadow->blur, shadowHeight); - int inflatedHeight = height() + shadowHeight; + int shadowTop; + int shadowBottom; + style()->getBoxShadowVerticalExtent(shadowTop, shadowBottom); + + int inflatedHeight = height() + shadowBottom; if (hasReflection()) inflatedHeight = max(inflatedHeight, reflectionBox().bottom()); return inflatedHeight; @@ -567,10 +572,11 @@ int RenderBlock::overflowHeight(bool includeInterior) const int RenderBlock::overflowWidth(bool includeInterior) const { if (!includeInterior && hasOverflowClip()) { - int shadowWidth = 0; - for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next) - shadowWidth = max(boxShadow->x + boxShadow->blur, shadowWidth); - int inflatedWidth = width() + shadowWidth; + int shadowLeft; + int shadowRight; + style()->getBoxShadowHorizontalExtent(shadowLeft, shadowRight); + + int inflatedWidth = width() + shadowRight; if (hasReflection()) inflatedWidth = max(inflatedWidth, reflectionBox().right()); return inflatedWidth; @@ -581,9 +587,10 @@ int RenderBlock::overflowWidth(bool includeInterior) const int RenderBlock::overflowLeft(bool includeInterior) const { if (!includeInterior && hasOverflowClip()) { - int shadowLeft = 0; - for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next) - shadowLeft = min(boxShadow->x - boxShadow->blur, shadowLeft); + int shadowLeft; + int shadowRight; + style()->getBoxShadowHorizontalExtent(shadowLeft, shadowRight); + int left = shadowLeft; if (hasReflection()) left = min(left, reflectionBox().x()); @@ -595,9 +602,10 @@ int RenderBlock::overflowLeft(bool includeInterior) const int RenderBlock::overflowTop(bool includeInterior) const { if (!includeInterior && hasOverflowClip()) { - int shadowTop = 0; - for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next) - shadowTop = min(boxShadow->y - boxShadow->blur, shadowTop); + int shadowTop; + int shadowBottom; + style()->getBoxShadowVerticalExtent(shadowTop, shadowBottom); + int top = shadowTop; if (hasReflection()) top = min(top, reflectionBox().y()); @@ -610,17 +618,12 @@ IntRect RenderBlock::overflowRect(bool includeInterior) const { if (!includeInterior && hasOverflowClip()) { IntRect box = borderBoxRect(); - int shadowLeft = 0; - int shadowRight = 0; - int shadowTop = 0; - int shadowBottom = 0; - - for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next) { - shadowLeft = min(boxShadow->x - boxShadow->blur, shadowLeft); - shadowRight = max(boxShadow->x + boxShadow->blur, shadowRight); - shadowTop = min(boxShadow->y - boxShadow->blur, shadowTop); - shadowBottom = max(boxShadow->y + boxShadow->blur, shadowBottom); - } + + int shadowLeft; + int shadowRight; + int shadowTop; + int shadowBottom; + style()->getBoxShadowExtent(shadowTop, shadowRight, shadowBottom, shadowLeft); box.move(shadowLeft, shadowTop); box.setWidth(box.width() - shadowLeft + shadowRight); @@ -692,6 +695,45 @@ bool RenderBlock::isSelfCollapsingBlock() const return false; } +void RenderBlock::startDelayUpdateScrollInfo() +{ + if (gDelayUpdateScrollInfo == 0) { + ASSERT(!gDelayedUpdateScrollInfoSet); + gDelayedUpdateScrollInfoSet = new DelayedUpdateScrollInfoSet; + } + ASSERT(gDelayedUpdateScrollInfoSet); + ++gDelayUpdateScrollInfo; +} + +void RenderBlock::finishDelayUpdateScrollInfo() +{ + --gDelayUpdateScrollInfo; + ASSERT(gDelayUpdateScrollInfo >= 0); + if (gDelayUpdateScrollInfo == 0) { + ASSERT(gDelayedUpdateScrollInfoSet); + + for (DelayedUpdateScrollInfoSet::iterator it = gDelayedUpdateScrollInfoSet->begin(); it != gDelayedUpdateScrollInfoSet->end(); ++it) { + RenderBlock* block = *it; + if (block->hasOverflowClip()) { + block->layer()->updateScrollInfoAfterLayout(); + } + } + + delete gDelayedUpdateScrollInfoSet; + gDelayedUpdateScrollInfoSet = 0; + } +} + +void RenderBlock::updateScrollInfoAfterLayout() +{ + if (hasOverflowClip()) { + if (gDelayUpdateScrollInfo) + gDelayedUpdateScrollInfoSet->add(this); + else + layer()->updateScrollInfoAfterLayout(); + } +} + void RenderBlock::layout() { // Update our first letter info now. @@ -843,16 +885,23 @@ void RenderBlock::layoutBlock(bool relayoutChildren) 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, width() + boxShadow->x + boxShadow->blur); - m_overflowTop = min(m_overflowTop, boxShadow->y - boxShadow->blur); - m_overflowHeight = max(m_overflowHeight, height() + boxShadow->y + boxShadow->blur); - } - + int shadowLeft; + int shadowRight; + int shadowTop; + int shadowBottom; + style()->getBoxShadowExtent(shadowTop, shadowRight, shadowBottom, shadowLeft); + + m_overflowLeft = min(m_overflowLeft, shadowLeft); + m_overflowWidth = max(m_overflowWidth, width() + shadowRight); + m_overflowTop = min(m_overflowTop, shadowTop); + m_overflowHeight = max(m_overflowHeight, height() + shadowBottom); + if (hasReflection()) { - m_overflowTop = min(m_overflowTop, reflectionBox().y()); - m_overflowHeight = max(m_overflowHeight, reflectionBox().bottom()); + IntRect reflection(reflectionBox()); + m_overflowLeft = min(m_overflowLeft, reflection.x()); + m_overflowWidth = max(m_overflowWidth, reflection.right()); + m_overflowTop = min(m_overflowTop, reflection.y()); + m_overflowHeight = max(m_overflowHeight, reflection.bottom()); } } @@ -860,8 +909,7 @@ void RenderBlock::layoutBlock(bool relayoutChildren) // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if // we overflow or not. - if (hasOverflowClip()) - layer()->updateScrollInfoAfterLayout(); + updateScrollInfoAfterLayout(); // Repaint with our new bounds if they are different from our old bounds. bool didFullRepaint = repainter.repaintAfterLayout(); @@ -987,13 +1035,13 @@ bool RenderBlock::handleRunInChild(RenderBox* child) if (!child->isRunIn() || !child->childrenInline() && !child->isReplaced()) return false; - RenderBlock* blockRunIn = toRenderBlock(child); // Get the next non-positioned/non-floating RenderBlock. + RenderBlock* blockRunIn = toRenderBlock(child); RenderObject* curr = blockRunIn->nextSibling(); while (curr && curr->isFloatingOrPositioned()) curr = curr->nextSibling(); - if (!curr || !curr->isRenderBlock() || !curr->childrenInline() || curr->isRunIn()) + if (!curr || !curr->isRenderBlock() || !curr->childrenInline() || curr->isRunIn() || curr->isAnonymous()) return false; RenderBlock* currBlock = toRenderBlock(curr); @@ -1452,8 +1500,10 @@ void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom child->repaintDuringLayoutIfMoved(oldRect); } - if (!childHadLayout && child->checkForRepaintDuringLayout()) + if (!childHadLayout && child->checkForRepaintDuringLayout()) { child->repaint(); + child->repaintOverhangingFloats(true); + } ASSERT(oldLayoutDelta == view()->layoutDelta()); } @@ -1481,8 +1531,7 @@ bool RenderBlock::layoutOnlyPositionedObjects() statePusher.pop(); - if (hasOverflowClip()) - layer()->updateScrollInfoAfterLayout(); + updateScrollInfoAfterLayout(); #ifdef ANDROID_FIX // iframe flatten will call FrameView::layout() which calls performPostLayoutTasks, @@ -2444,10 +2493,10 @@ bool RenderBlock::positionNewFloats() if (o->style()->floating() == FLEFT) { int heightRemainingLeft = 1; int heightRemainingRight = 1; - int fx = leftRelOffset(y,lo, false, &heightRemainingLeft); - while (rightRelOffset(y,ro, false, &heightRemainingRight)-fx < fwidth) { + int fx = leftRelOffset(y, lo, false, &heightRemainingLeft); + while (rightRelOffset(y, ro, false, &heightRemainingRight)-fx < fwidth) { y += min(heightRemainingLeft, heightRemainingRight); - fx = leftRelOffset(y,lo, false, &heightRemainingLeft); + fx = leftRelOffset(y, lo, false, &heightRemainingLeft); } fx = max(0, fx); f->m_left = fx; @@ -2455,8 +2504,8 @@ bool RenderBlock::positionNewFloats() } else { int heightRemainingLeft = 1; int heightRemainingRight = 1; - int fx = rightRelOffset(y,ro, false, &heightRemainingRight); - while (fx - leftRelOffset(y,lo, false, &heightRemainingLeft) < fwidth) { + int fx = rightRelOffset(y, ro, false, &heightRemainingRight); + while (fx - leftRelOffset(y, lo, false, &heightRemainingLeft) < fwidth) { y += min(heightRemainingLeft, heightRemainingRight); fx = rightRelOffset(y, ro, false, &heightRemainingRight); } @@ -2481,7 +2530,7 @@ void RenderBlock::newLine(EClear clear) positionNewFloats(); // set y position int newY = 0; - switch(clear) + switch (clear) { case CLEFT: newY = leftBottom(); @@ -2652,12 +2701,12 @@ int RenderBlock::floatBottom() const { if (!m_floatingObjects) return 0; - int bottom=0; + int bottom = 0; FloatingObject* r; DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); for ( ; (r = it.current()); ++it ) if (r->m_bottom>bottom) - bottom=r->m_bottom; + bottom = r->m_bottom; return bottom; } @@ -2942,12 +2991,12 @@ int RenderBlock::leftBottom() { if (!m_floatingObjects) return 0; - int bottom=0; + int bottom = 0; FloatingObject* r; DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); for ( ; (r = it.current()); ++it ) if (r->m_bottom > bottom && r->type() == FloatingObject::FloatLeft) - bottom=r->m_bottom; + bottom = r->m_bottom; return bottom; } @@ -2956,12 +3005,12 @@ int RenderBlock::rightBottom() { if (!m_floatingObjects) return 0; - int bottom=0; + int bottom = 0; FloatingObject* r; DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); for ( ; (r = it.current()); ++it ) if (r->m_bottom>bottom && r->type() == FloatingObject::FloatRight) - bottom=r->m_bottom; + bottom = r->m_bottom; return bottom; } @@ -3269,12 +3318,12 @@ void RenderBlock::addVisualOverflow(const IntRect& r) m_overflowHeight = max(m_overflowHeight, r.bottom()); } -bool RenderBlock::isPointInOverflowControl(HitTestResult& result, int, int, int, int) +bool RenderBlock::isPointInOverflowControl(HitTestResult& result, int _x, int _y, int _tx, int _ty) { if (!scrollsOverflow()) return false; - return layer()->hitTestOverflowControls(result); + return layer()->hitTestOverflowControls(result, IntPoint(_x - _tx, _y - _ty)); } bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction) @@ -3898,7 +3947,7 @@ void RenderBlock::calcPrefWidths() } if (isTableCell()) { - Length w = static_cast<const RenderTableCell*>(this)->styleOrColWidth(); + Length w = toRenderTableCell(this)->styleOrColWidth(); if (w.isFixed() && w.value() > 0) m_maxPrefWidth = max(m_minPrefWidth, calcContentBoxWidth(w.value())); } @@ -3917,14 +3966,16 @@ void RenderBlock::calcPrefWidths() int toAdd = 0; toAdd = borderLeft() + borderRight() + paddingLeft() + paddingRight(); + if (hasOverflowClip() && style()->overflowY() == OSCROLL) + toAdd += verticalScrollbarWidth(); + m_minPrefWidth += toAdd; m_maxPrefWidth += toAdd; setPrefWidthsDirty(false); } -struct InlineMinMaxIterator -{ +struct InlineMinMaxIterator { /* InlineMinMaxIterator is a class that will iterate over all render objects that contribute to inline min/max width calculations. Note the following about the way it walks: (1) Positioned content is skipped (since it does not contribute to min/max width of a block) @@ -4393,8 +4444,16 @@ void RenderBlock::calcBlockPrefWidths() bool RenderBlock::hasLineIfEmpty() const { - return node() && ((node()->isContentEditable() && node()->rootEditableElement() == node()) || - (node()->isShadowNode() && node()->shadowParentNode()->hasTagName(inputTag))); + if (!node()) + return false; + + if (node()->isContentEditable() && node()->rootEditableElement() == node()) + return true; + + if (node()->isShadowNode() && (node()->shadowParentNode()->hasTagName(inputTag) || node()->shadowParentNode()->hasTagName(textareaTag))) + return true; + + return false; } int RenderBlock::lineHeight(bool firstLine, bool isRootLineBox) const diff --git a/WebCore/rendering/RenderBlock.h b/WebCore/rendering/RenderBlock.h index f313b3d..839be16 100644 --- a/WebCore/rendering/RenderBlock.h +++ b/WebCore/rendering/RenderBlock.h @@ -1,10 +1,8 @@ /* - * This file is part of the render object implementation for KHTML. - * * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2007 David Smith (catfish.man@gmail.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 @@ -35,14 +33,15 @@ namespace WebCore { class InlineIterator; -class Position; class RenderInline; class RootInlineBox; struct BidiRun; template <class Iterator, class Run> class BidiResolver; +template <class Iterator> class MidpointState; typedef BidiResolver<InlineIterator, BidiRun> InlineBidiResolver; +typedef MidpointState<InlineIterator> LineMidpointState; enum CaretType { CursorCaret, DragCaret }; @@ -51,26 +50,15 @@ public: RenderBlock(Node*); virtual ~RenderBlock(); - virtual RenderObjectChildList* virtualChildren() { return children(); } - virtual const RenderObjectChildList* virtualChildren() const { return children(); } const RenderObjectChildList* children() const { return &m_children; } RenderObjectChildList* children() { return &m_children; } virtual void destroy(); - virtual const char* renderName() const; - // These two functions are overridden for inline-block. virtual int lineHeight(bool firstLine, bool isRootLineBox = false) const; virtual int baselinePosition(bool firstLine, bool isRootLineBox = false) const; - virtual bool isRenderBlock() const { return true; } - virtual bool isBlockFlow() const { return (!isInline() || isReplaced()) && !isTable(); } - virtual bool isInlineBlockOrInlineTable() const { return isInline() && isReplaced(); } - - void makeChildrenNonInline(RenderObject* insertionPoint = 0); - virtual void removeLeftoverAnonymousBlock(RenderBlock* child); - RenderLineBoxList* lineBoxes() { return &m_lineBoxes; } const RenderLineBoxList* lineBoxes() const { return &m_lineBoxes; } @@ -78,7 +66,6 @@ public: InlineFlowBox* lastLineBox() const { return m_lineBoxes.lastLineBox(); } void deleteLineBoxTree(); - virtual void dirtyLinesFromChangedChild(RenderObject* child) { m_lineBoxes.dirtyLinesFromChangedChild(this, child); } // The height (and width) of a block when you include overflow spillage out of the bottom // of the block (e.g., a <div style="height:25px"> that has a 100px tall image inside @@ -88,15 +75,86 @@ public: virtual int overflowLeft(bool includeInterior = true) const; virtual int overflowTop(bool includeInterior = true) const; virtual IntRect overflowRect(bool includeInterior = true) const; - virtual void setOverflowHeight(int h) { m_overflowHeight = h; } - virtual void setOverflowWidth(int w) { m_overflowWidth = w; } void addVisualOverflow(const IntRect&); - virtual bool isSelfCollapsingBlock() const; + virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0); + virtual void removeChild(RenderObject*); - virtual int maxTopMargin(bool positive) const { return positive ? maxTopPosMargin() : maxTopNegMargin(); } - virtual int maxBottomMargin(bool positive) const { return positive ? maxBottomPosMargin() : maxBottomNegMargin(); } + virtual void layoutBlock(bool relayoutChildren); + + void insertPositionedObject(RenderBox*); + void removePositionedObject(RenderBox*); + void removePositionedObjects(RenderBlock*); + + void addPercentHeightDescendant(RenderBox*); + static void removePercentHeightDescendant(RenderBox*); + HashSet<RenderBox*>* percentHeightDescendants() const; + + RootInlineBox* createAndAppendRootInlineBox(); + + bool generatesLineBoxesForInlineChild(RenderObject*, bool isLineEmpty = true, bool previousLineBrokeCleanly = true); + + void markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove = 0, bool inLayout = true); + void markPositionedObjectsForLayout(); + + bool containsFloats() { return m_floatingObjects && !m_floatingObjects->isEmpty(); } + bool containsFloat(RenderObject*); + + IntRect floatRect() const; + + int lineWidth(int y, bool firstLine) const; + 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; + + int rightOffset(int y, bool firstLine) const { return rightRelOffset(y, rightOffset(), firstLine); } + int leftOffset(int y, bool firstLine) const { return leftRelOffset(y, leftOffset(), firstLine); } + + virtual VisiblePosition positionForPoint(const IntPoint&); + + // Block flows subclass availableWidth to handle multi column layout (shrinking the width available to children when laying out.) + virtual int availableWidth() const; + + RootInlineBox* firstRootBox() const { return static_cast<RootInlineBox*>(firstLineBox()); } + RootInlineBox* lastRootBox() const { return static_cast<RootInlineBox*>(lastLineBox()); } + + bool containsNonZeroBidiLevel() const; + + virtual void setSelectionState(SelectionState s); + + GapRects selectionGapRectsForRepaint(RenderBoxModelObject* repaintContainer); + IntRect fillLeftSelectionGap(RenderObject* selObj, int xPos, int yPos, int height, RenderBlock* rootBlock, + int blockX, int blockY, int tx, int ty, const PaintInfo*); + IntRect fillRightSelectionGap(RenderObject* selObj, int xPos, int yPos, int height, RenderBlock* rootBlock, + int blockX, int blockY, int tx, int ty, const PaintInfo*); + IntRect fillHorizontalSelectionGap(RenderObject* selObj, int xPos, int yPos, int width, int height, const PaintInfo*); + + void getHorizontalSelectionGapInfo(SelectionState, bool& leftGap, bool& rightGap); + + // Helper methods for computing line counts and heights for line counts. + RootInlineBox* lineAtIndex(int); + int lineCount(); + int heightForLineCount(int); + void clearTruncation(); + + void adjustRectForColumns(IntRect&) const; + + void addContinuationWithOutline(RenderInline*); + + RenderInline* inlineContinuation() const { return m_inlineContinuation; } + void setInlineContinuation(RenderInline* c) { m_inlineContinuation = c; } + + // This function is a convenience helper for creating an anonymous block that inherits its + // style from this RenderBlock. + RenderBlock* createAnonymousBlock() const; + + Vector<IntRect>* columnRects() const; + int columnGap() const; + +protected: + virtual void setOverflowHeight(int h) { m_overflowHeight = h; } + virtual void setOverflowWidth(int w) { m_overflowWidth = w; } int maxTopPosMargin() const { return m_maxMargin ? m_maxMargin->m_topPos : MaxMargin::topPosDefault(this); } int maxTopNegMargin() const { return m_maxMargin ? m_maxMargin->m_topNeg : MaxMargin::topNegDefault(this); } @@ -115,60 +173,104 @@ public: } } - virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0); - virtual void removeChild(RenderObject*); + virtual void layout(); + + void layoutPositionedObjects(bool relayoutChildren); + + virtual void paint(PaintInfo&, int tx, int ty); + virtual void paintObject(PaintInfo&, int tx, int ty); + + int rightRelOffset(int y, int fixedOffset, bool applyTextIndent = true, int* heightRemaining = 0) const; + int leftRelOffset(int y, int fixedOffset, bool applyTextIndent = true, int* heightRemaining = 0) const; + + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); + + virtual void calcPrefWidths(); + + virtual int firstLineBoxBaseline() const; + virtual int lastLineBoxBaseline() const; + + virtual void updateFirstLetter(); + + virtual void updateHitTestResult(HitTestResult&, const IntPoint&); + + // Delay update scrollbar until finishDelayRepaint() will be + // called. This function is used when a flexbox is laying out its + // descendant. If multiple calls are made to startDelayRepaint(), + // finishDelayRepaint() will do nothing until finishDelayRepaint() + // is called the same number of times. + static void startDelayUpdateScrollInfo(); + static void finishDelayUpdateScrollInfo(); + + virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + + virtual bool hasLineIfEmpty() const; + bool layoutOnlyPositionedObjects(); + +private: + virtual RenderObjectChildList* virtualChildren() { return children(); } + virtual const RenderObjectChildList* virtualChildren() const { return children(); } + + virtual const char* renderName() const; + + virtual bool isRenderBlock() const { return true; } + virtual bool isBlockFlow() const { return (!isInline() || isReplaced()) && !isTable(); } + virtual bool isInlineBlockOrInlineTable() const { return isInline() && isReplaced(); } + + void makeChildrenNonInline(RenderObject* insertionPoint = 0); + virtual void removeLeftoverAnonymousBlock(RenderBlock* child); + + virtual void dirtyLinesFromChangedChild(RenderObject* child) { m_lineBoxes.dirtyLinesFromChangedChild(this, child); } + + virtual bool isSelfCollapsingBlock() const; + + virtual int maxTopMargin(bool positive) const { return positive ? maxTopPosMargin() : maxTopNegMargin(); } + virtual int maxBottomMargin(bool positive) const { return positive ? maxBottomPosMargin() : maxBottomNegMargin(); } virtual void repaintOverhangingFloats(bool paintAllDescendants); - virtual void layout(); - virtual void layoutBlock(bool relayoutChildren); void layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom); void layoutInlineChildren(bool relayoutChildren, int& repaintTop, int& repaintBottom); - void layoutPositionedObjects(bool relayoutChildren); - void insertPositionedObject(RenderBox*); - void removePositionedObject(RenderBox*); - void removePositionedObjects(RenderBlock*); - - void addPercentHeightDescendant(RenderBox*); - static void removePercentHeightDescendant(RenderBox*); - HashSet<RenderBox*>* percentHeightDescendants() const; - virtual void positionListMarker() { } virtual void borderFitAdjust(int& x, int& w) const; // Shrink the box in which the border paints if border-fit is set. virtual void updateBeforeAfterContent(PseudoId); - RootInlineBox* createRootInlineBox(); + virtual RootInlineBox* createRootInlineBox(); // Subclassed by SVG and Ruby. // Called to lay out the legend for a fieldset. virtual RenderObject* layoutLegend(bool /*relayoutChildren*/) { return 0; } - // the implementation of the following functions is in bidi.cpp struct FloatWithRect { FloatWithRect(RenderBox* f) : object(f) , rect(IntRect(f->x() - f->marginLeft(), f->y() - f->marginTop(), f->width() + f->marginLeft() + f->marginRight(), f->height() + f->marginTop() + f->marginBottom())) + , everHadLayout(f->m_everHadLayout) { } RenderBox* object; IntRect rect; + bool everHadLayout; }; - void bidiReorderLine(InlineBidiResolver&, const InlineIterator& end); - RootInlineBox* determineStartPosition(bool& firstLine, bool& fullLayout, InlineBidiResolver&, Vector<FloatWithRect>& floats, unsigned& numCleanFloats); + // The following functions' implementations are in RenderBlockLineLayout.cpp. + void bidiReorderLine(InlineBidiResolver&, const InlineIterator& end, bool previousLineBrokeCleanly); + RootInlineBox* determineStartPosition(bool& firstLine, bool& fullLayout, bool& previousLineBrokeCleanly, + InlineBidiResolver&, Vector<FloatWithRect>& floats, unsigned& numCleanFloats); RootInlineBox* determineEndPosition(RootInlineBox* startBox, InlineIterator& cleanLineStart, BidiStatus& cleanLineBidiStatus, int& yPos); bool matchedEndLine(const InlineBidiResolver&, const InlineIterator& endLineStart, const BidiStatus& endLineStatus, RootInlineBox*& endLine, int& endYPos, int& repaintBottom, int& repaintTop); - bool generatesLineBoxesForInlineChild(RenderObject*); - void skipTrailingWhitespace(InlineIterator&); - int skipLeadingWhitespace(InlineBidiResolver&, bool firstLine); + + void skipTrailingWhitespace(InlineIterator&, bool isLineEmpty, bool previousLineBrokeCleanly); + int skipLeadingWhitespace(InlineBidiResolver&, bool firstLine, bool isLineEmpty, bool previousLineBrokeCleanly); void fitBelowFloats(int widthToFit, bool firstLine, int& availableWidth); - InlineIterator findNextLineBreak(InlineBidiResolver&, bool firstLine, EClear* clear = 0); + InlineIterator findNextLineBreak(InlineBidiResolver&, bool firstLine, bool& isLineEmpty, bool& previousLineBrokeCleanly, EClear* clear = 0); RootInlineBox* constructLine(unsigned runCount, BidiRun* firstRun, BidiRun* lastRun, bool firstLine, bool lastLine, RenderObject* endObject); InlineFlowBox* createLineBoxes(RenderObject*, bool firstLine); void computeHorizontalPositionsForLine(RootInlineBox*, bool firstLine, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd); @@ -176,10 +278,8 @@ public: void checkLinesForOverflow(); void deleteEllipsisLineBoxes(); void checkLinesForTextOverflow(); - // end bidi.cpp functions + // End of functions defined in RenderBlockLineLayout.cpp. - virtual void paint(PaintInfo&, int tx, int ty); - virtual void paintObject(PaintInfo&, int tx, int ty); void paintFloats(PaintInfo&, int tx, int ty, bool preservePhase = false); void paintContents(PaintInfo&, int tx, int ty); void paintColumnContents(PaintInfo&, int tx, int ty, bool paintFloats = false); @@ -197,11 +297,6 @@ public: bool positionNewFloats(); void clearFloats(); int getClearDelta(RenderBox* child, int yPos); - void markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove = 0, bool inLayout = true); - void markPositionedObjectsForLayout(); - - bool containsFloats() { return m_floatingObjects && !m_floatingObjects->isEmpty(); } - bool containsFloat(RenderObject*); virtual bool avoidsFloats() const; @@ -213,49 +308,20 @@ public: int floatBottom() const; inline int leftBottom(); inline int rightBottom(); - IntRect floatRect() const; - - int lineWidth(int y, bool firstLine) const; - 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; int rightOffset() const; - int rightRelOffset(int y, int fixedOffset, bool applyTextIndent = true, int* heightRemaining = 0) const; - int rightOffset(int y, bool firstLine) const { return rightRelOffset(y, rightOffset(), firstLine); } - int leftOffset() const; - int leftRelOffset(int y, int fixedOffset, bool applyTextIndent = true, int* heightRemaining = 0) const; - int leftOffset(int y, bool firstLine) const { return leftRelOffset(y, leftOffset(), firstLine); } - - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); virtual bool hitTestColumns(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); virtual bool hitTestContents(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); virtual bool isPointInOverflowControl(HitTestResult&, int x, int y, int tx, int ty); - virtual VisiblePosition positionForPoint(const IntPoint&); - - // Block flows subclass availableWidth to handle multi column layout (shrinking the width available to children when laying out.) - virtual int availableWidth() const; - - virtual void calcPrefWidths(); void calcInlinePrefWidths(); void calcBlockPrefWidths(); - virtual int firstLineBoxBaseline() const; - virtual int lastLineBoxBaseline() const; - - 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; - virtual void updateFirstLetter(); - bool inRootBlockContext() const; virtual IntRect rectWithOutlineForRepaint(RenderBoxModelObject* repaintContainer, int outlineWidth); @@ -263,17 +329,12 @@ public: virtual RenderObject* hoverAncestor() const; virtual void updateDragState(bool dragOn); - virtual void updateHitTestResult(HitTestResult&, const IntPoint&); - virtual void childBecameNonInline(RenderObject* child); - virtual void setSelectionState(SelectionState s); - virtual IntRect selectionRectForRepaint(RenderBoxModelObject* repaintContainer, bool /*clipToVisibleContent*/) { return selectionGapRectsForRepaint(repaintContainer); } - GapRects selectionGapRectsForRepaint(RenderBoxModelObject* repaintContainer); virtual bool shouldPaintSelectionGaps() const; bool isSelectionRoot() const; GapRects fillSelectionGaps(RenderBlock* rootBlock, int blockX, int blockY, int tx, int ty, @@ -284,64 +345,29 @@ public: int& lastTop, int& lastLeft, int& lastRight, const PaintInfo*); IntRect fillVerticalSelectionGap(int lastTop, int lastLeft, int lastRight, int bottomY, RenderBlock* rootBlock, int blockX, int blockY, const PaintInfo*); - IntRect fillLeftSelectionGap(RenderObject* selObj, int xPos, int yPos, int height, RenderBlock* rootBlock, - int blockX, int blockY, int tx, int ty, const PaintInfo*); - IntRect fillRightSelectionGap(RenderObject* selObj, int xPos, int yPos, int height, RenderBlock* rootBlock, - int blockX, int blockY, int tx, int ty, const PaintInfo*); - IntRect fillHorizontalSelectionGap(RenderObject* selObj, int xPos, int yPos, int width, int height, const PaintInfo*); - - void getHorizontalSelectionGapInfo(SelectionState, bool& leftGap, bool& rightGap); int leftSelectionOffset(RenderBlock* rootBlock, int y); int rightSelectionOffset(RenderBlock* rootBlock, int y); virtual void absoluteRects(Vector<IntRect>&, int tx, int ty); virtual void absoluteQuads(Vector<FloatQuad>&); - // Helper methods for computing line counts and heights for line counts. - RootInlineBox* lineAtIndex(int); - int lineCount(); - int heightForLineCount(int); - void clearTruncation(); - int desiredColumnWidth() const; unsigned desiredColumnCount() const; - Vector<IntRect>* columnRects() const; void setDesiredColumnCountAndWidth(int count, int width); - int columnGap() const; - void adjustRectForColumns(IntRect&) const; - - void addContinuationWithOutline(RenderInline*); void paintContinuationOutlines(PaintInfo&, int tx, int ty); - RenderInline* inlineContinuation() const { return m_inlineContinuation; } - void setInlineContinuation(RenderInline* c) { m_inlineContinuation = c; } - virtual IntRect localCaretRect(InlineBox*, int caretOffset, int* extraWidthToEndOfLine = 0); virtual void addFocusRingRects(GraphicsContext*, int tx, int ty); - // This function is a convenience helper for creating an anonymous block that inherits its - // style from this RenderBlock. - RenderBlock* createAnonymousBlock() const; - -private: void adjustPointToColumnContents(IntPoint&) const; void adjustForBorderFit(int x, int& left, int& right) const; // Helper function for borderFitAdjust void markLinesDirtyInVerticalRange(int top, int bottom); -protected: - virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle); - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); - void newLine(EClear); - virtual bool hasLineIfEmpty() const; - bool layoutOnlyPositionedObjects(); - virtual RootInlineBox* createRootBox(); // Subclassed by SVG. - -private: Position positionForBox(InlineBox*, bool start = true) const; Position positionForRenderer(RenderObject*, bool start = true) const; VisiblePosition positionForPointWithInlineChildren(const IntPoint&); @@ -354,7 +380,8 @@ private: bool expandsToEncloseOverhangingFloats() const; -protected: + void updateScrollInfoAfterLayout(); + struct FloatingObject { enum Type { FloatLeft, @@ -465,7 +492,6 @@ protected: void setCollapsedBottomMargin(const MarginInfo&); // End helper functions and structs used by layoutBlockChildren. -private: typedef ListHashSet<RenderBox*>::const_iterator Iterator; DeprecatedPtrList<FloatingObject>* m_floatingObjects; ListHashSet<RenderBox*>* m_positionedObjects; @@ -499,33 +525,34 @@ private: MaxMargin* m_maxMargin; -protected: RenderObjectChildList m_children; RenderLineBoxList m_lineBoxes; // All of the root line boxes created for this block flow. For example, <div>Hello<br>world.</div> will have two total lines for the <div>. +protected: // How much content overflows out of our block vertically or horizontally. int m_overflowHeight; int m_overflowWidth; int m_overflowLeft; int m_overflowTop; - + +private: mutable int m_lineHeight; }; -inline RenderBlock* toRenderBlock(RenderObject* o) +inline RenderBlock* toRenderBlock(RenderObject* object) { - ASSERT(!o || o->isRenderBlock()); - return static_cast<RenderBlock*>(o); + ASSERT(!object || object->isRenderBlock()); + return static_cast<RenderBlock*>(object); } -inline const RenderBlock* toRenderBlock(const RenderObject* o) +inline const RenderBlock* toRenderBlock(const RenderObject* object) { - ASSERT(!o || o->isRenderBlock()); - return static_cast<const RenderBlock*>(o); + ASSERT(!object || object->isRenderBlock()); + return static_cast<const RenderBlock*>(object); } // This will catch anyone doing an unnecessary cast. -void toRenderBlock(const RenderBlock* o); +void toRenderBlock(const RenderBlock*); } // namespace WebCore diff --git a/WebCore/rendering/bidi.cpp b/WebCore/rendering/RenderBlockLineLayout.cpp index dc5176e..2a70d6a 100644 --- a/WebCore/rendering/bidi.cpp +++ b/WebCore/rendering/RenderBlockLineLayout.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2000 Lars Knoll (knoll@kde.org) - * Copyright (C) 2004, 2006, 2007, 2008 Apple Inc. All right reserved. + * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009 Apple Inc. All right reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -20,17 +20,13 @@ */ #include "config.h" -#include "bidi.h" +#include "BidiResolver.h" #include "CharacterNames.h" -#include "Document.h" -#include "Element.h" -#include "FrameView.h" #include "InlineTextBox.h" #include "Logging.h" #include "RenderArena.h" #include "RenderInline.h" -#include "RenderLayer.h" #include "RenderListMarker.h" #include "RenderView.h" #include "break_lines.h" @@ -38,13 +34,6 @@ #include <wtf/RefCountedLeakCounter.h> #include <wtf/StdLibExtras.h> #include <wtf/Vector.h> -#ifdef ANDROID_LAYOUT -#include "Frame.h" -#include "FrameTree.h" -#include "Settings.h" -#include "Text.h" -#include "HTMLNames.h" -#endif // ANDROID_LAYOUT using namespace std; using namespace WTF; @@ -77,7 +66,7 @@ public: bool atEnd() const; UChar current() const; - WTF::Unicode::Direction direction() const; + Direction direction() const; RenderBlock* block; RenderObject* obj; @@ -85,17 +74,6 @@ public: int nextBreakablePosition; }; -// Midpoint globals. The goal is not to do any allocation when dealing with -// these midpoints, so we just keep an array around and never clear it. We track -// the number of items and position using the two other variables. -static Vector<InlineIterator>* smidpoints; -static unsigned sNumMidpoints; -static unsigned sCurrMidpoint; -static bool betweenMidpoints; - -static bool isLineEmpty = true; -static bool previousLineBrokeCleanly = true; - static int getBorderPaddingMargin(RenderBoxModelObject* child, bool endOfInline) { bool leftSide = (child->style()->direction() == LTR) ? !endOfInline : endOfInline; @@ -120,8 +98,35 @@ static int inlineWidth(RenderObject* child, bool start = true, bool end = true) return extraWidth; } +struct BidiRun : BidiCharacterRun { + BidiRun(int start, int stop, RenderObject* object, BidiContext* context, Direction dir) + : BidiCharacterRun(start, stop, context, dir) + , m_object(object) + , m_box(0) + { + } + + void destroy(); + + // Overloaded new operator. + void* operator new(size_t, RenderArena*) throw(); + + // Overridden to prevent the normal delete from being called. + void operator delete(void*, size_t); + + BidiRun* next() { return static_cast<BidiRun*>(m_next); } + +private: + // The normal operator new is disallowed. + void* operator new(size_t) throw(); + +public: + RenderObject* m_object; + InlineBox* m_box; +}; + #ifndef NDEBUG -static WTF::RefCountedLeakCounter bidiRunCounter("BidiRun"); +static RefCountedLeakCounter bidiRunCounter("BidiRun"); static bool inBidiRunDestroy; #endif @@ -334,35 +339,35 @@ ALWAYS_INLINE Direction InlineIterator::direction() const // ------------------------------------------------------------------------------------------------- -static void chopMidpointsAt(RenderObject* obj, unsigned pos) +static void chopMidpointsAt(LineMidpointState& lineMidpointState, RenderObject* obj, unsigned pos) { - if (!sNumMidpoints) + if (!lineMidpointState.numMidpoints) return; - InlineIterator* midpoints = smidpoints->data(); - for (int i = sNumMidpoints - 1; i >= 0; i--) { + InlineIterator* midpoints = lineMidpointState.midpoints.data(); + for (int i = lineMidpointState.numMidpoints - 1; i >= 0; i--) { const InlineIterator& point = midpoints[i]; if (point.obj == obj && point.pos == pos) { - sNumMidpoints = i; + lineMidpointState.numMidpoints = i; break; } } } -static void checkMidpoints(InlineIterator& lBreak) +static void checkMidpoints(LineMidpointState& lineMidpointState, InlineIterator& lBreak) { // Check to see if our last midpoint is a start point beyond the line break. If so, // shave it off the list, and shave off a trailing space if the previous end point doesn't // preserve whitespace. - if (lBreak.obj && sNumMidpoints && sNumMidpoints % 2 == 0) { - InlineIterator* midpoints = smidpoints->data(); - InlineIterator& endpoint = midpoints[sNumMidpoints-2]; - const InlineIterator& startpoint = midpoints[sNumMidpoints-1]; + if (lBreak.obj && lineMidpointState.numMidpoints && !(lineMidpointState.numMidpoints % 2)) { + InlineIterator* midpoints = lineMidpointState.midpoints.data(); + InlineIterator& endpoint = midpoints[lineMidpointState.numMidpoints - 2]; + const InlineIterator& startpoint = midpoints[lineMidpointState.numMidpoints - 1]; InlineIterator currpoint = endpoint; while (!currpoint.atEnd() && currpoint != startpoint && currpoint != lBreak) currpoint.increment(); if (currpoint == lBreak) { // We hit the line break before the start point. Shave off the start point. - sNumMidpoints--; + lineMidpointState.numMidpoints--; if (endpoint.obj->style()->collapseWhiteSpace()) { if (endpoint.obj->isText()) { // Don't shave a character off the endpoint if it was from a soft hyphen. @@ -382,13 +387,13 @@ static void checkMidpoints(InlineIterator& lBreak) } } -static void addMidpoint(const InlineIterator& midpoint) +static void addMidpoint(LineMidpointState& lineMidpointState, const InlineIterator& midpoint) { - if (smidpoints->size() <= sNumMidpoints) - smidpoints->grow(sNumMidpoints + 10); + if (lineMidpointState.midpoints.size() <= lineMidpointState.numMidpoints) + lineMidpointState.midpoints.grow(lineMidpointState.numMidpoints + 10); - InlineIterator* midpoints = smidpoints->data(); - midpoints[sNumMidpoints++] = midpoint; + InlineIterator* midpoints = lineMidpointState.midpoints.data(); + midpoints[lineMidpointState.numMidpoints++] = midpoint; } static void appendRunsForObject(int start, int end, RenderObject* obj, InlineBidiResolver& resolver) @@ -397,18 +402,19 @@ static void appendRunsForObject(int start, int end, RenderObject* obj, InlineBid (obj->isPositioned() && !obj->style()->hasStaticX() && !obj->style()->hasStaticY() && !obj->container()->isRenderInline())) return; - bool haveNextMidpoint = (sCurrMidpoint < sNumMidpoints); + LineMidpointState& lineMidpointState = resolver.midpointState(); + bool haveNextMidpoint = (lineMidpointState.currentMidpoint < lineMidpointState.numMidpoints); InlineIterator nextMidpoint; if (haveNextMidpoint) - nextMidpoint = smidpoints->at(sCurrMidpoint); - if (betweenMidpoints) { + nextMidpoint = lineMidpointState.midpoints[lineMidpointState.currentMidpoint]; + if (lineMidpointState.betweenMidpoints) { if (!(haveNextMidpoint && nextMidpoint.obj == obj)) return; // This is a new start point. Stop ignoring objects and // adjust our start. - betweenMidpoints = false; + lineMidpointState.betweenMidpoints = false; start = nextMidpoint.pos; - sCurrMidpoint++; + lineMidpointState.currentMidpoint++; if (start < end) return appendRunsForObject(start, end, obj, resolver); } else { @@ -420,8 +426,8 @@ static void appendRunsForObject(int start, int end, RenderObject* obj, InlineBid // An end midpoint has been encountered within our object. We // need to go ahead and append a run with our endpoint. if (static_cast<int>(nextMidpoint.pos + 1) <= end) { - betweenMidpoints = true; - sCurrMidpoint++; + lineMidpointState.betweenMidpoints = true; + lineMidpointState.currentMidpoint++; if (nextMidpoint.pos != UINT_MAX) { // UINT_MAX means stop at the object and don't include any of it. if (static_cast<int>(nextMidpoint.pos + 1) > start) resolver.addRun(new (obj->renderArena()) @@ -466,7 +472,7 @@ void InlineBidiResolver::appendRun() static inline InlineBox* createInlineBoxForRenderer(RenderObject* obj, bool isRootLineBox, bool isOnlyRun = false) { if (isRootLineBox) - return toRenderBlock(obj)->createRootInlineBox(); + return toRenderBlock(obj)->createAndAppendRootInlineBox(); if (obj->isText()) { InlineTextBox* textBox = toRenderText(obj)->createInlineTextBox(); @@ -480,7 +486,7 @@ static inline InlineBox* createInlineBoxForRenderer(RenderObject* obj, bool isRo if (obj->isBox()) return toRenderBox(obj)->createInlineBox(); - return toRenderInline(obj)->createInlineFlowBox(); + return toRenderInline(obj)->createAndAppendInlineFlowBox(); } static inline void dirtyLineBoxesForRenderer(RenderObject* o, bool fullLayout) @@ -658,7 +664,7 @@ void RenderBlock::computeHorizontalPositionsForLine(RootInlineBox* lineBox, bool // objects horizontally. The total width of the line can be increased if we end up // justifying text. int x = leftOffset(height(), firstLine); - switch(textAlign) { + switch (textAlign) { case LEFT: case WEBKIT_LEFT: // The direction of the block should determine what happens with wide lines. In @@ -798,7 +804,7 @@ void RenderBlock::computeVerticalPositionsForLine(RootInlineBox* lineBox, BidiRu } // collects one line of the paragraph and transforms it to visual order -void RenderBlock::bidiReorderLine(InlineBidiResolver& resolver, const InlineIterator& end) +void RenderBlock::bidiReorderLine(InlineBidiResolver& resolver, const InlineIterator& end, bool previousLineBrokeCleanly) { resolver.createBidiRunsForLine(end, style()->visuallyOrdered(), previousLineBrokeCleanly); } @@ -825,7 +831,6 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i // Figure out if we should clear out our line boxes. // FIXME: Handle resize eventually! - // FIXME: Do something better when floats are present. bool fullLayout = !firstLineBox() || !firstChild() || selfNeedsLayout() || relayoutChildren; if (fullLayout) lineBoxes()->deleteLineBoxes(renderArena()); @@ -842,32 +847,6 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i deleteEllipsisLineBoxes(); if (firstChild()) { -#ifdef ANDROID_LAYOUT - // if we are in fitColumnToScreen mode and viewport width is not device-width, - // and the current object is not float:right in LTR or not float:left in RTL, - // and text align is auto, or justify or left in LTR, or right in RTL, we - // will wrap text around screen width so that it doesn't need to scroll - // horizontally when reading a paragraph. - const Settings* settings = document()->settings(); - bool doTextWrap = settings && settings->viewportWidth() != 0 && - settings->layoutAlgorithm() == Settings::kLayoutFitColumnToScreen; - if (doTextWrap) { - int ta = style()->textAlign(); - int dir = style()->direction(); - bool autowrap = style()->autoWrap(); - // if the RenderBlock is positioned, don't wrap text around screen - // width as it may cause text to overlap. - bool positioned = isPositioned(); - EFloat cssfloat = style()->floating(); - doTextWrap = autowrap && !positioned && - (((dir == LTR && cssfloat != FRIGHT) || - (dir == RTL && cssfloat != FLEFT)) && - ((ta == TAAUTO) || (ta == JUSTIFY) || - ((ta == LEFT || ta == WEBKIT_LEFT) && (dir == LTR)) || - ((ta == RIGHT || ta == WEBKIT_RIGHT) && (dir == RTL)))); - } - bool hasTextToWrap = false; -#endif // layout replaced elements bool endOfInline = false; RenderObject* o = bidiFirst(this, 0, false); @@ -886,11 +865,6 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i if (o->isPositioned()) o->containingBlock()->insertPositionedObject(box); else { -#ifdef ANDROID_LAYOUT - // ignore text wrap for textField or menuList - if (doTextWrap && (o->isTextField() || o->isMenuList())) - doTextWrap = false; -#endif if (o->isFloating()) floats.append(FloatWithRect(box)); else if (fullLayout || o->needsLayout()) // Replaced elements @@ -902,80 +876,18 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i if (fullLayout || o->selfNeedsLayout()) dirtyLineBoxesForRenderer(o, fullLayout); o->setNeedsLayout(false); -#ifdef ANDROID_LAYOUT - if (doTextWrap && !hasTextToWrap && o->isText()) { - Node* node = o->node(); - // as it is very common for sites to use a serial of <a> or - // <li> as tabs, we don't force text to wrap if all the text - // are short and within an <a> or <li> tag, and only separated - // by short word like "|" or ";". - if (node && node->isTextNode() && - !static_cast<Text*>(node)->containsOnlyWhitespace()) { - int length = static_cast<Text*>(node)->length(); - // FIXME, need a magic number to decide it is too long to - // be a tab. Pick 25 for now as it covers around 160px - // (half of 320px) with the default font. - if (length > 25 || (length > 3 && - (!node->parent()->hasTagName(HTMLNames::aTag) && - !node->parent()->hasTagName(HTMLNames::liTag)))) - hasTextToWrap = true; - } - } -#endif if (!o->isText()) toRenderInline(o)->invalidateVerticalPosition(); // FIXME: Should do better here and not always invalidate everything. } o = bidiNext(this, o, 0, false, &endOfInline); } -#ifdef ANDROID_LAYOUT - // try to make sure that inline text will not span wider than the - // screen size unless the container has a fixed height, - if (doTextWrap && hasTextToWrap) { - // check all the nested containing blocks, unless it is table or - // table-cell, to make sure there is no fixed height as it implies - // fixed layout. If we constrain the text to fit screen, we may - // cause text overlap with the block after. - bool isConstrained = false; - RenderObject* obj = this; - while (obj) { - if (obj->style()->height().isFixed() && (!obj->isTable() && !obj->isTableCell())) { - isConstrained = true; - break; - } - if (obj->isFloating() || obj->isPositioned()) { - // floating and absolute or fixed positioning are done out - // of normal flow. Don't need to worry about height any more. - break; - } - obj = obj->container(); - } - if (!isConstrained) { - int screenWidth = view()->frameView()->screenWidth(); - if (screenWidth > 0 && width() > screenWidth) { - // if the current padding is smaller, add an extra to make - // it 2 * ANDROID_FCTS_MARGIN_PADDING so that the text won't - // overlap with the screen edge. If the current padding is - // negative, leave it alone. - int padding = paddingLeft() + paddingRight(); - if (padding < 0 || padding >= 2 * ANDROID_FCTS_MARGIN_PADDING) - padding = 0; - else - padding = 2 * ANDROID_FCTS_MARGIN_PADDING - padding; - int maxWidth = screenWidth - padding; - setWidth(min(width(), maxWidth)); - m_minPrefWidth = min(m_minPrefWidth, maxWidth); - m_maxPrefWidth = min(m_maxPrefWidth, maxWidth); - m_overflowWidth = min(m_overflowWidth, maxWidth); - } - } - } -#endif // We want to skip ahead to the first dirty line InlineBidiResolver resolver; unsigned floatIndex; bool firstLine = true; - RootInlineBox* startLine = determineStartPosition(firstLine, fullLayout, resolver, floats, floatIndex); + bool previousLineBrokeCleanly = true; + RootInlineBox* startLine = determineStartPosition(firstLine, fullLayout, previousLineBrokeCleanly, resolver, floats, floatIndex); if (fullLayout && !selfNeedsLayout()) { setNeedsLayout(true, false); // Mark ourselves as needing a full layout. This way we'll repaint like @@ -992,11 +904,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i FloatingObject* lastFloat = m_floatingObjects ? m_floatingObjects->last() : 0; - if (!smidpoints) - smidpoints = new Vector<InlineIterator>(); - - sNumMidpoints = 0; - sCurrMidpoint = 0; + LineMidpointState& lineMidpointState = resolver.midpointState(); // We also find the first clean line and extract these lines. We will add them back // if we determine that we're able to synchronize after handling all our dirty lines. @@ -1044,16 +952,19 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i bool checkForFloatsFromLastLine = false; int lastHeight = height(); + bool isLineEmpty = true; + while (!end.atEnd()) { // FIXME: Is this check necessary before the first iteration or can it be moved to the end? if (checkForEndLineMatch && (endLineMatched = matchedEndLine(resolver, cleanLineStart, cleanLineBidiStatus, endLine, endLineYPos, repaintBottom, repaintTop))) break; - betweenMidpoints = false; + lineMidpointState.reset(); + isLineEmpty = true; EClear clear = CNONE; - end = findNextLineBreak(resolver, firstLine, &clear); + end = findNextLineBreak(resolver, firstLine, isLineEmpty, previousLineBrokeCleanly, &clear); if (resolver.position().atEnd()) { resolver.deleteRuns(); checkForFloatsFromLastLine = true; @@ -1062,7 +973,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i ASSERT(end != resolver.position()); if (!isLineEmpty) { - bidiReorderLine(resolver, end); + bidiReorderLine(resolver, end, previousLineBrokeCleanly); ASSERT(resolver.position() == end); BidiRun* trailingSpaceRun = 0; @@ -1176,8 +1087,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i } lastHeight = height(); - sNumMidpoints = 0; - sCurrMidpoint = 0; + lineMidpointState.reset(); resolver.setPosition(end); } @@ -1232,11 +1142,19 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i } lastFloat = m_floatingObjects->last(); } + size_t floatCount = floats.size(); + // Floats that did not have layout did not repaint when we laid them out. They would have + // painted by now if they had moved, but if they stayed at (0, 0), they still need to be + // painted. + for (size_t i = 0; i < floatCount; ++i) { + if (!floats[i].everHadLayout) { + RenderBox* f = floats[i].object; + if (!f->x() && !f->y() && f->checkForRepaintDuringLayout()) + f->repaint(); + } + } } - sNumMidpoints = 0; - sCurrMidpoint = 0; - // Now add in the bottom border/padding. setHeight(height() + toAdd); @@ -1255,7 +1173,8 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i checkLinesForTextOverflow(); } -RootInlineBox* RenderBlock::determineStartPosition(bool& firstLine, bool& fullLayout, InlineBidiResolver& resolver, Vector<FloatWithRect>& floats, unsigned& numCleanFloats) +RootInlineBox* RenderBlock::determineStartPosition(bool& firstLine, bool& fullLayout, bool& previousLineBrokeCleanly, + InlineBidiResolver& resolver, Vector<FloatWithRect>& floats, unsigned& numCleanFloats) { RootInlineBox* curr = 0; RootInlineBox* last = 0; @@ -1486,7 +1405,7 @@ bool RenderBlock::matchedEndLine(const InlineBidiResolver& resolver, const Inlin return false; } -static inline bool skipNonBreakingSpace(const InlineIterator& it) +static inline bool skipNonBreakingSpace(const InlineIterator& it, bool isLineEmpty, bool previousLineBrokeCleanly) { if (it.obj->style()->nbspMode() != SPACE || it.current() != noBreakSpace) return false; @@ -1502,7 +1421,7 @@ static inline bool skipNonBreakingSpace(const InlineIterator& it) return true; } -static inline bool shouldCollapseWhiteSpace(const RenderStyle* style) +static inline bool shouldCollapseWhiteSpace(const RenderStyle* style, bool isLineEmpty, bool previousLineBrokeCleanly) { return style->collapseWhiteSpace() || (style->whiteSpace() == PRE_WRAP && (!isLineEmpty || !previousLineBrokeCleanly)); } @@ -1525,7 +1444,7 @@ static bool inlineFlowRequiresLineBox(RenderInline* flow) return !flow->firstChild() && flow->hasHorizontalBordersPaddingOrMargin(); } -static inline bool requiresLineBox(const InlineIterator& it) +static inline bool requiresLineBox(const InlineIterator& it, bool isLineEmpty, bool previousLineBrokeCleanly) { if (it.obj->isFloatingOrPositioned()) return false; @@ -1533,19 +1452,20 @@ static inline bool requiresLineBox(const InlineIterator& it) if (it.obj->isRenderInline() && !inlineFlowRequiresLineBox(toRenderInline(it.obj))) return false; - if (!shouldCollapseWhiteSpace(it.obj->style()) || it.obj->isBR()) + if (!shouldCollapseWhiteSpace(it.obj->style(), isLineEmpty, previousLineBrokeCleanly) || it.obj->isBR()) return true; UChar current = it.current(); - return current != ' ' && current != '\t' && current != softHyphen && (current != '\n' || shouldPreserveNewline(it.obj)) && !skipNonBreakingSpace(it); + return current != ' ' && current != '\t' && current != softHyphen && (current != '\n' || shouldPreserveNewline(it.obj)) + && !skipNonBreakingSpace(it, isLineEmpty, previousLineBrokeCleanly); } -bool RenderBlock::generatesLineBoxesForInlineChild(RenderObject* inlineObj) +bool RenderBlock::generatesLineBoxesForInlineChild(RenderObject* inlineObj, bool isLineEmpty, bool previousLineBrokeCleanly) { ASSERT(inlineObj->parent() == this); InlineIterator it(this, inlineObj, 0); - while (!it.atEnd() && !requiresLineBox(it)) + while (!it.atEnd() && !requiresLineBox(it, isLineEmpty, previousLineBrokeCleanly)) it.increment(); return !it.atEnd(); @@ -1557,9 +1477,9 @@ bool RenderBlock::generatesLineBoxesForInlineChild(RenderObject* inlineObj) // object iteration process. // NB. this function will insert any floating elements that would otherwise // be skipped but it will not position them. -void RenderBlock::skipTrailingWhitespace(InlineIterator& iterator) +void RenderBlock::skipTrailingWhitespace(InlineIterator& iterator, bool isLineEmpty, bool previousLineBrokeCleanly) { - while (!iterator.atEnd() && !requiresLineBox(iterator)) { + while (!iterator.atEnd() && !requiresLineBox(iterator, isLineEmpty, previousLineBrokeCleanly)) { RenderObject* object = iterator.obj; if (object->isFloating()) { insertFloatingObject(toRenderBox(object)); @@ -1590,10 +1510,10 @@ void RenderBlock::skipTrailingWhitespace(InlineIterator& iterator) } } -int RenderBlock::skipLeadingWhitespace(InlineBidiResolver& resolver, bool firstLine) +int RenderBlock::skipLeadingWhitespace(InlineBidiResolver& resolver, bool firstLine, bool isLineEmpty, bool previousLineBrokeCleanly) { int availableWidth = lineWidth(height(), firstLine); - while (!resolver.position().atEnd() && !requiresLineBox(resolver.position())) { + while (!resolver.position().atEnd() && !requiresLineBox(resolver.position(), isLineEmpty, previousLineBrokeCleanly)) { RenderObject* object = resolver.position().obj; if (object->isFloating()) { insertFloatingObject(toRenderBox(object)); @@ -1630,14 +1550,14 @@ int RenderBlock::skipLeadingWhitespace(InlineBidiResolver& resolver, bool firstL // This is currently just used for list markers and inline flows that have line boxes. Neither should // have an effect on whitespace at the start of the line. -static bool shouldSkipWhitespaceAfterStartObject(RenderBlock* block, RenderObject* o) +static bool shouldSkipWhitespaceAfterStartObject(RenderBlock* block, RenderObject* o, LineMidpointState& lineMidpointState) { RenderObject* next = bidiNext(block, o); 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)); + addMidpoint(lineMidpointState, InlineIterator(0, o, 0)); return true; } } @@ -1676,13 +1596,15 @@ static inline unsigned textWidth(RenderText* text, unsigned from, unsigned len, return font.width(TextRun(text->characters() + from, len, !collapseWhiteSpace, xPos)); } -InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool firstLine, EClear* clear) +InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool firstLine, bool& isLineEmpty, bool& previousLineBrokeCleanly, + EClear* clear) { ASSERT(resolver.position().block == this); bool appliedStartWidth = resolver.position().pos > 0; - - int width = skipLeadingWhitespace(resolver, firstLine); + LineMidpointState& lineMidpointState = resolver.midpointState(); + + int width = skipLeadingWhitespace(resolver, firstLine, isLineEmpty, previousLineBrokeCleanly); int w = 0; int tmpW = 0; @@ -1807,8 +1729,8 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool ignoreStart.obj = o; ignoreStart.pos = 0; if (ignoringSpaces) { - addMidpoint(ignoreStart); // Stop ignoring spaces. - addMidpoint(ignoreStart); // Start ignoring again. + addMidpoint(lineMidpointState, ignoreStart); // Stop ignoring spaces. + addMidpoint(lineMidpointState, ignoreStart); // Start ignoring again. } } @@ -1827,10 +1749,10 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool isLineEmpty = false; if (ignoringSpaces) { trailingSpaceObject = 0; - addMidpoint(InlineIterator(0, o, 0)); // Stop ignoring spaces. - addMidpoint(InlineIterator(0, o, 0)); // Start ignoring again. + addMidpoint(lineMidpointState, InlineIterator(0, o, 0)); // Stop ignoring spaces. + addMidpoint(lineMidpointState, InlineIterator(0, o, 0)); // Start ignoring again. } else if (style()->collapseWhiteSpace() && resolver.position().obj == o - && shouldSkipWhitespaceAfterStartObject(this, o)) { + && shouldSkipWhitespaceAfterStartObject(this, o, lineMidpointState)) { // Like with list markers, we start ignoring spaces to make sure that any // additional spaces we see will be discarded. currentCharacterIsSpace = true; @@ -1854,7 +1776,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool } if (ignoringSpaces) - addMidpoint(InlineIterator(0, o, 0)); + addMidpoint(lineMidpointState, InlineIterator(0, o, 0)); isLineEmpty = false; ignoringSpaces = false; @@ -1864,8 +1786,8 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool // Optimize for a common case. If we can't find whitespace after the list // item, then this is all moot. -dwh - if (o->isListMarker() && !static_cast<RenderListMarker*>(o)->isInside()) { - if (style()->collapseWhiteSpace() && shouldSkipWhitespaceAfterStartObject(this, o)) { + if (o->isListMarker() && !toRenderListMarker(o)->isInside()) { + if (style()->collapseWhiteSpace() && shouldSkipWhitespaceAfterStartObject(this, o, lineMidpointState)) { // Like with inline flows, we start ignoring spaces to make sure that any // additional spaces we see will be discarded. currentCharacterIsSpace = true; @@ -1928,10 +1850,11 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool else 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--; + if (lineMidpointState.numMidpoints && lineMidpointState.midpoints[lineMidpointState.numMidpoints - 1].obj == o && + lineMidpointState.midpoints[lineMidpointState.numMidpoints - 1].pos == pos) + lineMidpointState.numMidpoints--; else - addMidpoint(beforeSoftHyphen); + addMidpoint(lineMidpointState, beforeSoftHyphen); // Add the width up to but not including the hyphen. tmpW += textWidth(t, lastSpace, pos - lastSpace, f, w + tmpW, isFixedPitch, collapseWhiteSpace) + lastSpaceWordSpacing; @@ -1943,7 +1866,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool InlineIterator afterSoftHyphen(0, o, pos); afterSoftHyphen.increment(); - addMidpoint(afterSoftHyphen); + addMidpoint(lineMidpointState, afterSoftHyphen); } pos++; @@ -1974,7 +1897,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool ignoringSpaces = false; lastSpaceWordSpacing = 0; lastSpace = pos; // e.g., "Foo goo", don't add in any of the ignored spaces. - addMidpoint(InlineIterator(0, o, pos)); + addMidpoint(lineMidpointState, InlineIterator(0, o, pos)); stoppedIgnoringSpaces = true; } else { // Just keep ignoring these spaces. @@ -2012,15 +1935,15 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool lBreak.obj = o; lBreak.pos = pos; lBreak.nextBreakablePosition = nextBreakable; - skipTrailingWhitespace(lBreak); + skipTrailingWhitespace(lBreak, isLineEmpty, previousLineBrokeCleanly); } } if (lineWasTooWide || w + tmpW > width) { 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 - addMidpoint(InlineIterator(0, o, pos)); // Start + addMidpoint(lineMidpointState, InlineIterator(0, o, pos - 1)); // Stop + addMidpoint(lineMidpointState, InlineIterator(0, o, pos)); // Start } lBreak.increment(); previousLineBrokeCleanly = true; @@ -2038,8 +1961,8 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool if (c == '\n' && preserveNewline) { if (!stoppedIgnoringSpaces && pos > 0) { // We need to stop right before the newline and then start up again. - addMidpoint(InlineIterator(0, o, pos - 1)); // Stop - addMidpoint(InlineIterator(0, o, pos)); // Start + addMidpoint(lineMidpointState, InlineIterator(0, o, pos - 1)); // Stop + addMidpoint(lineMidpointState, InlineIterator(0, o, pos)); // Start } lBreak.obj = o; lBreak.pos = pos; @@ -2085,7 +2008,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool // We just entered a mode where we are ignoring // spaces. Create a midpoint to terminate the run // before the second space. - addMidpoint(ignoreStart); + addMidpoint(lineMidpointState, ignoreStart); } } } else if (ignoringSpaces) { @@ -2094,7 +2017,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool ignoringSpaces = false; lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0; lastSpace = pos; // e.g., "Foo goo", don't add in any of the ignored spaces. - addMidpoint(InlineIterator(0, o, pos)); + addMidpoint(lineMidpointState, InlineIterator(0, o, pos)); } if (currentCharacterIsSpace && !previousCharacterIsSpace) { @@ -2183,7 +2106,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool if (!o->isFloatingOrPositioned()) { last = o; - if (last->isReplaced() && autoWrap && (!last->isImage() || allowImagesToBreak) && (!last->isListMarker() || static_cast<RenderListMarker*>(last)->isInside())) { + if (last->isReplaced() && autoWrap && (!last->isImage() || allowImagesToBreak) && (!last->isListMarker() || toRenderListMarker(last)->isInside())) { w += tmpW; tmpW = 0; lBreak.obj = next; @@ -2246,15 +2169,15 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool lBreak.increment(); // Sanity check our midpoints. - checkMidpoints(lBreak); + checkMidpoints(lineMidpointState, lBreak); if (trailingSpaceObject) { // This object is either going to be part of the last midpoint, or it is going // to be the actual endpoint. In both cases we just decrease our pos by 1 level to // exclude the space, allowing it to - in effect - collapse into the newline. - if (sNumMidpoints%2==1) { - InlineIterator* midpoints = smidpoints->data(); - midpoints[sNumMidpoints-1].pos--; + if (lineMidpointState.numMidpoints % 2) { + InlineIterator* midpoints = lineMidpointState.midpoints.data(); + midpoints[lineMidpointState.numMidpoints - 1].pos--; } //else if (lBreak.pos > 0) // lBreak.pos--; @@ -2264,7 +2187,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool unsigned length = text->textLength(); unsigned pos = length >= 2 ? length - 2 : UINT_MAX; InlineIterator endMid(0, trailingSpaceObject, pos); - addMidpoint(endMid); + addMidpoint(lineMidpointState, endMid); } } @@ -2280,9 +2203,9 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool 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 = toRenderText(lBreak.obj)->characters()[lBreak.pos-1]; + UChar c = toRenderText(lBreak.obj)->characters()[lBreak.pos - 1]; if (c == softHyphen) - chopMidpointsAt(lBreak.obj, lBreak.pos-2); + chopMidpointsAt(lineMidpointState, lBreak.obj, lBreak.pos - 2); } return lBreak; diff --git a/WebCore/rendering/RenderBox.cpp b/WebCore/rendering/RenderBox.cpp index 9eb5898..4c2bff0 100644 --- a/WebCore/rendering/RenderBox.cpp +++ b/WebCore/rendering/RenderBox.cpp @@ -3,7 +3,7 @@ * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com) * (C) 2005, 2006 Samuel Weinig (sam.weinig@gmail.com) - * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 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 @@ -254,22 +254,22 @@ 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 layer()->scrollWidth(); - return overflowWidth(); + // For objects with visible overflow, this matches IE. + if (style()->direction() == LTR) + return max(clientWidth(), rightmostPosition(true, false) - borderLeft()); + return clientWidth() - min(0, leftmostPosition(true, false) - borderLeft()); } int RenderBox::scrollHeight() const { if (hasOverflowClip()) return layer()->scrollHeight(); - return overflowHeight(); + // For objects with visible overflow, this matches IE. + return max(clientHeight(), lowestPosition(true, false) - borderTop()); } int RenderBox::scrollLeft() const @@ -588,9 +588,7 @@ void RenderBox::paintRootBoxDecorations(PaintInfo& paintInfo, int tx, int ty) int bw = max(w + marginLeft() + marginRight() + borderLeft() + borderRight(), rw); int bh = max(h + marginTop() + marginBottom() + borderTop() + borderBottom(), rh); - int my = max(by, paintInfo.rect.y()); - - paintFillLayers(paintInfo, bgColor, bgLayer, my, paintInfo.rect.height(), bx, by, bw, bh); + paintFillLayers(paintInfo, bgColor, bgLayer, bx, by, bw, bh); if (style()->hasBorder() && style()->display() != INLINE) paintBorder(paintInfo.context, tx, ty, w, h, style()); @@ -613,16 +611,9 @@ void RenderBox::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty) // balloon layout is an example of this). borderFitAdjust(tx, w); - int my = max(ty, paintInfo.rect.y()); - int mh; - if (ty < paintInfo.rect.y()) - mh = max(0, h - (paintInfo.rect.y() - ty)); - else - mh = min(paintInfo.rect.height(), h); - // FIXME: Should eventually give the theme control over whether the box shadow should paint, since controls could have // custom shadows of their own. - paintBoxShadow(paintInfo.context, tx, ty, w, h, style()); + paintBoxShadow(paintInfo.context, tx, ty, w, h, style(), Normal); // If we have a native theme appearance, paint that before painting our background. // The theme will tell us whether or not we should also paint the CSS background. @@ -632,10 +623,11 @@ void RenderBox::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty) // independent of the body. Go through the DOM to get to the root element's render object, // since the root could be inline and wrapped in an anonymous block. if (!isBody() || document()->documentElement()->renderer()->style()->hasBackground()) - paintFillLayers(paintInfo, style()->backgroundColor(), style()->backgroundLayers(), my, mh, tx, ty, w, h); + paintFillLayers(paintInfo, style()->backgroundColor(), style()->backgroundLayers(), tx, ty, w, h); if (style()->hasAppearance()) theme()->paintDecorations(this, paintInfo, IntRect(tx, ty, w, h)); } + paintBoxShadow(paintInfo.context, tx, ty, w, h, style(), Inset); // The theme will tell us whether or not we should also paint the CSS border. if ((!style()->hasAppearance() || (!themePainted && theme()->paintBorderOnly(this, paintInfo, IntRect(tx, ty, w, h)))) && style()->hasBorder()) @@ -654,17 +646,10 @@ void RenderBox::paintMask(PaintInfo& paintInfo, int tx, int ty) // balloon layout is an example of this). borderFitAdjust(tx, w); - int my = max(ty, paintInfo.rect.y()); - int mh; - if (ty < paintInfo.rect.y()) - mh = max(0, h - (paintInfo.rect.y() - ty)); - else - mh = min(paintInfo.rect.height(), h); - - paintMaskImages(paintInfo, my, mh, tx, ty, w, h); + paintMaskImages(paintInfo, tx, ty, w, h); } -void RenderBox::paintMaskImages(const PaintInfo& paintInfo, int my, int mh, int tx, int ty, int w, int h) +void RenderBox::paintMaskImages(const PaintInfo& paintInfo, int tx, int ty, int w, int h) { // Figure out if we need to push a transparency layer to render our mask. bool pushTransparencyLayer = false; @@ -695,7 +680,7 @@ void RenderBox::paintMaskImages(const PaintInfo& paintInfo, int my, int mh, int compositeOp = CompositeSourceOver; } - paintFillLayers(paintInfo, Color(), style()->maskLayers(), my, mh, tx, ty, w, h, compositeOp); + paintFillLayers(paintInfo, Color(), style()->maskLayers(), tx, ty, w, h, compositeOp); paintNinePieceImage(paintInfo.context, tx, ty, w, h, style(), style()->maskBoxImage(), compositeOp); if (pushTransparencyLayer) @@ -721,20 +706,18 @@ IntRect RenderBox::maskClipRect() return result; } -void RenderBox::paintFillLayers(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, - int clipY, int clipH, int tx, int ty, int width, int height, CompositeOperator op) +void RenderBox::paintFillLayers(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, int tx, int ty, int width, int height, CompositeOperator op) { if (!fillLayer) return; - paintFillLayers(paintInfo, c, fillLayer->next(), clipY, clipH, tx, ty, width, height, op); - paintFillLayer(paintInfo, c, fillLayer, clipY, clipH, tx, ty, width, height, op); + paintFillLayers(paintInfo, c, fillLayer->next(), tx, ty, width, height, op); + paintFillLayer(paintInfo, c, fillLayer, tx, ty, width, height, op); } -void RenderBox::paintFillLayer(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, - int clipY, int clipH, int tx, int ty, int width, int height, CompositeOperator op) +void RenderBox::paintFillLayer(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, int tx, int ty, int width, int height, CompositeOperator op) { - paintFillLayerExtended(paintInfo, c, fillLayer, clipY, clipH, tx, ty, width, height, 0, op); + paintFillLayerExtended(paintInfo, c, fillLayer, tx, ty, width, height, 0, op); } void RenderBox::imageChanged(WrappedImagePtr image, const IntRect*) @@ -1567,7 +1550,7 @@ int RenderBox::calcPercentageHeight(const Length& height) // no size and allow the flexing of the table or the cell to its specified height to cause us // to grow to fill the space. This could end up being wrong in some cases, but it is // preferable to the alternative (sizing intrinsically and making the row end up too big). - RenderTableCell* cell = static_cast<RenderTableCell*>(cb); + RenderTableCell* cell = toRenderTableCell(cb); if (scrollsOverflowY() && (!cell->style()->height().isAuto() || !cell->table()->style()->height().isAuto())) return 0; return -1; @@ -1631,7 +1614,7 @@ int RenderBox::calcReplacedWidthUsing(Length width) const default: return intrinsicSize().width(); } - } +} int RenderBox::calcReplacedHeight() const { diff --git a/WebCore/rendering/RenderBox.h b/WebCore/rendering/RenderBox.h index ba96f01..cb2297b 100644 --- a/WebCore/rendering/RenderBox.h +++ b/WebCore/rendering/RenderBox.h @@ -251,7 +251,7 @@ public: virtual void paintObject(PaintInfo&, int /*tx*/, int /*ty*/) { ASSERT_NOT_REACHED(); } virtual void paintBoxDecorations(PaintInfo&, int tx, int ty); - virtual void paintMask(PaintInfo& paintInfo, int tx, int ty); + virtual void paintMask(PaintInfo&, int tx, int ty); virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); // Called when a positioned object moves but doesn't change size. A simplified layout is done @@ -288,10 +288,10 @@ protected: virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); virtual void updateBoxModelInfoFromStyle(); - void paintFillLayer(const PaintInfo&, const Color&, const FillLayer*, int clipY, int clipHeight, int tx, int ty, int width, int height, CompositeOperator = CompositeSourceOver); - void paintFillLayers(const PaintInfo&, const Color&, const FillLayer*, int clipY, int clipHeight, int tx, int ty, int width, int height, CompositeOperator = CompositeSourceOver); + void paintFillLayer(const PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int width, int height, CompositeOperator = CompositeSourceOver); + void paintFillLayers(const PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int width, int height, CompositeOperator = CompositeSourceOver); - void paintMaskImages(const PaintInfo&, int clipY, int clipHeight, int tx, int ty, int width, int height); + void paintMaskImages(const PaintInfo&, int tx, int ty, int width, int height); #if PLATFORM(MAC) void paintCustomHighlight(int tx, int ty, const AtomicString& type, bool behindText); @@ -365,16 +365,16 @@ private: static bool s_hadOverflowClip; }; -inline RenderBox* toRenderBox(RenderObject* o) +inline RenderBox* toRenderBox(RenderObject* object) { - ASSERT(!o || o->isBox()); - return static_cast<RenderBox*>(o); + ASSERT(!object || object->isBox()); + return static_cast<RenderBox*>(object); } -inline const RenderBox* toRenderBox(const RenderObject* o) +inline const RenderBox* toRenderBox(const RenderObject* object) { - ASSERT(!o || o->isBox()); - return static_cast<const RenderBox*>(o); + ASSERT(!object || object->isBox()); + return static_cast<const RenderBox*>(object); } // This will catch anyone doing an unnecessary cast. diff --git a/WebCore/rendering/RenderBoxModelObject.cpp b/WebCore/rendering/RenderBoxModelObject.cpp index 7ad1a5e..3a7ff71 100644 --- a/WebCore/rendering/RenderBoxModelObject.cpp +++ b/WebCore/rendering/RenderBoxModelObject.cpp @@ -173,13 +173,20 @@ void RenderBoxModelObject::updateBoxModelInfoFromStyle() int RenderBoxModelObject::relativePositionOffsetX() const { + // Objects that shrink to avoid floats normally use available line width when computing containing block width. However + // in the case of relative positioning using percentages, we can't do this. The offset should always be resolved using the + // available width of the containing block. Therefore we don't use containingBlockWidthForContent() here, but instead explicitly + // call availableWidth on our containing block. if (!style()->left().isAuto()) { + RenderBlock* cb = containingBlock(); if (!style()->right().isAuto() && containingBlock()->style()->direction() == RTL) - return -style()->right().calcValue(containingBlockWidthForContent()); - return style()->left().calcValue(containingBlockWidthForContent()); + return -style()->right().calcValue(cb->availableWidth()); + return style()->left().calcValue(cb->availableWidth()); + } + if (!style()->right().isAuto()) { + RenderBlock* cb = containingBlock(); + return -style()->right().calcValue(cb->availableWidth()); } - if (!style()->right().isAuto()) - return -style()->right().calcValue(containingBlockWidthForContent()); return 0; } @@ -297,8 +304,7 @@ int RenderBoxModelObject::paddingRight(bool) const } -void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, const Color& c, const FillLayer* bgLayer, int clipY, int clipH, - int tx, int ty, int w, int h, InlineFlowBox* box, CompositeOperator op) +void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, const Color& c, const FillLayer* bgLayer, int tx, int ty, int w, int h, InlineFlowBox* box, CompositeOperator op) { GraphicsContext* context = paintInfo.context; bool includeLeftEdge = box ? box->includeLeftEdge() : true; @@ -323,6 +329,18 @@ void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co clippedToBorderRadius = true; } + bool clippedWithLocalScrolling = hasOverflowClip() && bgLayer->attachment() == LocalBackgroundAttachment; + if (clippedWithLocalScrolling) { + // Clip to the overflow area. + context->save(); + context->clip(toRenderBox(this)->overflowClipRect(tx, ty)); + + // Now adjust our tx, ty, w, h to reflect a scrolled content box with borders at the ends. + layer()->subtractScrolledContentOffset(tx, ty); + w = bLeft + layer()->scrollWidth() + bRight; + h = borderTop() + layer()->scrollHeight() + borderBottom(); + } + if (bgLayer->clip() == PaddingFillBox || bgLayer->clip() == ContentFillBox) { // Clip to the padding or content boxes as necessary. bool includePadding = bgLayer->clip() == ContentFillBox; @@ -340,7 +358,7 @@ void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co maskRect.intersect(paintInfo.rect); // Now create the mask. - OwnPtr<ImageBuffer> maskImage = ImageBuffer::create(maskRect.size(), false); + OwnPtr<ImageBuffer> maskImage = ImageBuffer::create(maskRect.size()); if (!maskImage) return; @@ -411,7 +429,8 @@ void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co // Paint the color first underneath all images. if (!bgLayer->next()) { - IntRect rect(tx, clipY, w, clipH); + IntRect rect(tx, ty, w, h); + rect.intersect(paintInfo.rect); // If we have an alpha and we are painting the root element, go ahead and blend with the base background color. if (isOpaqueRoot) { Color baseColor = view()->frameView()->baseBackgroundColor(); @@ -469,6 +488,9 @@ void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co if (clippedToBorderRadius) // Undo the border radius clip context->restore(); + + if (clippedWithLocalScrolling) // Undo the clip for local background attachments. + context->restore(); } IntSize RenderBoxModelObject::calculateBackgroundSize(const FillLayer* bgLayer, int scaledWidth, int scaledHeight) const @@ -525,9 +547,9 @@ void RenderBoxModelObject::calculateBackgroundImageGeometry(const FillLayer* bgL int rh = 0; // CSS2 chapter 14.2.1 - - if (bgLayer->attachment()) { - // Scroll + bool fixedAttachment = bgLayer->attachment() == FixedBackgroundAttachment; + if (!fixedAttachment) { + // Scroll and Local if (bgLayer->origin() != BorderFillBox) { left = borderLeft(); right = borderRight(); @@ -557,7 +579,7 @@ void RenderBoxModelObject::calculateBackgroundImageGeometry(const FillLayer* bgL pw = w - left - right; ph = h - top - bottom; } else { - // Fixed + // Fixed background attachment. IntRect vr = viewRect(); cx = vr.x(); cy = vr.y(); @@ -571,7 +593,7 @@ void RenderBoxModelObject::calculateBackgroundImageGeometry(const FillLayer* bgL int ch; IntSize scaledImageSize; - if (isRoot() && bgLayer->attachment()) + if (isRoot() && !fixedAttachment) scaledImageSize = calculateBackgroundSize(bgLayer, rw, rh); else scaledImageSize = calculateBackgroundSize(bgLayer, pw, ph); @@ -582,7 +604,7 @@ void RenderBoxModelObject::calculateBackgroundImageGeometry(const FillLayer* bgL EFillRepeat backgroundRepeat = bgLayer->repeat(); int xPosition; - if (isRoot() && bgLayer->attachment()) + if (isRoot() && !fixedAttachment) xPosition = bgLayer->xPosition().calcMinValue(rw - scaledImageWidth, true); else xPosition = bgLayer->xPosition().calcMinValue(pw - scaledImageWidth, true); @@ -596,7 +618,7 @@ void RenderBoxModelObject::calculateBackgroundImageGeometry(const FillLayer* bgL } int yPosition; - if (isRoot() && bgLayer->attachment()) + if (isRoot() && !fixedAttachment) yPosition = bgLayer->yPosition().calcMinValue(rh - scaledImageHeight, true); else yPosition = bgLayer->yPosition().calcMinValue(ph - scaledImageHeight, true); @@ -609,7 +631,7 @@ void RenderBoxModelObject::calculateBackgroundImageGeometry(const FillLayer* bgL ch = scaledImageHeight + min(yPosition + top, 0); } - if (!bgLayer->attachment()) { + if (fixedAttachment) { sx += max(tx - cx, 0); sy += max(ty - cy, 0); } @@ -1124,52 +1146,209 @@ void RenderBoxModelObject::paintBorder(GraphicsContext* graphicsContext, int tx, graphicsContext->restore(); } -void RenderBoxModelObject::paintBoxShadow(GraphicsContext* context, int tx, int ty, int w, int h, const RenderStyle* s, bool begin, bool end) +void RenderBoxModelObject::paintBoxShadow(GraphicsContext* context, int tx, int ty, int w, int h, const RenderStyle* s, ShadowStyle shadowStyle, bool begin, bool end) { // FIXME: Deal with border-image. Would be great to use border-image as a mask. + if (context->paintingDisabled()) + return; + IntRect rect(tx, ty, w, h); + IntSize topLeft; + IntSize topRight; + IntSize bottomLeft; + IntSize bottomRight; + bool hasBorderRadius = s->hasBorderRadius(); + if (hasBorderRadius && (begin || end)) { + IntSize topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius; + s->getBorderRadiiForRect(rect, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius); + + if (begin) { + if (shadowStyle == Inset) { + topLeftRadius.expand(-borderLeft(), -borderTop()); + topLeftRadius.clampNegativeToZero(); + bottomLeftRadius.expand(-borderLeft(), -borderBottom()); + bottomLeftRadius.clampNegativeToZero(); + } + topLeft = topLeftRadius; + bottomLeft = bottomLeftRadius; + } + if (end) { + if (shadowStyle == Inset) { + topRightRadius.expand(-borderRight(), -borderTop()); + topRightRadius.clampNegativeToZero(); + bottomRightRadius.expand(-borderRight(), -borderBottom()); + bottomRightRadius.clampNegativeToZero(); + } + topRight = topRightRadius; + bottomRight = bottomRightRadius; + } + } + + if (shadowStyle == Inset) { + rect.move(begin ? borderLeft() : 0, borderTop()); + rect.setWidth(rect.width() - (begin ? borderLeft() : 0) - (end ? borderRight() : 0)); + rect.setHeight(rect.height() - borderTop() - borderBottom()); + } + bool hasOpaqueBackground = s->backgroundColor().isValid() && s->backgroundColor().alpha() == 255; for (ShadowData* shadow = s->boxShadow(); shadow; shadow = shadow->next) { - context->save(); + if (shadow->style != shadowStyle) + continue; IntSize shadowOffset(shadow->x, shadow->y); int shadowBlur = shadow->blur; - IntRect fillRect(rect); + int shadowSpread = shadow->spread; + Color& shadowColor = shadow->color; + + if (shadow->style == Normal) { + IntRect fillRect(rect); + fillRect.inflate(shadowSpread); + if (fillRect.isEmpty()) + continue; - if (hasBorderRadius) { IntRect shadowRect(rect); - shadowRect.inflate(shadowBlur); + shadowRect.inflate(shadowBlur + shadowSpread); shadowRect.move(shadowOffset); + + context->save(); context->clip(shadowRect); // Move the fill just outside the clip, adding 1 pixel separation so that the fill does not // bleed in (due to antialiasing) if the context is transformed. - IntSize extraOffset(w + max(0, shadowOffset.width()) + shadowBlur + 1, 0); + IntSize extraOffset(w + max(0, shadowOffset.width()) + shadowBlur + 2 * shadowSpread + 1, 0); shadowOffset -= extraOffset; fillRect.move(extraOffset); - } - context->setShadow(shadowOffset, shadowBlur, shadow->color); - if (hasBorderRadius) { - IntSize topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius; - s->getBorderRadiiForRect(rect, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius); + context->setShadow(shadowOffset, shadowBlur, shadowColor); + if (hasBorderRadius) { + IntRect rectToClipOut = rect; + IntSize topLeftToClipOut = topLeft; + IntSize topRightToClipOut = topRight; + IntSize bottomLeftToClipOut = bottomLeft; + IntSize bottomRightToClipOut = bottomRight; + + if (shadowSpread < 0) { + topLeft.expand(shadowSpread, shadowSpread); + topLeft.clampNegativeToZero(); - IntSize topLeft = begin ? topLeftRadius : IntSize(); - IntSize topRight = end ? topRightRadius : IntSize(); - IntSize bottomLeft = begin ? bottomLeftRadius : IntSize(); - IntSize bottomRight = end ? bottomRightRadius : IntSize(); + topRight.expand(shadowSpread, shadowSpread); + topRight.clampNegativeToZero(); - if (!hasOpaqueBackground) - context->clipOutRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight); - context->fillRoundedRect(fillRect, topLeft, topRight, bottomLeft, bottomRight, Color::black); + bottomLeft.expand(shadowSpread, shadowSpread); + bottomLeft.clampNegativeToZero(); + + bottomRight.expand(shadowSpread, shadowSpread); + bottomRight.clampNegativeToZero(); + } + + // If the box is opaque, it is unnecessary to clip it out. However, doing so saves time + // when painting the shadow. On the other hand, it introduces subpixel gaps along the + // corners. Those are avoided by insetting the clipping path by one pixel. + if (hasOpaqueBackground) { + rectToClipOut.inflate(-1); + + topLeftToClipOut.expand(-1, -1); + topLeftToClipOut.clampNegativeToZero(); + + topRightToClipOut.expand(-1, -1); + topRightToClipOut.clampNegativeToZero(); + + bottomLeftToClipOut.expand(-1, -1); + bottomLeftToClipOut.clampNegativeToZero(); + + bottomRightToClipOut.expand(-1, -1); + bottomRightToClipOut.clampNegativeToZero(); + } + + if (!rectToClipOut.isEmpty()) + context->clipOutRoundedRect(rectToClipOut, topLeftToClipOut, topRightToClipOut, bottomLeftToClipOut, bottomRightToClipOut); + context->fillRoundedRect(fillRect, topLeft, topRight, bottomLeft, bottomRight, Color::black); + } else { + IntRect rectToClipOut = rect; + + // If the box is opaque, it is unnecessary to clip it out. However, doing so saves time + // when painting the shadow. On the other hand, it introduces subpixel gaps along the + // edges if they are not pixel-aligned. Those are avoided by insetting the clipping path + // by one pixel. + if (hasOpaqueBackground) { + TransformationMatrix currentTransformation = context->getCTM(); + if (currentTransformation.a() != 1 || (currentTransformation.d() != 1 && currentTransformation.d() != -1) + || currentTransformation.b() || currentTransformation.c()) + rectToClipOut.inflate(-1); + } + + if (!rectToClipOut.isEmpty()) + context->clipOut(rectToClipOut); + context->fillRect(fillRect, Color::black); + } + + context->restore(); } else { - if (!hasOpaqueBackground) - context->clipOut(rect); - context->fillRect(fillRect, Color::black); + // Inset shadow. + IntRect holeRect(rect); + holeRect.inflate(-shadowSpread); + + if (holeRect.isEmpty()) { + if (hasBorderRadius) + context->fillRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight, shadowColor); + else + context->fillRect(rect, shadowColor); + continue; + } + if (!begin) { + holeRect.move(-max(shadowOffset.width(), 0) - shadowBlur, 0); + holeRect.setWidth(holeRect.width() + max(shadowOffset.width(), 0) + shadowBlur); + } + if (!end) + holeRect.setWidth(holeRect.width() - min(shadowOffset.width(), 0) + shadowBlur); + + Color fillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), 255); + + IntRect outerRect(rect); + outerRect.inflateX(w - 2 * shadowSpread); + outerRect.inflateY(h - 2 * shadowSpread); + + context->save(); + + if (hasBorderRadius) + context->clip(Path::createRoundedRectangle(rect, topLeft, topRight, bottomLeft, bottomRight)); + else + context->clip(rect); + + IntSize extraOffset(2 * w + max(0, shadowOffset.width()) + shadowBlur - 2 * shadowSpread + 1, 0); + context->translate(extraOffset.width(), extraOffset.height()); + shadowOffset -= extraOffset; + + context->beginPath(); + context->addPath(Path::createRectangle(outerRect)); + + if (hasBorderRadius) { + if (shadowSpread > 0) { + topLeft.expand(-shadowSpread, -shadowSpread); + topLeft.clampNegativeToZero(); + + topRight.expand(-shadowSpread, -shadowSpread); + topRight.clampNegativeToZero(); + + bottomLeft.expand(-shadowSpread, -shadowSpread); + bottomLeft.clampNegativeToZero(); + + bottomRight.expand(-shadowSpread, -shadowSpread); + bottomRight.clampNegativeToZero(); + } + context->addPath(Path::createRoundedRectangle(holeRect, topLeft, topRight, bottomLeft, bottomRight)); + } else + context->addPath(Path::createRectangle(holeRect)); + + context->setFillRule(RULE_EVENODD); + context->setFillColor(fillColor); + context->setShadow(shadowOffset, shadowBlur, shadowColor); + context->fillPath(); + + context->restore(); } - context->restore(); } } diff --git a/WebCore/rendering/RenderBoxModelObject.h b/WebCore/rendering/RenderBoxModelObject.h index f2c6326..baa5ecb 100644 --- a/WebCore/rendering/RenderBoxModelObject.h +++ b/WebCore/rendering/RenderBoxModelObject.h @@ -89,9 +89,8 @@ public: 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 paintBoxShadow(GraphicsContext*, int tx, int ty, int w, int h, const RenderStyle*, bool begin = true, bool end = true); - 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); + void paintBoxShadow(GraphicsContext*, int tx, int ty, int w, int h, const RenderStyle*, ShadowStyle, bool begin = true, bool end = true); + void paintFillLayerExtended(const PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int width, int height, InlineFlowBox* = 0, CompositeOperator = CompositeSourceOver); // The difference between this inline's baseline position and the line's baseline position. int verticalPosition(bool firstLine) const; @@ -115,16 +114,16 @@ private: static bool s_layerWasSelfPainting; }; -inline RenderBoxModelObject* toRenderBoxModelObject(RenderObject* o) +inline RenderBoxModelObject* toRenderBoxModelObject(RenderObject* object) { - ASSERT(!o || o->isBoxModelObject()); - return static_cast<RenderBoxModelObject*>(o); + ASSERT(!object || object->isBoxModelObject()); + return static_cast<RenderBoxModelObject*>(object); } -inline const RenderBoxModelObject* toRenderBoxModelObject(const RenderObject* o) +inline const RenderBoxModelObject* toRenderBoxModelObject(const RenderObject* object) { - ASSERT(!o || o->isBoxModelObject()); - return static_cast<const RenderBoxModelObject*>(o); + ASSERT(!object || object->isBoxModelObject()); + return static_cast<const RenderBoxModelObject*>(object); } // This will catch anyone doing an unnecessary cast. diff --git a/WebCore/rendering/RenderButton.cpp b/WebCore/rendering/RenderButton.cpp index b266f42..6d36a0f 100644 --- a/WebCore/rendering/RenderButton.cpp +++ b/WebCore/rendering/RenderButton.cpp @@ -164,6 +164,11 @@ void RenderButton::setText(const String& str) } } +String RenderButton::text() const +{ + return m_buttonText ? m_buttonText->text() : 0; +} + void RenderButton::updateBeforeAfterContent(PseudoId type) { if (m_inner) diff --git a/WebCore/rendering/RenderButton.h b/WebCore/rendering/RenderButton.h index 89f7cf8..3a74589 100644 --- a/WebCore/rendering/RenderButton.h +++ b/WebCore/rendering/RenderButton.h @@ -55,7 +55,8 @@ public: virtual IntRect controlClipRect(int /*tx*/, int /*ty*/) const; void setText(const String&); - + String text() const; + virtual bool canHaveChildren() const; protected: @@ -73,16 +74,16 @@ protected: bool m_default; }; -inline RenderButton* toRenderButton(RenderObject* o) +inline RenderButton* toRenderButton(RenderObject* object) { - ASSERT(!o || o->isRenderButton()); - return static_cast<RenderButton*>(o); + ASSERT(!object || object->isRenderButton()); + return static_cast<RenderButton*>(object); } -inline const RenderButton* toRenderButton(const RenderObject* o) +inline const RenderButton* toRenderButton(const RenderObject* object) { - ASSERT(!o || o->isRenderButton()); - return static_cast<const RenderButton*>(o); + ASSERT(!object || object->isRenderButton()); + return static_cast<const RenderButton*>(object); } // This will catch anyone doing an unnecessary cast. diff --git a/WebCore/rendering/RenderCounter.cpp b/WebCore/rendering/RenderCounter.cpp index fd6d80d..67e5cba 100644 --- a/WebCore/rendering/RenderCounter.cpp +++ b/WebCore/rendering/RenderCounter.cpp @@ -107,8 +107,8 @@ static bool planCounter(RenderObject* object, const AtomicString& counterName, b if (counterName == "list-item") { if (object->isListItem()) { - if (static_cast<RenderListItem*>(object)->hasExplicitValue()) { - value = static_cast<RenderListItem*>(object)->explicitValue(); + if (toRenderListItem(object)->hasExplicitValue()) { + value = toRenderListItem(object)->explicitValue(); isReset = true; return true; } diff --git a/WebCore/rendering/RenderCounter.h b/WebCore/rendering/RenderCounter.h index 55aab73..961968e 100644 --- a/WebCore/rendering/RenderCounter.h +++ b/WebCore/rendering/RenderCounter.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2004 Allan Sandfeld Jensen (kde@carewolf.com) - * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 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 @@ -33,21 +33,30 @@ class RenderCounter : public RenderText { public: RenderCounter(Document*, const CounterContent&); + void invalidate(); + + static void destroyCounterNodes(RenderObject*); + +private: virtual const char* renderName() const; virtual bool isCounter() const; virtual PassRefPtr<StringImpl> originalText() const; virtual void calcPrefWidths(int leadWidth); - void invalidate(); - - static void destroyCounterNodes(RenderObject*); - -private: CounterContent m_counter; mutable CounterNode* m_counterNode; }; +inline RenderCounter* toRenderCounter(RenderObject* object) +{ + ASSERT(!object || object->isCounter()); + return static_cast<RenderCounter*>(object); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderCounter(const RenderCounter*); + } // namespace WebCore #endif // RenderCounter_h diff --git a/WebCore/rendering/RenderDataGrid.cpp b/WebCore/rendering/RenderDataGrid.cpp new file mode 100644 index 0000000..bdf723f --- /dev/null +++ b/WebCore/rendering/RenderDataGrid.cpp @@ -0,0 +1,250 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(DATAGRID) + +#include "RenderDataGrid.h" + +#include "CSSStyleSelector.h" +#include "FocusController.h" +#include "Frame.h" +#include "GraphicsContext.h" +#include "Page.h" +#include "RenderView.h" +#include "Scrollbar.h" + +using std::min; + +namespace WebCore { + +static const int cDefaultWidth = 300; + +RenderDataGrid::RenderDataGrid(Element* elt) + : RenderBlock(elt) +{ +} + +RenderDataGrid::~RenderDataGrid() +{ +} + +void RenderDataGrid::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) +{ + RenderBlock::styleDidChange(diff, oldStyle); + recalcStyleForColumns(); +} + +void RenderDataGrid::recalcStyleForColumns() +{ + DataGridColumnList* columns = gridElement()->columns(); + unsigned length = columns->length(); + for (unsigned i = 0; i < length; ++i) + recalcStyleForColumn(columns->item(i)); +} + +void RenderDataGrid::recalcStyleForColumn(DataGridColumn* column) +{ + if (!column->columnStyle()) + column->setColumnStyle(document()->styleSelector()->pseudoStyleForDataGridColumn(column, style())); + if (!column->headerStyle()) + column->setHeaderStyle(document()->styleSelector()->pseudoStyleForDataGridColumnHeader(column, style())); +} + +RenderStyle* RenderDataGrid::columnStyle(DataGridColumn* column) +{ + if (!column->columnStyle()) + recalcStyleForColumn(column); + return column->columnStyle(); +} + +RenderStyle* RenderDataGrid::headerStyle(DataGridColumn* column) +{ + if (!column->headerStyle()) + recalcStyleForColumn(column); + return column->headerStyle(); +} + +void RenderDataGrid::calcPrefWidths() +{ + m_minPrefWidth = 0; + m_maxPrefWidth = 0; + + if (style()->width().isFixed() && style()->width().value() > 0) + m_minPrefWidth = m_maxPrefWidth = calcContentBoxWidth(style()->width().value()); + else + m_maxPrefWidth = calcContentBoxWidth(cDefaultWidth); + + if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) { + m_maxPrefWidth = max(m_maxPrefWidth, calcContentBoxWidth(style()->minWidth().value())); + m_minPrefWidth = max(m_minPrefWidth, calcContentBoxWidth(style()->minWidth().value())); + } else if (style()->width().isPercent() || (style()->width().isAuto() && style()->height().isPercent())) + m_minPrefWidth = 0; + else + m_minPrefWidth = m_maxPrefWidth; + + if (style()->maxWidth().isFixed() && style()->maxWidth().value() != undefinedLength) { + m_maxPrefWidth = min(m_maxPrefWidth, calcContentBoxWidth(style()->maxWidth().value())); + m_minPrefWidth = min(m_minPrefWidth, calcContentBoxWidth(style()->maxWidth().value())); + } + + int toAdd = paddingLeft() + paddingRight() + borderLeft() + borderRight(); + m_minPrefWidth += toAdd; + m_maxPrefWidth += toAdd; + + setPrefWidthsDirty(false); +} + +void RenderDataGrid::layout() +{ + RenderBlock::layout(); + layoutColumns(); +} + +void RenderDataGrid::layoutColumns() +{ + // FIXME: Implement. +} + +void RenderDataGrid::paintObject(PaintInfo& paintInfo, int tx, int ty) +{ + if (style()->visibility() != VISIBLE) + return; + + // Paint our background and border. + RenderBlock::paintObject(paintInfo, tx, ty); + + if (paintInfo.phase != PaintPhaseForeground) + return; + + // Paint our column headers first. + paintColumnHeaders(paintInfo, tx, ty); +} + +void RenderDataGrid::paintColumnHeaders(PaintInfo& paintInfo, int tx, int ty) +{ + DataGridColumnList* columns = gridElement()->columns(); + unsigned length = columns->length(); + for (unsigned i = 0; i < length; ++i) { + DataGridColumn* column = columns->item(i); + RenderStyle* columnStyle = headerStyle(column); + + // Don't render invisible columns. + if (!columnStyle || columnStyle->display() == NONE || columnStyle->visibility() != VISIBLE) + continue; + + // Paint the column header if it intersects the dirty rect. + IntRect columnRect(column->rect()); + columnRect.move(tx, ty); + if (columnRect.intersects(paintInfo.rect)) + paintColumnHeader(column, paintInfo, tx, ty); + } +} + +void RenderDataGrid::paintColumnHeader(DataGridColumn*, PaintInfo&, int, int) +{ + // FIXME: Implement. +} + +// Scrolling implementation functions +void RenderDataGrid::valueChanged(Scrollbar*) +{ + // FIXME: Implement. +} + +void RenderDataGrid::invalidateScrollbarRect(Scrollbar*, const IntRect&) +{ + // FIXME: Implement. +} + +bool RenderDataGrid::isActive() const +{ + Page* page = document()->frame()->page(); + return page && page->focusController()->isActive(); +} + + +IntRect RenderDataGrid::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntRect& scrollbarRect) const +{ + RenderView* view = this->view(); + if (!view) + return scrollbarRect; + + IntRect rect = scrollbarRect; + + int scrollbarLeft = width() - borderRight() - scrollbar->width(); + int scrollbarTop = borderTop(); + rect.move(scrollbarLeft, scrollbarTop); + + return view->frameView()->convertFromRenderer(this, rect); +} + +IntRect RenderDataGrid::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntRect& parentRect) const +{ + RenderView* view = this->view(); + if (!view) + return parentRect; + + IntRect rect = view->frameView()->convertToRenderer(this, parentRect); + + int scrollbarLeft = width() - borderRight() - scrollbar->width(); + int scrollbarTop = borderTop(); + rect.move(-scrollbarLeft, -scrollbarTop); + return rect; +} + +IntPoint RenderDataGrid::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntPoint& scrollbarPoint) const +{ + RenderView* view = this->view(); + if (!view) + return scrollbarPoint; + + IntPoint point = scrollbarPoint; + + int scrollbarLeft = width() - borderRight() - scrollbar->width(); + int scrollbarTop = borderTop(); + point.move(scrollbarLeft, scrollbarTop); + + return view->frameView()->convertFromRenderer(this, point); +} + +IntPoint RenderDataGrid::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const +{ + RenderView* view = this->view(); + if (!view) + return parentPoint; + + IntPoint point = view->frameView()->convertToRenderer(this, parentPoint); + + int scrollbarLeft = width() - borderRight() - scrollbar->width(); + int scrollbarTop = borderTop(); + point.move(-scrollbarLeft, -scrollbarTop); + return point; +} + +} + +#endif diff --git a/WebCore/rendering/RenderDataGrid.h b/WebCore/rendering/RenderDataGrid.h new file mode 100644 index 0000000..467edcc --- /dev/null +++ b/WebCore/rendering/RenderDataGrid.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RenderDataGrid_h +#define RenderDataGrid_h + +#if ENABLE(DATAGRID) + +#include "HTMLDataGridElement.h" +#include "RenderBlock.h" +#include "ScrollbarClient.h" +#include "StyleImage.h" +#include <wtf/RefPtr.h> +#include <wtf/Vector.h> + +namespace WebCore { + +class RenderDataGrid : public RenderBlock, private ScrollbarClient { +public: + RenderDataGrid(Element*); + ~RenderDataGrid(); + + virtual const char* renderName() const { return "RenderDataGrid"; } + virtual bool canHaveChildren() const { return false; } + virtual void calcPrefWidths(); + virtual void layout(); + virtual void paintObject(PaintInfo&, int tx, int ty); + + void columnsChanged(); + +private: + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + + RenderStyle* columnStyle(DataGridColumn*); + RenderStyle* headerStyle(DataGridColumn*); + void recalcStyleForColumns(); + void recalcStyleForColumn(DataGridColumn*); + + void layoutColumns(); + void paintColumnHeaders(PaintInfo&, int tx, int ty); + void paintColumnHeader(DataGridColumn*, PaintInfo&, int tx, int ty); + + HTMLDataGridElement* gridElement() const { return static_cast<HTMLDataGridElement*>(node()); } + + // ScrollbarClient interface. + virtual void valueChanged(Scrollbar*); + virtual void invalidateScrollbarRect(Scrollbar*, const IntRect&); + virtual bool isActive() const; + virtual bool scrollbarCornerPresent() const { return false; } // We don't support resize on data grids yet. If we did this would have to change. + virtual IntRect convertFromScrollbarToContainingView(const Scrollbar*, const IntRect&) const; + virtual IntRect convertFromContainingViewToScrollbar(const Scrollbar*, const IntRect&) const; + virtual IntPoint convertFromScrollbarToContainingView(const Scrollbar*, const IntPoint&) const; + virtual IntPoint convertFromContainingViewToScrollbar(const Scrollbar*, const IntPoint&) const; + + RefPtr<Scrollbar> m_vBar; +}; + +} + +#endif + +#endif // RenderDataGrid_h diff --git a/WebCore/rendering/RenderFieldset.cpp b/WebCore/rendering/RenderFieldset.cpp index 310dbe4..437991a 100644 --- a/WebCore/rendering/RenderFieldset.cpp +++ b/WebCore/rendering/RenderFieldset.cpp @@ -99,7 +99,7 @@ RenderObject* RenderFieldset::layoutLegend(bool relayoutChildren) int b = borderTop(); int h = legend->height(); legend->setLocation(xPos, max((b-h)/2, 0)); - setHeight(max(b,h) + paddingTop()); + setHeight(max(b, h) + paddingTop()); } return legend; } @@ -131,13 +131,10 @@ void RenderFieldset::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty) h -= yOff; ty += yOff; - int my = max(ty, paintInfo.rect.y()); - int end = min(paintInfo.rect.bottom(), ty + h); - int mh = end - my; + paintBoxShadow(paintInfo.context, tx, ty, w, h, style(), Normal); - paintBoxShadow(paintInfo.context, tx, ty, w, h, style()); - - paintFillLayers(paintInfo, style()->backgroundColor(), style()->backgroundLayers(), my, mh, tx, ty, w, h); + paintFillLayers(paintInfo, style()->backgroundColor(), style()->backgroundLayers(), tx, ty, w, h); + paintBoxShadow(paintInfo.context, tx, ty, w, h, style(), Inset); if (!style()->hasBorder()) return; @@ -176,11 +173,7 @@ void RenderFieldset::paintMask(PaintInfo& paintInfo, int tx, int ty) h -= yOff; ty += yOff; - int my = max(ty, paintInfo.rect.y()); - int end = min(paintInfo.rect.bottom(), ty + h); - int mh = end - my; - - paintMaskImages(paintInfo, my, mh, tx, ty, w, h); + paintMaskImages(paintInfo, tx, ty, w, h); } void RenderFieldset::paintBorderMinusLegend(GraphicsContext* graphicsContext, int tx, int ty, int w, int h, diff --git a/WebCore/rendering/RenderFieldset.h b/WebCore/rendering/RenderFieldset.h index ed57d3a..df6a1da 100644 --- a/WebCore/rendering/RenderFieldset.h +++ b/WebCore/rendering/RenderFieldset.h @@ -1,10 +1,8 @@ /* - * This file is part of the DOM implementation for KDE. - * * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2000 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2004, 2006 Apple Computer, Inc. + * Copyright (C) 2004, 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 @@ -34,6 +32,9 @@ class RenderFieldset : public RenderBlock { public: RenderFieldset(Node*); + RenderBox* findLegend() const; + +private: virtual const char* renderName() const { return "RenderFieldSet"; } virtual bool isFieldset() const { return true; } @@ -43,17 +44,23 @@ public: virtual bool avoidsFloats() const { return true; } virtual bool stretchesToMinIntrinsicWidth() const { return true; } - RenderBox* findLegend() const; - -protected: virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); -private: virtual void paintBoxDecorations(PaintInfo&, int tx, int ty); - virtual void paintMask(PaintInfo& paintInfo, int tx, int ty); + virtual void paintMask(PaintInfo&, int tx, int ty); + void paintBorderMinusLegend(GraphicsContext*, int tx, int ty, int w, int h, const RenderStyle*, int lx, int lw, int lb); }; +inline RenderFieldset* toRenderFieldset(RenderObject* object) +{ + ASSERT(!object || object->isFieldset()); + return static_cast<RenderFieldset*>(object); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderFieldset(const RenderFieldset*); + } // namespace WebCore #endif // RenderFieldset_h diff --git a/WebCore/rendering/RenderFileUploadControl.h b/WebCore/rendering/RenderFileUploadControl.h index 85bc09f..bd7d62a 100644 --- a/WebCore/rendering/RenderFileUploadControl.h +++ b/WebCore/rendering/RenderFileUploadControl.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007 Apple Inc. + * Copyright (C) 2006, 2007, 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 @@ -35,13 +35,7 @@ class HTMLInputElement; class RenderFileUploadControl : public RenderBlock, private FileChooserClient { public: RenderFileUploadControl(HTMLInputElement*); - ~RenderFileUploadControl(); - - virtual const char* renderName() const { return "RenderFileUploadControl"; } - - virtual void updateFromElement(); - virtual void calcPrefWidths(); - virtual void paintObject(PaintInfo&, int tx, int ty); + virtual ~RenderFileUploadControl(); void click(); @@ -54,10 +48,15 @@ public: bool allowsMultipleFiles(); -protected: +private: + virtual const char* renderName() const { return "RenderFileUploadControl"; } + + virtual void updateFromElement(); + virtual void calcPrefWidths(); + virtual void paintObject(PaintInfo&, int tx, int ty); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); -private: int maxFilenameWidth() const; PassRefPtr<RenderStyle> createButtonStyle(const RenderStyle* parentStyle) const; @@ -65,6 +64,15 @@ private: RefPtr<FileChooser> m_fileChooser; }; +inline RenderFileUploadControl* toRenderFileUploadControl(RenderObject* object) +{ + ASSERT(!object || !strcmp(object->renderName(), "RenderFileUploadControl")); + return static_cast<RenderFileUploadControl*>(object); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderFileUploadControl(const RenderFileUploadControl*); + } // namespace WebCore #endif // RenderFileUploadControl_h diff --git a/WebCore/rendering/RenderFlexibleBox.cpp b/WebCore/rendering/RenderFlexibleBox.cpp index d4eaaf4..6bbcc43 100644 --- a/WebCore/rendering/RenderFlexibleBox.cpp +++ b/WebCore/rendering/RenderFlexibleBox.cpp @@ -41,7 +41,8 @@ namespace WebCore { class FlexBoxIterator { public: - FlexBoxIterator(RenderFlexibleBox* parent) { + FlexBoxIterator(RenderFlexibleBox* parent) + { box = parent; if (box->style()->boxOrient() == HORIZONTAL && box->style()->direction() == RTL) forward = box->style()->boxDirection() != BNORMAL; @@ -61,17 +62,20 @@ public: reset(); } - void reset() { + void reset() + { current = 0; currentOrdinal = forward ? 0 : lastOrdinal+1; } - RenderBox* first() { + RenderBox* first() + { reset(); return next(); } - RenderBox* next() { + RenderBox* next() + { do { if (!current) { if (forward) { @@ -192,6 +196,10 @@ void RenderFlexibleBox::calcPrefWidths() } int toAdd = borderLeft() + borderRight() + paddingLeft() + paddingRight(); + + if (hasOverflowClip() && style()->overflowY() == OSCROLL) + toAdd += verticalScrollbarWidth(); + m_minPrefWidth += toAdd; m_maxPrefWidth += toAdd; @@ -288,13 +296,17 @@ void RenderFlexibleBox::layoutBlock(bool relayoutChildren) 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, width() + boxShadow->x + boxShadow->blur); - m_overflowTop = min(m_overflowTop, boxShadow->y - boxShadow->blur); - m_overflowHeight = max(m_overflowHeight, height() + boxShadow->y + boxShadow->blur); - } - + int shadowLeft; + int shadowRight; + int shadowTop; + int shadowBottom; + style()->getBoxShadowExtent(shadowTop, shadowRight, shadowBottom, shadowLeft); + + m_overflowLeft = min(m_overflowLeft, shadowLeft); + m_overflowWidth = max(m_overflowWidth, width() + shadowRight); + m_overflowTop = min(m_overflowTop, shadowTop); + m_overflowHeight = max(m_overflowHeight, height() + shadowBottom); + if (hasReflection()) { IntRect reflection(reflectionBox()); m_overflowTop = min(m_overflowTop, reflection.y()); @@ -317,23 +329,10 @@ void RenderFlexibleBox::layoutBlock(bool relayoutChildren) setNeedsLayout(false); } -void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren) +// The first walk over our kids is to find out if we have any flexible children. +static void gatherFlexChildrenInfo(FlexBoxIterator& iterator, bool relayoutChildren, unsigned int& highestFlexGroup, unsigned int& lowestFlexGroup, bool& haveFlex) { - int toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight(); - int yPos = borderTop() + paddingTop(); - int xPos = borderLeft() + paddingLeft(); - bool heightSpecified = false; - int oldHeight = 0; - - unsigned int highestFlexGroup = 0; - unsigned int lowestFlexGroup = 0; - bool haveFlex = false; - int remainingSpace = 0; - m_overflowHeight = height(); - - // The first walk over our kids is to find out if we have any flexible children. - FlexBoxIterator iterator(this); - RenderBox* child = iterator.next(); + RenderBox* child = iterator.first(); while (child) { // Check to see if this child flexes. if (!child->isPositioned() && child->style()->boxFlex() > 0.0f) { @@ -353,7 +352,29 @@ void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren) } child = iterator.next(); } - +} + +void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren) +{ + int toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight(); + int yPos = borderTop() + paddingTop(); + int xPos = borderLeft() + paddingLeft(); + bool heightSpecified = false; + int oldHeight = 0; + + int remainingSpace = 0; + m_overflowHeight = height(); + + FlexBoxIterator iterator(this); + unsigned int highestFlexGroup = 0; + unsigned int lowestFlexGroup = 0; + bool haveFlex = false; + gatherFlexChildrenInfo(iterator, relayoutChildren, highestFlexGroup, lowestFlexGroup, haveFlex); + + RenderBox* child; + + RenderBlock::startDelayUpdateScrollInfo(); + // We do 2 passes. The first pass is simply to lay everyone out at // their preferred widths. The second pass handles flexing the children. do { @@ -578,7 +599,9 @@ void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren) } while (haveFlex); m_flexingChildren = false; - + + RenderBlock::finishDelayUpdateScrollInfo(); + if (remainingSpace > 0 && ((style()->direction() == LTR && style()->boxPack() != BSTART) || (style()->direction() == RTL && style()->boxPack() != BEND))) { // Children must be repositioned. @@ -665,39 +688,21 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren) { int xPos = borderLeft() + paddingLeft(); int yPos = borderTop() + paddingTop(); - if( style()->direction() == RTL ) + if (style()->direction() == RTL) xPos = width() - paddingRight() - borderRight(); int toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight(); bool heightSpecified = false; int oldHeight = 0; - + + int remainingSpace = 0; + + FlexBoxIterator iterator(this); unsigned int highestFlexGroup = 0; unsigned int lowestFlexGroup = 0; bool haveFlex = false; - int remainingSpace = 0; - - // The first walk over our kids is to find out if we have any flexible children. - FlexBoxIterator iterator(this); - RenderBox* child = iterator.next(); - while (child) { - // Check to see if this child flexes. - if (!child->isPositioned() && child->style()->boxFlex() > 0.0f) { - // We always have to lay out flexible objects again, since the flex distribution - // may have changed, and we need to reallocate space. - child->setOverrideSize(-1); - if (!relayoutChildren) - child->setChildNeedsLayout(true, false); - haveFlex = true; - unsigned int flexGroup = child->style()->boxFlexGroup(); - if (lowestFlexGroup == 0) - lowestFlexGroup = flexGroup; - if (flexGroup < lowestFlexGroup) - lowestFlexGroup = flexGroup; - if (flexGroup > highestFlexGroup) - highestFlexGroup = flexGroup; - } - child = iterator.next(); - } + gatherFlexChildrenInfo(iterator, relayoutChildren, highestFlexGroup, lowestFlexGroup, haveFlex); + + RenderBox* child; // We confine the line clamp ugliness to vertical flexible boxes (thus keeping it out of // mainstream block layout); this is not really part of the XUL box model. @@ -806,6 +811,8 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren) } } + RenderBlock::startDelayUpdateScrollInfo(); + // We do 2 passes. The first pass is simply to lay everyone out at // their preferred widths. The second pass handles flexing the children. // Our first pass is done without flexing. We simply lay the children @@ -994,6 +1001,8 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren) } } while (haveFlex); + RenderBlock::finishDelayUpdateScrollInfo(); + if (style()->boxPack() != BSTART && remainingSpace > 0) { // Children must be repositioned. int offset = 0; diff --git a/WebCore/rendering/RenderFrame.h b/WebCore/rendering/RenderFrame.h index 47dad32..5b3b533 100644 --- a/WebCore/rendering/RenderFrame.h +++ b/WebCore/rendering/RenderFrame.h @@ -46,6 +46,15 @@ private: virtual void viewCleared(); }; +inline RenderFrame* toRenderFrame(RenderObject* object) +{ + ASSERT(!object || object->isFrame()); + return static_cast<RenderFrame*>(object); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderFrame(const RenderFrame*); + } // namespace WebCore #endif // RenderFrame_h diff --git a/WebCore/rendering/RenderFrameSet.cpp b/WebCore/rendering/RenderFrameSet.cpp index 0353bb1..0838798 100644 --- a/WebCore/rendering/RenderFrameSet.cpp +++ b/WebCore/rendering/RenderFrameSet.cpp @@ -68,7 +68,7 @@ inline HTMLFrameSetElement* RenderFrameSet::frameSet() const static Color borderStartEdgeColor() { - return Color(170,170,170); + return Color(170, 170, 170); } static Color borderEndEdgeColor() @@ -419,9 +419,9 @@ void RenderFrameSet::computeEdgeInfo() for (int c = 0; c < cols; ++c) { FrameEdgeInfo edgeInfo; if (child->isFrameSet()) - edgeInfo = static_cast<RenderFrameSet*>(child)->edgeInfo(); + edgeInfo = toRenderFrameSet(child)->edgeInfo(); else - edgeInfo = static_cast<RenderFrame*>(child)->edgeInfo(); + edgeInfo = toRenderFrame(child)->edgeInfo(); fillFromEdgeInfo(edgeInfo, r, c); child = child->nextSibling(); if (!child) @@ -693,9 +693,10 @@ bool RenderFrameSet::userResize(MouseEvent* evt) void RenderFrameSet::setIsResizing(bool isResizing) { m_isResizing = isResizing; - for (RenderObject* p = parent(); p; p = p->parent()) - if (p->isFrameSet()) - static_cast<RenderFrameSet*>(p)->m_isChildResizing = isResizing; + for (RenderObject* ancestor = parent(); ancestor; ancestor = ancestor->parent()) { + if (ancestor->isFrameSet()) + toRenderFrameSet(ancestor)->m_isChildResizing = isResizing; + } if (Frame* frame = document()->frame()) frame->eventHandler()->setResizingFrameSet(isResizing ? frameSet() : 0); } diff --git a/WebCore/rendering/RenderFrameSet.h b/WebCore/rendering/RenderFrameSet.h index 0c80ad9..aa3ac64 100644 --- a/WebCore/rendering/RenderFrameSet.h +++ b/WebCore/rendering/RenderFrameSet.h @@ -32,8 +32,7 @@ class MouseEvent; enum FrameEdge { LeftFrameEdge, RightFrameEdge, TopFrameEdge, BottomFrameEdge }; -struct FrameEdgeInfo -{ +struct FrameEdgeInfo { FrameEdgeInfo(bool preventResize = false, bool allowBorder = true) : m_preventResize(4) , m_allowBorder(4) @@ -58,19 +57,9 @@ public: RenderFrameSet(HTMLFrameSetElement*); virtual ~RenderFrameSet(); - virtual RenderObjectChildList* virtualChildren() { return children(); } - virtual const RenderObjectChildList* virtualChildren() const { return children(); } const RenderObjectChildList* children() const { return &m_children; } RenderObjectChildList* children() { return &m_children; } - virtual const char* renderName() const { return "RenderFrameSet"; } - virtual bool isFrameSet() const { return true; } - - virtual void layout(); - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); - virtual void paint(PaintInfo& paintInfo, int tx, int ty); - virtual bool isChildAllowed(RenderObject*, RenderStyle*) const; - FrameEdgeInfo edgeInfo() const; bool userResize(MouseEvent*); @@ -88,7 +77,7 @@ public: private: static const int noSplit = -1; - class GridAxis : Noncopyable { + class GridAxis : public Noncopyable { public: GridAxis(); void resize(int); @@ -100,6 +89,17 @@ private: int m_splitResizeOffset; }; + virtual RenderObjectChildList* virtualChildren() { return children(); } + virtual const RenderObjectChildList* virtualChildren() const { return children(); } + + virtual const char* renderName() const { return "RenderFrameSet"; } + virtual bool isFrameSet() const { return true; } + + virtual void layout(); + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); + virtual void paint(PaintInfo&, int tx, int ty); + virtual bool isChildAllowed(RenderObject*, RenderStyle*) const; + inline HTMLFrameSetElement* frameSet() const; void setIsResizing(bool); @@ -115,8 +115,8 @@ private: void startResizing(GridAxis&, int position); void continueResizing(GridAxis&, int position); - void paintRowBorder(const PaintInfo& paintInfo, const IntRect& rect); - void paintColumnBorder(const PaintInfo& paintInfo, const IntRect& rect); + void paintRowBorder(const PaintInfo&, const IntRect&); + void paintColumnBorder(const PaintInfo&, const IntRect&); RenderObjectChildList m_children; @@ -130,6 +130,16 @@ private: #endif }; + +inline RenderFrameSet* toRenderFrameSet(RenderObject* object) +{ + ASSERT(!object || object->isFrameSet()); + return static_cast<RenderFrameSet*>(object); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderFrameSet(const RenderFrameSet*); + } // namespace WebCore #endif // RenderFrameSet_h diff --git a/WebCore/rendering/RenderHTMLCanvas.h b/WebCore/rendering/RenderHTMLCanvas.h index ad6c505..e82cf9a 100644 --- a/WebCore/rendering/RenderHTMLCanvas.h +++ b/WebCore/rendering/RenderHTMLCanvas.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2004, 2006, 2007, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -36,17 +36,23 @@ class RenderHTMLCanvas : public RenderReplaced { public: RenderHTMLCanvas(HTMLCanvasElement*); - virtual const char* renderName() const { return "RenderHTMLCanvas"; } - - virtual void paintReplaced(PaintInfo& paintInfo, int tx, int ty); - void canvasSizeChanged(); -protected: +private: + virtual const char* renderName() const { return "RenderHTMLCanvas"; } + virtual void paintReplaced(PaintInfo&, int tx, int ty); virtual void intrinsicSizeChanged() { canvasSizeChanged(); } - }; +inline RenderHTMLCanvas* toRenderHTMLCanvas(RenderObject* object) +{ + ASSERT(!object || !strcmp(object->renderName(), "RenderHTMLCanvas")); + return static_cast<RenderHTMLCanvas*>(object); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderHTMLCanvas(const RenderHTMLCanvas*); + } // namespace WebCore #endif // RenderHTMLCanvas_h diff --git a/WebCore/rendering/RenderImage.cpp b/WebCore/rendering/RenderImage.cpp index f48a219..5c11e41 100644 --- a/WebCore/rendering/RenderImage.cpp +++ b/WebCore/rendering/RenderImage.cpp @@ -26,9 +26,6 @@ #include "config.h" #include "RenderImage.h" -#include "BitmapImage.h" -#include "Document.h" -#include "FrameView.h" #include "GraphicsContext.h" #include "HTMLImageElement.h" #include "HTMLInputElement.h" @@ -93,8 +90,7 @@ private: Timer<RenderImage> m_highQualityRepaintTimer; }; -class RenderImageScaleObserver -{ +class RenderImageScaleObserver { public: static bool shouldImagePaintAtLowQuality(RenderImage*, const IntSize&); @@ -447,20 +443,19 @@ HTMLMapElement* RenderImage::imageMap() return i ? i->document()->getImageMap(i->useMap()) : 0; } -bool RenderImage::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction) +bool RenderImage::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction) { HitTestResult tempResult(result.point()); - bool inside = RenderReplaced::nodeAtPoint(request, tempResult, _x, _y, _tx, _ty, hitTestAction); + bool inside = RenderReplaced::nodeAtPoint(request, tempResult, x, y, tx, ty, hitTestAction); if (inside && node()) { - int tx = _tx + x(); - int ty = _ty + y(); - - HTMLMapElement* map = imageMap(); - if (map) { - // we're a client side image map - inside = map->mapMouseEvent(_x - tx, _y - ty, IntSize(contentWidth(), contentHeight()), tempResult); - tempResult.setInnerNonSharedNode(node()); + if (HTMLMapElement* map = imageMap()) { + IntRect contentBox = contentBoxRect(); + float zoom = style()->effectiveZoom(); + int mapX = lroundf((x - tx - this->x() - contentBox.x()) / zoom); + int mapY = lroundf((y - ty - this->y() - contentBox.y()) / zoom); + if (map->mapMouseEvent(mapX, mapY, contentBox.size(), tempResult)) + tempResult.setInnerNonSharedNode(node()); } } diff --git a/WebCore/rendering/RenderImage.h b/WebCore/rendering/RenderImage.h index 042452f..2224412 100644 --- a/WebCore/rendering/RenderImage.h +++ b/WebCore/rendering/RenderImage.h @@ -3,7 +3,7 @@ * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2006 Allan Sandfeld Jensen (kde@carewolf.com) * (C) 2006 Samuel Weinig (sam.weinig@gmail.com) - * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2004, 2005, 2006, 2007, 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,8 +25,6 @@ #ifndef RenderImage_h #define RenderImage_h -#include "CachedImage.h" -#include "CachedResourceHandle.h" #include "RenderReplaced.h" namespace WebCore { @@ -38,18 +36,6 @@ public: RenderImage(Node*); virtual ~RenderImage(); - virtual const char* renderName() const { return "RenderImage"; } - - virtual bool isImage() const { return true; } - virtual bool isRenderImage() const { return true; } - - virtual void paintReplaced(PaintInfo& paintInfo, int tx, int ty); - - virtual int minimumReplacedHeight() const; - - virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); - virtual void notifyFinished(CachedResource*); - bool setImageSizeForAltText(CachedImage* newImage = 0); void updateAltText(); @@ -57,13 +43,6 @@ public: void setCachedImage(CachedImage*); CachedImage* cachedImage() const { return m_cachedImage.get(); } - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); - - virtual int calcReplacedWidth(bool includeMaxWidth = true) const; - virtual int calcReplacedHeight() const; - - virtual void calcPrefWidths(); - HTMLMapElement* imageMap(); void resetAnimation(); @@ -73,8 +52,29 @@ 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 /* width */ = 0, int /* height */ = 0) { return m_cachedImage ? m_cachedImage->image() : nullImage(); } virtual bool errorOccurred() const { return m_cachedImage && m_cachedImage->errorOccurred(); } + + virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); + +private: + virtual const char* renderName() const { return "RenderImage"; } + + virtual bool isImage() const { return true; } + virtual bool isRenderImage() const { return true; } + + virtual void paintReplaced(PaintInfo&, int tx, int ty); + + virtual int minimumReplacedHeight() const; + + virtual void notifyFinished(CachedResource*); + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); + + virtual int calcReplacedWidth(bool includeMaxWidth = true) const; + virtual int calcReplacedHeight() const; + + virtual void calcPrefWidths(); + 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); } virtual bool imageHasRelativeWidth() const { return m_cachedImage ? m_cachedImage->imageHasRelativeWidth() : false; } @@ -84,7 +84,6 @@ protected: virtual void intrinsicSizeChanged() { imageChanged(imagePtr()); } -private: int calcAspectRatioWidth() const; int calcAspectRatioHeight() const; @@ -95,6 +94,7 @@ protected: // The image we are rendering. CachedResourceHandle<CachedImage> m_cachedImage; +private: // Text to display as long as the image isn't available. String m_altText; @@ -103,16 +103,16 @@ protected: friend class RenderImageScaleObserver; }; -inline RenderImage* toRenderImage(RenderObject* o) +inline RenderImage* toRenderImage(RenderObject* object) { - ASSERT(!o || o->isRenderImage()); - return static_cast<RenderImage*>(o); + ASSERT(!object || object->isRenderImage()); + return static_cast<RenderImage*>(object); } -inline const RenderImage* toRenderImage(const RenderObject* o) +inline const RenderImage* toRenderImage(const RenderObject* object) { - ASSERT(!o || o->isRenderImage()); - return static_cast<const RenderImage*>(o); + ASSERT(!object || object->isRenderImage()); + return static_cast<const RenderImage*>(object); } // This will catch anyone doing an unnecessary cast. diff --git a/WebCore/rendering/RenderInline.cpp b/WebCore/rendering/RenderInline.cpp index 3965d94..53962d2 100644 --- a/WebCore/rendering/RenderInline.cpp +++ b/WebCore/rendering/RenderInline.cpp @@ -1,9 +1,7 @@ /* - * This file is part of the render object implementation for KHTML. - * * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) - * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc. + * 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 @@ -51,10 +49,6 @@ RenderInline::RenderInline(Node* node) setChildrenInline(true); } -RenderInline::~RenderInline() -{ -} - void RenderInline::destroy() { // Detach our continuation first. @@ -258,7 +252,7 @@ void RenderInline::splitInlines(RenderBlock* fromBlock, RenderBlock* toBlock, // We have been reparented and are now under the fromBlock. We need // to walk up our inline parent chain until we hit the containing block. // Once we hit the containing block we're done. - RenderBoxModelObject* curr = static_cast<RenderBoxModelObject*>(parent()); + RenderBoxModelObject* curr = toRenderBoxModelObject(parent()); RenderBoxModelObject* currChild = this; // FIXME: Because splitting is O(n^2) as tags nest pathologically, we cap the depth at which we're willing to clone. @@ -302,7 +296,7 @@ void RenderInline::splitInlines(RenderBlock* fromBlock, RenderBlock* toBlock, // Keep walking up the chain. currChild = curr; - curr = static_cast<RenderBoxModelObject*>(curr->parent()); + curr = toRenderBoxModelObject(curr->parent()); splitDepth++; } @@ -384,7 +378,7 @@ void RenderInline::addChildToContinuation(RenderObject* newChild, RenderObject* ASSERT(!beforeChild || beforeChild->parent()->isRenderBlock() || beforeChild->parent()->isRenderInline()); RenderBoxModelObject* beforeChildParent = 0; if (beforeChild) - beforeChildParent = static_cast<RenderBoxModelObject*>(beforeChild->parent()); + beforeChildParent = toRenderBoxModelObject(beforeChild->parent()); else { RenderBoxModelObject* cont = nextContinuation(flow); if (cont) @@ -749,14 +743,14 @@ void RenderInline::dirtyLineBoxes(bool fullLayout) m_lineBoxes.dirtyLineBoxes(); } -InlineFlowBox* RenderInline::createFlowBox() +InlineFlowBox* RenderInline::createInlineFlowBox() { return new (renderArena()) InlineFlowBox(this); } -InlineFlowBox* RenderInline::createInlineFlowBox() +InlineFlowBox* RenderInline::createAndAppendInlineFlowBox() { - InlineFlowBox* flowBox = createFlowBox(); + InlineFlowBox* flowBox = createInlineFlowBox(); m_lineBoxes.appendLineBox(flowBox); return flowBox; } diff --git a/WebCore/rendering/RenderInline.h b/WebCore/rendering/RenderInline.h index cf6b84b..14d76ca 100644 --- a/WebCore/rendering/RenderInline.h +++ b/WebCore/rendering/RenderInline.h @@ -1,9 +1,7 @@ /* - * This file is part of the render object implementation for KHTML. - * * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) - * Copyright (C) 2003 Apple Computer, Inc. + * 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 @@ -35,20 +33,51 @@ class Position; class RenderInline : public RenderBoxModelObject { public: RenderInline(Node*); - virtual ~RenderInline(); + virtual void destroy(); + + virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0); + + virtual int marginLeft() const; + virtual int marginRight() const; + + virtual void absoluteRects(Vector<IntRect>&, int tx, int ty); + virtual void absoluteQuads(Vector<FloatQuad>&); + + IntRect linesBoundingBox() const; + + InlineFlowBox* createAndAppendInlineFlowBox(); + + void dirtyLineBoxes(bool fullLayout); + + RenderLineBoxList* lineBoxes() { return &m_lineBoxes; } + const RenderLineBoxList* lineBoxes() const { return &m_lineBoxes; } + + InlineFlowBox* firstLineBox() const { return m_lineBoxes.firstLineBox(); } + InlineFlowBox* lastLineBox() const { return m_lineBoxes.lastLineBox(); } + + RenderBoxModelObject* continuation() const { return m_continuation; } + + virtual void updateDragState(bool dragOn); + + IntSize relativePositionedInlineOffset(const RenderBox* child) const; + + virtual void addFocusRingRects(GraphicsContext*, int tx, int ty); + void paintOutline(GraphicsContext*, int tx, int ty); + + int verticalPositionFromCache(bool firstLine) const; + void invalidateVerticalPosition() { m_verticalPosition = PositionUndefined; } + +private: virtual RenderObjectChildList* virtualChildren() { return children(); } virtual const RenderObjectChildList* virtualChildren() const { return children(); } const RenderObjectChildList* children() const { return &m_children; } RenderObjectChildList* children() { return &m_children; } - virtual void destroy(); - virtual const char* renderName() const; virtual bool isRenderInline() const { return true; } - virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0); void addChildToContinuation(RenderObject* newChild, RenderObject* beforeChild); virtual void addChildIgnoringContinuation(RenderObject* newChild, RenderObject* beforeChild = 0); @@ -73,94 +102,64 @@ public: // Just ignore top/bottom margins on RenderInlines. virtual int marginTop() const { return 0; } virtual int marginBottom() const { return 0; } - virtual int marginLeft() const; - virtual int marginRight() const; - - virtual void absoluteRects(Vector<IntRect>&, int tx, int ty); - virtual void absoluteQuads(Vector<FloatQuad>&); - virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer); virtual IntRect rectWithOutlineForRepaint(RenderBoxModelObject* repaintContainer, int outlineWidth); virtual void computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& rect, bool fixed); virtual VisiblePosition positionForPoint(const IntPoint&); - IntRect linesBoundingBox() const; - virtual IntRect borderBoundingBox() const { IntRect boundingBox = linesBoundingBox(); return IntRect(0, 0, boundingBox.width(), boundingBox.height()); } - InlineFlowBox* createInlineFlowBox(); - void dirtyLineBoxes(bool fullLayout); - virtual void dirtyLinesFromChangedChild(RenderObject* child) { m_lineBoxes.dirtyLinesFromChangedChild(this, child); } - - RenderLineBoxList* lineBoxes() { return &m_lineBoxes; } - const RenderLineBoxList* lineBoxes() const { return &m_lineBoxes; } + virtual InlineFlowBox* createInlineFlowBox(); // Subclassed by SVG and Ruby - InlineFlowBox* firstLineBox() const { return m_lineBoxes.firstLineBox(); } - InlineFlowBox* lastLineBox() const { return m_lineBoxes.lastLineBox(); } + virtual void dirtyLinesFromChangedChild(RenderObject* child) { m_lineBoxes.dirtyLinesFromChangedChild(this, child); } virtual int lineHeight(bool firstLine, bool isRootLineBox = false) const; - RenderBoxModelObject* continuation() const { return m_continuation; } RenderInline* inlineContinuation() const; void setContinuation(RenderBoxModelObject* c) { m_continuation = c; } - virtual void updateDragState(bool dragOn); - virtual void childBecameNonInline(RenderObject* child); virtual void updateHitTestResult(HitTestResult&, const IntPoint&); - IntSize relativePositionedInlineOffset(const RenderBox* child) const; - - virtual void addFocusRingRects(GraphicsContext*, int tx, int ty); - void paintOutline(GraphicsContext*, int tx, int ty); - virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); - int verticalPositionFromCache(bool firstLine) const; - void invalidateVerticalPosition() { m_verticalPosition = PositionUndefined; } - #if ENABLE(DASHBOARD_SUPPORT) virtual void addDashboardRegions(Vector<DashboardRegionValue>&); #endif -protected: virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); virtual void updateBoxModelInfoFromStyle(); - virtual InlineFlowBox* createFlowBox(); // Subclassed by SVG static RenderInline* cloneInline(RenderInline* src); -private: void paintOutlineForLine(GraphicsContext*, int tx, int ty, const IntRect& prevLine, const IntRect& thisLine, const IntRect& nextLine); RenderBoxModelObject* continuationBefore(RenderObject* beforeChild); -protected: RenderObjectChildList m_children; RenderLineBoxList m_lineBoxes; // All of the line boxes created for this inline flow. For example, <i>Hello<br>world.</i> will have two <i> line boxes. -private: RenderBoxModelObject* m_continuation; // Can be either a block or an inline. <b><i><p>Hello</p></i></b>. In this example the <i> will have a block as its continuation but the // <b> will just have an inline as its continuation. mutable int m_lineHeight; mutable int m_verticalPosition; }; -inline RenderInline* toRenderInline(RenderObject* o) +inline RenderInline* toRenderInline(RenderObject* object) { - ASSERT(!o || o->isRenderInline()); - return static_cast<RenderInline*>(o); + ASSERT(!object || object->isRenderInline()); + return static_cast<RenderInline*>(object); } -inline const RenderInline* toRenderInline(const RenderObject* o) +inline const RenderInline* toRenderInline(const RenderObject* object) { - ASSERT(!o || o->isRenderInline()); - return static_cast<const RenderInline*>(o); + ASSERT(!object || object->isRenderInline()); + return static_cast<const RenderInline*>(object); } // This will catch anyone doing an unnecessary cast. diff --git a/WebCore/rendering/RenderLayer.cpp b/WebCore/rendering/RenderLayer.cpp index 80c7155..ab78f40 100644 --- a/WebCore/rendering/RenderLayer.cpp +++ b/WebCore/rendering/RenderLayer.cpp @@ -167,7 +167,7 @@ RenderLayer::RenderLayer(RenderBoxModelObject* renderer) , m_has3DTransformedDescendant(false) #if USE(ACCELERATED_COMPOSITING) , m_hasCompositingDescendant(false) - , m_mustOverlayCompositedLayers(false) + , m_mustOverlapCompositedLayers(false) #endif , m_marquee(0) , m_staticX(0) @@ -229,11 +229,24 @@ RenderLayerCompositor* RenderLayer::compositor() const void RenderLayer::rendererContentChanged() { + // This can get called when video becomes accelerated, so the layers may change. + if (compositor()->updateLayerCompositingState(this)) + compositor()->setCompositingLayersNeedRebuild(); + if (m_backing) m_backing->rendererContentChanged(); } #endif // USE(ACCELERATED_COMPOSITING) +bool RenderLayer::hasAcceleratedCompositing() const +{ +#if USE(ACCELERATED_COMPOSITING) + return compositor()->hasAcceleratedCompositing(); +#else + return false; +#endif +} + void RenderLayer::setStaticY(int staticY) { if (m_staticY == staticY) @@ -242,17 +255,17 @@ void RenderLayer::setStaticY(int staticY) renderer()->setChildNeedsLayout(true, false); } -void RenderLayer::updateLayerPositions(bool doFullRepaint, bool checkForRepaint) +void RenderLayer::updateLayerPositions(UpdateLayerPositionsFlags flags) { - if (doFullRepaint) { + if (flags & DoFullRepaint) { renderer()->repaint(); #if USE(ACCELERATED_COMPOSITING) - checkForRepaint = false; + flags &= ~CheckForRepaint; // We need the full repaint to propagate to child layers if we are hardware compositing. if (!compositor()->inCompositingMode()) - doFullRepaint = false; + flags &= ~DoFullRepaint; #else - checkForRepaint = doFullRepaint = false; + flags &= ~(CheckForRepaint | DoFullRepaint); #endif } @@ -279,7 +292,7 @@ void RenderLayer::updateLayerPositions(bool doFullRepaint, bool checkForRepaint) RenderBoxModelObject* repaintContainer = renderer()->containerForRepaint(); IntRect newRect = renderer()->clippedOverflowRectForRepaint(repaintContainer); IntRect newOutlineBox = renderer()->outlineBoundsForRepaint(repaintContainer); - if (checkForRepaint) { + if (flags & CheckForRepaint) { if (view && !view->printing()) { if (m_needsFullRepaint) { renderer()->repaintUsingContainer(repaintContainer, m_repaintRect); @@ -303,14 +316,11 @@ void RenderLayer::updateLayerPositions(bool doFullRepaint, bool checkForRepaint) m_reflection->layout(); for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) - child->updateLayerPositions(doFullRepaint, checkForRepaint); + child->updateLayerPositions(flags); #if USE(ACCELERATED_COMPOSITING) - if (!parent()) - compositor()->updateRootLayerPosition(); - - if (isComposited()) - backing()->updateAfterLayout(); + if ((flags & UpdateCompositingLayers) && isComposited()) + backing()->updateAfterLayout(RenderLayerBacking::CompositingChildren); #endif // With all our children positioned, now update our marquee if we need to. @@ -318,6 +328,13 @@ void RenderLayer::updateLayerPositions(bool doFullRepaint, bool checkForRepaint) m_marquee->updateMarqueePosition(); } +void RenderLayer::computeRepaintRects() +{ + RenderBoxModelObject* repaintContainer = renderer()->containerForRepaint(); + m_repaintRect = renderer()->clippedOverflowRectForRepaint(repaintContainer); + m_outlineBox = renderer()->outlineBoundsForRepaint(repaintContainer); +} + void RenderLayer::updateTransform() { // hasTransform() on the renderer is also true when there is transform-style: preserve-3d or perspective set, @@ -338,7 +355,7 @@ void RenderLayer::updateTransform() ASSERT(box); m_transform->makeIdentity(); box->style()->applyTransform(*m_transform, box->borderBoxRect().size(), RenderStyle::IncludeTransformOrigin); - makeMatrixRenderable(*m_transform); + makeMatrixRenderable(*m_transform, hasAcceleratedCompositing()); } if (had3DTransform != has3DTransform()) @@ -355,7 +372,7 @@ TransformationMatrix RenderLayer::currentTransform() const TransformationMatrix currTransform; RefPtr<RenderStyle> style = renderer()->animation()->getAnimatedStyleForRenderer(renderer()); style->applyTransform(currTransform, renderBox()->borderBoxRect().size(), RenderStyle::IncludeTransformOrigin); - makeMatrixRenderable(currTransform); + makeMatrixRenderable(currTransform, hasAcceleratedCompositing()); return currTransform; } #endif @@ -443,7 +460,7 @@ void RenderLayer::updateVisibilityStatus() else { do { r = r->parent(); - if (r==renderer()) + if (r == renderer()) r = 0; } while (r && !r->nextSibling()); if (r) @@ -948,7 +965,6 @@ void RenderLayer::panScrollFromPoint(const IntPoint& sourcePoint) const int shortDistanceLimit = 100; // We delimit a 200 pixels long square enclosing the original point const int speedReducer = 2; // Within this square we divide the scrolling speed by 2 - const int iconRadius = 10; Frame* frame = renderer()->document()->frame(); if (!frame) return; @@ -965,9 +981,9 @@ void RenderLayer::panScrollFromPoint(const IntPoint& sourcePoint) int xDelta = currentMousePosition.x() - sourcePoint.x(); int yDelta = currentMousePosition.y() - sourcePoint.y(); - if (abs(xDelta) < iconRadius) // at the center we let the space for the icon + if (abs(xDelta) < ScrollView::noPanScrollRadius) // at the center we let the space for the icon xDelta = 0; - if (abs(yDelta) < iconRadius) + if (abs(yDelta) < ScrollView::noPanScrollRadius) yDelta = 0; // Let's attenuate the speed for the short distances @@ -1048,13 +1064,16 @@ void RenderLayer::scrollToOffset(int x, int y, bool updateScrollbars, bool repai m_scrollX = newScrollX; m_scrollY = y; - // Update the positions of our child layers. + // Update the positions of our child layers. Don't have updateLayerPositions() update + // compositing layers, because we need to do a deep update from the compositing ancestor. for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) - child->updateLayerPositions(false, false); + child->updateLayerPositions(0); #if USE(ACCELERATED_COMPOSITING) - if (isComposited()) - m_backing->updateGraphicsLayerGeometry(); + if (compositor()->inCompositingMode()) { + if (RenderLayer* compositingAncestor = ancestorCompositingLayer()) + compositingAncestor->backing()->updateAfterLayout(RenderLayerBacking::AllDescendants); + } #endif RenderView* view = renderer()->view(); @@ -1300,7 +1319,7 @@ void RenderLayer::resize(const PlatformMouseEvent& evt, const IntSize& oldOffset ExceptionCode ec; - if (difference.width()) { + if (resize != RESIZE_VERTICAL && difference.width()) { if (element->isFormControlElement()) { // Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>). style->setProperty(CSSPropertyMarginLeft, String::number(renderer->marginLeft() / zoomFactor) + "px", false, ec); @@ -1312,7 +1331,7 @@ void RenderLayer::resize(const PlatformMouseEvent& evt, const IntSize& oldOffset style->setProperty(CSSPropertyWidth, String::number(baseWidth + difference.width()) + "px", false, ec); } - if (difference.height()) { + if (resize != RESIZE_HORIZONTAL && difference.height()) { if (element->isFormControlElement()) { // Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>). style->setProperty(CSSPropertyMarginTop, String::number(renderer->marginTop() / zoomFactor) + "px", false, ec); @@ -1412,6 +1431,66 @@ bool RenderLayer::scrollbarCornerPresent() const return !scrollCornerRect(this, renderBox()->borderBoxRect()).isEmpty(); } +IntRect RenderLayer::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntRect& scrollbarRect) const +{ + RenderView* view = renderer()->view(); + if (!view) + return scrollbarRect; + + IntRect rect = scrollbarRect; + rect.move(scrollbarOffset(scrollbar)); + + return view->frameView()->convertFromRenderer(renderer(), rect); +} + +IntRect RenderLayer::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntRect& parentRect) const +{ + RenderView* view = renderer()->view(); + if (!view) + return parentRect; + + IntRect rect = view->frameView()->convertToRenderer(renderer(), parentRect); + rect.move(-scrollbarOffset(scrollbar)); + return rect; +} + +IntPoint RenderLayer::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntPoint& scrollbarPoint) const +{ + RenderView* view = renderer()->view(); + if (!view) + return scrollbarPoint; + + IntPoint point = scrollbarPoint; + point.move(scrollbarOffset(scrollbar)); + return view->frameView()->convertFromRenderer(renderer(), point); +} + +IntPoint RenderLayer::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const +{ + RenderView* view = renderer()->view(); + if (!view) + return parentPoint; + + IntPoint point = view->frameView()->convertToRenderer(renderer(), parentPoint); + + point.move(-scrollbarOffset(scrollbar)); + return point; +} + +IntSize RenderLayer::scrollbarOffset(const Scrollbar* scrollbar) const +{ + RenderBox* box = renderBox(); + + if (scrollbar == m_vBar.get()) + return IntSize(box->width() - box->borderRight() - scrollbar->width(), box->borderTop()); + + if (scrollbar == m_hBar.get()) + return IntSize(box->borderLeft(), box->height() - box->borderBottom() - scrollbar->height()); + + ASSERT_NOT_REACHED(); + return IntSize(); +} + void RenderLayer::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect) { IntRect scrollRect = rect; @@ -1823,34 +1902,29 @@ bool RenderLayer::isPointInResizeControl(const IntPoint& absolutePoint) const return resizerCornerRect(this, localBounds).contains(localPoint); } -bool RenderLayer::hitTestOverflowControls(HitTestResult& result) +bool RenderLayer::hitTestOverflowControls(HitTestResult& result, const IntPoint& localPoint) { if (!m_hBar && !m_vBar && (!renderer()->hasOverflowClip() || renderer()->style()->resize() == RESIZE_NONE)) return false; RenderBox* box = renderBox(); ASSERT(box); - - int x = 0; - int y = 0; - convertToLayerCoords(root(), x, y); - IntRect absBounds(x, y, box->width(), box->height()); IntRect resizeControlRect; if (renderer()->style()->resize() != RESIZE_NONE) { - resizeControlRect = resizerCornerRect(this, absBounds); - if (resizeControlRect.contains(result.point())) + resizeControlRect = resizerCornerRect(this, box->borderBoxRect()); + if (resizeControlRect.contains(localPoint)) return true; } int resizeControlSize = max(resizeControlRect.height(), 0); if (m_vBar) { - IntRect vBarRect(absBounds.right() - box->borderRight() - m_vBar->width(), - absBounds.y() + box->borderTop(), + IntRect vBarRect(box->width() - box->borderRight() - m_vBar->width(), + box->borderTop(), m_vBar->width(), - absBounds.height() - (box->borderTop() + box->borderBottom()) - (m_hBar ? m_hBar->height() : resizeControlSize)); - if (vBarRect.contains(result.point())) { + box->height() - (box->borderTop() + box->borderBottom()) - (m_hBar ? m_hBar->height() : resizeControlSize)); + if (vBarRect.contains(localPoint)) { result.setScrollbar(m_vBar.get()); return true; } @@ -1858,11 +1932,11 @@ bool RenderLayer::hitTestOverflowControls(HitTestResult& result) resizeControlSize = max(resizeControlRect.width(), 0); if (m_hBar) { - IntRect hBarRect(absBounds.x() + box->borderLeft(), - absBounds.bottom() - box->borderBottom() - m_hBar->height(), - absBounds.width() - (box->borderLeft() + box->borderRight()) - (m_vBar ? m_vBar->width() : resizeControlSize), + IntRect hBarRect(box->borderLeft(), + box->height() - box->borderBottom() - m_hBar->height(), + box->width() - (box->borderLeft() + box->borderRight()) - (m_vBar ? m_vBar->width() : resizeControlSize), m_hBar->height()); - if (hBarRect.contains(result.point())) { + if (hBarRect.contains(localPoint)) { result.setScrollbar(m_hBar.get()); return true; } @@ -1894,7 +1968,7 @@ bool RenderLayer::scroll(ScrollDirection direction, ScrollGranularity granularit void RenderLayer::paint(GraphicsContext* p, const IntRect& damageRect, PaintRestriction paintRestriction, RenderObject *paintingRoot) { RenderObject::OverlapTestRequestMap overlapTestRequests; - paintLayer(this, p, damageRect, false, paintRestriction, paintingRoot, &overlapTestRequests); + paintLayer(this, p, damageRect, paintRestriction, paintingRoot, &overlapTestRequests); RenderObject::OverlapTestRequestMap::iterator end = overlapTestRequests.end(); for (RenderObject::OverlapTestRequestMap::iterator it = overlapTestRequests.begin(); it != end; ++it) it->first->setOverlapTestResult(false); @@ -1930,15 +2004,29 @@ static void performOverlapTests(RenderObject::OverlapTestRequestMap& overlapTest overlapTestRequests.remove(overlappedRequestClients[i]); } +#if USE(ACCELERATED_COMPOSITING) +static bool shouldDoSoftwarePaint(const RenderLayer* layer, bool paintingReflection) +{ + return paintingReflection && !layer->has3DTransform(); +} +#endif + void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p, - const IntRect& paintDirtyRect, bool haveTransparency, PaintRestriction paintRestriction, + const IntRect& paintDirtyRect, PaintRestriction paintRestriction, RenderObject* paintingRoot, RenderObject::OverlapTestRequestMap* overlapTestRequests, - bool appliedTransform, bool temporaryClipRects) + PaintLayerFlags paintFlags) { #if USE(ACCELERATED_COMPOSITING) - // Composited RenderLayers are painted via the backing's paintIntoLayer(). - if (isComposited() && !backing()->paintingGoesToWindow()) - return; + if (isComposited()) { + // The updatingControlTints() painting pass goes through compositing layers, + // but we need to ensure that we don't cache clip rects computed with the wrong root in this case. + if (p->updatingControlTints()) + paintFlags |= PaintLayerTemporaryClipRects; + else if (!backing()->paintingGoesToWindow() && !shouldDoSoftwarePaint(this, paintFlags & PaintLayerPaintingReflection)) { + // If this RenderLayer should paint into its backing, that will be done via RenderLayerBacking::paintIntoLayer(). + return; + } + } #endif // Avoid painting layers when stylesheets haven't loaded. This eliminates FOUC. @@ -1952,24 +2040,24 @@ void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p, return; if (paintsWithTransparency()) - haveTransparency = true; + paintFlags |= PaintLayerHaveTransparency; // Apply a transform if we have one. A reflection is considered to be a transform, since it is a flip and a translate. - if (paintsWithTransform() && !appliedTransform) { + if (paintsWithTransform() && !(paintFlags & PaintLayerAppliedTransform)) { // If the transform can't be inverted, then don't paint anything. if (!m_transform->isInvertible()) return; // If we have a transparency layer enclosing us and we are the root of a transform, then we need to establish the transparency // layer from the parent now. - if (haveTransparency) + if (paintFlags & PaintLayerHaveTransparency) parent()->beginTransparencyLayers(p, rootLayer); // Make sure the parent's clip rects have been calculated. IntRect clipRect = paintDirtyRect; if (parent()) { ClipRects parentRects; - parentClipRects(rootLayer, parentRects, temporaryClipRects); + parentClipRects(rootLayer, parentRects, paintFlags & PaintLayerTemporaryClipRects); clipRect = parentRects.overflowClipRect(); clipRect.intersect(paintDirtyRect); } @@ -1996,7 +2084,7 @@ void 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, overlapTestRequests, true, temporaryClipRects); + paintLayer(this, p, transform.inverse().mapRect(paintDirtyRect), paintRestriction, paintingRoot, overlapTestRequests, paintFlags | PaintLayerAppliedTransform); p->restore(); @@ -2006,24 +2094,27 @@ void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p, return; } + PaintLayerFlags localPaintFlags = paintFlags & ~PaintLayerAppliedTransform; + bool haveTransparency = localPaintFlags & PaintLayerHaveTransparency; + // Paint the reflection first if we have one. - if (m_reflection && !m_paintingInsideReflection && (!m_transform || appliedTransform)) { + if (m_reflection && !m_paintingInsideReflection) { // Mark that we are now inside replica painting. m_paintingInsideReflection = true; - reflectionLayer()->paintLayer(rootLayer, p, paintDirtyRect, haveTransparency, paintRestriction, paintingRoot, overlapTestRequests, false, temporaryClipRects); + reflectionLayer()->paintLayer(rootLayer, p, paintDirtyRect, paintRestriction, paintingRoot, overlapTestRequests, localPaintFlags | PaintLayerPaintingReflection); m_paintingInsideReflection = false; } // Calculate the clip rects we should use. IntRect layerBounds, damageRect, clipRectToApply, outlineRect; - calculateRects(rootLayer, paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect, temporaryClipRects); + calculateRects(rootLayer, paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect, localPaintFlags & PaintLayerTemporaryClipRects); int x = layerBounds.x(); int y = layerBounds.y(); int tx = x - renderBoxX(); int ty = y - renderBoxY(); // Ensure our lists are up-to-date. - updateLayerListsIfNeeded(); + updateCompositingAndLayerListsIfNeeded(); bool selectionOnly = paintRestriction == PaintRestrictionSelectionOnly || paintRestriction == PaintRestrictionSelectionOnlyBlackText; bool forceBlackText = paintRestriction == PaintRestrictionSelectionOnlyBlackText; @@ -2061,7 +2152,7 @@ void 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, overlapTestRequests, false, temporaryClipRects); + it[0]->paintLayer(rootLayer, p, paintDirtyRect, paintRestriction, paintingRoot, overlapTestRequests, localPaintFlags); // Now establish the appropriate clip and paint our child RenderObjects. if (shouldPaint && !clipRectToApply.isEmpty()) { @@ -2100,12 +2191,12 @@ void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p, // Paint any child layers that have overflow. if (m_normalFlowList) for (Vector<RenderLayer*>::iterator it = m_normalFlowList->begin(); it != m_normalFlowList->end(); ++it) - it[0]->paintLayer(rootLayer, p, paintDirtyRect, haveTransparency, paintRestriction, paintingRoot, overlapTestRequests, false, temporaryClipRects); + it[0]->paintLayer(rootLayer, p, paintDirtyRect, paintRestriction, paintingRoot, overlapTestRequests, localPaintFlags); // 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, overlapTestRequests, false, temporaryClipRects); + it[0]->paintLayer(rootLayer, p, paintDirtyRect, paintRestriction, paintingRoot, overlapTestRequests, localPaintFlags); if (renderer()->hasMask() && shouldPaint && !selectionOnly && !damageRect.isEmpty()) { setClip(p, paintDirtyRect, damageRect); @@ -2303,7 +2394,7 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont #if USE(ACCELERATED_COMPOSITING) if (isComposited()) { // It doesn't make sense to project hitTestRect into the plane of this layer, so use the same bounds we use for painting. - localHitTestRect = compositor()->calculateCompositedBounds(this, this); + localHitTestRect = backing()->compositedBounds(); } else #endif localHitTestRect = newTransformState->mappedQuad().enclosingBoundingBox(); @@ -2313,7 +2404,7 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont } // Ensure our lists and 3d status are up-to-date. - updateLayerListsIfNeeded(); + updateCompositingAndLayerListsIfNeeded(); update3DTransformedDescendantStatus(); RefPtr<HitTestingTransformState> localTransformState; @@ -2551,13 +2642,13 @@ void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, ClipRects& cl } if (renderer()->hasOverflowClip()) { - IntRect newOverflowClip = toRenderBox(renderer())->overflowClipRect(x,y); + IntRect newOverflowClip = toRenderBox(renderer())->overflowClipRect(x, y); clipRects.setOverflowClipRect(intersection(newOverflowClip, clipRects.overflowClipRect())); if (renderer()->isPositioned() || renderer()->isRelPositioned()) clipRects.setPosClipRect(intersection(newOverflowClip, clipRects.posClipRect())); } if (renderer()->hasClip()) { - IntRect newPosClip = toRenderBox(renderer())->clipRect(x,y); + IntRect newPosClip = toRenderBox(renderer())->clipRect(x, y); clipRects.setPosClipRect(intersection(newPosClip, clipRects.posClipRect())); clipRects.setOverflowClipRect(intersection(newPosClip, clipRects.overflowClipRect())); clipRects.setFixedClipRect(intersection(newPosClip, clipRects.fixedClipRect())); @@ -2607,10 +2698,10 @@ void RenderLayer::calculateRects(const RenderLayer* rootLayer, const IntRect& pa if (renderer()->hasOverflowClip() || renderer()->hasClip()) { // This layer establishes a clip of some kind. if (renderer()->hasOverflowClip()) - foregroundRect.intersect(toRenderBox(renderer())->overflowClipRect(x,y)); + foregroundRect.intersect(toRenderBox(renderer())->overflowClipRect(x, y)); if (renderer()->hasClip()) { // Clip applies to *us* as well, so go ahead and update the damageRect. - IntRect newPosClip = toRenderBox(renderer())->clipRect(x,y); + IntRect newPosClip = toRenderBox(renderer())->clipRect(x, y); backgroundRect.intersect(newPosClip); foregroundRect.intersect(newPosClip); outlineRect.intersect(newPosClip); @@ -2621,10 +2712,13 @@ void RenderLayer::calculateRects(const RenderLayer* rootLayer, const IntRect& pa if (ShadowData* boxShadow = renderer()->style()->boxShadow()) { IntRect overflow = layerBounds; do { - IntRect shadowRect = layerBounds; - shadowRect.move(boxShadow->x, boxShadow->y); - shadowRect.inflate(boxShadow->blur); - overflow.unite(shadowRect); + if (boxShadow->style == Normal) { + IntRect shadowRect = layerBounds; + shadowRect.move(boxShadow->x, boxShadow->y); + shadowRect.inflate(boxShadow->blur + boxShadow->spread); + overflow.unite(shadowRect); + } + boxShadow = boxShadow->next; } while (boxShadow); backgroundRect.intersect(overflow); @@ -2897,7 +2991,7 @@ void RenderLayer::dirtyZOrderLists() #if USE(ACCELERATED_COMPOSITING) if (!renderer()->documentBeingDestroyed()) - compositor()->setCompositingLayersNeedUpdate(); + compositor()->setCompositingLayersNeedRebuild(); #endif } @@ -2916,7 +3010,7 @@ void RenderLayer::dirtyNormalFlowList() #if USE(ACCELERATED_COMPOSITING) if (!renderer()->documentBeingDestroyed()) - compositor()->setCompositingLayersNeedUpdate(); + compositor()->setCompositingLayersNeedRebuild(); #endif } @@ -2986,6 +3080,12 @@ void RenderLayer::collectLayers(Vector<RenderLayer*>*& posBuffer, Vector<RenderL void RenderLayer::updateLayerListsIfNeeded() { + updateZOrderLists(); + updateNormalFlowList(); +} + +void RenderLayer::updateCompositingAndLayerListsIfNeeded() +{ #if USE(ACCELERATED_COMPOSITING) if (compositor()->inCompositingMode()) { if ((isStackingContext() && m_zOrderListsDirty) || m_normalFlowListDirty) @@ -2993,8 +3093,7 @@ void RenderLayer::updateLayerListsIfNeeded() return; } #endif - updateZOrderLists(); - updateNormalFlowList(); + updateLayerListsIfNeeded(); } void RenderLayer::repaintIncludingDescendants() @@ -3051,7 +3150,7 @@ void RenderLayer::repaintIncludingNonCompositingDescendants(RenderBoxModelObject bool RenderLayer::shouldBeNormalFlowOnly() const { - return (renderer()->hasOverflowClip() || renderer()->hasReflection() || renderer()->hasMask()) && + return (renderer()->hasOverflowClip() || renderer()->hasReflection() || renderer()->hasMask() || renderer()->isVideo()) && !renderer()->isPositioned() && !renderer()->isRelPositioned() && !renderer()->hasTransform() && @@ -3060,7 +3159,7 @@ bool RenderLayer::shouldBeNormalFlowOnly() const bool RenderLayer::isSelfPaintingLayer() const { - return !isNormalFlowOnly() || renderer()->hasReflection() || renderer()->hasMask() || renderer()->isTableRow(); + return !isNormalFlowOnly() || renderer()->hasReflection() || renderer()->hasMask() || renderer()->isTableRow() || renderer()->isVideo(); } void RenderLayer::styleChanged(StyleDifference diff, const RenderStyle*) @@ -3106,7 +3205,7 @@ void RenderLayer::styleChanged(StyleDifference diff, const RenderStyle*) updateTransform(); if (compositor()->updateLayerCompositingState(this)) - compositor()->setCompositingLayersNeedUpdate(); + compositor()->setCompositingLayersNeedRebuild(); else if (m_backing) m_backing->updateGraphicsLayerGeometry(); diff --git a/WebCore/rendering/RenderLayer.h b/WebCore/rendering/RenderLayer.h index 9c8de5e..1772c66 100644 --- a/WebCore/rendering/RenderLayer.h +++ b/WebCore/rendering/RenderLayer.h @@ -264,7 +264,7 @@ public: void positionOverflowControls(int tx, int ty); bool isPointInResizeControl(const IntPoint& absolutePoint) const; - bool hitTestOverflowControls(HitTestResult&); + bool hitTestOverflowControls(HitTestResult&, const IntPoint& localPoint); IntSize offsetFromResizeCorner(const IntPoint& absolutePoint) const; void paintOverflowControls(GraphicsContext*, int tx, int ty, const IntRect& damageRect); @@ -289,9 +289,19 @@ public: // Allows updates of layer content without repainting. void rendererContentChanged(); #endif + + // Returns true if the accelerated compositing is enabled + bool hasAcceleratedCompositing() const; void updateLayerPosition(); - void updateLayerPositions(bool doFullRepaint = false, bool checkForRepaint = true); + + enum UpdateLayerPositionsFlag { + DoFullRepaint = 1, + CheckForRepaint = 1 << 1, + UpdateCompositingLayers = 1 << 2, + }; + typedef unsigned UpdateLayerPositionsFlags; + void updateLayerPositions(UpdateLayerPositionsFlags = DoFullRepaint | UpdateCompositingLayers); void updateTransform(); @@ -372,6 +382,7 @@ public: // Return a cached repaint rect, computed relative to the layer renderer's containerForRepaint. IntRect repaintRect() const { return m_repaintRect; } + void computeRepaintRects(); void setNeedsFullRepaint(bool f = true) { m_needsFullRepaint = f; } int staticX() const { return m_staticX; } @@ -438,11 +449,20 @@ private: void collectLayers(Vector<RenderLayer*>*&, Vector<RenderLayer*>*&); void updateLayerListsIfNeeded(); + void updateCompositingAndLayerListsIfNeeded(); + enum PaintLayerFlag { + PaintLayerHaveTransparency = 1, + PaintLayerAppliedTransform = 1 << 1, + PaintLayerTemporaryClipRects = 1 << 2, + PaintLayerPaintingReflection = 1 << 3 + }; + + typedef unsigned PaintLayerFlags; + void paintLayer(RenderLayer* rootLayer, GraphicsContext*, const IntRect& paintDirtyRect, - bool haveTransparency, PaintRestriction, RenderObject* paintingRoot, - RenderObject::OverlapTestRequestMap* = 0, - bool appliedTransform = false, bool temporaryClipRects = false); + PaintRestriction, RenderObject* paintingRoot, RenderObject::OverlapTestRequestMap* = 0, + PaintLayerFlags paintFlags = 0); RenderLayer* hitTestLayer(RenderLayer* rootLayer, RenderLayer* containerLayer, const HitTestRequest& request, HitTestResult& result, const IntRect& hitTestRect, const IntPoint& hitTestPoint, bool appliedTransform, @@ -458,11 +478,18 @@ private: bool shouldBeNormalFlowOnly() const; + // ScrollBarClient interface virtual void valueChanged(Scrollbar*); virtual void invalidateScrollbarRect(Scrollbar*, const IntRect&); virtual bool isActive() const; virtual bool scrollbarCornerPresent() const; - + virtual IntRect convertFromScrollbarToContainingView(const Scrollbar*, const IntRect&) const; + virtual IntRect convertFromContainingViewToScrollbar(const Scrollbar*, const IntRect&) const; + virtual IntPoint convertFromScrollbarToContainingView(const Scrollbar*, const IntPoint&) const; + virtual IntPoint convertFromContainingViewToScrollbar(const Scrollbar*, const IntPoint&) const; + + IntSize scrollbarOffset(const Scrollbar*) const; + void updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow); void childVisibilityChanged(bool newVisibility); @@ -482,6 +509,7 @@ private: void createReflection(); void updateReflectionStyle(); bool paintingInsideReflection() const { return m_paintingInsideReflection; } + void setPaintingInsideReflection(bool b) { m_paintingInsideReflection = b; } void parentClipRects(const RenderLayer* rootLayer, ClipRects&, bool temporaryClipRects = false) const; @@ -497,8 +525,8 @@ private: bool hasCompositingDescendant() const { return m_hasCompositingDescendant; } void setHasCompositingDescendant(bool b) { m_hasCompositingDescendant = b; } - bool mustOverlayCompositedLayers() const { return m_mustOverlayCompositedLayers; } - void setMustOverlayCompositedLayers(bool b) { m_mustOverlayCompositedLayers = b; } + bool mustOverlapCompositedLayers() const { return m_mustOverlapCompositedLayers; } + void setMustOverlapCompositedLayers(bool b) { m_mustOverlapCompositedLayers = b; } #endif private: @@ -591,7 +619,7 @@ protected: // in a preserves3D hierarchy. Hint to do 3D-aware hit testing. #if USE(ACCELERATED_COMPOSITING) bool m_hasCompositingDescendant : 1; - bool m_mustOverlayCompositedLayers : 1; + bool m_mustOverlapCompositedLayers : 1; #endif RenderMarquee* m_marquee; // Used by layers with overflow:marquee diff --git a/WebCore/rendering/RenderLayerBacking.cpp b/WebCore/rendering/RenderLayerBacking.cpp index e16ecf7..e98c458 100644 --- a/WebCore/rendering/RenderLayerBacking.cpp +++ b/WebCore/rendering/RenderLayerBacking.cpp @@ -55,10 +55,9 @@ RenderLayerBacking::RenderLayerBacking(RenderLayer* layer) : m_owningLayer(layer) , m_ancestorClippingLayer(0) , m_graphicsLayer(0) - , m_contentsLayer(0) + , m_foregroundLayer(0) , m_clippingLayer(0) , m_hasDirectlyCompositedContent(false) - , m_compositingContentOffsetDirty(true) { createGraphicsLayer(); } @@ -66,7 +65,7 @@ RenderLayerBacking::RenderLayerBacking(RenderLayer* layer) RenderLayerBacking::~RenderLayerBacking() { updateClippingLayers(false, false); - updateContentsLayer(false); + updateForegroundLayer(false); destroyGraphicsLayer(); } @@ -75,14 +74,17 @@ void RenderLayerBacking::createGraphicsLayer() m_graphicsLayer = GraphicsLayer::createGraphicsLayer(this); #ifndef NDEBUG - if (renderer()->node()->isDocumentNode()) - m_graphicsLayer->setName("Document Node"); - else { - if (renderer()->node()->isHTMLElement() && renderer()->node()->hasID()) - m_graphicsLayer->setName(renderer()->renderName() + String(" ") + static_cast<HTMLElement*>(renderer()->node())->id()); - else - m_graphicsLayer->setName(renderer()->renderName()); - } + if (renderer()->node()) { + if (renderer()->node()->isDocumentNode()) + m_graphicsLayer->setName("Document Node"); + else { + if (renderer()->node()->isHTMLElement() && renderer()->node()->hasID()) + m_graphicsLayer->setName(renderer()->renderName() + String(" ") + static_cast<HTMLElement*>(renderer()->node())->id()); + else + m_graphicsLayer->setName(renderer()->renderName()); + } + } else + m_graphicsLayer->setName("Anonymous Node"); #endif // NDEBUG updateLayerOpacity(); @@ -97,8 +99,8 @@ void RenderLayerBacking::destroyGraphicsLayer() delete m_graphicsLayer; m_graphicsLayer = 0; - delete m_contentsLayer; - m_contentsLayer = 0; + delete m_foregroundLayer; + m_foregroundLayer = 0; delete m_clippingLayer; m_clippingLayer = 0; @@ -106,7 +108,7 @@ void RenderLayerBacking::destroyGraphicsLayer() void RenderLayerBacking::updateLayerOpacity() { - m_graphicsLayer->setOpacity(compositingOpacity(renderer()->opacity()), 0, 0); + m_graphicsLayer->setOpacity(compositingOpacity(renderer()->opacity())); } void RenderLayerBacking::updateLayerTransform() @@ -118,17 +120,31 @@ void RenderLayerBacking::updateLayerTransform() TransformationMatrix t; if (m_owningLayer->hasTransform()) { style->applyTransform(t, toRenderBox(renderer())->borderBoxRect().size(), RenderStyle::ExcludeTransformOrigin); - makeMatrixRenderable(t); + makeMatrixRenderable(t, compositor()->hasAcceleratedCompositing()); } m_graphicsLayer->setTransform(t); } -void RenderLayerBacking::updateAfterLayout() +void RenderLayerBacking::updateAfterLayout(UpdateDepth updateDepth) { - // Only need to update geometry if there isn't a layer update pending. - if (!compositor()->compositingLayersNeedUpdate()) - updateGraphicsLayerGeometry(); + RenderLayerCompositor* layerCompositor = compositor(); + if (!layerCompositor->compositingLayersNeedRebuild()) { + // Calling updateGraphicsLayerGeometry() here gives incorrect results, because the + // position of this layer's GraphicsLayer depends on the position of our compositing + // ancestor's GraphicsLayer. That cannot be determined until all the descendant + // RenderLayers of that ancestor have been processed via updateLayerPositions(). + // + // The solution is to update compositing children of this layer here, + // via updateCompositingChildrenGeometry(). + setCompositedBounds(layerCompositor->calculateCompositedBounds(m_owningLayer, m_owningLayer)); + layerCompositor->updateCompositingDescendantGeometry(m_owningLayer, m_owningLayer, updateDepth); + + if (!m_owningLayer->parent()) { + updateGraphicsLayerGeometry(); + layerCompositor->updateRootLayerPosition(); + } + } } bool RenderLayerBacking::updateGraphicsLayerConfiguration() @@ -136,7 +152,7 @@ bool RenderLayerBacking::updateGraphicsLayerConfiguration() RenderLayerCompositor* compositor = this->compositor(); bool layerConfigChanged = false; - if (updateContentsLayer(compositor->needsContentsCompositingLayer(m_owningLayer))) + if (updateForegroundLayer(compositor->needsContentsCompositingLayer(m_owningLayer))) layerConfigChanged = true; if (updateClippingLayers(compositor->clippedByAncestor(m_owningLayer), compositor->clipsCompositingDescendants(m_owningLayer))) @@ -178,16 +194,16 @@ void RenderLayerBacking::updateGraphicsLayerGeometry() m_graphicsLayer->setPreserves3D(style->transformStyle3D() == TransformStyle3DPreserve3D); m_graphicsLayer->setBackfaceVisibility(style->backfaceVisibility() == BackfaceVisibilityVisible); - m_compositingContentOffsetDirty = true; - RenderLayer* compAncestor = m_owningLayer->ancestorCompositingLayer(); // We compute everything relative to the enclosing compositing layer. IntRect ancestorCompositingBounds; - if (compAncestor) - ancestorCompositingBounds = compositor()->calculateCompositedBounds(compAncestor, compAncestor); - - IntRect localCompositingBounds = compositor()->calculateCompositedBounds(m_owningLayer, m_owningLayer); + if (compAncestor) { + ASSERT(compAncestor->backing()); + ancestorCompositingBounds = compAncestor->backing()->compositedBounds(); + } + + IntRect localCompositingBounds = compositedBounds(); IntRect relativeCompositingBounds(localCompositingBounds); int deltaX = 0, deltaY = 0; @@ -276,21 +292,21 @@ void RenderLayerBacking::updateGraphicsLayerGeometry() m_graphicsLayer->setAnchorPoint(FloatPoint3D(0.5f, 0.5f, 0)); } - if (m_contentsLayer) { + if (m_foregroundLayer) { // The contents layer is always coincidental with the graphicsLayer for now. - m_contentsLayer->setPosition(IntPoint(0, 0)); - m_contentsLayer->setSize(newSize); - m_contentsLayer->setOffsetFromRenderer(m_graphicsLayer->offsetFromRenderer()); + m_foregroundLayer->setPosition(IntPoint(0, 0)); + m_foregroundLayer->setSize(newSize); + m_foregroundLayer->setOffsetFromRenderer(m_graphicsLayer->offsetFromRenderer()); } - m_graphicsLayer->updateContentsRect(); + m_graphicsLayer->setContentsRect(contentsBox()); if (!m_hasDirectlyCompositedContent) m_graphicsLayer->setDrawsContent(!isSimpleContainerCompositingLayer() && !paintingGoesToWindow()); } void RenderLayerBacking::updateInternalHierarchy() { - // m_contentsLayer has to be inserted in the correct order with child layers, + // m_foregroundLayer has to be inserted in the correct order with child layers, // so it's not inserted here. if (m_ancestorClippingLayer) { m_ancestorClippingLayer->removeAllChildren(); @@ -347,24 +363,24 @@ bool RenderLayerBacking::updateClippingLayers(bool needsAncestorClip, bool needs return layersChanged; } -bool RenderLayerBacking::updateContentsLayer(bool needsContentsLayer) +bool RenderLayerBacking::updateForegroundLayer(bool needsForegroundLayer) { bool layerChanged = false; - if (needsContentsLayer) { - if (!m_contentsLayer) { - m_contentsLayer = GraphicsLayer::createGraphicsLayer(this); + if (needsForegroundLayer) { + if (!m_foregroundLayer) { + m_foregroundLayer = GraphicsLayer::createGraphicsLayer(this); #ifndef NDEBUG - m_contentsLayer->setName("Contents"); + m_foregroundLayer->setName("Contents"); #endif - m_contentsLayer->setDrawsContent(true); - m_contentsLayer->setDrawingPhase(GraphicsLayerPaintForegroundMask); + m_foregroundLayer->setDrawsContent(true); + m_foregroundLayer->setDrawingPhase(GraphicsLayerPaintForegroundMask); m_graphicsLayer->setDrawingPhase(GraphicsLayerPaintBackgroundMask); layerChanged = true; } - } else if (m_contentsLayer) { - m_contentsLayer->removeFromParent(); - delete m_contentsLayer; - m_contentsLayer = 0; + } else if (m_foregroundLayer) { + m_foregroundLayer->removeFromParent(); + delete m_foregroundLayer; + m_foregroundLayer = 0; m_graphicsLayer->setDrawingPhase(GraphicsLayerPaintAllMask); layerChanged = true; } @@ -410,7 +426,7 @@ static bool hasBoxDecorationsWithBackgroundImage(const RenderStyle* style) bool RenderLayerBacking::rendererHasBackground() const { // FIXME: share more code here - if (renderer()->node()->isDocumentNode()) { + if (renderer()->node() && renderer()->node()->isDocumentNode()) { RenderObject* htmlObject = renderer()->firstChild(); if (!htmlObject) return false; @@ -433,7 +449,7 @@ bool RenderLayerBacking::rendererHasBackground() const const Color& RenderLayerBacking::rendererBackgroundColor() const { // FIXME: share more code here - if (renderer()->node()->isDocumentNode()) { + if (renderer()->node() && renderer()->node()->isDocumentNode()) { RenderObject* htmlObject = renderer()->firstChild(); RenderStyle* style = htmlObject->style(); if (style->hasBackground()) @@ -469,7 +485,7 @@ bool RenderLayerBacking::isSimpleContainerCompositingLayer() const if (!renderObject->firstChild()) return true; - if (renderObject->node()->isDocumentNode()) { + if (renderObject->node() && renderObject->node()->isDocumentNode()) { // Look to see if the root object has a non-simple backgound RenderObject* rootObject = renderObject->document()->documentElement()->renderer(); if (!rootObject) @@ -529,29 +545,29 @@ bool RenderLayerBacking::hasNonCompositingContent() const // FIXME: test for overflow controls. if (m_owningLayer->isStackingContext()) { // Use the m_hasCompositingDescendant bit to optimize? - Vector<RenderLayer*>* negZOrderList = m_owningLayer->negZOrderList(); - if (negZOrderList && negZOrderList->size() > 0) { - for (Vector<RenderLayer*>::const_iterator it = negZOrderList->begin(); it != negZOrderList->end(); ++it) { - RenderLayer* curLayer = (*it); + if (Vector<RenderLayer*>* negZOrderList = m_owningLayer->negZOrderList()) { + size_t listSize = negZOrderList->size(); + for (size_t i = 0; i < listSize; ++i) { + RenderLayer* curLayer = negZOrderList->at(i); if (!curLayer->isComposited()) return true; } } - Vector<RenderLayer*>* posZOrderList = m_owningLayer->posZOrderList(); - if (posZOrderList && posZOrderList->size() > 0) { - for (Vector<RenderLayer*>::const_iterator it = posZOrderList->begin(); it != posZOrderList->end(); ++it) { - RenderLayer* curLayer = (*it); + if (Vector<RenderLayer*>* posZOrderList = m_owningLayer->posZOrderList()) { + size_t listSize = posZOrderList->size(); + for (size_t i = 0; i < listSize; ++i) { + RenderLayer* curLayer = posZOrderList->at(i); if (!curLayer->isComposited()) return true; } } } - Vector<RenderLayer*>* normalFlowList = m_owningLayer->normalFlowList(); - if (normalFlowList && normalFlowList->size() > 0) { - for (Vector<RenderLayer*>::const_iterator it = normalFlowList->begin(); it != normalFlowList->end(); ++it) { - RenderLayer* curLayer = (*it); + if (Vector<RenderLayer*>* normalFlowList = m_owningLayer->normalFlowList()) { + size_t listSize = normalFlowList->size(); + for (size_t i = 0; i < listSize; ++i) { + RenderLayer* curLayer = normalFlowList->at(i); if (!curLayer->isComposited()) return true; } @@ -567,11 +583,15 @@ bool RenderLayerBacking::canUseDirectCompositing() const RenderObject* renderObject = renderer(); // Reject anything that isn't an image - if (!renderObject->isImage()) + if (!renderObject->isImage() && !renderObject->isVideo()) return false; if (renderObject->hasMask() || renderObject->hasReflection()) return false; + + // Video can use an inner layer even if it has box decorations; we draw those into another layer. + if (renderObject->isVideo()) + return true; // Reject anything that would require the image to be drawn via the GraphicsContext, // like border, shadows etc. Solid background color is OK. @@ -587,7 +607,7 @@ void RenderLayerBacking::rendererContentChanged() void RenderLayerBacking::updateImageContents() { ASSERT(renderer()->isImage()); - RenderImage* imageRenderer = static_cast<RenderImage*>(renderer()); + RenderImage* imageRenderer = toRenderImage(renderer()); CachedImage* cachedImage = imageRenderer->cachedImage(); if (!cachedImage) @@ -637,24 +657,25 @@ FloatPoint RenderLayerBacking::computePerspectiveOrigin(const IntRect& borderBox } // Return the offset from the top-left of this compositing layer at which the renderer's contents are painted. -IntSize RenderLayerBacking::contentOffsetInCompostingLayer() +IntSize RenderLayerBacking::contentOffsetInCompostingLayer() const { - if (!m_compositingContentOffsetDirty) - return m_compositingContentOffset; - - IntRect relativeCompositingBounds = compositor()->calculateCompositedBounds(m_owningLayer, m_owningLayer); - m_compositingContentOffset = IntSize(-relativeCompositingBounds.x(), -relativeCompositingBounds.y()); - m_compositingContentOffsetDirty = false; - - return m_compositingContentOffset; + return IntSize(-m_compositedBounds.x(), -m_compositedBounds.y()); } -IntRect RenderLayerBacking::contentsBox(const GraphicsLayer*) +IntRect RenderLayerBacking::contentsBox() const { if (!renderer()->isBox()) return IntRect(); - IntRect contentsRect = toRenderBox(renderer())->contentBoxRect(); + IntRect contentsRect; +#if ENABLE(VIDEO) + if (renderer()->isVideo()) { + RenderVideo* videoRenderer = toRenderVideo(renderer()); + contentsRect = videoRenderer->videoBox(); + } else +#endif + contentsRect = toRenderBox(renderer())->contentBoxRect(); + IntSize contentOffset = contentOffsetInCompostingLayer(); contentsRect.move(contentOffset); return contentsRect; @@ -679,16 +700,17 @@ bool RenderLayerBacking::paintingGoesToWindow() const void RenderLayerBacking::setContentsNeedDisplay() { - if (m_graphicsLayer) + if (m_graphicsLayer && m_graphicsLayer->drawsContent()) m_graphicsLayer->setNeedsDisplay(); - if (m_contentsLayer) - m_contentsLayer->setNeedsDisplay(); + + if (m_foregroundLayer && m_foregroundLayer->drawsContent()) + m_foregroundLayer->setNeedsDisplay(); } // r is in the coordinate space of the layer's render object void RenderLayerBacking::setContentsNeedDisplayInRect(const IntRect& r) { - if (m_graphicsLayer) { + if (m_graphicsLayer && m_graphicsLayer->drawsContent()) { FloatPoint dirtyOrigin = contentsToGraphicsLayerCoordinates(m_graphicsLayer, FloatPoint(r.x(), r.y())); FloatRect dirtyRect(dirtyOrigin, r.size()); FloatRect bounds(FloatPoint(), m_graphicsLayer->size()); @@ -696,9 +718,9 @@ void RenderLayerBacking::setContentsNeedDisplayInRect(const IntRect& r) m_graphicsLayer->setNeedsDisplayInRect(dirtyRect); } - if (m_contentsLayer) { + if (m_foregroundLayer && m_foregroundLayer->drawsContent()) { // FIXME: do incremental repaint - m_contentsLayer->setNeedsDisplay(); + m_foregroundLayer->setNeedsDisplay(); } } @@ -720,7 +742,7 @@ static void restoreClip(GraphicsContext* p, const IntRect& paintDirtyRect, const // Share this with RenderLayer::paintLayer, which would have to be educated about GraphicsLayerPaintingPhase? void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext* context, const IntRect& paintDirtyRect, // in the coords of rootLayer - bool haveTransparency, PaintRestriction paintRestriction, GraphicsLayerPaintingPhase paintingPhase, + PaintRestriction paintRestriction, GraphicsLayerPaintingPhase paintingPhase, RenderObject* paintingRoot) { if (paintingGoesToWindow()) { @@ -730,6 +752,14 @@ void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext* m_owningLayer->updateLayerListsIfNeeded(); + // Paint the reflection first if we have one. + if (m_owningLayer->hasReflection()) { + // Mark that we are now inside replica painting. + m_owningLayer->setPaintingInsideReflection(true); + m_owningLayer->reflectionLayer()->paintLayer(rootLayer, context, paintDirtyRect, paintRestriction, paintingRoot, 0, RenderLayer::PaintLayerPaintingReflection); + m_owningLayer->setPaintingInsideReflection(false); + } + // Calculate the clip rects we should use. IntRect layerBounds, damageRect, clipRectToApply, outlineRect; m_owningLayer->calculateRects(rootLayer, paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect); @@ -747,13 +777,15 @@ void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext* if (paintingRoot && !renderer()->isDescendantOf(paintingRoot)) paintingRootForRenderer = paintingRoot; - if (paintingPhase & GraphicsLayerPaintBackgroundMask) { + bool shouldPaint = m_owningLayer->hasVisibleContent() && m_owningLayer->isSelfPaintingLayer(); + + if (shouldPaint && (paintingPhase & GraphicsLayerPaintBackgroundMask)) { // If this is the root then we need to send in a bigger bounding box // because we'll be painting the background as well (see RenderBox::paintRootBoxDecorations()). IntRect paintBox = clipRectToApply; // FIXME: do we need this code? - if (renderer()->node()->isDocumentNode() && renderer()->document()->isHTMLDocument()) { + if (renderer()->node() && renderer()->node()->isDocumentNode() && renderer()->document()->isHTMLDocument()) { RenderBox* box = toRenderBox(renderer()); int w = box->width(); int h = box->height(); @@ -791,13 +823,13 @@ void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext* restoreClip(context, paintDirtyRect, damageRect); } - if (paintingPhase & GraphicsLayerPaintForegroundMask) { + if (shouldPaint && (paintingPhase & GraphicsLayerPaintForegroundMask)) { // Now walk the sorted list of children with negative z-indices. Only RenderLayers without compositing layers will paint. // FIXME: should these be painted as background? Vector<RenderLayer*>* negZOrderList = m_owningLayer->negZOrderList(); if (negZOrderList) { for (Vector<RenderLayer*>::iterator it = negZOrderList->begin(); it != negZOrderList->end(); ++it) - it[0]->paintLayer(rootLayer, context, paintDirtyRect, haveTransparency, paintRestriction, paintingRoot); + it[0]->paintLayer(rootLayer, context, paintDirtyRect, paintRestriction, paintingRoot); } bool forceBlackText = paintRestriction == PaintRestrictionSelectionOnlyBlackText; @@ -836,14 +868,14 @@ void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext* Vector<RenderLayer*>* normalFlowList = m_owningLayer->normalFlowList(); if (normalFlowList) { for (Vector<RenderLayer*>::iterator it = normalFlowList->begin(); it != normalFlowList->end(); ++it) - it[0]->paintLayer(rootLayer, context, paintDirtyRect, haveTransparency, paintRestriction, paintingRoot); + it[0]->paintLayer(rootLayer, context, paintDirtyRect, paintRestriction, paintingRoot); } // Now walk the sorted list of children with positive z-indices. Vector<RenderLayer*>* posZOrderList = m_owningLayer->posZOrderList(); if (posZOrderList) { for (Vector<RenderLayer*>::iterator it = posZOrderList->begin(); it != posZOrderList->end(); ++it) - it[0]->paintLayer(rootLayer, context, paintDirtyRect, haveTransparency, paintRestriction, paintingRoot); + it[0]->paintLayer(rootLayer, context, paintDirtyRect, paintRestriction, paintingRoot); } if (renderer()->hasMask() && !selectionOnly && !damageRect.isEmpty()) { @@ -866,7 +898,7 @@ void RenderLayerBacking::paintContents(const GraphicsLayer*, GraphicsContext& co { // We have to use the same root as for hit testing, because both methods // can compute and cache clipRects. - IntRect enclosingBBox = compositor()->calculateCompositedBounds(m_owningLayer, m_owningLayer); + IntRect enclosingBBox = compositedBounds(); IntRect clipRect(clip); @@ -880,7 +912,7 @@ void RenderLayerBacking::paintContents(const GraphicsLayer*, GraphicsContext& co IntRect dirtyRect = enclosingBBox; dirtyRect.intersect(clipRect); - paintIntoLayer(m_owningLayer, &context, dirtyRect, false, PaintRestrictionNone, drawingPhase, renderer()); + paintIntoLayer(m_owningLayer, &context, dirtyRect, PaintRestrictionNone, drawingPhase, renderer()); } bool RenderLayerBacking::startAnimation(double beginTime, const Animation* anim, const KeyframeList& keyframes) @@ -891,8 +923,8 @@ bool RenderLayerBacking::startAnimation(double beginTime, const Animation* anim, if (!hasOpacity && !hasTransform) return false; - GraphicsLayer::TransformValueList transformVector; - GraphicsLayer::FloatValueList opacityVector; + KeyframeValueList transformVector(AnimatedPropertyWebkitTransform); + KeyframeValueList opacityVector(AnimatedPropertyOpacity); for (Vector<KeyframeValue>::const_iterator it = keyframes.beginKeyframes(); it != keyframes.endKeyframes(); ++it) { const RenderStyle* keyframeStyle = it->style(); @@ -905,22 +937,26 @@ bool RenderLayerBacking::startAnimation(double beginTime, const Animation* anim, const TimingFunction* tf = keyframeStyle->hasAnimations() ? &((*keyframeStyle->animations()).animation(0)->timingFunction()) : 0; if (hasTransform) - transformVector.insert(key, &(keyframeStyle->transform()), tf); - + transformVector.insert(new TransformAnimationValue(key, &(keyframeStyle->transform()), tf)); + if (hasOpacity) - opacityVector.insert(key, keyframeStyle->opacity(), tf); + opacityVector.insert(new FloatAnimationValue(key, keyframeStyle->opacity(), tf)); } bool didAnimateTransform = !hasTransform; bool didAnimateOpacity = !hasOpacity; - if (hasTransform && m_graphicsLayer->animateTransform(transformVector, toRenderBox(renderer())->borderBoxRect().size(), anim, beginTime, false)) + if (hasTransform && m_graphicsLayer->addAnimation(transformVector, toRenderBox(renderer())->borderBoxRect().size(), anim, keyframes.animationName(), beginTime)) didAnimateTransform = true; - if (hasOpacity && m_graphicsLayer->animateFloat(AnimatedPropertyOpacity, opacityVector, anim, beginTime)) + if (hasOpacity && m_graphicsLayer->addAnimation(opacityVector, IntSize(), anim, keyframes.animationName(), beginTime)) didAnimateOpacity = true; - return didAnimateTransform && didAnimateOpacity; + bool runningAcceleratedAnimation = didAnimateTransform && didAnimateOpacity; + if (runningAcceleratedAnimation) + compositor()->didStartAcceleratedAnimation(); + + return runningAcceleratedAnimation; } bool RenderLayerBacking::startTransition(double beginTime, int property, const RenderStyle* fromStyle, const RenderStyle* toStyle) @@ -931,29 +967,27 @@ bool RenderLayerBacking::startTransition(double beginTime, int property, const R if (property == (int)CSSPropertyOpacity) { const Animation* opacityAnim = toStyle->transitionForProperty(CSSPropertyOpacity); if (opacityAnim && !opacityAnim->isEmptyOrZeroDuration()) { - // If beginTime is not 0, we are restarting this transition, so first set the from value - // in case it was smashed by a previous animation. - if (beginTime > 0) - m_graphicsLayer->setOpacity(compositingOpacity(fromStyle->opacity()), 0, 0); - - if (m_graphicsLayer->setOpacity(compositingOpacity(toStyle->opacity()), opacityAnim, beginTime)) + KeyframeValueList opacityVector(AnimatedPropertyOpacity); + opacityVector.insert(new FloatAnimationValue(0, compositingOpacity(fromStyle->opacity()))); + opacityVector.insert(new FloatAnimationValue(1, compositingOpacity(toStyle->opacity()))); + if (m_graphicsLayer->addAnimation(opacityVector, toRenderBox(renderer())->borderBoxRect().size(), opacityAnim, String(), beginTime)) didAnimate = true; } } if (property == (int)CSSPropertyWebkitTransform && m_owningLayer->hasTransform()) { - // We get a TransformOperation, which is a linked list of primitive operations and their arguments. - // Arguments can be floats or Length values, which need to be converted to numbers using - // val.calcFloatValue(renderer()->width()) (or height()). const Animation* transformAnim = toStyle->transitionForProperty(CSSPropertyWebkitTransform); if (transformAnim && !transformAnim->isEmptyOrZeroDuration()) { - GraphicsLayer::TransformValueList transformVector; - transformVector.insert(0, &fromStyle->transform(), 0); - transformVector.insert(1, &toStyle->transform(), 0); - if (m_graphicsLayer->animateTransform(transformVector, toRenderBox(renderer())->borderBoxRect().size(), transformAnim, beginTime, true)) + KeyframeValueList transformVector(AnimatedPropertyWebkitTransform); + transformVector.insert(new TransformAnimationValue(0, &fromStyle->transform())); + transformVector.insert(new TransformAnimationValue(1, &toStyle->transform())); + if (m_graphicsLayer->addAnimation(transformVector, toRenderBox(renderer())->borderBoxRect().size(), transformAnim, String(), beginTime)) didAnimate = true; } } + + if (didAnimate) + compositor()->didStartAcceleratedAnimation(); return didAnimate; } @@ -963,21 +997,32 @@ void RenderLayerBacking::notifyAnimationStarted(const GraphicsLayer*, double tim renderer()->animation()->notifyAnimationStarted(renderer(), time); } -void RenderLayerBacking::animationFinished(const String& name, int index, bool reset) +void RenderLayerBacking::notifySyncRequired(const GraphicsLayer*) { - m_graphicsLayer->removeFinishedAnimations(name, index, reset); + if (!renderer()->documentBeingDestroyed()) + compositor()->scheduleSync(); +} + +void RenderLayerBacking::animationFinished(const String& animationName) +{ + m_graphicsLayer->removeAnimationsForKeyframes(animationName); +} + +void RenderLayerBacking::animationPaused(const String& animationName) +{ + m_graphicsLayer->pauseAnimation(animationName); } void RenderLayerBacking::transitionFinished(int property) { AnimatedPropertyID animatedProperty = cssToGraphicsLayerProperty(property); if (animatedProperty != AnimatedPropertyInvalid) - m_graphicsLayer->removeFinishedTransitions(animatedProperty); + m_graphicsLayer->removeAnimationsForProperty(animatedProperty); } -void RenderLayerBacking::suspendAnimations() +void RenderLayerBacking::suspendAnimations(double time) { - m_graphicsLayer->suspendAnimations(); + m_graphicsLayer->suspendAnimations(time); } void RenderLayerBacking::resumeAnimations() @@ -985,6 +1030,16 @@ void RenderLayerBacking::resumeAnimations() m_graphicsLayer->resumeAnimations(); } +IntRect RenderLayerBacking::compositedBounds() const +{ + return m_compositedBounds; +} + +void RenderLayerBacking::setCompositedBounds(const IntRect& bounds) +{ + m_compositedBounds = bounds; + +} int RenderLayerBacking::graphicsLayerToCSSProperty(AnimatedPropertyID property) { int cssProperty = CSSPropertyInvalid; diff --git a/WebCore/rendering/RenderLayerBacking.h b/WebCore/rendering/RenderLayerBacking.h index a6a6c1f..b027685 100644 --- a/WebCore/rendering/RenderLayerBacking.h +++ b/WebCore/rendering/RenderLayerBacking.h @@ -53,12 +53,15 @@ public: RenderLayer* owningLayer() const { return m_owningLayer; } - void updateAfterLayout(); + enum UpdateDepth { CompositingChildren, AllDescendants }; + void updateAfterLayout(UpdateDepth); // Returns true if layer configuration changed. bool updateGraphicsLayerConfiguration(); - void updateGraphicsLayerGeometry(); - void updateInternalHierarchy(); + // Update graphics layer position and bounds. + void updateGraphicsLayerGeometry(); // make private + // Update contents and clipping structure. + void updateInternalHierarchy(); // make private GraphicsLayer* graphicsLayer() const { return m_graphicsLayer; } @@ -70,8 +73,8 @@ public: bool hasAncestorClippingLayer() const { return m_ancestorClippingLayer != 0; } GraphicsLayer* ancestorClippingLayer() const { return m_ancestorClippingLayer; } - bool hasContentsLayer() const { return m_contentsLayer != 0; } - GraphicsLayer* contentsLayer() const { return m_contentsLayer; } + bool hasContentsLayer() const { return m_foregroundLayer != 0; } + GraphicsLayer* foregroundLayer() const { return m_foregroundLayer; } GraphicsLayer* parentForSublayers() const { return m_clippingLayer ? m_clippingLayer : m_graphicsLayer; } GraphicsLayer* childForSuperlayers() const { return m_ancestorClippingLayer ? m_ancestorClippingLayer : m_graphicsLayer; } @@ -94,21 +97,26 @@ public: // Interface to start, finish, suspend and resume animations and transitions bool startAnimation(double beginTime, const Animation* anim, const KeyframeList& keyframes); bool startTransition(double beginTime, int property, const RenderStyle* fromStyle, const RenderStyle* toStyle); - void animationFinished(const String& name, int index, bool reset); + void animationFinished(const String& name); + void animationPaused(const String& name); void transitionFinished(int property); - void suspendAnimations(); + void suspendAnimations(double time = 0); void resumeAnimations(); + IntRect compositedBounds() const; + void setCompositedBounds(const IntRect&); + FloatPoint graphicsLayerToContentsCoordinates(const GraphicsLayer*, const FloatPoint&); FloatPoint contentsToGraphicsLayerCoordinates(const GraphicsLayer*, const FloatPoint&); // GraphicsLayerClient interface virtual void notifyAnimationStarted(const GraphicsLayer*, double startTime); + virtual void notifySyncRequired(const GraphicsLayer*); virtual void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const IntRect& clip); - virtual IntRect contentsBox(const GraphicsLayer*); + IntRect contentsBox() const; private: void createGraphicsLayer(); @@ -118,9 +126,9 @@ private: RenderLayerCompositor* compositor() const { return m_owningLayer->compositor(); } bool updateClippingLayers(bool needsAncestorClip, bool needsDescendantClip); - bool updateContentsLayer(bool needsContentsLayer); + bool updateForegroundLayer(bool needsForegroundLayer); - IntSize contentOffsetInCompostingLayer(); + IntSize contentOffsetInCompostingLayer() const; // Result is transform origin in pixels. FloatPoint3D computeTransformOrigin(const IntRect& borderBox) const; // Result is perspective origin in pixels. @@ -146,7 +154,7 @@ private: bool hasNonCompositingContent() const; void paintIntoLayer(RenderLayer* rootLayer, GraphicsContext*, const IntRect& paintDirtyRect, - bool haveTransparency, PaintRestriction paintRestriction, GraphicsLayerPaintingPhase, RenderObject* paintingRoot); + PaintRestriction paintRestriction, GraphicsLayerPaintingPhase, RenderObject* paintingRoot); static int graphicsLayerToCSSProperty(AnimatedPropertyID); static AnimatedPropertyID cssToGraphicsLayerProperty(int); @@ -156,13 +164,12 @@ private: GraphicsLayer* m_ancestorClippingLayer; // only used if we are clipped by an ancestor which is not a stacking context GraphicsLayer* m_graphicsLayer; - GraphicsLayer* m_contentsLayer; // only used in cases where we need to draw the foreground separately + GraphicsLayer* m_foregroundLayer; // only used in cases where we need to draw the foreground separately GraphicsLayer* m_clippingLayer; // only used if we have clipping on a stacking context, with compositing children - IntSize m_compositingContentOffset; + IntRect m_compositedBounds; - bool m_hasDirectlyCompositedContent: 1; - bool m_compositingContentOffsetDirty: 1; + bool m_hasDirectlyCompositedContent; }; } // namespace WebCore diff --git a/WebCore/rendering/RenderLayerCompositor.cpp b/WebCore/rendering/RenderLayerCompositor.cpp index fec3b1d..fb15800 100644 --- a/WebCore/rendering/RenderLayerCompositor.cpp +++ b/WebCore/rendering/RenderLayerCompositor.cpp @@ -38,7 +38,9 @@ #include "HitTestResult.h" #include "Page.h" #include "RenderLayerBacking.h" +#include "RenderVideo.h" #include "RenderView.h" +#include "Settings.h" #if PROFILE_LAYER_REBUILD #include <wtf/CurrentTime.h> @@ -58,34 +60,29 @@ namespace WebCore { struct CompositingState { CompositingState(RenderLayer* compAncestor) - : m_subtreeIsCompositing(false) - , m_compositingAncestor(compAncestor) + : m_compositingAncestor(compAncestor) + , m_subtreeIsCompositing(false) #ifndef NDEBUG , m_depth(0) #endif { } - bool m_subtreeIsCompositing; RenderLayer* m_compositingAncestor; + bool m_subtreeIsCompositing; #ifndef NDEBUG int m_depth; #endif }; -static TransformationMatrix flipTransform() -{ - TransformationMatrix flipper; - flipper.flipY(); - return flipper; -} - RenderLayerCompositor::RenderLayerCompositor(RenderView* renderView) : m_renderView(renderView) , m_rootPlatformLayer(0) + , m_hasAcceleratedCompositing(true) + , m_compositingConsultsOverlap(true) , m_compositing(false) , m_rootLayerAttached(false) - , m_compositingLayersNeedUpdate(false) + , m_compositingLayersNeedRebuild(false) #if PROFILE_LAYER_REBUILD , m_rootLayerUpdateCount(0) #endif // PROFILE_LAYER_REBUILD @@ -108,39 +105,52 @@ void RenderLayerCompositor::enableCompositingMode(bool enable /* = true */) // the empty root layer, which has minimal overhead. if (m_compositing) ensureRootPlatformLayer(); + else + destroyRootPlatformLayer(); } } -void RenderLayerCompositor::setCompositingLayersNeedUpdate(bool needUpdate) +void RenderLayerCompositor::cacheAcceleratedCompositingEnabledFlag() { - if (inCompositingMode()) { - if (!m_compositingLayersNeedUpdate && needUpdate) - scheduleViewUpdate(); + bool hasAcceleratedCompositing = false; + if (Settings* settings = m_renderView->document()->settings()) + hasAcceleratedCompositing = settings->acceleratedCompositingEnabled(); - m_compositingLayersNeedUpdate = needUpdate; - } + if (hasAcceleratedCompositing != m_hasAcceleratedCompositing) + setCompositingLayersNeedRebuild(); + + m_hasAcceleratedCompositing = hasAcceleratedCompositing; +} + +void RenderLayerCompositor::setCompositingLayersNeedRebuild(bool needRebuild) +{ + if (inCompositingMode()) + m_compositingLayersNeedRebuild = needRebuild; } -void RenderLayerCompositor::scheduleViewUpdate() +void RenderLayerCompositor::scheduleSync() { Frame* frame = m_renderView->frameView()->frame(); Page* page = frame ? frame->page() : 0; if (!page) return; - page->chrome()->client()->scheduleViewUpdate(); + page->chrome()->client()->scheduleCompositingLayerSync(); } void RenderLayerCompositor::updateCompositingLayers(RenderLayer* updateRoot) { - if (!m_compositingLayersNeedUpdate) + // When m_compositingConsultsOverlap is true, then layer positions affect compositing, + // so we can only bail here when we're not looking at overlap. + if (!m_compositingLayersNeedRebuild && !m_compositingConsultsOverlap) return; ASSERT(inCompositingMode()); + bool needLayerRebuild = m_compositingLayersNeedRebuild; if (!updateRoot) { - // Only clear the flag if we're updating the entire hierarchy - m_compositingLayersNeedUpdate = false; + // Only clear the flag if we're updating the entire hierarchy. + m_compositingLayersNeedRebuild = false; updateRoot = rootRenderLayer(); } @@ -156,13 +166,20 @@ void RenderLayerCompositor::updateCompositingLayers(RenderLayer* updateRoot) // complex. { CompositingState compState(updateRoot); - computeCompositingRequirements(updateRoot, compState); + bool layersChanged; + if (m_compositingConsultsOverlap) { + OverlapMap overlapTestRequestMap; + computeCompositingRequirements(updateRoot, &overlapTestRequestMap, compState, layersChanged); + } else + computeCompositingRequirements(updateRoot, 0, compState, layersChanged); + + needLayerRebuild |= layersChanged; } // Now create and parent the compositing layers. { CompositingState compState(updateRoot); - rebuildCompositingLayerTree(updateRoot, compState); + rebuildCompositingLayerTree(updateRoot, compState, needLayerRebuild); } #if PROFILE_LAYER_REBUILD @@ -171,16 +188,23 @@ void RenderLayerCompositor::updateCompositingLayers(RenderLayer* updateRoot) fprintf(stderr, "Update %d: computeCompositingRequirements for the world took %fms\n", m_rootLayerUpdateCount, 1000.0 * (endTime - startTime)); #endif - ASSERT(updateRoot || !m_compositingLayersNeedUpdate); + ASSERT(updateRoot || !m_compositingLayersNeedRebuild); + + if (!hasAcceleratedCompositing()) + enableCompositingMode(false); } -bool RenderLayerCompositor::updateLayerCompositingState(RenderLayer* layer, CompositingChangeRepaint shouldRepaint) +bool RenderLayerCompositor::updateBacking(RenderLayer* layer, CompositingChangeRepaint shouldRepaint) { - bool needsLayer = needsToBeComposited(layer); bool layerChanged = false; - if (needsLayer) { + if (needsToBeComposited(layer)) { enableCompositingMode(); + + // 3D transforms turn off the testing of overlap. + if (requiresCompositingForTransform(layer->renderer())) + setCompositingConsultsOverlap(false); + if (!layer->backing()) { // If we need to repaint, do so before making backing @@ -195,12 +219,30 @@ bool RenderLayerCompositor::updateLayerCompositingState(RenderLayer* layer, Comp layer->clearBacking(); layerChanged = true; + // The layer's cached repaints rects are relative to the repaint container, so change when + // compositing changes; we need to update them here. + layer->computeRepaintRects(); + // If we need to repaint, do so now that we've removed the backing if (shouldRepaint == CompositingChangeRepaintNow) repaintOnCompositingChange(layer); } } +#if ENABLE(VIDEO) + if (layerChanged && layer->renderer()->isVideo()) { + // If it's a video, give the media player a chance to hook up to the layer. + RenderVideo* video = toRenderVideo(layer->renderer()); + video->acceleratedRenderingStateChanged(); + } +#endif + return layerChanged; +} + +bool RenderLayerCompositor::updateLayerCompositingState(RenderLayer* layer, CompositingChangeRepaint shouldRepaint) +{ + bool layerChanged = updateBacking(layer, shouldRepaint); + // See if we need content or clipping layers. Methods called here should assume // that the compositing state of descendant layers has not been updated yet. if (layer->backing() && layer->backing()->updateGraphicsLayerConfiguration()) @@ -211,6 +253,10 @@ bool RenderLayerCompositor::updateLayerCompositingState(RenderLayer* layer, Comp void RenderLayerCompositor::repaintOnCompositingChange(RenderLayer* layer) { + // If the renderer is not attached yet, no need to repaint. + if (!layer->renderer()->parent()) + return; + RenderBoxModelObject* repaintContainer = layer->renderer()->containerForRepaint(); if (!repaintContainer) repaintContainer = m_renderView; @@ -226,17 +272,27 @@ void RenderLayerCompositor::repaintOnCompositingChange(RenderLayer* layer) // The bounds of the GraphicsLayer created for a compositing layer is the union of the bounds of all the descendant // RenderLayers that are rendered by the composited RenderLayer. -IntRect RenderLayerCompositor::calculateCompositedBounds(const RenderLayer* layer, const RenderLayer* ancestorLayer, IntRect* layerBoundingBox) +IntRect RenderLayerCompositor::calculateCompositedBounds(const RenderLayer* layer, const RenderLayer* ancestorLayer) { + if (!layer->isSelfPaintingLayer()) + return IntRect(); + IntRect boundingBoxRect, unionBounds; boundingBoxRect = unionBounds = layer->localBoundingBox(); + if (layer->renderer()->hasOverflowClip() || layer->renderer()->hasMask()) { + int ancestorRelX = 0, ancestorRelY = 0; + layer->convertToLayerCoords(ancestorLayer, ancestorRelX, ancestorRelY); + boundingBoxRect.move(ancestorRelX, ancestorRelY); + return boundingBoxRect; + } + ASSERT(layer->isStackingContext() || (!layer->m_posZOrderList || layer->m_posZOrderList->size() == 0)); - Vector<RenderLayer*>* negZOrderList = layer->negZOrderList(); - if (negZOrderList) { - for (Vector<RenderLayer*>::iterator it = negZOrderList->begin(); it != negZOrderList->end(); ++it) { - RenderLayer* curLayer = (*it); + if (Vector<RenderLayer*>* negZOrderList = layer->negZOrderList()) { + size_t listSize = negZOrderList->size(); + for (size_t i = 0; i < listSize; ++i) { + RenderLayer* curLayer = negZOrderList->at(i); if (!curLayer->isComposited()) { IntRect childUnionBounds = calculateCompositedBounds(curLayer, layer); unionBounds.unite(childUnionBounds); @@ -244,10 +300,10 @@ IntRect RenderLayerCompositor::calculateCompositedBounds(const RenderLayer* laye } } - Vector<RenderLayer*>* posZOrderList = layer->posZOrderList(); - if (posZOrderList) { - for (Vector<RenderLayer*>::iterator it = posZOrderList->begin(); it != posZOrderList->end(); ++it) { - RenderLayer* curLayer = (*it); + if (Vector<RenderLayer*>* posZOrderList = layer->posZOrderList()) { + size_t listSize = posZOrderList->size(); + for (size_t i = 0; i < listSize; ++i) { + RenderLayer* curLayer = posZOrderList->at(i); if (!curLayer->isComposited()) { IntRect childUnionBounds = calculateCompositedBounds(curLayer, layer); unionBounds.unite(childUnionBounds); @@ -255,10 +311,10 @@ IntRect RenderLayerCompositor::calculateCompositedBounds(const RenderLayer* laye } } - Vector<RenderLayer*>* normalFlowList = layer->normalFlowList(); - if (normalFlowList) { - for (Vector<RenderLayer*>::iterator it = normalFlowList->begin(); it != normalFlowList->end(); ++it) { - RenderLayer* curLayer = (*it); + if (Vector<RenderLayer*>* normalFlowList = layer->normalFlowList()) { + size_t listSize = normalFlowList->size(); + for (size_t i = 0; i < listSize; ++i) { + RenderLayer* curLayer = normalFlowList->at(i); if (!curLayer->isComposited()) { IntRect curAbsBounds = calculateCompositedBounds(curLayer, layer); unionBounds.unite(curAbsBounds); @@ -276,39 +332,38 @@ IntRect RenderLayerCompositor::calculateCompositedBounds(const RenderLayer* laye layer->convertToLayerCoords(ancestorLayer, ancestorRelX, ancestorRelY); unionBounds.move(ancestorRelX, ancestorRelY); - if (layerBoundingBox) { - boundingBoxRect.move(ancestorRelX, ancestorRelY); - *layerBoundingBox = boundingBoxRect; - } - return unionBounds; } void RenderLayerCompositor::layerWasAdded(RenderLayer* /*parent*/, RenderLayer* /*child*/) { - setCompositingLayersNeedUpdate(); + setCompositingLayersNeedRebuild(); } void RenderLayerCompositor::layerWillBeRemoved(RenderLayer* parent, RenderLayer* child) { - if (child->isComposited()) - setCompositingParent(child, 0); - - // If the document is being torn down (document's renderer() is null), then there's - // no need to do any layer updating. - if (parent->renderer()->documentBeingDestroyed()) + if (!child->isComposited() || parent->renderer()->documentBeingDestroyed()) return; + setCompositingParent(child, 0); + RenderLayer* compLayer = parent->enclosingCompositingLayer(); if (compLayer) { - IntRect ancestorRect = calculateCompositedBounds(child, compLayer); - compLayer->setBackingNeedsRepaintInRect(ancestorRect); + ASSERT(compLayer->backing()); + IntRect compBounds = child->backing()->compositedBounds(); + + int offsetX = 0, offsetY = 0; + child->convertToLayerCoords(compLayer, offsetX, offsetY); + compBounds.move(offsetX, offsetY); + + compLayer->setBackingNeedsRepaintInRect(compBounds); + // The contents of this layer may be moving from a GraphicsLayer to the window, // so we need to make sure the window system synchronizes those changes on the screen. m_renderView->frameView()->setNeedsOneShotDrawingSynchronization(); } - setCompositingLayersNeedUpdate(); + setCompositingLayersNeedRebuild(); } RenderLayer* RenderLayerCompositor::enclosingNonStackingClippingLayer(const RenderLayer* layer) const @@ -323,6 +378,31 @@ RenderLayer* RenderLayerCompositor::enclosingNonStackingClippingLayer(const Rend return 0; } +void RenderLayerCompositor::addToOverlapMap(OverlapMap& overlapMap, RenderLayer* layer, IntRect& layerBounds, bool& boundsComputed) +{ + if (layer->isRootLayer()) + return; + + if (!boundsComputed) { + layerBounds = layer->renderer()->localToAbsoluteQuad(FloatRect(layer->localBoundingBox())).enclosingBoundingBox(); + boundsComputed = true; + } + + overlapMap.add(layer, layerBounds); +} + +bool RenderLayerCompositor::overlapsCompositedLayers(OverlapMap& overlapMap, const IntRect& layerBounds) +{ + RenderLayerCompositor::OverlapMap::const_iterator end = overlapMap.end(); + for (RenderLayerCompositor::OverlapMap::const_iterator it = overlapMap.begin(); it != end; ++it) { + const IntRect& bounds = it->second; + if (layerBounds.intersects(bounds)) + return true; + } + + return false; +} + // Recurse through the layers in z-index and overflow order (which is equivalent to painting order) // For the z-order children of a compositing layer: // If a child layers has a compositing layer, then all subsequent layers must @@ -332,7 +412,7 @@ RenderLayer* RenderLayerCompositor::enclosingNonStackingClippingLayer(const Rend // must be compositing so that its contents render over that child. // This implies that its positive z-index children must also be compositing. // -void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, struct CompositingState& ioCompState) +void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, OverlapMap* overlapMap, struct CompositingState& compositingState, bool& layersChanged) { layer->updateLayerPosition(); layer->updateZOrderLists(); @@ -340,61 +420,82 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, s // Clear the flag layer->setHasCompositingDescendant(false); - layer->setMustOverlayCompositedLayers(ioCompState.m_subtreeIsCompositing); - const bool willBeComposited = needsToBeComposited(layer); - // If we are going to become composited, repaint the old rendering destination - if (!layer->isComposited() && willBeComposited) - repaintOnCompositingChange(layer); + bool mustOverlapCompositedLayers = compositingState.m_subtreeIsCompositing; - ioCompState.m_subtreeIsCompositing = willBeComposited; + bool haveComputedBounds = false; + IntRect absBounds; + if (overlapMap && mustOverlapCompositedLayers) { + // If we're testing for overlap, we only need to composite if we overlap something that is already composited. + absBounds = layer->renderer()->localToAbsoluteQuad(FloatRect(layer->localBoundingBox())).enclosingBoundingBox(); + haveComputedBounds = true; + mustOverlapCompositedLayers &= overlapsCompositedLayers(*overlapMap, absBounds); + } + + layer->setMustOverlapCompositedLayers(mustOverlapCompositedLayers); + + // The children of this layer don't need to composite, unless there is + // a compositing layer among them, so start by inheriting the compositing + // ancestor with m_subtreeIsCompositing set to false. + CompositingState childState(compositingState.m_compositingAncestor); +#ifndef NDEBUG + ++childState.m_depth; +#endif - CompositingState childState = ioCompState; - if (willBeComposited) + const bool willBeComposited = needsToBeComposited(layer); + if (willBeComposited) { + // Tell the parent it has compositing descendants. + compositingState.m_subtreeIsCompositing = true; + // This layer now acts as the ancestor for kids. childState.m_compositingAncestor = layer; + if (overlapMap) + addToOverlapMap(*overlapMap, layer, absBounds, haveComputedBounds); + } - // The children of this stacking context don't need to composite, unless there is - // a compositing layer among them, so start by assuming false. - childState.m_subtreeIsCompositing = false; - -#ifndef NDEBUG - ++childState.m_depth; +#if ENABLE(VIDEO) + // Video is special. It's a replaced element with a content layer, but has shadow content + // for the controller that must render in front. Without this, the controls fail to show + // when the video element is a stacking context (e.g. due to opacity or transform). + if (willBeComposited && layer->renderer()->isVideo()) + childState.m_subtreeIsCompositing = true; #endif if (layer->isStackingContext()) { ASSERT(!layer->m_zOrderListsDirty); - Vector<RenderLayer*>* negZOrderList = layer->negZOrderList(); - if (negZOrderList && negZOrderList->size() > 0) { - for (Vector<RenderLayer*>::const_iterator it = negZOrderList->begin(); it != negZOrderList->end(); ++it) { - RenderLayer* curLayer = (*it); - computeCompositingRequirements(curLayer, childState); - - // if we have to make a layer for this child, make one now so we can have a contents layer - // (since we need to ensure that the -ve z-order child renders underneath our contents) + if (Vector<RenderLayer*>* negZOrderList = layer->negZOrderList()) { + size_t listSize = negZOrderList->size(); + for (size_t i = 0; i < listSize; ++i) { + RenderLayer* curLayer = negZOrderList->at(i); + computeCompositingRequirements(curLayer, overlapMap, childState, layersChanged); + + // If we have to make a layer for this child, make one now so we can have a contents layer + // (since we need to ensure that the -ve z-order child renders underneath our contents). if (childState.m_subtreeIsCompositing) { - // make |this| compositing - layer->setMustOverlayCompositedLayers(true); + // make layer compositing + layer->setMustOverlapCompositedLayers(true); childState.m_compositingAncestor = layer; + if (overlapMap) + addToOverlapMap(*overlapMap, layer, absBounds, haveComputedBounds); } } } } ASSERT(!layer->m_normalFlowListDirty); - Vector<RenderLayer*>* normalFlowList = layer->normalFlowList(); - if (normalFlowList && normalFlowList->size() > 0) { - for (Vector<RenderLayer*>::const_iterator it = normalFlowList->begin(); it != normalFlowList->end(); ++it) { - RenderLayer* curLayer = (*it); - computeCompositingRequirements(curLayer, childState); + if (Vector<RenderLayer*>* normalFlowList = layer->normalFlowList()) { + size_t listSize = normalFlowList->size(); + for (size_t i = 0; i < listSize; ++i) { + RenderLayer* curLayer = normalFlowList->at(i); + computeCompositingRequirements(curLayer, overlapMap, childState, layersChanged); } } if (layer->isStackingContext()) { - Vector<RenderLayer*>* posZOrderList = layer->posZOrderList(); - if (posZOrderList && posZOrderList->size() > 0) { - for (Vector<RenderLayer*>::const_iterator it = posZOrderList->begin(); it != posZOrderList->end(); ++it) { - RenderLayer* curLayer = (*it); - computeCompositingRequirements(curLayer, childState); + if (Vector<RenderLayer*>* posZOrderList = layer->posZOrderList()) { + size_t listSize = posZOrderList->size(); + for (size_t i = 0; i < listSize; ++i) { + RenderLayer* curLayer = posZOrderList->at(i); + computeCompositingRequirements(curLayer, overlapMap, childState, layersChanged); } } } @@ -403,24 +504,40 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, s // be composited. Also, if we have opacity < 1, then we need to be a layer so that // the child layers are opaque, then rendered with opacity on this layer. if (childState.m_subtreeIsCompositing && - (layer->renderer()->hasTransform() || layer->renderer()->style()->opacity() < 1)) - layer->setMustOverlayCompositedLayers(true); + (layer->renderer()->hasTransform() || layer->renderer()->style()->opacity() < 1)) { + layer->setMustOverlapCompositedLayers(true); + if (overlapMap) + addToOverlapMap(*overlapMap, layer, absBounds, haveComputedBounds); + } // Subsequent layers in the parent stacking context also need to composite. if (childState.m_subtreeIsCompositing) - ioCompState.m_subtreeIsCompositing = true; + compositingState.m_subtreeIsCompositing = true; + + // If the layer is going into compositing mode, repaint its old location. + if (!layer->isComposited() && needsToBeComposited(layer)) + repaintOnCompositingChange(layer); // Set the flag to say that this SC has compositing children. // this can affect the answer to needsToBeComposited() when clipping, // but that's ok here. layer->setHasCompositingDescendant(childState.m_subtreeIsCompositing); + + // Update backing now, so that we can use isComposited() reliably during tree traversal in rebuildCompositingLayerTree(). + if (updateBacking(layer, CompositingChangeRepaintNow)) + layersChanged = true; } void RenderLayerCompositor::setCompositingParent(RenderLayer* childLayer, RenderLayer* parentLayer) { ASSERT(childLayer->isComposited()); - ASSERT(!parentLayer || parentLayer->isComposited()); - + + // It's possible to be called with a parent that isn't yet composited when we're doing + // partial updates as required by painting or hit testing. Just bail in that case; + // we'll do a full layer update soon. + if (!parentLayer || !parentLayer->isComposited()) + return; + if (parentLayer) { GraphicsLayer* hostingLayer = parentLayer->backing()->parentForSublayers(); GraphicsLayer* hostedLayer = childLayer->backing()->childForSuperlayers(); @@ -451,20 +568,45 @@ void RenderLayerCompositor::parentInRootLayer(RenderLayer* layer) } } -void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, struct CompositingState& ioCompState) +#if ENABLE(VIDEO) +bool RenderLayerCompositor::canAccelerateVideoRendering(RenderVideo* o) const { - bool wasComposited = layer->isComposited(); + // FIXME: ideally we need to look at all ancestors for mask or video. But for now, + // just bail on the obvious cases. + if (o->hasMask() || o->hasReflection() || !m_hasAcceleratedCompositing) + return false; + + return o->supportsAcceleratedRendering(); +} +#endif +void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, struct CompositingState& compositingState, bool updateHierarchy) +{ // Make the layer compositing if necessary, and set up clipping and content layers. // Note that we can only do work here that is independent of whether the descendant layers // have been processed. computeCompositingRequirements() will already have done the repaint if necessary. - updateLayerCompositingState(layer, CompositingChangeWillRepaintLater); + RenderLayerBacking* layerBacking = layer->backing(); + if (layerBacking) { + // The compositing state of all our children has been updated already, so now + // we can compute and cache the composited bounds for this layer. + layerBacking->setCompositedBounds(calculateCompositedBounds(layer, layer)); + + layerBacking->updateGraphicsLayerConfiguration(); + layerBacking->updateGraphicsLayerGeometry(); + + if (!layer->parent()) + updateRootLayerPosition(); + + // FIXME: make this more incremental + if (updateHierarchy) + layerBacking->parentForSublayers()->removeAllChildren(); + } // host the document layer in the RenderView's root layer - if (layer->isRootLayer()) + if (updateHierarchy && layer->isRootLayer() && layer->isComposited()) parentInRootLayer(layer); - CompositingState childState = ioCompState; + CompositingState childState = compositingState; if (layer->isComposited()) childState.m_compositingAncestor = layer; @@ -472,14 +614,6 @@ void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, stru ++childState.m_depth; #endif - RenderLayerBacking* layerBacking = layer->backing(); - - // FIXME: make this more incremental - if (layerBacking) { - layerBacking->parentForSublayers()->removeAllChildren(); - layerBacking->updateInternalHierarchy(); - } - // The children of this stacking context don't need to composite, unless there is // a compositing layer among them, so start by assuming false. childState.m_subtreeIsCompositing = false; @@ -487,58 +621,89 @@ void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, stru if (layer->isStackingContext()) { ASSERT(!layer->m_zOrderListsDirty); - Vector<RenderLayer*>* negZOrderList = layer->negZOrderList(); - if (negZOrderList && negZOrderList->size() > 0) { - for (Vector<RenderLayer*>::const_iterator it = negZOrderList->begin(); it != negZOrderList->end(); ++it) { - RenderLayer* curLayer = (*it); - rebuildCompositingLayerTree(curLayer, childState); - if (curLayer->isComposited()) + if (Vector<RenderLayer*>* negZOrderList = layer->negZOrderList()) { + size_t listSize = negZOrderList->size(); + for (size_t i = 0; i < listSize; ++i) { + RenderLayer* curLayer = negZOrderList->at(i); + rebuildCompositingLayerTree(curLayer, childState, updateHierarchy); + if (updateHierarchy && curLayer->isComposited()) setCompositingParent(curLayer, childState.m_compositingAncestor); } } - if (layerBacking && layerBacking->contentsLayer()) { + if (updateHierarchy && layerBacking && layerBacking->foregroundLayer()) { // we only have a contents layer if we have an m_layer - layerBacking->contentsLayer()->removeFromParent(); + layerBacking->foregroundLayer()->removeFromParent(); GraphicsLayer* hostingLayer = layerBacking->clippingLayer() ? layerBacking->clippingLayer() : layerBacking->graphicsLayer(); - hostingLayer->addChild(layerBacking->contentsLayer()); + hostingLayer->addChild(layerBacking->foregroundLayer()); } } ASSERT(!layer->m_normalFlowListDirty); - Vector<RenderLayer*>* normalFlowList = layer->normalFlowList(); - if (normalFlowList && normalFlowList->size() > 0) { - for (Vector<RenderLayer*>::iterator it = normalFlowList->begin(); it != normalFlowList->end(); ++it) { - RenderLayer* curLayer = (*it); - rebuildCompositingLayerTree(curLayer, childState); - if (curLayer->isComposited()) + if (Vector<RenderLayer*>* normalFlowList = layer->normalFlowList()) { + size_t listSize = normalFlowList->size(); + for (size_t i = 0; i < listSize; ++i) { + RenderLayer* curLayer = normalFlowList->at(i); + rebuildCompositingLayerTree(curLayer, childState, updateHierarchy); + if (updateHierarchy && curLayer->isComposited()) setCompositingParent(curLayer, childState.m_compositingAncestor); } } if (layer->isStackingContext()) { - Vector<RenderLayer*>* posZOrderList = layer->posZOrderList(); - if (posZOrderList && posZOrderList->size() > 0) { - for (Vector<RenderLayer*>::const_iterator it = posZOrderList->begin(); it != posZOrderList->end(); ++it) { - RenderLayer* curLayer = (*it); - rebuildCompositingLayerTree(curLayer, childState); - if (curLayer->isComposited()) + if (Vector<RenderLayer*>* posZOrderList = layer->posZOrderList()) { + size_t listSize = posZOrderList->size(); + for (size_t i = 0; i < listSize; ++i) { + RenderLayer* curLayer = posZOrderList->at(i); + rebuildCompositingLayerTree(curLayer, childState, updateHierarchy); + if (updateHierarchy && curLayer->isComposited()) setCompositingParent(curLayer, childState.m_compositingAncestor); } } } +} + + +// Recurs down the RenderLayer tree until its finds the compositing descendants of compositingAncestor and updates their geometry. +void RenderLayerCompositor::updateCompositingDescendantGeometry(RenderLayer* compositingAncestor, RenderLayer* layer, RenderLayerBacking::UpdateDepth updateDepth) +{ + if (layer != compositingAncestor) { + if (RenderLayerBacking* layerBacking = layer->backing()) { + layerBacking->setCompositedBounds(calculateCompositedBounds(layer, layer)); + layerBacking->updateGraphicsLayerGeometry(); + if (updateDepth == RenderLayerBacking::CompositingChildren) + return; + } + } + + if (!layer->hasCompositingDescendant()) + return; - if (layerBacking) { - // Do work here that requires that we've processed all of the descendant layers - layerBacking->updateGraphicsLayerGeometry(); - } else if (wasComposited) { - // We stopped being a compositing layer. Now that our descendants have been udated, we can - // repaint our new rendering destination. - repaintOnCompositingChange(layer); + if (layer->isStackingContext()) { + if (Vector<RenderLayer*>* negZOrderList = layer->negZOrderList()) { + size_t listSize = negZOrderList->size(); + for (size_t i = 0; i < listSize; ++i) + updateCompositingDescendantGeometry(compositingAncestor, negZOrderList->at(i), updateDepth); + } + } + + if (Vector<RenderLayer*>* normalFlowList = layer->normalFlowList()) { + size_t listSize = normalFlowList->size(); + for (size_t i = 0; i < listSize; ++i) + updateCompositingDescendantGeometry(compositingAncestor, normalFlowList->at(i), updateDepth); + } + + if (layer->isStackingContext()) { + if (Vector<RenderLayer*>* posZOrderList = layer->posZOrderList()) { + size_t listSize = posZOrderList->size(); + for (size_t i = 0; i < listSize; ++i) + updateCompositingDescendantGeometry(compositingAncestor, posZOrderList->at(i), updateDepth); + } } } + void RenderLayerCompositor::repaintCompositedLayersAbsoluteRect(const IntRect& absRect) { recursiveRepaintLayerRect(rootRenderLayer(), absRect); @@ -550,10 +715,10 @@ void RenderLayerCompositor::recursiveRepaintLayerRect(RenderLayer* layer, const layer->setBackingNeedsRepaintInRect(rect); if (layer->hasCompositingDescendant()) { - Vector<RenderLayer*>* negZOrderList = layer->negZOrderList(); - if (negZOrderList) { - for (Vector<RenderLayer*>::iterator it = negZOrderList->begin(); it != negZOrderList->end(); ++it) { - RenderLayer* curLayer = (*it); + if (Vector<RenderLayer*>* negZOrderList = layer->negZOrderList()) { + size_t listSize = negZOrderList->size(); + for (size_t i = 0; i < listSize; ++i) { + RenderLayer* curLayer = negZOrderList->at(i); int x = 0, y = 0; curLayer->convertToLayerCoords(layer, x, y); IntRect childRect(rect); @@ -562,10 +727,10 @@ void RenderLayerCompositor::recursiveRepaintLayerRect(RenderLayer* layer, const } } - Vector<RenderLayer*>* posZOrderList = layer->posZOrderList(); - if (posZOrderList) { - for (Vector<RenderLayer*>::iterator it = posZOrderList->begin(); it != posZOrderList->end(); ++it) { - RenderLayer* curLayer = (*it); + if (Vector<RenderLayer*>* posZOrderList = layer->posZOrderList()) { + size_t listSize = posZOrderList->size(); + for (size_t i = 0; i < listSize; ++i) { + RenderLayer* curLayer = posZOrderList->at(i); int x = 0, y = 0; curLayer->convertToLayerCoords(layer, x, y); IntRect childRect(rect); @@ -573,17 +738,16 @@ void RenderLayerCompositor::recursiveRepaintLayerRect(RenderLayer* layer, const recursiveRepaintLayerRect(curLayer, childRect); } } - - Vector<RenderLayer*>* normalFlowList = layer->normalFlowList(); - if (normalFlowList) { - for (Vector<RenderLayer*>::iterator it = normalFlowList->begin(); it != normalFlowList->end(); ++it) { - RenderLayer* curLayer = (*it); - int x = 0, y = 0; - curLayer->convertToLayerCoords(layer, x, y); - IntRect childRect(rect); - childRect.move(-x, -y); - recursiveRepaintLayerRect(curLayer, childRect); - } + } + if (Vector<RenderLayer*>* normalFlowList = layer->normalFlowList()) { + size_t listSize = normalFlowList->size(); + for (size_t i = 0; i < listSize; ++i) { + RenderLayer* curLayer = normalFlowList->at(i); + int x = 0, y = 0; + curLayer->convertToLayerCoords(layer, x, y); + IntRect childRect(rect); + childRect.move(-x, -y); + recursiveRepaintLayerRect(curLayer, childRect); } } } @@ -629,7 +793,15 @@ void RenderLayerCompositor::willMoveOffscreen() void RenderLayerCompositor::updateRootLayerPosition() { if (m_rootPlatformLayer) - m_rootPlatformLayer->setSize(FloatSize(m_renderView->docWidth(), m_renderView->docHeight())); + m_rootPlatformLayer->setSize(FloatSize(m_renderView->overflowWidth(), m_renderView->overflowHeight())); +} + +void RenderLayerCompositor::didStartAcceleratedAnimation() +{ + // If an accelerated animation or transition runs, we have to turn off overlap checking because + // we don't do layout for every frame, but we have to ensure that the layering is + // correct between the animating object and other objects on the page. + setCompositingConsultsOverlap(false); } bool RenderLayerCompositor::has3DContent() const @@ -639,52 +811,21 @@ bool RenderLayerCompositor::has3DContent() const bool RenderLayerCompositor::needsToBeComposited(const RenderLayer* layer) const { - return requiresCompositingLayer(layer) || layer->mustOverlayCompositedLayers(); -} + if (!m_hasAcceleratedCompositing || !layer->isSelfPaintingLayer()) + return false; -#define VERBOSE_COMPOSITINGLAYER 0 + return requiresCompositingLayer(layer) || layer->mustOverlapCompositedLayers(); +} // Note: this specifies whether the RL needs a compositing layer for intrinsic reasons. // Use needsToBeComposited() to determine if a RL actually needs a compositing layer. // static bool RenderLayerCompositor::requiresCompositingLayer(const RenderLayer* layer) const { - // FIXME: cache the result of these tests? -#if VERBOSE_COMPOSITINGLAYER - bool gotReason = false; - - if (!gotReason && inCompositingMode() && layer->isRootLayer()) { - fprintf(stderr, "RenderLayer %p requires compositing layer because: it's the document root\n", layer); - gotReason = true; - } - - if (!gotReason && requiresCompositingForTransform(layer->renderer())) { - fprintf(stderr, "RenderLayer %p requires compositing layer because: it has 3d transform, perspective, backface, or animating transform\n", layer); - gotReason = true; - } - - if (!gotReason && layer->renderer()->style()->backfaceVisibility() == BackfaceVisibilityHidden) { - fprintf(stderr, "RenderLayer %p requires compositing layer because: it has backface-visibility: hidden\n", layer); - gotReason = true; - } - - if (!gotReason && clipsCompositingDescendants(layer)) { - fprintf(stderr, "RenderLayer %p requires compositing layer because: it has overflow clip\n", layer); - gotReason = true; - } - - if (!gotReason && requiresCompositingForAnimation(layer->renderer())) { - fprintf(stderr, "RenderLayer %p requires compositing layer because: it has a running transition for opacity or transform\n", layer); - gotReason = true; - } - - if (!gotReason) - fprintf(stderr, "RenderLayer %p does not require compositing layer\n", layer); -#endif - // The root layer always has a compositing layer, but it may not have backing. return (inCompositingMode() && layer->isRootLayer()) || requiresCompositingForTransform(layer->renderer()) || + requiresCompositingForVideo(layer->renderer()) || layer->renderer()->style()->backfaceVisibility() == BackfaceVisibilityHidden || clipsCompositingDescendants(layer) || requiresCompositingForAnimation(layer->renderer()); @@ -737,7 +878,7 @@ bool RenderLayerCompositor::clipsCompositingDescendants(const RenderLayer* layer layer->renderer()->hasOverflowClip(); } -bool RenderLayerCompositor::requiresCompositingForTransform(RenderObject* renderer) +bool RenderLayerCompositor::requiresCompositingForTransform(RenderObject* renderer) const { RenderStyle* style = renderer->style(); // Note that we ask the renderer if it has a transform, because the style may have transforms, @@ -745,12 +886,23 @@ bool RenderLayerCompositor::requiresCompositingForTransform(RenderObject* render return renderer->hasTransform() && (style->transform().has3DOperation() || style->transformStyle3D() == TransformStyle3DPreserve3D || style->hasPerspective()); } -bool RenderLayerCompositor::requiresCompositingForAnimation(RenderObject* renderer) +bool RenderLayerCompositor::requiresCompositingForVideo(RenderObject* renderer) const { - AnimationController* animController = renderer->animation(); - if (animController) - return animController->isAnimatingPropertyOnRenderer(renderer, CSSPropertyOpacity) || - animController->isAnimatingPropertyOnRenderer(renderer, CSSPropertyWebkitTransform); +#if ENABLE(VIDEO) + if (renderer->isVideo()) { + RenderVideo* video = toRenderVideo(renderer); + return canAccelerateVideoRendering(video); + } +#endif + return false; +} + +bool RenderLayerCompositor::requiresCompositingForAnimation(RenderObject* renderer) const +{ + if (AnimationController* animController = renderer->animation()) { + return (animController->isAnimatingPropertyOnRenderer(renderer, CSSPropertyOpacity) && inCompositingMode()) + || animController->isAnimatingPropertyOnRenderer(renderer, CSSPropertyWebkitTransform); + } return false; } @@ -768,11 +920,10 @@ void RenderLayerCompositor::ensureRootPlatformLayer() return; m_rootPlatformLayer = GraphicsLayer::createGraphicsLayer(0); - m_rootPlatformLayer->setSize(FloatSize(m_renderView->docWidth(), m_renderView->docHeight())); + m_rootPlatformLayer->setSize(FloatSize(m_renderView->overflowWidth(), m_renderView->overflowHeight())); m_rootPlatformLayer->setPosition(FloatPoint(0, 0)); - - if (GraphicsLayer::compositingCoordinatesOrientation() == GraphicsLayer::CompositingCoordinatesBottomUp) - m_rootPlatformLayer->setChildrenTransform(flipTransform()); + // The root layer does flipping if we need it on this platform. + m_rootPlatformLayer->setGeometryOrientation(GraphicsLayer::compositingCoordinatesOrientation()); // Need to clip to prevent transformed content showing outside this frame m_rootPlatformLayer->setMasksToBounds(true); @@ -780,6 +931,16 @@ void RenderLayerCompositor::ensureRootPlatformLayer() didMoveOnscreen(); } +void RenderLayerCompositor::destroyRootPlatformLayer() +{ + if (!m_rootPlatformLayer) + return; + + willMoveOffscreen(); + delete m_rootPlatformLayer; + m_rootPlatformLayer = 0; +} + bool RenderLayerCompositor::layerHas3DContent(const RenderLayer* layer) const { const RenderStyle* style = layer->renderer()->style(); @@ -791,29 +952,29 @@ bool RenderLayerCompositor::layerHas3DContent(const RenderLayer* layer) const return true; if (layer->isStackingContext()) { - Vector<RenderLayer*>* negZOrderList = layer->negZOrderList(); - if (negZOrderList) { - for (Vector<RenderLayer*>::iterator it = negZOrderList->begin(); it != negZOrderList->end(); ++it) { - RenderLayer* curLayer = (*it); + if (Vector<RenderLayer*>* negZOrderList = layer->negZOrderList()) { + size_t listSize = negZOrderList->size(); + for (size_t i = 0; i < listSize; ++i) { + RenderLayer* curLayer = negZOrderList->at(i); if (layerHas3DContent(curLayer)) return true; } } - Vector<RenderLayer*>* posZOrderList = layer->posZOrderList(); - if (posZOrderList) { - for (Vector<RenderLayer*>::iterator it = posZOrderList->begin(); it != posZOrderList->end(); ++it) { - RenderLayer* curLayer = (*it); + if (Vector<RenderLayer*>* posZOrderList = layer->posZOrderList()) { + size_t listSize = posZOrderList->size(); + for (size_t i = 0; i < listSize; ++i) { + RenderLayer* curLayer = posZOrderList->at(i); if (layerHas3DContent(curLayer)) return true; } } } - Vector<RenderLayer*>* normalFlowList = layer->normalFlowList(); - if (normalFlowList) { - for (Vector<RenderLayer*>::iterator it = normalFlowList->begin(); it != normalFlowList->end(); ++it) { - RenderLayer* curLayer = (*it); + if (Vector<RenderLayer*>* normalFlowList = layer->normalFlowList()) { + size_t listSize = normalFlowList->size(); + for (size_t i = 0; i < listSize; ++i) { + RenderLayer* curLayer = normalFlowList->at(i); if (layerHas3DContent(curLayer)) return true; } diff --git a/WebCore/rendering/RenderLayerCompositor.h b/WebCore/rendering/RenderLayerCompositor.h index 76cb35f..02929dc 100644 --- a/WebCore/rendering/RenderLayerCompositor.h +++ b/WebCore/rendering/RenderLayerCompositor.h @@ -27,12 +27,16 @@ #define RenderLayerCompositor_h #include "RenderLayer.h" +#include "RenderLayerBacking.h" namespace WebCore { #define PROFILE_LAYER_REBUILD 0 class GraphicsLayer; +#if ENABLE(VIDEO) +class RenderVideo; +#endif // RenderLayerCompositor manages the hierarchy of // composited RenderLayers. It determines which RenderLayers @@ -53,11 +57,24 @@ public: // This will make a compositing layer at the root automatically, and hook up to // the native view/window system. void enableCompositingMode(bool enable = true); - - void setCompositingLayersNeedUpdate(bool needUpdate = true); - bool compositingLayersNeedUpdate() const { return m_compositingLayersNeedUpdate; } - - void scheduleViewUpdate(); + + // Returns true if the accelerated compositing is enabled + bool hasAcceleratedCompositing() const { return m_hasAcceleratedCompositing; } + + // Copy the acceleratedCompositingEnabledFlag from Settings + void cacheAcceleratedCompositingEnabledFlag(); + + // Called when the layer hierarchy needs to be updated (compositing layers have been + // created, destroyed or re-parented). + void setCompositingLayersNeedRebuild(bool needRebuild = true); + bool compositingLayersNeedRebuild() const { return m_compositingLayersNeedRebuild; } + + // Controls whether or not to consult geometry when deciding which layers need + // to be composited. Defaults to true. + void setCompositingConsultsOverlap(bool b) { m_compositingConsultsOverlap = b; } + bool compositingConsultsOverlap() const { return m_compositingConsultsOverlap; } + + void scheduleSync(); // Rebuild the tree of compositing layers void updateCompositingLayers(RenderLayer* updateRoot = 0); @@ -66,6 +83,9 @@ public: enum CompositingChangeRepaint { CompositingChangeRepaintNow, CompositingChangeWillRepaintLater }; bool updateLayerCompositingState(RenderLayer*, CompositingChangeRepaint = CompositingChangeRepaintNow); + // Update the geometry for compositing children of compositingAncestor. + void updateCompositingDescendantGeometry(RenderLayer* compositingAncestor, RenderLayer* layer, RenderLayerBacking::UpdateDepth); + // Whether layer's backing needs a graphics layer to do clipping by an ancestor (non-stacking-context parent with overflow). bool clippedByAncestor(RenderLayer*) const; // Whether layer's backing needs a graphics layer to clip z-order children of the given layer. @@ -75,7 +95,7 @@ public: bool needsContentsCompositingLayer(const RenderLayer*) const; // Return the bounding box required for compositing layer and its childern, relative to ancestorLayer. // If layerBoundingBox is not 0, on return it contains the bounding box of this layer only. - IntRect calculateCompositedBounds(const RenderLayer* layer, const RenderLayer* ancestorLayer, IntRect* layerBoundingBox = 0); + IntRect calculateCompositedBounds(const RenderLayer* layer, const RenderLayer* ancestorLayer); // Repaint the appropriate layers when the given RenderLayer starts or stops being composited. void repaintOnCompositingChange(RenderLayer*); @@ -97,6 +117,13 @@ public: void willMoveOffscreen(); void updateRootLayerPosition(); + + void didStartAcceleratedAnimation(); + +#if ENABLE(VIDEO) + // Use by RenderVideo to ask if it should try to use accelerated compositing. + bool canAccelerateVideoRendering(RenderVideo*) const; +#endif // Walk the tree looking for layers with 3d transforms. Useful in case you need // to know if there is non-affine content, e.g. for drawing into an image. @@ -108,11 +135,19 @@ private: // Whether the layer has an intrinsic need for compositing layer. bool requiresCompositingLayer(const RenderLayer*) const; + // Make or destroy the backing for this layer; returns true if backing changed. + bool updateBacking(RenderLayer*, CompositingChangeRepaint shouldRepaint); + // Repaint the given rect (which is layer's coords), and regions of child layers that intersect that rect. void recursiveRepaintLayerRect(RenderLayer* layer, const IntRect& rect); - void computeCompositingRequirements(RenderLayer*, struct CompositingState&); - void rebuildCompositingLayerTree(RenderLayer* layer, struct CompositingState&); + typedef HashMap<RenderLayer*, IntRect> OverlapMap; + static void addToOverlapMap(OverlapMap&, RenderLayer*, IntRect& layerBounds, bool& boundsComputed); + static bool overlapsCompositedLayers(OverlapMap&, const IntRect& layerBounds); + + // Returns true if any layer's compositing changed + void computeCompositingRequirements(RenderLayer*, OverlapMap*, struct CompositingState&, bool& layersChanged); + void rebuildCompositingLayerTree(RenderLayer* layer, struct CompositingState&, bool updateHierarchy); // Hook compositing layers together void setCompositingParent(RenderLayer* childLayer, RenderLayer* parentLayer); @@ -123,17 +158,22 @@ private: bool layerHas3DContent(const RenderLayer*) const; void ensureRootPlatformLayer(); - + void destroyRootPlatformLayer(); + // Whether a running transition or animation enforces the need for a compositing layer. - static bool requiresCompositingForAnimation(RenderObject*); - static bool requiresCompositingForTransform(RenderObject*); + bool requiresCompositingForAnimation(RenderObject*) const; + bool requiresCompositingForTransform(RenderObject*) const; + bool requiresCompositingForVideo(RenderObject*) const; private: RenderView* m_renderView; GraphicsLayer* m_rootPlatformLayer; + bool m_hasAcceleratedCompositing; + bool m_compositingConsultsOverlap; bool m_compositing; bool m_rootLayerAttached; - bool m_compositingLayersNeedUpdate; + bool m_compositingLayersNeedRebuild; + #if PROFILE_LAYER_REBUILD int m_rootLayerUpdateCount; #endif diff --git a/WebCore/rendering/RenderListBox.cpp b/WebCore/rendering/RenderListBox.cpp index 83c569e..e6c28f7 100644 --- a/WebCore/rendering/RenderListBox.cpp +++ b/WebCore/rendering/RenderListBox.cpp @@ -370,7 +370,7 @@ bool RenderListBox::isPointInOverflowControl(HitTestResult& result, int _x, int return false; IntRect vertRect(_tx + width() - borderRight() - m_vBar->width(), - _ty, + _ty + borderTop(), m_vBar->width(), height() - borderTop() - borderBottom()); @@ -416,22 +416,22 @@ void RenderListBox::panScroll(const IntPoint& panStartMousePosition) int yDelta = currentMousePosition.y() - panStartMousePosition.y(); - // If the point is too far from the center we limit the speed + // If the point is too far from the center we limit the speed yDelta = max(min(yDelta, maxSpeed), -maxSpeed); - if(abs(yDelta) < iconRadius) // at the center we let the space for the icon + if (abs(yDelta) < iconRadius) // at the center we let the space for the icon return; if (yDelta > 0) //offsetY = view()->viewHeight(); absOffset.move(0, listHeight()); - else if (yDelta < 0) - yDelta--; + else if (yDelta < 0) + yDelta--; // Let's attenuate the speed yDelta /= speedReducer; - IntPoint scrollPoint(0,0); + IntPoint scrollPoint(0, 0); scrollPoint.setY(absOffset.y() + yDelta); int newOffset = scrollToward(scrollPoint); if (newOffset < 0) @@ -623,6 +623,64 @@ void RenderListBox::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& repaintRectangle(scrollRect); } +IntRect RenderListBox::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntRect& scrollbarRect) const +{ + RenderView* view = this->view(); + if (!view) + return scrollbarRect; + + IntRect rect = scrollbarRect; + + int scrollbarLeft = width() - borderRight() - scrollbar->width(); + int scrollbarTop = borderTop(); + rect.move(scrollbarLeft, scrollbarTop); + + return view->frameView()->convertFromRenderer(this, rect); +} + +IntRect RenderListBox::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntRect& parentRect) const +{ + RenderView* view = this->view(); + if (!view) + return parentRect; + + IntRect rect = view->frameView()->convertToRenderer(this, parentRect); + + int scrollbarLeft = width() - borderRight() - scrollbar->width(); + int scrollbarTop = borderTop(); + rect.move(-scrollbarLeft, -scrollbarTop); + return rect; +} + +IntPoint RenderListBox::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntPoint& scrollbarPoint) const +{ + RenderView* view = this->view(); + if (!view) + return scrollbarPoint; + + IntPoint point = scrollbarPoint; + + int scrollbarLeft = width() - borderRight() - scrollbar->width(); + int scrollbarTop = borderTop(); + point.move(scrollbarLeft, scrollbarTop); + + return view->frameView()->convertFromRenderer(this, point); +} + +IntPoint RenderListBox::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const +{ + RenderView* view = this->view(); + if (!view) + return parentPoint; + + IntPoint point = view->frameView()->convertToRenderer(this, parentPoint); + + int scrollbarLeft = width() - borderRight() - scrollbar->width(); + int scrollbarTop = borderTop(); + point.move(-scrollbarLeft, -scrollbarTop); + return point; +} + PassRefPtr<Scrollbar> RenderListBox::createScrollbar() { RefPtr<Scrollbar> widget; diff --git a/WebCore/rendering/RenderListBox.h b/WebCore/rendering/RenderListBox.h index b8c0540..e5454e5 100644 --- a/WebCore/rendering/RenderListBox.h +++ b/WebCore/rendering/RenderListBox.h @@ -1,7 +1,7 @@ /* * This file is part of the select element renderer in WebCore. * - * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -39,8 +39,21 @@ namespace WebCore { class RenderListBox : public RenderBlock, private ScrollbarClient { public: RenderListBox(Element*); - ~RenderListBox(); + virtual ~RenderListBox(); + void selectionChanged(); + + void setOptionsChanged(bool changed) { m_optionsChanged = changed; } + + int listIndexAtOffset(int x, int y); + IntRect itemBoundingBoxRect(int tx, int ty, int index); + + bool scrollToRevealElementAtListIndex(int index); + bool listIndexIsVisible(int index); + + int scrollToward(const IntPoint&); // Returns the new index or -1 if no scroll occurred + +private: virtual const char* renderName() const { return "RenderListBox"; } virtual bool isListBox() const { return true; } @@ -63,16 +76,6 @@ public: virtual void layout(); - void selectionChanged(); - - void setOptionsChanged(bool changed) { m_optionsChanged = changed; } - - int listIndexAtOffset(int x, int y); - IntRect itemBoundingBoxRect(int tx, int ty, int index); - - bool scrollToRevealElementAtListIndex(int index); - bool listIndexIsVisible(int index); - virtual bool canBeProgramaticallyScrolled(bool) const { return true; } virtual void autoscroll(); virtual void stopAutoscroll(); @@ -80,8 +83,6 @@ public: virtual bool shouldPanScroll() const { return true; } virtual void panScroll(const IntPoint&); - int scrollToward(const IntPoint&); // Returns the new index or -1 if no scroll occurred - virtual int verticalScrollbarWidth() const; virtual int scrollLeft() const; virtual int scrollTop() const; @@ -92,15 +93,17 @@ public: virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); -protected: virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); -private: // ScrollbarClient interface. virtual void valueChanged(Scrollbar*); virtual void invalidateScrollbarRect(Scrollbar*, const IntRect&); virtual bool isActive() const; virtual bool scrollbarCornerPresent() const { return false; } // We don't support resize on list boxes yet. If we did this would have to change. + virtual IntRect convertFromScrollbarToContainingView(const Scrollbar*, const IntRect&) const; + virtual IntRect convertFromContainingViewToScrollbar(const Scrollbar*, const IntRect&) const; + virtual IntPoint convertFromScrollbarToContainingView(const Scrollbar*, const IntPoint&) const; + virtual IntPoint convertFromContainingViewToScrollbar(const Scrollbar*, const IntPoint&) const; void setHasVerticalScrollbar(bool hasScrollbar); PassRefPtr<Scrollbar> createScrollbar(); @@ -126,6 +129,15 @@ private: RefPtr<Scrollbar> m_vBar; }; +inline RenderListBox* toRenderListBox(RenderObject* object) +{ + ASSERT(!object || object->isListBox()); + return static_cast<RenderListBox*>(object); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderListBox(const RenderListBox*); + } // namepace WebCore #endif // RenderListBox_h diff --git a/WebCore/rendering/RenderListItem.cpp b/WebCore/rendering/RenderListItem.cpp index fb965d2..374ef66 100644 --- a/WebCore/rendering/RenderListItem.cpp +++ b/WebCore/rendering/RenderListItem.cpp @@ -91,20 +91,20 @@ static Node* enclosingList(Node* node) static RenderListItem* previousListItem(Node* list, const RenderListItem* item) { - for (Node* n = item->node()->traversePreviousNode(); n != list; n = n->traversePreviousNode()) { - RenderObject* o = n->renderer(); - if (o && o->isListItem()) { - Node* otherList = enclosingList(n); - // This item is part of our current list, so it's what we're looking for. - if (list == otherList) - return static_cast<RenderListItem*>(o); - // We found ourself inside another list; lets skip the rest of it. - // Use traverseNextNode() here because the other list itself may actually - // be a list item itself. We need to examine it, so we do this to counteract - // the traversePreviousNode() that will be done by the loop. - if (otherList) - n = otherList->traverseNextNode(); - } + for (Node* node = item->node()->traversePreviousNode(); node != list; node = node->traversePreviousNode()) { + RenderObject* renderer = node->renderer(); + if (!renderer || !renderer->isListItem()) + continue; + Node* otherList = enclosingList(node); + // This item is part of our current list, so it's what we're looking for. + if (list == otherList) + return toRenderListItem(renderer); + // We found ourself inside another list; lets skip the rest of it. + // Use traverseNextNode() here because the other list itself may actually + // be a list item itself. We need to examine it, so we do this to counteract + // the traversePreviousNode() that will be done by the loop. + if (otherList) + node = otherList->traverseNextNode(); } return 0; } @@ -302,9 +302,9 @@ void RenderListItem::explicitValueChanged() RenderObject* listRenderer = 0; if (listNode) listRenderer = listNode->renderer(); - for (RenderObject* r = this; r; r = r->nextInPreOrder(listRenderer)) - if (r->isListItem()) { - RenderListItem* item = static_cast<RenderListItem*>(r); + for (RenderObject* renderer = this; renderer; renderer = renderer->nextInPreOrder(listRenderer)) + if (renderer->isListItem()) { + RenderListItem* item = toRenderListItem(renderer); if (!item->m_hasExplicitValue) { item->m_isValueUpToDate = false; if (RenderListMarker* marker = item->m_marker) diff --git a/WebCore/rendering/RenderListItem.h b/WebCore/rendering/RenderListItem.h index 91844f7..21544f9 100644 --- a/WebCore/rendering/RenderListItem.h +++ b/WebCore/rendering/RenderListItem.h @@ -1,7 +1,7 @@ /* * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) - * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 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 @@ -33,12 +33,6 @@ class RenderListItem : public RenderBlock { public: RenderListItem(Node*); - virtual const char* renderName() const { return "RenderListItem"; } - - virtual bool isListItem() const { return true; } - - virtual void destroy(); - int value() const { if (!m_isValueUpToDate) updateValueNow(); return m_value; } void updateValue(); @@ -47,6 +41,16 @@ public: void setExplicitValue(int value); void clearExplicitValue(); + void setNotInList(bool notInList) { m_notInList = notInList; } + bool notInList() const { return m_notInList; } + +private: + virtual const char* renderName() const { return "RenderListItem"; } + + virtual bool isListItem() const { return true; } + + virtual void destroy(); + virtual bool isEmpty() const; virtual void paint(PaintInfo&, int tx, int ty); @@ -55,15 +59,10 @@ public: virtual void positionListMarker(); - void setNotInList(bool notInList) { m_notInList = notInList; } - bool notInList() const { return m_notInList; } - const String& markerText() const; -protected: virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); -private: void updateMarkerLocation(); inline int calcValue() const; void updateValueNow() const; @@ -78,6 +77,15 @@ private: bool m_notInList : 1; }; +inline RenderListItem* toRenderListItem(RenderObject* object) +{ + ASSERT(!object || object->isListItem()); + return static_cast<RenderListItem*>(object); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderListItem(const RenderListItem*); + } // namespace WebCore #endif // RenderListItem_h diff --git a/WebCore/rendering/RenderListMarker.h b/WebCore/rendering/RenderListMarker.h index 57580a8..5b46278 100644 --- a/WebCore/rendering/RenderListMarker.h +++ b/WebCore/rendering/RenderListMarker.h @@ -1,7 +1,7 @@ /* * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) - * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 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 @@ -36,8 +36,15 @@ String listMarkerText(EListStyleType, int value); class RenderListMarker : public RenderBox { public: RenderListMarker(RenderListItem*); - ~RenderListMarker(); + virtual ~RenderListMarker(); + virtual void calcPrefWidths(); + + const String& text() const { return m_text; } + + bool isInside() const; + +private: virtual const char* renderName() const { return "RenderListMarker"; } virtual bool isListMarker() const { return true; } @@ -45,7 +52,6 @@ public: virtual void paint(PaintInfo&, int tx, int ty); virtual void layout(); - virtual void calcPrefWidths(); virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); @@ -56,9 +62,6 @@ public: bool isImage() const; bool isText() const { return !isImage(); } - const String& text() const { return m_text; } - - bool isInside() const; virtual void setSelectionState(SelectionState); virtual IntRect selectionRectForRepaint(RenderBoxModelObject* repaintContainer, bool clipToVisibleContent = true); @@ -66,11 +69,9 @@ public: void updateMargins(); -protected: virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle); virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); -private: IntRect getRelativeMarkerRect(); String m_text; @@ -78,6 +79,21 @@ private: RenderListItem* m_listItem; }; +inline RenderListMarker* toRenderListMarker(RenderObject* object) +{ + ASSERT(!object || object->isListMarker()); + return static_cast<RenderListMarker*>(object); +} + +inline const RenderListMarker* toRenderListMarker(const RenderObject* object) +{ + ASSERT(!object || object->isListMarker()); + return static_cast<const RenderListMarker*>(object); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderListMarker(const RenderListMarker*); + } // namespace WebCore #endif // RenderListMarker_h diff --git a/WebCore/rendering/RenderMarquee.cpp b/WebCore/rendering/RenderMarquee.cpp index 48659f7..31a8305 100644 --- a/WebCore/rendering/RenderMarquee.cpp +++ b/WebCore/rendering/RenderMarquee.cpp @@ -235,7 +235,7 @@ void RenderMarquee::updateMarqueeStyle() // to a marquee of 200px. if (isHorizontal()) { if (s->height().isFixed() && s->height().value() < s->fontSize()) - s->setHeight(Length(s->fontSize(),Fixed)); + s->setHeight(Length(s->fontSize(), Fixed)); } else if (s->height().isAuto()) //vertical marquee with no specified height s->setHeight(Length(200, Fixed)); @@ -309,4 +309,3 @@ void RenderMarquee::timerFired(Timer<RenderMarquee>*) } } // namespace WebCore - diff --git a/WebCore/rendering/RenderMedia.cpp b/WebCore/rendering/RenderMedia.cpp index 2ffa2f6..b87e99d 100644 --- a/WebCore/rendering/RenderMedia.cpp +++ b/WebCore/rendering/RenderMedia.cpp @@ -45,7 +45,8 @@ using namespace HTMLNames; static const double cTimeUpdateRepeatDelay = 0.2; static const double cOpacityAnimationRepeatDelay = 0.05; // FIXME get this from style -static const double cOpacityAnimationDuration = 0.1; +static const double cOpacityAnimationDurationFadeIn = 0.1; +static const double cOpacityAnimationDurationFadeOut = 0.3; RenderMedia::RenderMedia(HTMLMediaElement* video) : RenderReplaced(video) @@ -53,9 +54,9 @@ RenderMedia::RenderMedia(HTMLMediaElement* video) , m_opacityAnimationTimer(this, &RenderMedia::opacityAnimationTimerFired) , m_mouseOver(false) , m_opacityAnimationStartTime(0) + , m_opacityAnimationDuration(cOpacityAnimationDurationFadeIn) , m_opacityAnimationFrom(0) , m_opacityAnimationTo(1.0f) - , m_previousVisible(VISIBLE) { } @@ -65,6 +66,7 @@ RenderMedia::RenderMedia(HTMLMediaElement* video, const IntSize& intrinsicSize) , m_opacityAnimationTimer(this, &RenderMedia::opacityAnimationTimerFired) , m_mouseOver(false) , m_opacityAnimationStartTime(0) + , m_opacityAnimationDuration(cOpacityAnimationDurationFadeIn) , m_opacityAnimationFrom(0) , m_opacityAnimationTo(1.0f) { @@ -104,20 +106,32 @@ void RenderMedia::styleDidChange(StyleDifference diff, const RenderStyle* oldSty RenderReplaced::styleDidChange(diff, oldStyle); if (m_controlsShadowRoot) { - if (m_panel->renderer()) - m_panel->renderer()->setStyle(getCachedPseudoStyle(MEDIA_CONTROLS_PANEL)); - - if (m_timelineContainer->renderer()) - m_timelineContainer->renderer()->setStyle(getCachedPseudoStyle(MEDIA_CONTROLS_TIMELINE_CONTAINER)); - - m_muteButton->updateStyle(); - m_playButton->updateStyle(); - m_seekBackButton->updateStyle(); - m_seekForwardButton->updateStyle(); - m_timeline->updateStyle(); - m_fullscreenButton->updateStyle(); - m_currentTimeDisplay->updateStyle(); - m_timeRemainingDisplay->updateStyle(); + if (m_panel) + m_panel->updateStyle(); + if (m_muteButton) + m_muteButton->updateStyle(); + if (m_playButton) + m_playButton->updateStyle(); + if (m_seekBackButton) + m_seekBackButton->updateStyle(); + if (m_seekForwardButton) + m_seekForwardButton->updateStyle(); + if (m_rewindButton) + m_rewindButton->updateStyle(); + if (m_returnToRealtimeButton) + m_returnToRealtimeButton->updateStyle(); + if (m_statusDisplay) + m_statusDisplay->updateStyle(); + if (m_timelineContainer) + m_timelineContainer->updateStyle(); + if (m_timeline) + m_timeline->updateStyle(); + if (m_fullscreenButton) + m_fullscreenButton->updateStyle(); + if (m_currentTimeDisplay) + m_currentTimeDisplay->updateStyle(); + if (m_timeRemainingDisplay) + m_timeRemainingDisplay->updateStyle(); } } @@ -132,6 +146,13 @@ void RenderMedia::layout() return; IntSize newSize = contentBoxRect().size(); if (newSize != oldSize || controlsRenderer->needsLayout()) { + + if (m_currentTimeDisplay && m_timeRemainingDisplay) { + bool shouldShowTimeDisplays = shouldShowTimeDisplayControls(); + m_currentTimeDisplay->setVisible(shouldShowTimeDisplays); + m_timeRemainingDisplay->setVisible(shouldShowTimeDisplays); + } + controlsRenderer->setLocation(borderLeft() + paddingLeft(), borderTop() + paddingTop()); controlsRenderer->style()->setHeight(Length(newSize.height(), Fixed)); controlsRenderer->style()->setWidth(Length(newSize.width(), Fixed)); @@ -151,17 +172,8 @@ void RenderMedia::createControlsShadowRoot() void RenderMedia::createPanel() { ASSERT(!m_panel); - RenderStyle* style = getCachedPseudoStyle(MEDIA_CONTROLS_PANEL); - m_panel = new HTMLDivElement(HTMLNames::divTag, document()); - RenderObject* renderer = m_panel->createRenderer(renderArena(), style); - if (renderer) { - m_panel->setRenderer(renderer); - renderer->setStyle(style); - m_panel->setAttached(); - m_panel->setInDocument(true); - m_controlsShadowRoot->addChild(m_panel); - m_controlsShadowRoot->renderer()->addChild(renderer); - } + m_panel = new MediaControlElement(document(), MEDIA_CONTROLS_PANEL, mediaElement()); + m_panel->attachToParent(m_controlsShadowRoot.get()); } void RenderMedia::createMuteButton() @@ -192,20 +204,32 @@ void RenderMedia::createSeekForwardButton() m_seekForwardButton->attachToParent(m_panel.get()); } +void RenderMedia::createRewindButton() +{ + ASSERT(!m_rewindButton); + m_rewindButton = new MediaControlRewindButtonElement(document(), mediaElement()); + m_rewindButton->attachToParent(m_panel.get()); +} + +void RenderMedia::createReturnToRealtimeButton() +{ + ASSERT(!m_returnToRealtimeButton); + m_returnToRealtimeButton = new MediaControlReturnToRealtimeButtonElement(document(), mediaElement()); + m_returnToRealtimeButton->attachToParent(m_panel.get()); +} + +void RenderMedia::createStatusDisplay() +{ + ASSERT(!m_statusDisplay); + m_statusDisplay = new MediaControlStatusDisplayElement(document(), mediaElement()); + m_statusDisplay->attachToParent(m_panel.get()); +} + void RenderMedia::createTimelineContainer() { ASSERT(!m_timelineContainer); - RenderStyle* style = getCachedPseudoStyle(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); - } + m_timelineContainer = new MediaControlTimelineContainerElement(document(), mediaElement()); + m_timelineContainer->attachToParent(m_panel.get()); } void RenderMedia::createTimeline() @@ -215,18 +239,18 @@ void RenderMedia::createTimeline() m_timeline->setAttribute(precisionAttr, "float"); m_timeline->attachToParent(m_timelineContainer.get()); } - + void RenderMedia::createCurrentTimeDisplay() { ASSERT(!m_currentTimeDisplay); - m_currentTimeDisplay = new MediaTimeDisplayElement(document(), mediaElement(), true); + m_currentTimeDisplay = new MediaControlTimeDisplayElement(document(), MEDIA_CONTROLS_CURRENT_TIME_DISPLAY, mediaElement()); m_currentTimeDisplay->attachToParent(m_timelineContainer.get()); } void RenderMedia::createTimeRemainingDisplay() { ASSERT(!m_timeRemainingDisplay); - m_timeRemainingDisplay = new MediaTimeDisplayElement(document(), mediaElement(), false); + m_timeRemainingDisplay = new MediaControlTimeDisplayElement(document(), MEDIA_CONTROLS_TIME_REMAINING_DISPLAY, mediaElement()); m_timeRemainingDisplay->attachToParent(m_timelineContainer.get()); } @@ -251,10 +275,13 @@ void RenderMedia::updateControls() m_panel = 0; m_muteButton = 0; m_playButton = 0; + m_statusDisplay = 0; m_timelineContainer = 0; m_timeline = 0; m_seekBackButton = 0; m_seekForwardButton = 0; + m_rewindButton = 0; + m_returnToRealtimeButton = 0; m_currentTimeDisplay = 0; m_timeRemainingDisplay = 0; m_fullscreenButton = 0; @@ -269,38 +296,65 @@ void RenderMedia::updateControls() if (!m_controlsShadowRoot) { createControlsShadowRoot(); createPanel(); - createMuteButton(); - createPlayButton(); - createTimelineContainer(); - createTimeline(); - createSeekBackButton(); - createSeekForwardButton(); - createCurrentTimeDisplay(); - createTimeRemainingDisplay(); - createFullscreenButton(); + if (m_panel) { + createRewindButton(); + createMuteButton(); + createPlayButton(); + createReturnToRealtimeButton(); + createStatusDisplay(); + createTimelineContainer(); + createSeekBackButton(); + createSeekForwardButton(); + createFullscreenButton(); + if (m_timelineContainer) { + createCurrentTimeDisplay(); + createTimeline(); + createTimeRemainingDisplay(); + } + m_panel->attach(); + } } if (media->canPlay()) { if (m_timeUpdateTimer.isActive()) m_timeUpdateTimer.stop(); - } else if (style()->visibility() == VISIBLE && m_timeline && m_timeline->renderer() && m_timeline->renderer()->style()->display() != NONE ) { + } 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_panel) { + // update() might alter the opacity of the element, especially if we are in the middle + // of an animation. This is the only element concerned as we animate only this element. + float opacityBeforeChangingStyle = m_panel->renderer() ? m_panel->renderer()->style()->opacity() : 0; + m_panel->update(); + changeOpacity(m_panel.get(), opacityBeforeChangingStyle); + } if (m_muteButton) m_muteButton->update(); if (m_playButton) m_playButton->update(); + if (m_timelineContainer) + m_timelineContainer->update(); if (m_timeline) m_timeline->update(); + if (m_currentTimeDisplay) + m_currentTimeDisplay->update(); + if (m_timeRemainingDisplay) + m_timeRemainingDisplay->update(); if (m_seekBackButton) m_seekBackButton->update(); if (m_seekForwardButton) m_seekForwardButton->update(); + if (m_rewindButton) + m_rewindButton->update(); + if (m_returnToRealtimeButton) + m_returnToRealtimeButton->update(); + if (m_statusDisplay) + m_statusDisplay->update(); if (m_fullscreenButton) m_fullscreenButton->update(); + updateTimeDisplay(); updateControlVisibility(); } @@ -355,26 +409,34 @@ void RenderMedia::updateControlVisibility() if (!media->hasVideo()) return; - // do fading manually, css animations don't work well with shadow trees - bool visible = style()->visibility() == VISIBLE && (m_mouseOver || media->canPlay()); - if (visible == (m_opacityAnimationTo > 0)) + // Don't fade if the media element is not visible + if (style()->visibility() != VISIBLE) return; + + bool shouldHideController = !m_mouseOver && !media->canPlay(); + + // Do fading manually, css animations don't work with shadow trees - if (style()->visibility() != m_previousVisible) { - // 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(), m_opacityAnimationTo); + float animateFrom = m_panel->renderer()->style()->opacity(); + float animateTo = shouldHideController ? 0.0f : 1.0f; + + if (animateFrom == animateTo) return; - } - if (visible) { - m_opacityAnimationFrom = m_panel->renderer()->style()->opacity(); - m_opacityAnimationTo = 1.0f; - } else { - m_opacityAnimationFrom = m_panel->renderer()->style()->opacity(); - m_opacityAnimationTo = 0; + if (m_opacityAnimationTimer.isActive()) { + if (m_opacityAnimationTo == animateTo) + return; + m_opacityAnimationTimer.stop(); } + + if (animateFrom < animateTo) + m_opacityAnimationDuration = cOpacityAnimationDurationFadeIn; + else + m_opacityAnimationDuration = cOpacityAnimationDurationFadeOut; + + m_opacityAnimationFrom = animateFrom; + m_opacityAnimationTo = animateTo; + m_opacityAnimationStartTime = currentTime(); m_opacityAnimationTimer.startRepeating(cOpacityAnimationRepeatDelay); } @@ -393,11 +455,11 @@ void RenderMedia::changeOpacity(HTMLElement* e, float opacity) void RenderMedia::opacityAnimationTimerFired(Timer<RenderMedia>*) { double time = currentTime() - m_opacityAnimationStartTime; - if (time >= cOpacityAnimationDuration) { - time = cOpacityAnimationDuration; + if (time >= m_opacityAnimationDuration) { + time = m_opacityAnimationDuration; m_opacityAnimationTimer.stop(); } - float opacity = narrowPrecisionToFloat(m_opacityAnimationFrom + (m_opacityAnimationTo - m_opacityAnimationFrom) * time / cOpacityAnimationDuration); + float opacity = narrowPrecisionToFloat(m_opacityAnimationFrom + (m_opacityAnimationTo - m_opacityAnimationFrom) * time / m_opacityAnimationDuration); changeOpacity(m_panel.get(), opacity); } @@ -418,6 +480,12 @@ void RenderMedia::forwardEvent(Event* event) if (m_seekForwardButton && m_seekForwardButton->hitTest(point)) m_seekForwardButton->defaultEventHandler(event); + if (m_rewindButton && m_rewindButton->hitTest(point)) + m_rewindButton->defaultEventHandler(event); + + if (m_returnToRealtimeButton && m_returnToRealtimeButton->hitTest(point)) + m_returnToRealtimeButton->defaultEventHandler(event); + if (m_timeline && m_timeline->hitTest(point)) m_timeline->defaultEventHandler(event); @@ -465,6 +533,19 @@ int RenderMedia::leftmostPosition(bool includeOverflowInterior, bool includeSelf return min(left, m_controlsShadowRoot->renderBox()->x() + m_controlsShadowRoot->renderBox()->leftmostPosition(includeOverflowInterior, includeSelf)); } + +// We want the timeline slider to be at least 100 pixels wide. +static const int minWidthToDisplayTimeDisplays = 16 + 16 + 45 + 100 + 45 + 16 + 1; + +bool RenderMedia::shouldShowTimeDisplayControls() const +{ + if (!m_currentTimeDisplay && !m_timeRemainingDisplay) + return false; + + int width = mediaElement()->renderBox()->width(); + return width >= minWidthToDisplayTimeDisplays * style()->effectiveZoom(); +} + } // namespace WebCore #endif diff --git a/WebCore/rendering/RenderMedia.h b/WebCore/rendering/RenderMedia.h index 6013d7b..5697bda 100644 --- a/WebCore/rendering/RenderMedia.h +++ b/WebCore/rendering/RenderMedia.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -38,9 +38,14 @@ class HTMLMediaElement; class MediaControlMuteButtonElement; class MediaControlPlayButtonElement; class MediaControlSeekButtonElement; +class MediaControlRewindButtonElement; +class MediaControlReturnToRealtimeButtonElement; class MediaControlTimelineElement; class MediaControlFullscreenButtonElement; -class MediaTimeDisplayElement; +class MediaControlTimeDisplayElement; +class MediaControlStatusDisplayElement; +class MediaControlTimelineContainerElement; +class MediaControlElement; class MediaPlayer; class RenderMedia : public RenderReplaced { @@ -49,23 +54,16 @@ public: RenderMedia(HTMLMediaElement*, const IntSize& intrinsicSize); virtual ~RenderMedia(); - virtual RenderObjectChildList* virtualChildren() { return children(); } - virtual const RenderObjectChildList* virtualChildren() const { return children(); } const RenderObjectChildList* children() const { return &m_children; } RenderObjectChildList* children() { return &m_children; } - virtual void destroy(); - - virtual void layout(); - - virtual const char* renderName() const { return "RenderMedia"; } - virtual bool isMedia() const { return true; } - HTMLMediaElement* mediaElement() const; MediaPlayer* player() const; static String formatTime(float time); + bool shouldShowTimeDisplayControls() const; + void updateFromElement(); void updatePlayer(); void updateControls(); @@ -73,11 +71,22 @@ public: void forwardEvent(Event*); +protected: + virtual void layout(); + +private: + virtual RenderObjectChildList* virtualChildren() { return children(); } + virtual const RenderObjectChildList* virtualChildren() const { return children(); } + + virtual void destroy(); + + virtual const char* renderName() const { return "RenderMedia"; } + virtual bool isMedia() const { return true; } + virtual 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; -private: void createControlsShadowRoot(); void destroyControlsShadowRoot(); void createPanel(); @@ -85,6 +94,9 @@ private: void createPlayButton(); void createSeekBackButton(); void createSeekForwardButton(); + void createRewindButton(); + void createReturnToRealtimeButton(); + void createStatusDisplay(); void createTimelineContainer(); void createTimeline(); void createCurrentTimeDisplay(); @@ -100,16 +112,19 @@ private: virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); RefPtr<HTMLElement> m_controlsShadowRoot; - RefPtr<HTMLElement> m_panel; + RefPtr<MediaControlElement> m_panel; RefPtr<MediaControlMuteButtonElement> m_muteButton; RefPtr<MediaControlPlayButtonElement> m_playButton; RefPtr<MediaControlSeekButtonElement> m_seekBackButton; RefPtr<MediaControlSeekButtonElement> m_seekForwardButton; + RefPtr<MediaControlRewindButtonElement> m_rewindButton; + RefPtr<MediaControlReturnToRealtimeButtonElement> m_returnToRealtimeButton; RefPtr<MediaControlTimelineElement> m_timeline; RefPtr<MediaControlFullscreenButtonElement> m_fullscreenButton; - RefPtr<HTMLElement> m_timelineContainer; - RefPtr<MediaTimeDisplayElement> m_currentTimeDisplay; - RefPtr<MediaTimeDisplayElement> m_timeRemainingDisplay; + RefPtr<MediaControlTimelineContainerElement> m_timelineContainer; + RefPtr<MediaControlTimeDisplayElement> m_currentTimeDisplay; + RefPtr<MediaControlTimeDisplayElement> m_timeRemainingDisplay; + RefPtr<MediaControlStatusDisplayElement> m_statusDisplay; RenderObjectChildList m_children; Node* m_lastUnderNode; Node* m_nodeUnderMouse; @@ -118,11 +133,20 @@ private: Timer<RenderMedia> m_opacityAnimationTimer; bool m_mouseOver; double m_opacityAnimationStartTime; + double m_opacityAnimationDuration; float m_opacityAnimationFrom; float m_opacityAnimationTo; - EVisibility m_previousVisible; }; +inline RenderMedia* toRenderMedia(RenderObject* object) +{ + ASSERT(!object || object->isMedia()); + return static_cast<RenderMedia*>(object); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderMedia(const RenderMedia*); + } // namespace WebCore #endif diff --git a/WebCore/rendering/RenderMediaControls.cpp b/WebCore/rendering/RenderMediaControls.cpp index f1ff55f..06d901a 100644 --- a/WebCore/rendering/RenderMediaControls.cpp +++ b/WebCore/rendering/RenderMediaControls.cpp @@ -51,19 +51,20 @@ SOFT_LINK(SafariTheme, STPaintProgressIndicator, void, APIENTRY, (ProgressIndica static ThemeControlState determineState(RenderObject* o) { ThemeControlState result = 0; - if (theme()->isActive(o)) + RenderTheme* theme = o->theme(); + if (theme->isActive(o)) result |= SafariTheme::ActiveState; - if (theme()->isEnabled(o) && !theme()->isReadOnlyControl(o)) + if (theme->isEnabled(o) && !theme->isReadOnlyControl(o)) result |= SafariTheme::EnabledState; - if (theme()->isPressed(o)) + if (theme->isPressed(o)) result |= SafariTheme::PressedState; - if (theme()->isChecked(o)) + if (theme->isChecked(o)) result |= SafariTheme::CheckedState; - if (theme()->isIndeterminate(o)) + if (theme->isIndeterminate(o)) result |= SafariTheme::IndeterminateCheckedState; - if (theme()->isFocused(o)) + if (theme->isFocused(o)) result |= SafariTheme::FocusedState; - if (theme()->isDefault(o)) + if (theme->isDefault(o)) result |= SafariTheme::DefaultState; return result; } @@ -101,13 +102,17 @@ bool RenderMediaControls::paintMediaControlsPart(MediaControlElementType part, R break; case MediaMuteButton: case MediaUnMuteButton: - if (HTMLMediaElement* mediaElement = parentMediaElement(o)) - paintThemePart(mediaElement->muted() ? SafariTheme::MediaUnMuteButtonPart : SafariTheme::MediaMuteButtonPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o)); + if (MediaControlMuteButtonElement* btn = static_cast<MediaControlMuteButtonElement*>(o->node())) { + bool audioEnabled = btn->displayType() == MediaMuteButton; + paintThemePart(audioEnabled ? SafariTheme::MediaMuteButtonPart : SafariTheme::MediaUnMuteButtonPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o)); + } break; case MediaPauseButton: case MediaPlayButton: - if (HTMLMediaElement* mediaElement = parentMediaElement(o)) - paintThemePart(mediaElement->canPlay() ? SafariTheme::MediaPlayButtonPart : SafariTheme::MediaPauseButtonPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o)); + if (MediaControlPlayButtonElement* btn = static_cast<MediaControlPlayButtonElement*>(o->node())) { + bool currentlyPlaying = btn->displayType() == MediaPlayButton; + paintThemePart(currentlyPlaying ? SafariTheme::MediaPauseButtonPart : SafariTheme::MediaPlayButtonPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o)); + } break; case MediaSeekBackButton: paintThemePart(SafariTheme::MediaSeekBackButtonPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o)); @@ -116,15 +121,8 @@ bool RenderMediaControls::paintMediaControlsPart(MediaControlElementType part, R paintThemePart(SafariTheme::MediaSeekForwardButtonPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o)); break; case MediaSlider: { - HTMLMediaElement* mediaElement = parentMediaElement(o); - if (!mediaElement) - break; - - MediaPlayer* player = mediaElement->player(); - float duration = player ? player->duration() : 0; - float percentLoaded = duration ? player->maxTimeBuffered() /duration : 0; - - STPaintProgressIndicator(SafariTheme::MediaType, paintInfo.context->platformContext(), r, NSRegularControlSize, 0, percentLoaded); + if (HTMLMediaElement* mediaElement = parentMediaElement(o)) + STPaintProgressIndicator(SafariTheme::MediaType, paintInfo.context->platformContext(), r, NSRegularControlSize, 0, mediaElement->percentLoaded()); break; } case MediaSliderThumb: diff --git a/WebCore/rendering/RenderMenuList.cpp b/WebCore/rendering/RenderMenuList.cpp index 95de7a2..9d2e7e0 100644 --- a/WebCore/rendering/RenderMenuList.cpp +++ b/WebCore/rendering/RenderMenuList.cpp @@ -25,6 +25,7 @@ #include "RenderMenuList.h" #include "CSSStyleSelector.h" +#include "Frame.h" #include "FrameView.h" #include "HTMLNames.h" #include "NodeRenderStyle.h" @@ -296,8 +297,14 @@ void RenderMenuList::hidePopup() void RenderMenuList::valueChanged(unsigned listIndex, bool fireOnChange) { + // Check to ensure a page navigation has not occurred while + // the popup was up. + Document* doc = static_cast<Element*>(node())->document(); + if (!doc || doc != doc->frame()->document()) + return; + SelectElement* select = toSelectElement(static_cast<Element*>(node())); - select->setSelectedIndex(select->listToOptionIndex(listIndex), true, fireOnChange); + select->setSelectedIndexByUser(select->listToOptionIndex(listIndex), true, fireOnChange); } String RenderMenuList::itemText(unsigned listIndex) const @@ -311,6 +318,13 @@ String RenderMenuList::itemText(unsigned listIndex) const return String(); } +String RenderMenuList::itemToolTip(unsigned listIndex) const +{ + SelectElement* select = toSelectElement(static_cast<Element*>(node())); + Element* element = select->listItems()[listIndex]; + return element->title(); +} + bool RenderMenuList::itemIsEnabled(unsigned listIndex) const { SelectElement* select = toSelectElement(static_cast<Element*>(node())); diff --git a/WebCore/rendering/RenderMenuList.h b/WebCore/rendering/RenderMenuList.h index 7966eff..5c18e9e 100644 --- a/WebCore/rendering/RenderMenuList.h +++ b/WebCore/rendering/RenderMenuList.h @@ -40,7 +40,16 @@ class RenderText; class RenderMenuList : public RenderFlexibleBox, private PopupMenuClient { public: RenderMenuList(Element*); - ~RenderMenuList(); + virtual ~RenderMenuList(); + +public: + bool popupIsVisible() const { return m_popupIsVisible; } + void showPopup(); + void hidePopup(); + + void setOptionsChanged(bool changed) { m_optionsChanged = changed; } + + String text() const; private: virtual bool isMenuList() const { return true; } @@ -59,20 +68,11 @@ private: virtual void calcPrefWidths(); -public: - bool popupIsVisible() const { return m_popupIsVisible; } - void showPopup(); - void hidePopup(); - - void setOptionsChanged(bool changed) { m_optionsChanged = changed; } - - String text() const; - -private: virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); // PopupMenuClient methods virtual String itemText(unsigned listIndex) const; + virtual String itemToolTip(unsigned listIndex) const; virtual bool itemIsEnabled(unsigned listIndex) const; virtual PopupMenuStyle itemStyle(unsigned listIndex) const; virtual PopupMenuStyle menuStyle() const; @@ -113,6 +113,15 @@ private: bool m_popupIsVisible; }; +inline RenderMenuList* toRenderMenuList(RenderObject* object) +{ + ASSERT(!object || object->isMenuList()); + return static_cast<RenderMenuList*>(object); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderMenuList(const RenderMenuList*); + } #endif diff --git a/WebCore/rendering/RenderObject.cpp b/WebCore/rendering/RenderObject.cpp index 2aba22a..5137338 100644 --- a/WebCore/rendering/RenderObject.cpp +++ b/WebCore/rendering/RenderObject.cpp @@ -217,6 +217,13 @@ RenderObject::~RenderObject() #endif } +RenderTheme* RenderObject::theme() const +{ + ASSERT(document()->page()); + + return document()->page()->theme(); +} + bool RenderObject::isDescendantOf(const RenderObject* obj) const { for (const RenderObject* r = this; r; r = r->m_parent) { @@ -243,9 +250,10 @@ bool RenderObject::isHTMLMarquee() const static void updateListMarkerNumbers(RenderObject* child) { - for (RenderObject* r = child; r; r = r->nextSibling()) - if (r->isListItem()) - static_cast<RenderListItem*>(r)->updateValue(); + for (RenderObject* sibling = child; sibling; sibling = sibling->nextSibling()) { + if (sibling->isListItem()) + toRenderListItem(sibling)->updateValue(); + } } void RenderObject::addChild(RenderObject* newChild, RenderObject* beforeChild) @@ -281,7 +289,7 @@ void RenderObject::addChild(RenderObject* newChild, RenderObject* beforeChild) RenderTable* table; RenderObject* afterChild = beforeChild ? beforeChild->previousSibling() : children->lastChild(); if (afterChild && afterChild->isAnonymous() && afterChild->isTable()) - table = static_cast<RenderTable*>(afterChild); + table = toRenderTable(afterChild); else { table = new (renderArena()) RenderTable(document() /* is anonymous */); RefPtr<RenderStyle> newStyle = RenderStyle::create(); @@ -591,7 +599,7 @@ void RenderObject::setLayerNeedsFullRepaint() RenderBlock* RenderObject::containingBlock() const { if (isTableCell()) { - const RenderTableCell* cell = static_cast<const RenderTableCell*>(this); + const RenderTableCell* cell = toRenderTableCell(this); if (parent() && cell->section()) return cell->table(); return 0; @@ -639,13 +647,16 @@ static bool mustRepaintFillLayers(const RenderObject* renderer, const FillLayer* // Make sure we have a valid image. StyleImage* img = layer->image(); - bool shouldPaintBackgroundImage = img && img->canRender(renderer->style()->effectiveZoom()); + if (!img || !img->canRender(renderer->style()->effectiveZoom())) + return false; - // These are always percents or auto. - if (shouldPaintBackgroundImage && - (!layer->xPosition().isZero() || !layer->yPosition().isZero() || - layer->size().width().isPercent() || layer->size().height().isPercent())) - // The image will shift unpredictably if the size changes. + if (!layer->xPosition().isZero() || !layer->yPosition().isZero()) + return true; + + if (layer->isSizeSet()) { + if (layer->size().width().isPercent() || layer->size().height().isPercent()) + return true; + } else if (img->usesImageContainerSize()) return true; return false; @@ -767,7 +778,7 @@ void RenderObject::drawLineForBoxSide(GraphicsContext* graphicsContext, int x1, break; case BSRight: drawLineForBoxSide(graphicsContext, x1, y1 + max((adjbw1 * 2 + 1) / 3, 0), - x1 + third, y2 - max(( adjbw2 * 2 + 1) / 3, 0), + x1 + third, y2 - max((adjbw2 * 2 + 1) / 3, 0), s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird); drawLineForBoxSide(graphicsContext, x2 - third, y1 + max((-adjbw1 * 2 + 1) / 3, 0), x2, y2 - max((-adjbw2 * 2 + 1) / 3, 0), @@ -1206,12 +1217,11 @@ bool RenderObject::repaintAfterLayoutIfNeeded(RenderBoxModelObject* repaintConta // two rectangles (but typically only one). RenderStyle* outlineStyle = outlineStyleForRepaint(); int ow = outlineStyle->outlineSize(); - ShadowData* boxShadow = style()->boxShadow(); int width = abs(newOutlineBox.width() - oldOutlineBox.width()); if (width) { - int shadowRight = 0; - for (ShadowData* shadow = boxShadow; shadow; shadow = shadow->next) - shadowRight = max(shadow->x + shadow->blur, shadowRight); + int shadowLeft; + int shadowRight; + style()->getBoxShadowHorizontalExtent(shadowLeft, 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); @@ -1227,9 +1237,9 @@ bool RenderObject::repaintAfterLayoutIfNeeded(RenderBoxModelObject* repaintConta } int height = abs(newOutlineBox.height() - oldOutlineBox.height()); if (height) { - int shadowBottom = 0; - for (ShadowData* shadow = boxShadow; shadow; shadow = shadow->next) - shadowBottom = max(shadow->y + shadow->blur, shadowBottom); + int shadowTop; + int shadowBottom; + style()->getBoxShadowVerticalExtent(shadowTop, 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); @@ -1692,7 +1702,7 @@ void RenderObject::getTransformFromContainer(const RenderObject* containerObject transform.multLeft(layer->currentTransform()); #if ENABLE(3D_RENDERING) - if (containerObject && containerObject->style()->hasPerspective()) { + if (containerObject && containerObject->hasLayer() && containerObject->style()->hasPerspective()) { // Perpsective on the container affects us, so we have to factor it in here. ASSERT(containerObject->hasLayer()); FloatPoint perspectiveOrigin = toRenderBox(containerObject)->layer()->perspectiveOrigin(); @@ -1731,8 +1741,8 @@ IntSize RenderObject::offsetFromContainer(RenderObject* o) const IntRect RenderObject::localCaretRect(InlineBox*, int, int* extraWidthToEndOfLine) { - if (extraWidthToEndOfLine) - *extraWidthToEndOfLine = 0; + if (extraWidthToEndOfLine) + *extraWidthToEndOfLine = 0; return IntRect(); } @@ -1815,7 +1825,7 @@ void RenderObject::destroy() children->destroyLeftoverChildren(); // If this renderer is being autoscrolled, stop the autoscroll timer - if (document()->frame() && document()->frame()->eventHandler()->autoscrollRenderer() == this) + if (document()->frame()->eventHandler()->autoscrollRenderer() == this) document()->frame()->eventHandler()->stopAutoscrollTimer(true); if (m_hasCounterNodeMap) @@ -1973,6 +1983,27 @@ void RenderObject::layout() setNeedsLayout(false); } +PassRefPtr<RenderStyle> RenderObject::uncachedFirstLineStyle(RenderStyle* style) const +{ + if (!document()->usesFirstLineRules()) + return 0; + + ASSERT(!isText()); + + RefPtr<RenderStyle> result; + + if (isBlockFlow()) { + if (RenderBlock* firstLineBlock = this->firstLineBlock()) + result = firstLineBlock->getUncachedPseudoStyle(FIRST_LINE, style, firstLineBlock == this ? style : 0); + } else if (!isAnonymous() && isRenderInline()) { + RenderStyle* parentStyle = parent()->firstLineStyle(); + if (parentStyle != parent()->style()) + result = getUncachedPseudoStyle(FIRST_LINE_INHERITED, parentStyle, style); + } + + return result.release(); +} + RenderStyle* RenderObject::firstLineStyleSlowCase() const { ASSERT(document()->usesFirstLineRules()); @@ -2009,13 +2040,15 @@ RenderStyle* RenderObject::getCachedPseudoStyle(PseudoId pseudo, RenderStyle* pa return 0; } -PassRefPtr<RenderStyle> RenderObject::getUncachedPseudoStyle(PseudoId pseudo, RenderStyle* parentStyle) const +PassRefPtr<RenderStyle> RenderObject::getUncachedPseudoStyle(PseudoId pseudo, RenderStyle* parentStyle, RenderStyle* ownStyle) const { - if (pseudo < FIRST_INTERNAL_PSEUDOID && !style()->hasPseudoStyle(pseudo)) + if (pseudo < FIRST_INTERNAL_PSEUDOID && !ownStyle && !style()->hasPseudoStyle(pseudo)) return 0; - if (!parentStyle) + if (!parentStyle) { + ASSERT(!ownStyle); parentStyle = style(); + } Node* n = node(); while (n && !n->isElementNode()) @@ -2210,10 +2243,12 @@ void RenderObject::adjustRectForOutlineAndShadow(IntRect& rect) const int shadowBottom = 0; do { - shadowLeft = min(boxShadow->x - boxShadow->blur - outlineSize, shadowLeft); - shadowRight = max(boxShadow->x + boxShadow->blur + outlineSize, shadowRight); - shadowTop = min(boxShadow->y - boxShadow->blur - outlineSize, shadowTop); - shadowBottom = max(boxShadow->y + boxShadow->blur + outlineSize, shadowBottom); + if (boxShadow->style == Normal) { + shadowLeft = min(boxShadow->x - boxShadow->blur - boxShadow->spread - outlineSize, shadowLeft); + shadowRight = max(boxShadow->x + boxShadow->blur + boxShadow->spread + outlineSize, shadowRight); + shadowTop = min(boxShadow->y - boxShadow->blur - boxShadow->spread - outlineSize, shadowTop); + shadowBottom = max(boxShadow->y + boxShadow->blur + boxShadow->spread + outlineSize, shadowBottom); + } boxShadow = boxShadow->next; } while (boxShadow); diff --git a/WebCore/rendering/RenderObject.h b/WebCore/rendering/RenderObject.h index 0901bff..911169d 100644 --- a/WebCore/rendering/RenderObject.h +++ b/WebCore/rendering/RenderObject.h @@ -48,6 +48,7 @@ class RenderInline; class RenderBlock; class RenderFlow; class RenderLayer; +class RenderTheme; class TransformState; class VisiblePosition; @@ -137,6 +138,8 @@ public: RenderObject(Node*); virtual ~RenderObject(); + RenderTheme* theme() const; + virtual const char* renderName() const = 0; RenderObject* parent() const { return m_parent; } @@ -273,6 +276,7 @@ public: virtual bool isTextControl() const { return false; } virtual bool isTextArea() const { return false; } virtual bool isTextField() const { return false; } + virtual bool isVideo() const { return false; } virtual bool isWidget() const { return false; } bool isRoot() const { return document()->documentElement() == m_node; } @@ -378,7 +382,7 @@ public: // The pseudo element style can be cached or uncached. Use the cached method if the pseudo element doesn't respect // any pseudo classes (and therefore has no concept of changing state). RenderStyle* getCachedPseudoStyle(PseudoId, RenderStyle* parentStyle = 0) const; - PassRefPtr<RenderStyle> getUncachedPseudoStyle(PseudoId, RenderStyle* parentStyle = 0) const; + PassRefPtr<RenderStyle> getUncachedPseudoStyle(PseudoId, RenderStyle* parentStyle = 0, RenderStyle* ownStyle = 0) const; virtual void updateDragState(bool dragOn); @@ -549,7 +553,11 @@ public: RenderStyle* style() const { return m_style.get(); } RenderStyle* firstLineStyle() const { return document()->usesFirstLineRules() ? firstLineStyleSlowCase() : style(); } RenderStyle* style(bool firstLine) const { return firstLine ? firstLineStyle() : style(); } - + + // Used only by Element::pseudoStyleCacheIsInvalid to get a first line style based off of a + // given new style, without accessing the cache. + PassRefPtr<RenderStyle> uncachedFirstLineStyle(RenderStyle*) const; + // Anonymous blocks that are part of of a continuation chain will return their inline continuation's outline style instead. // This is typically only relevant when repainting. virtual RenderStyle* outlineStyleForRepaint() const { return style(); } @@ -955,12 +963,14 @@ inline void RenderObject::markContainingBlocksForLayout(bool scheduleRelayout, R last->scheduleRelayout(); } -inline void makeMatrixRenderable(TransformationMatrix& matrix) +inline void makeMatrixRenderable(TransformationMatrix& matrix, bool has3DRendering) { #if !ENABLE(3D_RENDERING) + UNUSED_PARAM(has3DRendering); matrix.makeAffine(); #else - UNUSED_PARAM(matrix); + if (!has3DRendering) + matrix.makeAffine(); #endif } diff --git a/WebCore/rendering/RenderObjectChildList.cpp b/WebCore/rendering/RenderObjectChildList.cpp index 32e856f..23ab98f 100644 --- a/WebCore/rendering/RenderObjectChildList.cpp +++ b/WebCore/rendering/RenderObjectChildList.cpp @@ -41,13 +41,12 @@ namespace WebCore { static void updateListMarkerNumbers(RenderObject* child) { - for (RenderObject* r = child; r; r = r->nextSibling()) { - if (r->isListItem()) - static_cast<RenderListItem*>(r)->updateValue(); + for (RenderObject* sibling = child; sibling; sibling = sibling->nextSibling()) { + if (sibling->isListItem()) + toRenderListItem(sibling)->updateValue(); } } - void RenderObjectChildList::destroyLeftoverChildren() { while (firstChild()) { @@ -281,7 +280,7 @@ static void invalidateCountersInContainer(RenderObject* container) return; for (RenderObject* content = container->firstChild(); content; content = content->nextSibling()) { if (content->isCounter()) - static_cast<RenderCounter*>(content)->invalidate(); + toRenderCounter(content)->invalidate(); } } diff --git a/WebCore/rendering/RenderPart.cpp b/WebCore/rendering/RenderPart.cpp index bcf9ef9..cb56c0c 100644 --- a/WebCore/rendering/RenderPart.cpp +++ b/WebCore/rendering/RenderPart.cpp @@ -41,13 +41,11 @@ RenderPart::~RenderPart() clearWidget(); } -void RenderPart::setWidget(Widget* widget) +void RenderPart::setWidget(PassRefPtr<Widget> widget) { if (widget == this->widget()) return; - if (widget && widget->isFrameView()) - static_cast<FrameView*>(widget)->ref(); RenderWidget::setWidget(widget); // make sure the scrollbars are set correctly for restore @@ -59,16 +57,4 @@ void RenderPart::viewCleared() { } -void RenderPart::deleteWidget(Widget* widget) -{ - // Since deref ends up calling setWidget back on us, need to make sure - // that widget is already 0 so it won't do any work. - ASSERT(!this->widget()); - - if (widget && widget->isFrameView()) - static_cast<FrameView*>(widget)->deref(); - else - delete widget; -} - } diff --git a/WebCore/rendering/RenderPart.h b/WebCore/rendering/RenderPart.h index e47ead0..08abf99 100644 --- a/WebCore/rendering/RenderPart.h +++ b/WebCore/rendering/RenderPart.h @@ -34,7 +34,7 @@ public: bool hasFallbackContent() const { return m_hasFallbackContent; } - virtual void setWidget(Widget*); + virtual void setWidget(PassRefPtr<Widget>); virtual void viewCleared(); protected: @@ -43,10 +43,17 @@ protected: private: virtual bool isRenderPart() const { return true; } virtual const char* renderName() const { return "RenderPart"; } - - virtual void deleteWidget(Widget*); }; +inline RenderPart* toRenderPart(RenderObject* object) +{ + ASSERT(!object || object->isRenderPart()); + return static_cast<RenderPart*>(object); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderPart(const RenderPart*); + } #endif diff --git a/WebCore/rendering/RenderPartObject.cpp b/WebCore/rendering/RenderPartObject.cpp index 0e7655b..5f6d903 100644 --- a/WebCore/rendering/RenderPartObject.cpp +++ b/WebCore/rendering/RenderPartObject.cpp @@ -72,7 +72,7 @@ static bool isURLAllowed(Document* doc, const String& url) KURL completeURL = doc->completeURL(url); bool foundSelfReference = false; for (Frame* frame = doc->frame(); frame; frame = frame->tree()->parent()) { - if (equalIgnoringRef(frame->loader()->url(), completeURL)) { + if (equalIgnoringFragmentIdentifier(frame->loader()->url(), completeURL)) { if (foundSelfReference) return false; foundSelfReference = true; @@ -142,6 +142,24 @@ static inline bool shouldUseEmbedDescendant(HTMLObjectElement* objectElement, co #endif } +static void mapDataParamToSrc(Vector<String>* paramNames, Vector<String>* paramValues) +{ + // Some plugins don't understand the "data" attribute of the OBJECT tag (i.e. Real and WMP + // require "src" attribute). + int srcIndex = -1, dataIndex = -1; + for (unsigned int i = 0; i < paramNames->size(); ++i) { + if (equalIgnoringCase((*paramNames)[i], "src")) + srcIndex = i; + else if (equalIgnoringCase((*paramNames)[i], "data")) + dataIndex = i; + } + + if (srcIndex == -1 && dataIndex != -1) { + paramNames->append("src"); + paramValues->append((*paramValues)[dataIndex]); + } +} + void RenderPartObject::updateWidget(bool onlyCreateNonNetscapePlugins) { String url; @@ -238,6 +256,8 @@ void RenderPartObject::updateWidget(bool onlyCreateNonNetscapePlugins) } } + mapDataParamToSrc(¶mNames, ¶mValues); + // 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); diff --git a/WebCore/rendering/RenderPartObject.h b/WebCore/rendering/RenderPartObject.h index 0370c9f..092395d 100644 --- a/WebCore/rendering/RenderPartObject.h +++ b/WebCore/rendering/RenderPartObject.h @@ -1,7 +1,7 @@ /* * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 2000 Simon Hausmann <hausmann@kde.org> - * Copyright (C) 2006, 2009 Apple Inc. + * Copyright (C) 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 @@ -46,6 +46,15 @@ private: virtual void viewCleared(); }; +inline RenderPartObject* toRenderPartObject(RenderObject* object) +{ + ASSERT(!object || !strcmp(object->renderName(), "RenderPartObject")); + return static_cast<RenderPartObject*>(object); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderPartObject(const RenderPartObject*); + } // namespace WebCore #endif // RenderPartObject_h diff --git a/WebCore/rendering/RenderPath.h b/WebCore/rendering/RenderPath.h index a4aefed..2ff179e 100644 --- a/WebCore/rendering/RenderPath.h +++ b/WebCore/rendering/RenderPath.h @@ -40,6 +40,9 @@ class RenderPath : public RenderSVGModelObject { public: RenderPath(SVGStyledTransformableElement*); + const Path& path() const; + +private: // Hit-detection seperated for the fill and the stroke bool fillContains(const FloatPoint&, bool requiresFill = true) const; bool strokeContains(const FloatPoint&, bool requiresStroke = true) const; @@ -49,7 +52,6 @@ public: virtual TransformationMatrix localToParentTransform() const; - const Path& path() const; void setPath(const Path&); virtual bool isRenderPath() const { return true; } @@ -73,6 +75,21 @@ private: TransformationMatrix m_localTransform; }; +inline RenderPath* toRenderPath(RenderObject* object) +{ + ASSERT(!object || object->isRenderPath()); + return static_cast<RenderPath*>(object); +} + +inline const RenderPath* toRenderPath(const RenderObject* object) +{ + ASSERT(!object || object->isRenderPath()); + return static_cast<const RenderPath*>(object); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderPath(const RenderPath*); + } #endif // ENABLE(SVG) diff --git a/WebCore/rendering/RenderReplaced.cpp b/WebCore/rendering/RenderReplaced.cpp index e61ac8e..692a66e 100644 --- a/WebCore/rendering/RenderReplaced.cpp +++ b/WebCore/rendering/RenderReplaced.cpp @@ -127,8 +127,7 @@ void RenderReplaced::paint(PaintInfo& paintInfo, int tx, int ty) drawSelectionTint = false; } - bool clipToBorderRadius = style()->overflowX() != OVISIBLE && style()->hasBorderRadius(); - if (clipToBorderRadius) { + if (style()->hasBorderRadius()) { // Push a clip if we have a border radius, since we want to round the foreground content that gets painted. paintInfo.context->save(); @@ -141,7 +140,7 @@ void RenderReplaced::paint(PaintInfo& paintInfo, int tx, int ty) paintReplaced(paintInfo, tx, ty); - if (clipToBorderRadius) + if (style()->hasBorderRadius()) paintInfo.context->restore(); // The selection tint never gets clipped by border-radius rounding, since we want it to run right up to the edges of @@ -332,9 +331,11 @@ void RenderReplaced::adjustOverflowForBoxShadowAndReflect() { IntRect overflow; for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next) { + if (boxShadow->style == Inset) + continue; IntRect shadow = borderBoxRect(); shadow.move(boxShadow->x, boxShadow->y); - shadow.inflate(boxShadow->blur); + shadow.inflate(boxShadow->blur + boxShadow->spread); overflow.unite(shadow); } diff --git a/WebCore/rendering/RenderReplaced.h b/WebCore/rendering/RenderReplaced.h index 4937446..70ad4f2 100644 --- a/WebCore/rendering/RenderReplaced.h +++ b/WebCore/rendering/RenderReplaced.h @@ -1,6 +1,6 @@ /* * Copyright (C) 1999 Lars Knoll (knoll@kde.org) - * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. + * Copyright (C) 2004, 2005, 2006, 2007, 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 @@ -32,6 +32,25 @@ public: RenderReplaced(Node*, const IntSize& intrinsicSize); virtual ~RenderReplaced(); +protected: + virtual void layout(); + + virtual IntSize intrinsicSize() const; + + virtual void setSelectionState(SelectionState); + + bool isSelected() const; + + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + + void setIntrinsicSize(const IntSize&); + virtual void intrinsicSizeChanged(); + + bool shouldPaint(PaintInfo&, int& tx, int& ty); + void adjustOverflowForBoxShadowAndReflect(); + IntRect localSelectionRect(bool checkWhetherSelected = true) const; + +private: virtual const char* renderName() const { return "RenderReplaced"; } virtual bool canHaveChildren() const { return false; } @@ -40,15 +59,12 @@ public: virtual int baselinePosition(bool firstLine, bool isRootLineBox = false) const; virtual void calcPrefWidths(); - - virtual void layout(); + virtual int minimumReplacedHeight() const { return 0; } virtual void paint(PaintInfo&, int tx, int ty); virtual void paintReplaced(PaintInfo&, int /*tx*/, int /*ty*/) { } - virtual IntSize intrinsicSize() const; - virtual int overflowHeight(bool includeInterior = true) const; virtual int overflowWidth(bool includeInterior = true) const; virtual int overflowLeft(bool includeInterior = true) const; @@ -61,22 +77,9 @@ public: virtual VisiblePosition positionForPoint(const IntPoint&); virtual bool canBeSelectionLeaf() const { return true; } - virtual void setSelectionState(SelectionState); - virtual IntRect selectionRectForRepaint(RenderBoxModelObject* repaintContainer, bool clipToVisibleContent = true); - - bool isSelected() const; -protected: - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); - - void setIntrinsicSize(const IntSize&); - virtual void intrinsicSizeChanged(); - - bool shouldPaint(PaintInfo&, int& tx, int& ty); - void adjustOverflowForBoxShadowAndReflect(); - IntRect localSelectionRect(bool checkWhetherSelected = true) const; + virtual IntRect selectionRectForRepaint(RenderBoxModelObject* repaintContainer, bool clipToVisibleContent = true); -private: IntSize m_intrinsicSize; }; diff --git a/WebCore/rendering/RenderReplica.cpp b/WebCore/rendering/RenderReplica.cpp index e805298..5fa3c62 100644 --- a/WebCore/rendering/RenderReplica.cpp +++ b/WebCore/rendering/RenderReplica.cpp @@ -72,9 +72,8 @@ void RenderReplica::paint(PaintInfo& paintInfo, int tx, int ty) // computing using the wrong rootLayer layer()->parent()->paintLayer(layer()->transform() ? layer()->parent() : layer()->enclosingTransformedAncestor(), paintInfo.context, paintInfo.rect, - true, PaintRestrictionNone, 0, 0, - true, // appliedTransform - true); // temporaryClipRects + PaintRestrictionNone, 0, 0, + RenderLayer::PaintLayerHaveTransparency | RenderLayer::PaintLayerAppliedTransform | RenderLayer::PaintLayerTemporaryClipRects | RenderLayer::PaintLayerPaintingReflection); else if (paintInfo.phase == PaintPhaseMask) paintMask(paintInfo, tx, ty); } diff --git a/WebCore/rendering/RenderSVGBlock.h b/WebCore/rendering/RenderSVGBlock.h index f8afd0f..a4ececb 100644 --- a/WebCore/rendering/RenderSVGBlock.h +++ b/WebCore/rendering/RenderSVGBlock.h @@ -34,6 +34,8 @@ class SVGElement; class RenderSVGBlock : public RenderBlock, protected SVGRenderBase { public: RenderSVGBlock(SVGElement*); + +private: virtual void setStyle(PassRefPtr<RenderStyle>); }; diff --git a/WebCore/rendering/RenderSVGContainer.cpp b/WebCore/rendering/RenderSVGContainer.cpp index 8a77d2e..d7aec99 100644 --- a/WebCore/rendering/RenderSVGContainer.cpp +++ b/WebCore/rendering/RenderSVGContainer.cpp @@ -42,10 +42,6 @@ RenderSVGContainer::RenderSVGContainer(SVGStyledElement* node) { } -RenderSVGContainer::~RenderSVGContainer() -{ -} - bool RenderSVGContainer::drawsContents() const { return m_drawsContents; diff --git a/WebCore/rendering/RenderSVGContainer.h b/WebCore/rendering/RenderSVGContainer.h index 4bb7e44..f2195e3 100644 --- a/WebCore/rendering/RenderSVGContainer.h +++ b/WebCore/rendering/RenderSVGContainer.h @@ -2,6 +2,7 @@ Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org> 2004, 2005, 2007 Rob Buis <buis@kde.org> Copyright (C) 2009 Google, Inc. All rights reserved. + Copyright (C) 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 @@ -33,10 +34,7 @@ class SVGElement; class RenderSVGContainer : public RenderSVGModelObject { public: RenderSVGContainer(SVGStyledElement*); - ~RenderSVGContainer(); - virtual RenderObjectChildList* virtualChildren() { return children(); } - virtual const RenderObjectChildList* virtualChildren() const { return children(); } const RenderObjectChildList* children() const { return &m_children; } RenderObjectChildList* children() { return &m_children; } @@ -44,11 +42,18 @@ public: void setDrawsContents(bool); bool drawsContents() const; +protected: + virtual void paint(PaintInfo&, int parentX, int parentY); + +private: + virtual RenderObjectChildList* virtualChildren() { return children(); } + virtual const RenderObjectChildList* virtualChildren() const { return children(); } + virtual bool isSVGContainer() const { return true; } virtual const char* renderName() const { return "RenderSVGContainer"; } virtual void layout(); - virtual void paint(PaintInfo&, int parentX, int parentY); + virtual void addFocusRingRects(GraphicsContext*, int tx, int ty); virtual FloatRect objectBoundingBox() const; @@ -56,7 +61,6 @@ public: virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction); -protected: // Allow RenderSVGTransformableContainer to hook in at the right time in layout() virtual void calculateLocalTransform() { } @@ -65,13 +69,29 @@ protected: virtual void applyViewportClip(PaintInfo&) { } virtual bool pointIsInsideViewportClip(const FloatPoint& /*pointInParent*/) { return true; } -private: bool selfWillPaint() const; RenderObjectChildList m_children; bool m_drawsContents : 1; }; +inline RenderSVGContainer* toRenderSVGContainer(RenderObject* object) +{ + // Note: isSVGContainer is also true for RenderSVGViewportContainer, which is not derived from this. + ASSERT(!object || object->isSVGContainer() && strcmp(object->renderName(), "RenderSVGViewportContainer")); + return static_cast<RenderSVGContainer*>(object); +} + +inline const RenderSVGContainer* toRenderSVGContainer(const RenderObject* object) +{ + // Note: isSVGContainer is also true for RenderSVGViewportContainer, which is not derived from this. + ASSERT(!object || object->isSVGContainer() && strcmp(object->renderName(), "RenderSVGViewportContainer")); + return static_cast<const RenderSVGContainer*>(object); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderSVGContainer(const RenderSVGContainer*); + } // namespace WebCore #endif // ENABLE(SVG) diff --git a/WebCore/rendering/RenderSVGHiddenContainer.cpp b/WebCore/rendering/RenderSVGHiddenContainer.cpp index f08c008..d4b39d3 100644 --- a/WebCore/rendering/RenderSVGHiddenContainer.cpp +++ b/WebCore/rendering/RenderSVGHiddenContainer.cpp @@ -35,10 +35,6 @@ RenderSVGHiddenContainer::RenderSVGHiddenContainer(SVGStyledElement* element) { } -RenderSVGHiddenContainer::~RenderSVGHiddenContainer() -{ -} - void RenderSVGHiddenContainer::layout() { ASSERT(needsLayout()); diff --git a/WebCore/rendering/RenderSVGHiddenContainer.h b/WebCore/rendering/RenderSVGHiddenContainer.h index 5a208d0..0ef0a43 100644 --- a/WebCore/rendering/RenderSVGHiddenContainer.h +++ b/WebCore/rendering/RenderSVGHiddenContainer.h @@ -36,9 +36,8 @@ namespace WebCore { class RenderSVGHiddenContainer : public RenderSVGContainer { public: RenderSVGHiddenContainer(SVGStyledElement*); - virtual ~RenderSVGHiddenContainer(); - virtual bool isSVGContainer() const { return true; } + private: virtual bool isSVGHiddenContainer() const { return true; } virtual const char* renderName() const { return "RenderSVGHiddenContainer"; } diff --git a/WebCore/rendering/RenderSVGImage.cpp b/WebCore/rendering/RenderSVGImage.cpp index b38352e..7e0b40d 100644 --- a/WebCore/rendering/RenderSVGImage.cpp +++ b/WebCore/rendering/RenderSVGImage.cpp @@ -2,7 +2,7 @@ Copyright (C) 2006 Alexander Kellett <lypanov@kde.org> Copyright (C) 2006 Apple Computer, Inc. Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> - Copyright (C) 2007, 2008 Rob Buis <buis@kde.org> + Copyright (C) 2007, 2008, 2009 Rob Buis <buis@kde.org> Copyright (C) 2009, Google, Inc. This library is free software; you can redistribute it and/or @@ -47,10 +47,6 @@ RenderSVGImage::RenderSVGImage(SVGImageElement* impl) { } -RenderSVGImage::~RenderSVGImage() -{ -} - void RenderSVGImage::adjustRectsForAspectRatio(FloatRect& destRect, FloatRect& srcRect, SVGPreserveAspectRatio* aspectRatio) { float origDestWidth = destRect.width(); @@ -59,7 +55,7 @@ void RenderSVGImage::adjustRectsForAspectRatio(FloatRect& destRect, FloatRect& s float widthToHeightMultiplier = srcRect.height() / srcRect.width(); if (origDestHeight > (origDestWidth * widthToHeightMultiplier)) { destRect.setHeight(origDestWidth * widthToHeightMultiplier); - switch(aspectRatio->align()) { + switch (aspectRatio->align()) { case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMID: case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID: case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMID: @@ -74,7 +70,7 @@ void RenderSVGImage::adjustRectsForAspectRatio(FloatRect& destRect, FloatRect& s } if (origDestWidth > (origDestHeight / widthToHeightMultiplier)) { destRect.setWidth(origDestHeight / widthToHeightMultiplier); - switch(aspectRatio->align()) { + switch (aspectRatio->align()) { case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMIN: case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID: case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMAX: @@ -93,7 +89,7 @@ void RenderSVGImage::adjustRectsForAspectRatio(FloatRect& destRect, FloatRect& s if (origDestHeight < (origDestWidth * widthToHeightMultiplier)) { float destToSrcMultiplier = srcRect.width() / destRect.width(); srcRect.setHeight(destRect.height() * destToSrcMultiplier); - switch(aspectRatio->align()) { + switch (aspectRatio->align()) { case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMID: case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID: case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMID: @@ -110,7 +106,7 @@ void RenderSVGImage::adjustRectsForAspectRatio(FloatRect& destRect, FloatRect& s if (origDestWidth < (origDestHeight / widthToHeightMultiplier)) { float destToSrcMultiplier = srcRect.height() / destRect.height(); srcRect.setWidth(destRect.width() * destToSrcMultiplier); - switch(aspectRatio->align()) { + switch (aspectRatio->align()) { case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMIN: case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID: case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMAX: @@ -227,9 +223,7 @@ FloatRect RenderSVGImage::repaintRectInLocalCoordinates() const void RenderSVGImage::imageChanged(WrappedImagePtr image, const IntRect* rect) { RenderImage::imageChanged(image, rect); - - // We override to invalidate a larger rect, since SVG images can draw outside their "bounds" - repaintRectangle(absoluteClippedOverflowRect()); // FIXME: Isn't this just repaint()? + repaint(); } IntRect RenderSVGImage::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) diff --git a/WebCore/rendering/RenderSVGImage.h b/WebCore/rendering/RenderSVGImage.h index 01b8b65..ef11719 100644 --- a/WebCore/rendering/RenderSVGImage.h +++ b/WebCore/rendering/RenderSVGImage.h @@ -1,6 +1,6 @@ /* Copyright (C) 2006 Alexander Kellett <lypanov@kde.org> - Copyright (C) 2006 Apple Computer, Inc. + Copyright (C) 2006, 2009 Apple Inc. All rights reserved. Copyright (C) 2007 Rob Buis <buis@kde.org> Copyright (C) 2009 Google, Inc. @@ -38,8 +38,8 @@ namespace WebCore { class RenderSVGImage : public RenderImage, SVGRenderBase { public: RenderSVGImage(SVGImageElement*); - virtual ~RenderSVGImage(); + private: virtual const char* renderName() const { return "RenderSVGImage"; } virtual bool isSVGImage() const { return true; } @@ -63,12 +63,11 @@ namespace WebCore { virtual void layout(); virtual void paint(PaintInfo&, int parentX, int parentY); - bool requiresLayer() const { return false; } + virtual bool requiresLayer() const { return false; } virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction); - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int _x, int _y, int _tx, int _ty, HitTestAction); + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); - private: virtual TransformationMatrix localTransform() const { return m_localTransform; } TransformationMatrix m_localTransform; diff --git a/WebCore/rendering/RenderSVGInline.cpp b/WebCore/rendering/RenderSVGInline.cpp index 3c44dd8..cf97b52 100644 --- a/WebCore/rendering/RenderSVGInline.cpp +++ b/WebCore/rendering/RenderSVGInline.cpp @@ -39,10 +39,10 @@ RenderSVGInline::RenderSVGInline(Node* n) { } -InlineFlowBox* RenderSVGInline::createFlowBox() +InlineFlowBox* RenderSVGInline::createInlineFlowBox() { InlineFlowBox* box = new (renderArena()) SVGInlineFlowBox(this); - box->setIsSVG(true); + box->setHasVirtualHeight(); return box; } diff --git a/WebCore/rendering/RenderSVGInline.h b/WebCore/rendering/RenderSVGInline.h index 1ff8d02..9f9f3f5 100644 --- a/WebCore/rendering/RenderSVGInline.h +++ b/WebCore/rendering/RenderSVGInline.h @@ -40,7 +40,7 @@ public: virtual void absoluteQuads(Vector<FloatQuad>&); private: - virtual InlineFlowBox* createFlowBox(); + virtual InlineFlowBox* createInlineFlowBox(); }; } diff --git a/WebCore/rendering/RenderSVGInlineText.cpp b/WebCore/rendering/RenderSVGInlineText.cpp index b1a21d7..48d01ae 100644 --- a/WebCore/rendering/RenderSVGInlineText.cpp +++ b/WebCore/rendering/RenderSVGInlineText.cpp @@ -134,7 +134,7 @@ FloatQuad RenderSVGInlineText::computeRepaintQuadForRange(RenderBoxModelObject* InlineTextBox* RenderSVGInlineText::createTextBox() { InlineTextBox* box = new (renderArena()) SVGInlineTextBox(this); - box->setIsSVG(true); + box->setHasVirtualHeight(); return box; } diff --git a/WebCore/rendering/RenderSVGInlineText.h b/WebCore/rendering/RenderSVGInlineText.h index c4a096d..e9c5d6e 100644 --- a/WebCore/rendering/RenderSVGInlineText.h +++ b/WebCore/rendering/RenderSVGInlineText.h @@ -33,6 +33,8 @@ namespace WebCore { class RenderSVGInlineText : public RenderText { public: RenderSVGInlineText(Node*, PassRefPtr<StringImpl>); + +private: virtual const char* renderName() const { return "RenderSVGInlineText"; } virtual void styleDidChange(StyleDifference, const RenderStyle*); @@ -49,7 +51,6 @@ public: virtual void destroy(); -private: virtual InlineTextBox* createTextBox(); IntRect computeRepaintRectForRange(RenderBoxModelObject* repaintContainer, int startPos, int endPos); FloatQuad computeRepaintQuadForRange(RenderBoxModelObject* repaintContainer, int startPos, int endPos); diff --git a/WebCore/rendering/RenderSVGRoot.cpp b/WebCore/rendering/RenderSVGRoot.cpp index 80c29dd..0a39bf4 100644 --- a/WebCore/rendering/RenderSVGRoot.cpp +++ b/WebCore/rendering/RenderSVGRoot.cpp @@ -48,10 +48,6 @@ RenderSVGRoot::RenderSVGRoot(SVGStyledElement* node) setReplaced(true); } -RenderSVGRoot::~RenderSVGRoot() -{ -} - int RenderSVGRoot::lineHeight(bool, bool) const { return height() + marginTop() + marginBottom(); diff --git a/WebCore/rendering/RenderSVGRoot.h b/WebCore/rendering/RenderSVGRoot.h index 50866d2..08c3058 100644 --- a/WebCore/rendering/RenderSVGRoot.h +++ b/WebCore/rendering/RenderSVGRoot.h @@ -2,6 +2,7 @@ Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org> 2004, 2005, 2007 Rob Buis <buis@kde.org> Copyright (C) 2009 Google, Inc. All rights reserved. + Copyright (C) 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 @@ -35,13 +36,14 @@ class TransformationMatrix; class RenderSVGRoot : public RenderBox, SVGRenderBase { public: RenderSVGRoot(SVGStyledElement*); - ~RenderSVGRoot(); - virtual RenderObjectChildList* virtualChildren() { return children(); } - virtual const RenderObjectChildList* virtualChildren() const { return children(); } const RenderObjectChildList* children() const { return &m_children; } RenderObjectChildList* children() { return &m_children; } +private: + virtual RenderObjectChildList* virtualChildren() { return children(); } + virtual const RenderObjectChildList* virtualChildren() const { return children(); } + virtual bool isSVGRoot() const { return true; } virtual const char* renderName() const { return "RenderSVGRoot"; } @@ -70,7 +72,6 @@ public: virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&) const; -private: void calcViewport(); const FloatSize& viewportSize() const; @@ -85,6 +86,21 @@ private: FloatSize m_viewportSize; }; +inline RenderSVGRoot* toRenderSVGRoot(RenderObject* object) +{ + ASSERT(!object || object->isSVGRoot()); + return static_cast<RenderSVGRoot*>(object); +} + +inline const RenderSVGRoot* toRenderSVGRoot(const RenderObject* object) +{ + ASSERT(!object || object->isSVGRoot()); + return static_cast<const RenderSVGRoot*>(object); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderSVGRoot(const RenderSVGRoot*); + } // namespace WebCore #endif // ENABLE(SVG) diff --git a/WebCore/rendering/RenderSVGText.cpp b/WebCore/rendering/RenderSVGText.cpp index 9e9809d..3919d7f 100644 --- a/WebCore/rendering/RenderSVGText.cpp +++ b/WebCore/rendering/RenderSVGText.cpp @@ -89,10 +89,10 @@ void RenderSVGText::layout() setNeedsLayout(false); } -RootInlineBox* RenderSVGText::createRootBox() +RootInlineBox* RenderSVGText::createRootInlineBox() { RootInlineBox* box = new (renderArena()) SVGRootInlineBox(this); - box->setIsSVG(true); + box->setHasVirtualHeight(); return box; } diff --git a/WebCore/rendering/RenderSVGText.h b/WebCore/rendering/RenderSVGText.h index c1f1430..9a2770b 100644 --- a/WebCore/rendering/RenderSVGText.h +++ b/WebCore/rendering/RenderSVGText.h @@ -37,6 +37,7 @@ class RenderSVGText : public RenderSVGBlock { public: RenderSVGText(SVGTextElement* node); +private: virtual const char* renderName() const { return "RenderSVGText"; } virtual bool isSVGText() const { return true; } @@ -61,11 +62,10 @@ public: virtual FloatRect objectBoundingBox() const; virtual FloatRect repaintRectInLocalCoordinates() const; -private: // FIXME: This can be removed when localTransform() is removed from RenderObject virtual TransformationMatrix localTransform() const { return m_localTransform; } - virtual RootInlineBox* createRootBox(); + virtual RootInlineBox* createRootInlineBox(); TransformationMatrix m_localTransform; }; diff --git a/WebCore/rendering/RenderSVGTextPath.h b/WebCore/rendering/RenderSVGTextPath.h index efab659..8e6ff42 100644 --- a/WebCore/rendering/RenderSVGTextPath.h +++ b/WebCore/rendering/RenderSVGTextPath.h @@ -2,6 +2,7 @@ * This file is part of the WebKit project. * * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 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 @@ -37,9 +38,9 @@ namespace WebCore { bool exactAlignment() const; bool stretchMethod() const; + private: virtual const char* renderName() const { return "RenderSVGTextPath"; } - private: float m_startOffset; bool m_exactAlignment : 1; @@ -47,6 +48,16 @@ namespace WebCore { Path m_layoutPath; }; + + inline RenderSVGTextPath* toRenderSVGTextPath(RenderObject* object) + { + ASSERT(!object || !strcmp(object->renderName(), "RenderSVGTextPath")); + return static_cast<RenderSVGTextPath*>(object); + } + + // This will catch anyone doing an unnecessary cast. + void toRenderSVGTextPath(const RenderSVGTextPath*); + } #endif // ENABLE(SVG) diff --git a/WebCore/rendering/RenderSVGViewportContainer.cpp b/WebCore/rendering/RenderSVGViewportContainer.cpp index d208621..a432ef3 100644 --- a/WebCore/rendering/RenderSVGViewportContainer.cpp +++ b/WebCore/rendering/RenderSVGViewportContainer.cpp @@ -38,14 +38,14 @@ RenderSVGViewportContainer::RenderSVGViewportContainer(SVGStyledElement* node) { } -RenderSVGViewportContainer::~RenderSVGViewportContainer() -{ -} - void RenderSVGViewportContainer::paint(PaintInfo& paintInfo, int parentX, int parentY) { + // FIXME: The if statement here evaluates to false. isEmpty() is exactly the same + // as what is on the right side, so it's basically !isEmpty && isEmpty. So this + // function does nothing. + // A value of zero disables rendering of the element. - if (!viewport().isEmpty() && (viewport().width() <= 0. || viewport().height() <= 0.)) + if (!m_viewport.isEmpty() && (m_viewport.width() <= 0. || m_viewport.height() <= 0.)) return; RenderSVGContainer::paint(paintInfo, parentX, parentY); @@ -54,12 +54,7 @@ void RenderSVGViewportContainer::paint(PaintInfo& paintInfo, int parentX, int pa void RenderSVGViewportContainer::applyViewportClip(PaintInfo& paintInfo) { if (style()->overflowX() != OVISIBLE) - paintInfo.context->clip(enclosingIntRect(viewport())); // FIXME: Eventually we'll want float-precision clipping -} - -FloatRect RenderSVGViewportContainer::viewport() const -{ - return m_viewport; + paintInfo.context->clip(enclosingIntRect(m_viewport)); // FIXME: Eventually we'll want float-precision clipping } void RenderSVGViewportContainer::calcViewport() @@ -91,10 +86,10 @@ TransformationMatrix RenderSVGViewportContainer::viewportTransform() const { if (node()->hasTagName(SVGNames::svgTag)) { SVGSVGElement* svg = static_cast<SVGSVGElement*>(node()); - return svg->viewBoxToViewTransform(viewport().width(), viewport().height()); + return svg->viewBoxToViewTransform(m_viewport.width(), m_viewport.height()); } else if (node()->hasTagName(SVGNames::markerTag)) { SVGMarkerElement* marker = static_cast<SVGMarkerElement*>(node()); - return marker->viewBoxToViewTransform(viewport().width(), viewport().height()); + return marker->viewBoxToViewTransform(m_viewport.width(), m_viewport.height()); } return TransformationMatrix(); @@ -103,7 +98,7 @@ TransformationMatrix RenderSVGViewportContainer::viewportTransform() const TransformationMatrix RenderSVGViewportContainer::localToParentTransform() const { TransformationMatrix viewportTranslation; - viewportTranslation.translate(viewport().x(), viewport().y()); + viewportTranslation.translate(m_viewport.x(), m_viewport.y()); return viewportTransform() * viewportTranslation; // If this class were ever given a localTransform(), then the above would read: // return viewportTransform() * localTransform() * viewportTranslation; @@ -121,7 +116,7 @@ bool RenderSVGViewportContainer::pointIsInsideViewportClip(const FloatPoint& poi // Respect the viewport clip (which is in parent coords). SVG does not support separate x/y overflow rules. if (style()->overflowX() == OHIDDEN) { ASSERT(style()->overflowY() == OHIDDEN); - if (!viewport().contains(pointInParent)) + if (!m_viewport.contains(pointInParent)) return false; } return true; diff --git a/WebCore/rendering/RenderSVGViewportContainer.h b/WebCore/rendering/RenderSVGViewportContainer.h index 8657af4..b8b30b5 100644 --- a/WebCore/rendering/RenderSVGViewportContainer.h +++ b/WebCore/rendering/RenderSVGViewportContainer.h @@ -2,6 +2,7 @@ Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org> 2004, 2005, 2007 Rob Buis <buis@kde.org> 2009 Google, Inc. + Copyright (C) 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 @@ -33,24 +34,21 @@ namespace WebCore { class RenderSVGViewportContainer : public RenderSVGContainer { public: RenderSVGViewportContainer(SVGStyledElement*); - ~RenderSVGViewportContainer(); - virtual bool isSVGContainer() const { return true; } - virtual const char* renderName() const { return "RenderSVGViewportContainer"; } + // FIXME: This is only public for SVGResourceMarker::draw, likely the callsite should be changed. + TransformationMatrix viewportTransform() const; virtual void paint(PaintInfo&, int parentX, int parentY); +private: + virtual bool isSVGContainer() const { return true; } + virtual const char* renderName() const { return "RenderSVGViewportContainer"; } + virtual TransformationMatrix localToParentTransform() const; // FIXME: This override should be removed once callers of RenderBox::absoluteTransform() can be removed. virtual TransformationMatrix absoluteTransform() const; - FloatRect viewport() const; - - // FIXME: This is only public for SVGResourceMarker::draw, likely the callsite should be changed. - TransformationMatrix viewportTransform() const; - -private: virtual void calcViewport(); virtual void applyViewportClip(PaintInfo&); @@ -59,6 +57,15 @@ private: FloatRect m_viewport; }; +inline RenderSVGViewportContainer* toRenderSVGViewportContainer(RenderObject* object) +{ + ASSERT(!object || !strcmp(object->renderName(), "RenderSVGViewportContainer")); + return static_cast<RenderSVGViewportContainer*>(object); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderSVGViewportContainer(const RenderSVGViewportContainer*); + } // namespace WebCore #endif // ENABLE(SVG) diff --git a/WebCore/rendering/RenderScrollbar.cpp b/WebCore/rendering/RenderScrollbar.cpp index db24a06..b3c5369 100644 --- a/WebCore/rendering/RenderScrollbar.cpp +++ b/WebCore/rendering/RenderScrollbar.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -25,6 +25,7 @@ #include "config.h" #include "RenderScrollbar.h" + #include "RenderScrollbarPart.h" #include "RenderScrollbarTheme.h" @@ -173,9 +174,14 @@ static PseudoId pseudoForScrollbarPart(ScrollbarPart part) return SCROLLBAR_THUMB; case TrackBGPart: return SCROLLBAR_TRACK; - default: + case ScrollbarBGPart: return SCROLLBAR; + case NoPart: + case AllParts: + break; } + ASSERT_NOT_REACHED(); + return SCROLLBAR; } void RenderScrollbar::updateScrollbarPart(ScrollbarPart partType, bool destroy) diff --git a/WebCore/rendering/RenderScrollbar.h b/WebCore/rendering/RenderScrollbar.h index 524c4e8..b3c00ef 100644 --- a/WebCore/rendering/RenderScrollbar.h +++ b/WebCore/rendering/RenderScrollbar.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,7 +33,6 @@ namespace WebCore { class RenderBox; -class RenderStyle; class RenderScrollbarPart; class RenderStyle; @@ -46,21 +45,9 @@ public: static PassRefPtr<Scrollbar> createCustomScrollbar(ScrollbarClient*, ScrollbarOrientation, RenderBox*); virtual ~RenderScrollbar(); - virtual void setParent(ScrollView*); - virtual void setEnabled(bool); - - virtual void paint(GraphicsContext*, const IntRect& damageRect); - - virtual void setHoveredPart(ScrollbarPart); - virtual void setPressedPart(ScrollbarPart); - - void updateScrollbarParts(bool destroy = false); - static ScrollbarPart partForStyleResolve(); static RenderScrollbar* scrollbarForStyleResolve(); - virtual void styleChanged(); - RenderBox* owningRenderer() const { return m_owner; } void paintPart(GraphicsContext*, ScrollbarPart, const IntRect&); @@ -72,6 +59,20 @@ public: int minimumThumbLength(); private: + virtual void setParent(ScrollView*); + virtual void setEnabled(bool); + + virtual void paint(GraphicsContext*, const IntRect& damageRect); + + virtual void setHoveredPart(ScrollbarPart); + virtual void setPressedPart(ScrollbarPart); + + virtual void styleChanged(); + + virtual bool isCustomScrollbar() const { return true; } + + void updateScrollbarParts(bool destroy = false); + PassRefPtr<RenderStyle> getScrollbarPseudoStyle(ScrollbarPart, PseudoId); void updateScrollbarPart(ScrollbarPart, bool destroy = false); @@ -79,6 +80,15 @@ private: HashMap<unsigned, RenderScrollbarPart*> m_parts; }; +inline RenderScrollbar* toRenderScrollbar(Scrollbar* scrollbar) +{ + ASSERT(!scrollbar || scrollbar->isCustomScrollbar()); + return static_cast<RenderScrollbar*>(scrollbar); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderScrollbar(const RenderScrollbar*); + } // namespace WebCore #endif // RenderScrollbar_h diff --git a/WebCore/rendering/RenderScrollbarTheme.cpp b/WebCore/rendering/RenderScrollbarTheme.cpp index d7cfb2b..06ca32a 100644 --- a/WebCore/rendering/RenderScrollbarTheme.cpp +++ b/WebCore/rendering/RenderScrollbarTheme.cpp @@ -66,17 +66,17 @@ bool RenderScrollbarTheme::hasThumb(Scrollbar* scrollbar) int RenderScrollbarTheme::minimumThumbLength(Scrollbar* scrollbar) { - return static_cast<RenderScrollbar*>(scrollbar)->minimumThumbLength(); + return toRenderScrollbar(scrollbar)->minimumThumbLength(); } IntRect RenderScrollbarTheme::backButtonRect(Scrollbar* scrollbar, ScrollbarPart partType, bool) { - return static_cast<RenderScrollbar*>(scrollbar)->buttonRect(partType); + return toRenderScrollbar(scrollbar)->buttonRect(partType); } IntRect RenderScrollbarTheme::forwardButtonRect(Scrollbar* scrollbar, ScrollbarPart partType, bool) { - return static_cast<RenderScrollbar*>(scrollbar)->buttonRect(partType); + return toRenderScrollbar(scrollbar)->buttonRect(partType); } IntRect RenderScrollbarTheme::trackRect(Scrollbar* scrollbar, bool) @@ -88,13 +88,13 @@ IntRect RenderScrollbarTheme::trackRect(Scrollbar* scrollbar, bool) int endLength; buttonSizesAlongTrackAxis(scrollbar, startLength, endLength); - return static_cast<RenderScrollbar*>(scrollbar)->trackRect(startLength, endLength); + return toRenderScrollbar(scrollbar)->trackRect(startLength, endLength); } IntRect RenderScrollbarTheme::constrainTrackRectToTrackPieces(Scrollbar* scrollbar, const IntRect& rect) { - IntRect backRect = static_cast<RenderScrollbar*>(scrollbar)->trackPieceRectWithMargins(BackTrackPart, rect); - IntRect forwardRect = static_cast<RenderScrollbar*>(scrollbar)->trackPieceRectWithMargins(ForwardTrackPart, rect); + IntRect backRect = toRenderScrollbar(scrollbar)->trackPieceRectWithMargins(BackTrackPart, rect); + IntRect forwardRect = toRenderScrollbar(scrollbar)->trackPieceRectWithMargins(ForwardTrackPart, rect); IntRect result = rect; if (scrollbar->orientation() == HorizontalScrollbar) { result.setX(backRect.x()); @@ -114,27 +114,27 @@ void RenderScrollbarTheme::paintScrollCorner(ScrollView*, GraphicsContext* conte void RenderScrollbarTheme::paintScrollbarBackground(GraphicsContext* context, Scrollbar* scrollbar) { - static_cast<RenderScrollbar*>(scrollbar)->paintPart(context, ScrollbarBGPart, scrollbar->frameRect()); + toRenderScrollbar(scrollbar)->paintPart(context, ScrollbarBGPart, scrollbar->frameRect()); } void RenderScrollbarTheme::paintTrackBackground(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect) { - static_cast<RenderScrollbar*>(scrollbar)->paintPart(context, TrackBGPart, rect); + toRenderScrollbar(scrollbar)->paintPart(context, TrackBGPart, rect); } void RenderScrollbarTheme::paintTrackPiece(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect, ScrollbarPart part) { - static_cast<RenderScrollbar*>(scrollbar)->paintPart(context, part, rect); + toRenderScrollbar(scrollbar)->paintPart(context, part, rect); } void RenderScrollbarTheme::paintButton(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect, ScrollbarPart part) { - static_cast<RenderScrollbar*>(scrollbar)->paintPart(context, part, rect); + toRenderScrollbar(scrollbar)->paintPart(context, part, rect); } void RenderScrollbarTheme::paintThumb(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect) { - static_cast<RenderScrollbar*>(scrollbar)->paintPart(context, ThumbPart, rect); + toRenderScrollbar(scrollbar)->paintPart(context, ThumbPart, rect); } } diff --git a/WebCore/rendering/RenderSlider.cpp b/WebCore/rendering/RenderSlider.cpp index f1e35e5..8a19d97 100644 --- a/WebCore/rendering/RenderSlider.cpp +++ b/WebCore/rendering/RenderSlider.cpp @@ -125,47 +125,57 @@ public: bool inDragMode() const { return m_inDragMode; } virtual void defaultEventHandler(Event*); + virtual void detach(); private: virtual bool isShadowNode() const { return true; } virtual Node* shadowParentNode() { return m_shadowParent; } + FloatPoint m_offsetToThumb; Node* m_shadowParent; - FloatPoint m_initialClickPoint; // initial click point in RenderSlider-local coordinates - int m_initialPosition; bool m_inDragMode; }; SliderThumbElement::SliderThumbElement(Document* document, Node* shadowParent) : HTMLDivElement(divTag, document) , m_shadowParent(shadowParent) - , m_initialPosition(0) , m_inDragMode(false) { } void SliderThumbElement::defaultEventHandler(Event* event) { + if (!event->isMouseEvent()) { + HTMLDivElement::defaultEventHandler(event); + return; + } + + MouseEvent* mouseEvent = static_cast<MouseEvent*>(event); + bool isLeftButton = mouseEvent->button() == LeftButton; const AtomicString& eventType = event->type(); - if (eventType == eventNames().mousedownEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) { - MouseEvent* mouseEvent = static_cast<MouseEvent*>(event); - RenderSlider* slider; - if (document()->frame() && renderer() && - (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(mouseEvent->absoluteLocation(), false, true); - // Cache the initial position of the thumb. - m_initialPosition = slider->currentPosition(); - m_inDragMode = true; - - document()->frame()->eventHandler()->setCapturingMouseEventsNode(m_shadowParent); - - event->setDefaultHandled(); - return; + + if (eventType == eventNames().mousedownEvent && isLeftButton) { + if (document()->frame() && renderer()) { + RenderSlider* slider = toRenderSlider(renderer()->parent()); + if (slider) { + if (slider->mouseEventIsInThumb(mouseEvent)) { + // We selected the thumb, we want the cursor to always stay at + // the same position relative to the thumb. + m_offsetToThumb = slider->mouseEventOffsetToThumb(mouseEvent); + } else { + // We are outside the thumb, move the thumb to the point were + // we clicked. We'll be exactly at the center of the thumb. + m_offsetToThumb.setX(0); + m_offsetToThumb.setY(0); + } + + m_inDragMode = true; + document()->frame()->eventHandler()->setCapturingMouseEventsNode(m_shadowParent); + event->setDefaultHandled(); + return; + } } - } else if (eventType == eventNames().mouseupEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) { + } else if (eventType == eventNames().mouseupEvent && isLeftButton) { if (m_inDragMode) { if (Frame* frame = document()->frame()) frame->eventHandler()->setCapturingMouseEventsNode(0); @@ -173,24 +183,31 @@ void SliderThumbElement::defaultEventHandler(Event* event) event->setDefaultHandled(); return; } - } else if (eventType == eventNames().mousemoveEvent && event->isMouseEvent()) { + } else if (eventType == eventNames().mousemoveEvent) { if (m_inDragMode && renderer() && renderer()->parent()) { - // Move the slider - MouseEvent* mouseEvent = static_cast<MouseEvent*>(event); - RenderSlider* slider = static_cast<RenderSlider*>(renderer()->parent()); - - FloatPoint curPoint = slider->absoluteToLocal(mouseEvent->absoluteLocation(), false, true); - IntPoint eventOffset(m_initialPosition + curPoint.x() - m_initialClickPoint.x() + renderBox()->width() / 2, - m_initialPosition + curPoint.y() - m_initialClickPoint.y() + renderBox()->height() / 2); - slider->setValueForPosition(slider->positionForOffset(eventOffset)); - event->setDefaultHandled(); - return; + RenderSlider* slider = toRenderSlider(renderer()->parent()); + if (slider) { + FloatPoint curPoint = slider->absoluteToLocal(mouseEvent->absoluteLocation(), false, true); + IntPoint eventOffset(curPoint.x() + m_offsetToThumb.x(), curPoint.y() + m_offsetToThumb.y()); + slider->setValueForPosition(slider->positionForOffset(eventOffset)); + event->setDefaultHandled(); + return; + } } } HTMLDivElement::defaultEventHandler(event); } +void SliderThumbElement::detach() +{ + if (m_inDragMode) { + if (Frame* frame = document()->frame()) + frame->eventHandler()->setCapturingMouseEventsNode(0); + } + HTMLDivElement::detach(); +} + RenderSlider::RenderSlider(HTMLInputElement* element) : RenderBlock(element) { @@ -272,6 +289,30 @@ PassRefPtr<RenderStyle> RenderSlider::createThumbStyle(const RenderStyle* parent return style.release(); } +IntRect RenderSlider::thumbRect() +{ + if (!m_thumb) + return IntRect(); + + IntRect thumbRect; + RenderBox* thumb = toRenderBox(m_thumb->renderer()); + + thumbRect.setWidth(thumb->style()->width().calcMinValue(contentWidth())); + thumbRect.setHeight(thumb->style()->height().calcMinValue(contentHeight())); + + double fraction = sliderPosition(static_cast<HTMLInputElement*>(node())); + IntRect contentRect = contentBoxRect(); + if (style()->appearance() == SliderVerticalPart) { + thumbRect.setX(contentRect.x() + (contentRect.width() - thumbRect.width()) / 2); + thumbRect.setY(contentRect.y() + static_cast<int>(nextafter((contentRect.height() - thumbRect.height()) + 1, 0) * (1 - fraction))); + } else { + thumbRect.setX(contentRect.x() + static_cast<int>(nextafter((contentRect.width() - thumbRect.width()) + 1, 0) * fraction)); + thumbRect.setY(contentRect.y() + (contentRect.height() - thumbRect.height()) / 2); + } + + return thumbRect; +} + void RenderSlider::layout() { ASSERT(needsLayout()); @@ -311,23 +352,8 @@ void RenderSlider::layout() thumb->layoutIfNeeded(); - IntRect thumbRect; - - thumbRect.setWidth(thumb->style()->width().calcMinValue(contentWidth())); - thumbRect.setHeight(thumb->style()->height().calcMinValue(contentHeight())); - - double fraction = sliderPosition(static_cast<HTMLInputElement*>(node())); - IntRect contentRect = contentBoxRect(); - if (style()->appearance() == SliderVerticalPart) { - thumbRect.setX(contentRect.x() + (contentRect.width() - thumbRect.width()) / 2); - thumbRect.setY(contentRect.y() + static_cast<int>(nextafter((contentRect.height() - thumbRect.height()) + 1, 0) * (1 - fraction))); - } else { - thumbRect.setX(contentRect.x() + static_cast<int>(nextafter((contentRect.width() - thumbRect.width()) + 1, 0) * fraction)); - thumbRect.setY(contentRect.y() + (contentRect.height() - thumbRect.height()) / 2); - } - - thumb->setFrameRect(thumbRect); - + IntRect rect = thumbRect(); + thumb->setFrameRect(rect); if (thumb->checkForRepaintDuringLayout()) thumb->repaintDuringLayoutIfMoved(oldThumbRect); @@ -391,6 +417,17 @@ bool RenderSlider::mouseEventIsInThumb(MouseEvent* evt) return thumbBounds.contains(roundedIntPoint(localPoint)); } +FloatPoint RenderSlider::mouseEventOffsetToThumb(MouseEvent* evt) +{ + ASSERT(m_thumb && m_thumb->renderer()); + FloatPoint localPoint = m_thumb->renderBox()->absoluteToLocal(evt->absoluteLocation(), false, true); + IntRect thumbBounds = m_thumb->renderBox()->borderBoxRect(); + FloatPoint offset; + offset.setX(thumbBounds.x() + thumbBounds.width() / 2 - localPoint.x()); + offset.setY(thumbBounds.y() + thumbBounds.height() / 2 - localPoint.y()); + return offset; +} + void RenderSlider::setValueForPosition(int position) { if (!m_thumb || !m_thumb->renderer()) diff --git a/WebCore/rendering/RenderSlider.h b/WebCore/rendering/RenderSlider.h index f1eab9c..92ad73b 100644 --- a/WebCore/rendering/RenderSlider.h +++ b/WebCore/rendering/RenderSlider.h @@ -36,17 +36,19 @@ namespace WebCore { void forwardEvent(Event*); bool inDragMode() const; + IntRect thumbRect(); private: virtual const char* renderName() const { return "RenderSlider"; } virtual bool isSlider() const { return true; } - virtual int baselinePosition( bool, bool ) const; + virtual int baselinePosition(bool, bool) const; virtual void calcPrefWidths(); virtual void layout(); virtual void updateFromElement(); bool mouseEventIsInThumb(MouseEvent*); + FloatPoint mouseEventOffsetToThumb(MouseEvent*); void setValueForPosition(int position); void setPositionFromValue(); @@ -65,6 +67,15 @@ namespace WebCore { friend class SliderThumbElement; }; + inline RenderSlider* toRenderSlider(RenderObject* object) + { + ASSERT(!object || object->isSlider()); + return static_cast<RenderSlider*>(object); + } + + // This will catch anyone doing an unnecessary cast. + void toRenderSlider(const RenderSlider*); + } // namespace WebCore #endif // RenderSlider_h diff --git a/WebCore/rendering/RenderTable.cpp b/WebCore/rendering/RenderTable.cpp index ed1be3e..7599999 100644 --- a/WebCore/rendering/RenderTable.cpp +++ b/WebCore/rendering/RenderTable.cpp @@ -4,7 +4,7 @@ * (C) 1998 Waldo Bastian (bastian@kde.org) * (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) - * 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. * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com) * * This library is free software; you can redistribute it and/or @@ -53,7 +53,6 @@ RenderTable::RenderTable(Node* node) , m_head(0) , m_foot(0) , m_firstBody(0) - , m_tableLayout(0) , m_currentBorder(0) , m_hasColElements(false) , m_needsSectionRecalc(0) @@ -69,11 +68,6 @@ RenderTable::RenderTable(Node* node) m_columns.fill(ColumnStruct(), 1); } -RenderTable::~RenderTable() -{ - delete m_tableLayout; -} - void RenderTable::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { RenderBlock::styleDidChange(diff, oldStyle); @@ -86,14 +80,12 @@ void RenderTable::styleDidChange(StyleDifference diff, const RenderStyle* oldSty m_columnPos[0] = m_hSpacing; if (!m_tableLayout || style()->tableLayout() != oldTableLayout) { - delete m_tableLayout; - // According to the CSS2 spec, you only use fixed table layout if an // explicit width is specified on the table. Auto width implies auto table layout. if (style()->tableLayout() == TFIXED && !style()->width().isAuto()) - m_tableLayout = new FixedTableLayout(this); + m_tableLayout.set(new FixedTableLayout(this)); else - m_tableLayout = new AutoTableLayout(this); + m_tableLayout.set(new AutoTableLayout(this)); } } @@ -136,18 +128,18 @@ void RenderTable::addChild(RenderObject* child, RenderObject* beforeChild) case TABLE_HEADER_GROUP: resetSectionPointerIfNotBefore(m_head, beforeChild); if (!m_head) { - m_head = static_cast<RenderTableSection*>(child); + m_head = toRenderTableSection(child); } else { resetSectionPointerIfNotBefore(m_firstBody, beforeChild); if (!m_firstBody) - m_firstBody = static_cast<RenderTableSection*>(child); + m_firstBody = toRenderTableSection(child); } wrapInAnonymousSection = false; break; case TABLE_FOOTER_GROUP: resetSectionPointerIfNotBefore(m_foot, beforeChild); if (!m_foot) { - m_foot = static_cast<RenderTableSection*>(child); + m_foot = toRenderTableSection(child); wrapInAnonymousSection = false; break; } @@ -155,7 +147,7 @@ void RenderTable::addChild(RenderObject* child, RenderObject* beforeChild) case TABLE_ROW_GROUP: resetSectionPointerIfNotBefore(m_firstBody, beforeChild); if (!m_firstBody) - m_firstBody = static_cast<RenderTableSection*>(child); + m_firstBody = toRenderTableSection(child); wrapInAnonymousSection = false; break; default: @@ -347,11 +339,14 @@ void RenderTable::layout() #endif if (child->isTableSection()) { child->layoutIfNeeded(); - RenderTableSection* section = static_cast<RenderTableSection*>(child); + RenderTableSection* section = toRenderTableSection(child); calculatedHeight += section->calcRowHeight(); if (collapsing) section->recalcOuterBorder(); ASSERT(!section->needsLayout()); + } else if (child->isTableCol()) { + child->layoutIfNeeded(); + ASSERT(!child->needsLayout()); } } @@ -408,7 +403,7 @@ void RenderTable::layout() for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { 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); + toRenderTableSection(child)->layoutRows(child == m_firstBody ? max(0, th - calculatedHeight) : 0); } if (!m_firstBody && th > calculatedHeight && !style()->htmlHacks()) { @@ -462,13 +457,17 @@ void RenderTable::layout() layoutPositionedObjects(true); 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, width() + boxShadow->x + boxShadow->blur); - m_overflowTop = min(m_overflowTop, boxShadow->y - boxShadow->blur); - m_overflowHeight = max(m_overflowHeight, height() + boxShadow->y + boxShadow->blur); - } - + int shadowLeft; + int shadowRight; + int shadowTop; + int shadowBottom; + style()->getBoxShadowExtent(shadowTop, shadowRight, shadowBottom, shadowLeft); + + m_overflowLeft = min(m_overflowLeft, shadowLeft); + m_overflowWidth = max(m_overflowWidth, width() + shadowRight); + m_overflowTop = min(m_overflowTop, shadowTop); + m_overflowHeight = max(m_overflowHeight, height() + shadowBottom); + if (hasReflection()) { IntRect reflection(reflectionBox()); m_overflowTop = min(m_overflowTop, reflection.y()); @@ -492,7 +491,7 @@ void RenderTable::setCellWidths() { for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { if (child->isTableSection()) - static_cast<RenderTableSection*>(child)->setCellWidths(); + toRenderTableSection(child)->setCellWidths(); } } @@ -552,7 +551,7 @@ void RenderTable::paintObject(PaintInfo& paintInfo, int tx, int ty) RenderObject* stop = nextInPreOrderAfterChildren(); for (RenderObject* o = firstChild(); o && o != stop; o = o->nextInPreOrder()) if (o->isTableCell()) - static_cast<RenderTableCell*>(o)->collectBorderStyles(borderStyles); + toRenderTableCell(o)->collectBorderStyles(borderStyles); RenderTableCell::sortBorderStyles(borderStyles); size_t count = borderStyles.size(); for (size_t i = 0; i < count; ++i) { @@ -578,16 +577,10 @@ void RenderTable::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty) ty += captionHeight; } - int my = max(ty, paintInfo.rect.y()); - int mh; - if (ty < paintInfo.rect.y()) - mh = max(0, h - (paintInfo.rect.y() - ty)); - else - mh = min(paintInfo.rect.height(), h); - - paintBoxShadow(paintInfo.context, tx, ty, w, h, style()); + paintBoxShadow(paintInfo.context, tx, ty, w, h, style(), Normal); - paintFillLayers(paintInfo, style()->backgroundColor(), style()->backgroundLayers(), my, mh, tx, ty, w, h); + paintFillLayers(paintInfo, style()->backgroundColor(), style()->backgroundLayers(), tx, ty, w, h); + paintBoxShadow(paintInfo.context, tx, ty, w, h, style(), Inset); if (style()->hasBorder() && !collapseBorders()) paintBorder(paintInfo.context, tx, ty, w, h, style()); @@ -609,14 +602,7 @@ void RenderTable::paintMask(PaintInfo& paintInfo, int tx, int ty) ty += captionHeight; } - int my = max(ty, paintInfo.rect.y()); - int mh; - if (ty < paintInfo.rect.y()) - mh = max(0, h - (paintInfo.rect.y() - ty)); - else - mh = min(paintInfo.rect.height(), h); - - paintMaskImages(paintInfo, my, mh, tx, ty, w, h); + paintMaskImages(paintInfo, tx, ty, w, h); } void RenderTable::calcPrefWidths() @@ -648,7 +634,7 @@ void RenderTable::splitColumn(int pos, int firstSpan) // change width of all rows. for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { if (child->isTableSection()) - static_cast<RenderTableSection*>(child)->splitColumn(pos, oldSize + 1); + toRenderTableSection(child)->splitColumn(pos, oldSize + 1); } m_columnPos.grow(numEffCols() + 1); @@ -666,7 +652,7 @@ void RenderTable::appendColumn(int span) // change width of all rows. for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { if (child->isTableSection()) - static_cast<RenderTableSection*>(child)->appendColumn(pos); + toRenderTableSection(child)->appendColumn(pos); } m_columnPos.grow(numEffCols() + 1); @@ -682,7 +668,7 @@ RenderTableCol* RenderTable::colElement(int col, bool* startEdge, bool* endEdge) while (child) { if (child->isTableCol()) { - RenderTableCol* colElem = static_cast<RenderTableCol*>(child); + RenderTableCol* colElem = toRenderTableCol(child); int span = colElem->span(); if (!colElem->firstChild()) { int startCol = cCol; @@ -735,7 +721,7 @@ void RenderTable::recalcSections() const break; case TABLE_HEADER_GROUP: if (child->isTableSection()) { - RenderTableSection* section = static_cast<RenderTableSection*>(child); + RenderTableSection* section = toRenderTableSection(child); if (!m_head) m_head = section; else if (!m_firstBody) @@ -745,7 +731,7 @@ void RenderTable::recalcSections() const break; case TABLE_FOOTER_GROUP: if (child->isTableSection()) { - RenderTableSection* section = static_cast<RenderTableSection*>(child); + RenderTableSection* section = toRenderTableSection(child); if (!m_foot) m_foot = section; else if (!m_firstBody) @@ -755,7 +741,7 @@ void RenderTable::recalcSections() const break; case TABLE_ROW_GROUP: if (child->isTableSection()) { - RenderTableSection* section = static_cast<RenderTableSection*>(child); + RenderTableSection* section = toRenderTableSection(child); if (!m_firstBody) m_firstBody = section; section->recalcCellsIfNeeded(); @@ -770,7 +756,7 @@ void RenderTable::recalcSections() const int maxCols = 0; for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { if (child->isTableSection()) { - RenderTableSection* section = static_cast<RenderTableSection*>(child); + RenderTableSection* section = toRenderTableSection(child); int sectionCols = section->numColumns(); if (sectionCols > maxCols) maxCols = sectionCols; @@ -960,9 +946,8 @@ int RenderTable::outerBorderBottom() const bottomSection = m_foot; else { RenderObject* child; - for (child = lastChild(); child && !child->isTableSection(); child = child->previousSibling()) - ; - bottomSection = child ? static_cast<RenderTableSection*>(child) : 0; + for (child = lastChild(); child && !child->isTableSection(); child = child->previousSibling()) { } + bottomSection = child ? toRenderTableSection(child) : 0; } if (bottomSection) { borderWidth = bottomSection->outerBorderBottom(); @@ -994,7 +979,7 @@ int RenderTable::outerBorderLeft() const for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { if (!child->isTableSection()) continue; - int sw = static_cast<RenderTableSection*>(child)->outerBorderLeft(); + int sw = toRenderTableSection(child)->outerBorderLeft(); if (sw == -1) continue; else @@ -1024,7 +1009,7 @@ int RenderTable::outerBorderRight() const for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { if (!child->isTableSection()) continue; - int sw = static_cast<RenderTableSection*>(child)->outerBorderRight(); + int sw = toRenderTableSection(child)->outerBorderRight(); if (sw == -1) continue; else @@ -1046,13 +1031,13 @@ RenderTableSection* RenderTable::sectionAbove(const RenderTableSection* section, RenderObject* prevSection = section == m_foot ? lastChild() : section->previousSibling(); while (prevSection) { - if (prevSection->isTableSection() && prevSection != m_head && prevSection != m_foot && (!skipEmptySections || static_cast<RenderTableSection*>(prevSection)->numRows())) + if (prevSection->isTableSection() && prevSection != m_head && prevSection != m_foot && (!skipEmptySections || toRenderTableSection(prevSection)->numRows())) break; prevSection = prevSection->previousSibling(); } if (!prevSection && m_head && (!skipEmptySections || m_head->numRows())) prevSection = m_head; - return static_cast<RenderTableSection*>(prevSection); + return toRenderTableSection(prevSection); } RenderTableSection* RenderTable::sectionBelow(const RenderTableSection* section, bool skipEmptySections) const @@ -1064,13 +1049,13 @@ RenderTableSection* RenderTable::sectionBelow(const RenderTableSection* section, RenderObject* nextSection = section == m_head ? firstChild() : section->nextSibling(); while (nextSection) { - if (nextSection->isTableSection() && nextSection != m_head && nextSection != m_foot && (!skipEmptySections || static_cast<RenderTableSection*>(nextSection)->numRows())) + if (nextSection->isTableSection() && nextSection != m_head && nextSection != m_foot && (!skipEmptySections || toRenderTableSection(nextSection)->numRows())) break; nextSection = nextSection->nextSibling(); } if (!nextSection && m_foot && (!skipEmptySections || m_foot->numRows())) nextSection = m_foot; - return static_cast<RenderTableSection*>(nextSection); + return toRenderTableSection(nextSection); } RenderTableCell* RenderTable::cellAbove(const RenderTableCell* cell) const diff --git a/WebCore/rendering/RenderTable.h b/WebCore/rendering/RenderTable.h index 2fb7a14..d07a727 100644 --- a/WebCore/rendering/RenderTable.h +++ b/WebCore/rendering/RenderTable.h @@ -1,12 +1,10 @@ /* - * This file is part of the DOM implementation for KDE. - * * Copyright (C) 1997 Martin Jones (mjones@kde.org) * (C) 1997 Torben Weis (weis@kde.org) * (C) 1998 Waldo Bastian (bastian@kde.org) * (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) - * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc. + * Copyright (C) 2003, 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 @@ -40,13 +38,6 @@ class TableLayout; class RenderTable : public RenderBlock { public: RenderTable(Node*); - ~RenderTable(); - - virtual const char* renderName() const { return "RenderTable"; } - - virtual bool isTable() const { return true; } - - virtual bool avoidsFloats() const { return true; } int getColumnPos(int col) const { return m_columnPos[col]; } @@ -70,26 +61,7 @@ public: int calcBorderRight() const; void recalcHorizontalBorders(); - // overrides virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0); - virtual void removeChild(RenderObject* oldChild); - - virtual void paint(PaintInfo&, int tx, int ty); - virtual void paintObject(PaintInfo&, int tx, int ty); - virtual void paintBoxDecorations(PaintInfo&, int tx, int ty); - virtual void paintMask(PaintInfo& paintInfo, int tx, int ty); - virtual void layout(); - virtual void calcPrefWidths(); - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int xPos, int yPos, int tx, int ty, HitTestAction); - - virtual int firstLineBoxBaseline() const; - - virtual RenderBlock* firstLineBlock() const; - virtual void updateFirstLetter(); - - virtual void setCellWidths(); - - virtual void calcWidth(); struct ColumnStruct { enum { @@ -163,8 +135,6 @@ public: bool hasSections() const { return m_head || m_foot || m_firstBody; } - virtual IntRect overflowClipRect(int tx, int ty); - void recalcSectionsIfNeeded() const { if (m_needsSectionRecalc) @@ -180,6 +150,33 @@ protected: virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); private: + virtual const char* renderName() const { return "RenderTable"; } + + virtual bool isTable() const { return true; } + + virtual bool avoidsFloats() const { return true; } + + virtual void removeChild(RenderObject* oldChild); + + virtual void paint(PaintInfo&, int tx, int ty); + virtual void paintObject(PaintInfo&, int tx, int ty); + virtual void paintBoxDecorations(PaintInfo&, int tx, int ty); + virtual void paintMask(PaintInfo&, int tx, int ty); + virtual void layout(); + virtual void calcPrefWidths(); + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int xPos, int yPos, int tx, int ty, HitTestAction); + + virtual int firstLineBoxBaseline() const; + + virtual RenderBlock* firstLineBlock() const; + virtual void updateFirstLetter(); + + virtual void setCellWidths(); + + virtual void calcWidth(); + + virtual IntRect overflowClipRect(int tx, int ty); + void recalcSections() const; mutable Vector<int> m_columnPos; @@ -190,7 +187,7 @@ private: mutable RenderTableSection* m_foot; mutable RenderTableSection* m_firstBody; - TableLayout* m_tableLayout; + OwnPtr<TableLayout> m_tableLayout; const CollapsedBorderValue* m_currentBorder; @@ -206,6 +203,21 @@ private: int m_borderRight; }; +inline RenderTable* toRenderTable(RenderObject* object) +{ + ASSERT(!object || object->isTable()); + return static_cast<RenderTable*>(object); +} + +inline const RenderTable* toRenderTable(const RenderObject* object) +{ + ASSERT(!object || object->isTable()); + return static_cast<const RenderTable*>(object); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderTable(const RenderTable*); + } // namespace WebCore #endif // RenderTable_h diff --git a/WebCore/rendering/RenderTableCell.cpp b/WebCore/rendering/RenderTableCell.cpp index f5e6ae2..8b7a068 100644 --- a/WebCore/rendering/RenderTableCell.cpp +++ b/WebCore/rendering/RenderTableCell.cpp @@ -4,7 +4,7 @@ * (C) 1998 Waldo Bastian (bastian@kde.org) * (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) - * Copyright (C) 2003, 2004, 2005, 2006, 2007 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 @@ -564,7 +564,7 @@ CollapsedBorderValue RenderTableCell::collapsedBottomBorder() const // Now check row groups. RenderTableSection* currSection = section(); - if (row() + rowSpan() >= static_cast<RenderTableSection*>(currSection)->numRows()) { + if (row() + rowSpan() >= currSection->numRows()) { // (5) Our row group's bottom border. result = compareBorders(result, CollapsedBorderValue(&currSection->style()->borderBottom(), BROWGROUP)); if (!result.exists()) @@ -845,10 +845,6 @@ void RenderTableCell::paintBackgroundsBehindCell(PaintInfo& paintInfo, int tx, i int w = width(); int h = height(); - int my = max(ty, paintInfo.rect.y()); - int end = min(paintInfo.rect.bottom(), ty + h); - int mh = end - my; - Color c = backgroundObject->style()->backgroundColor(); const FillLayer* bgLayer = backgroundObject->style()->backgroundLayers(); @@ -862,7 +858,7 @@ void RenderTableCell::paintBackgroundsBehindCell(PaintInfo& paintInfo, int tx, i paintInfo.context->save(); paintInfo.context->clip(clipRect); } - paintFillLayers(paintInfo, c, bgLayer, my, mh, tx, ty, w, h); + paintFillLayers(paintInfo, c, bgLayer, tx, ty, w, h); if (shouldClip) paintInfo.context->restore(); } @@ -878,10 +874,12 @@ void RenderTableCell::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty) int h = height(); if (style()->boxShadow()) - paintBoxShadow(paintInfo.context, tx, ty, w, h, style()); + paintBoxShadow(paintInfo.context, tx, ty, w, h, style(), Normal); // Paint our cell background. paintBackgroundsBehindCell(paintInfo, tx, ty, this); + if (style()->boxShadow()) + paintBoxShadow(paintInfo.context, tx, ty, w, h, style(), Inset); if (!style()->hasBorder() || tableElt->collapseBorders()) return; @@ -901,11 +899,7 @@ void RenderTableCell::paintMask(PaintInfo& paintInfo, int tx, int ty) int w = width(); int h = height(); - int my = max(ty, paintInfo.rect.y()); - int end = min(paintInfo.rect.bottom(), ty + h); - int mh = end - my; - - paintMaskImages(paintInfo, my, mh, tx, ty, w, h); + paintMaskImages(paintInfo, tx, ty, w, h); } } // namespace WebCore diff --git a/WebCore/rendering/RenderTableCell.h b/WebCore/rendering/RenderTableCell.h index 4b09032..9532bb6 100644 --- a/WebCore/rendering/RenderTableCell.h +++ b/WebCore/rendering/RenderTableCell.h @@ -4,7 +4,7 @@ * (C) 1998 Waldo Bastian (bastian@kde.org) * (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) - * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 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 @@ -33,12 +33,6 @@ class RenderTableCell : public RenderBlock { public: RenderTableCell(Node*); - virtual const char* renderName() const { return isAnonymous() ? "RenderTableCell (anonymous)" : "RenderTableCell"; } - - virtual bool isTableCell() const { return true; } - - virtual void destroy(); - // FIXME: need to implement cellIndex int cellIndex() const { return 0; } void setCellIndex(int) { } @@ -54,19 +48,19 @@ public: int row() const { return m_row; } void setRow(int row) { m_row = row; } - RenderTableSection* section() const { return static_cast<RenderTableSection*>(parent()->parent()); } - RenderTable* table() const { return static_cast<RenderTable*>(parent()->parent()->parent()); } + RenderTableSection* section() const { return toRenderTableSection(parent()->parent()); } + RenderTable* table() const { return toRenderTable(parent()->parent()->parent()); } Length styleOrColWidth() const; - virtual bool requiresLayer() const { return isPositioned() || isTransparent() || hasOverflowClip() || hasTransform() || hasMask() || hasReflection(); } - virtual void calcPrefWidths(); - virtual void calcWidth(); + +#if PLATFORM(ANDROID) #ifdef ANDROID_LAYOUT // RenderTableSection needs to access this in setCellWidths() int getVisibleWidth() { return m_visibleWidth; } -#endif +#endif +#endif void updateWidth(int); @@ -94,13 +88,8 @@ public: virtual void layout(); virtual void paint(PaintInfo&, int tx, int ty); - virtual void paintBoxDecorations(PaintInfo&, int tx, int ty); - virtual void paintMask(PaintInfo& paintInfo, int tx, int ty); - void paintCollapsedBorder(GraphicsContext*, int x, int y, int w, int h); - void paintBackgroundsBehindCell(PaintInfo&, int tx, int ty, RenderObject* backgroundObject); - virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer); - virtual void computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect&, bool fixed = false); + void paintBackgroundsBehindCell(PaintInfo&, int tx, int ty, RenderObject* backgroundObject); virtual int baselinePosition(bool firstLine = false, bool isRootLineBox = false) const; @@ -125,6 +114,24 @@ protected: virtual void mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState&) const; private: + virtual const char* renderName() const { return isAnonymous() ? "RenderTableCell (anonymous)" : "RenderTableCell"; } + + virtual bool isTableCell() const { return true; } + + virtual void destroy(); + + virtual bool requiresLayer() const { return isPositioned() || isTransparent() || hasOverflowClip() || hasTransform() || hasMask() || hasReflection(); } + + virtual void calcWidth(); + + virtual void paintBoxDecorations(PaintInfo&, int tx, int ty); + virtual void paintMask(PaintInfo&, int tx, int ty); + + virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer); + virtual void computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect&, bool fixed = false); + + void paintCollapsedBorder(GraphicsContext*, int x, int y, int w, int h); + int m_row; int m_column; int m_rowSpan; @@ -134,6 +141,21 @@ private: int m_percentageHeight; }; +inline RenderTableCell* toRenderTableCell(RenderObject* object) +{ + ASSERT(!object || object->isTableCell()); + return static_cast<RenderTableCell*>(object); +} + +inline const RenderTableCell* toRenderTableCell(const RenderObject* object) +{ + ASSERT(!object || object->isTableCell()); + return static_cast<const RenderTableCell*>(object); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderTableCell(const RenderTableCell*); + } // namespace WebCore #endif // RenderTableCell_h diff --git a/WebCore/rendering/RenderTableCol.cpp b/WebCore/rendering/RenderTableCol.cpp index f17963c..80e74e1 100644 --- a/WebCore/rendering/RenderTableCol.cpp +++ b/WebCore/rendering/RenderTableCol.cpp @@ -1,12 +1,10 @@ -/** - * This file is part of the DOM implementation for KDE. - * +/* * Copyright (C) 1997 Martin Jones (mjones@kde.org) * (C) 1997 Torben Weis (weis@kde.org) * (C) 1998 Waldo Bastian (bastian@kde.org) * (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) - * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc. + * Copyright (C) 2003, 2004, 2005, 2006, 2009 Apple Inc. All rights reserved. * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) * * This library is free software; you can redistribute it and/or @@ -31,13 +29,15 @@ #include "CachedImage.h" #include "HTMLNames.h" #include "HTMLTableColElement.h" +#include "RenderTable.h" namespace WebCore { using namespace HTMLNames; RenderTableCol::RenderTableCol(Node* node) - : RenderBox(node), m_span(1) + : RenderBox(node) + , m_span(1) { // init RenderObject attributes setInline(true); // our object is not Inline @@ -75,13 +75,11 @@ IntRect RenderTableCol::clippedOverflowRectForRepaint(RenderBoxModelObject* repa // 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(); - if (table && table->isTable()) - return table->clippedOverflowRectForRepaint(repaintContainer); - return IntRect(); + RenderTable* parentTable = table(); + if (!parentTable) + return IntRect(); + return parentTable->clippedOverflowRectForRepaint(repaintContainer); } void RenderTableCol::imageChanged(WrappedImagePtr, const IntRect*) @@ -90,4 +88,20 @@ void RenderTableCol::imageChanged(WrappedImagePtr, const IntRect*) repaint(); } +void RenderTableCol::calcPrefWidths() +{ + setPrefWidthsDirty(false); + + for (RenderObject* child = firstChild(); child; child = child->nextSibling()) + child->setPrefWidthsDirty(false); +} + +RenderTable* RenderTableCol::table() const +{ + RenderObject* table = parent(); + if (table && !table->isTable()) + table = table->parent(); + return table && table->isTable() ? toRenderTable(table) : 0; +} + } diff --git a/WebCore/rendering/RenderTableCol.h b/WebCore/rendering/RenderTableCol.h index 8c494b2..87209a1 100644 --- a/WebCore/rendering/RenderTableCol.h +++ b/WebCore/rendering/RenderTableCol.h @@ -1,12 +1,10 @@ /* - * This file is part of the DOM implementation for KDE. - * * Copyright (C) 1997 Martin Jones (mjones@kde.org) * (C) 1997 Torben Weis (weis@kde.org) * (C) 1998 Waldo Bastian (bastian@kde.org) * (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) - * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc. + * Copyright (C) 2003, 2004, 2005, 2006, 2009 Apple Inc. All rights reserved. * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) * * This library is free software; you can redistribute it and/or @@ -32,16 +30,24 @@ namespace WebCore { -class RenderTableCol : public RenderBox -{ +class RenderTable; + +class RenderTableCol : public RenderBox { public: RenderTableCol(Node*); - virtual RenderObjectChildList* virtualChildren() { return children(); } - virtual const RenderObjectChildList* virtualChildren() const { return children(); } const RenderObjectChildList* children() const { return &m_children; } RenderObjectChildList* children() { return &m_children; } + virtual void calcPrefWidths(); + + int span() const { return m_span; } + void setSpan(int span) { m_span = span; } + +private: + virtual RenderObjectChildList* virtualChildren() { return children(); } + virtual const RenderObjectChildList* virtualChildren() const { return children(); } + virtual const char* renderName() const { return "RenderTableCol"; } virtual bool isTableCol() const { return true; } virtual int lineHeight(bool) const { return 0; } @@ -54,14 +60,27 @@ public: virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer); virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); - int span() const { return m_span; } - void setSpan(int s) { m_span = s; } - -private: + RenderTable* table() const; + RenderObjectChildList m_children; int m_span; }; +inline RenderTableCol* toRenderTableCol(RenderObject* object) +{ + ASSERT(!object || object->isTableCol()); + return static_cast<RenderTableCol*>(object); +} + +inline const RenderTableCol* toRenderTableCol(const RenderObject* object) +{ + ASSERT(!object || object->isTableCol()); + return static_cast<const RenderTableCol*>(object); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderTableCol(const RenderTableCol*); + } #endif diff --git a/WebCore/rendering/RenderTableRow.cpp b/WebCore/rendering/RenderTableRow.cpp index 33b2c39..bafadfc 100644 --- a/WebCore/rendering/RenderTableRow.cpp +++ b/WebCore/rendering/RenderTableRow.cpp @@ -99,7 +99,7 @@ void RenderTableRow::addChild(RenderObject* child, RenderObject* beforeChild) while (beforeChild && beforeChild->parent() != this) beforeChild = beforeChild->parent(); - RenderTableCell* cell = static_cast<RenderTableCell*>(child); + RenderTableCell* cell = toRenderTableCell(child); // Generated content can result in us having a null section so make sure to null check our parent. if (parent()) @@ -121,7 +121,7 @@ void RenderTableRow::layout() for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { if (child->isTableCell()) { - RenderTableCell* cell = static_cast<RenderTableCell*>(child); + RenderTableCell* cell = toRenderTableCell(child); if (child->needsLayout()) { cell->calcVerticalMargins(); cell->layout(); @@ -147,6 +147,11 @@ void RenderTableRow::layout() IntRect RenderTableRow::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) { + ASSERT(parent()); + + if (repaintContainer == this) + return RenderBox::clippedOverflowRectForRepaint(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. @@ -185,7 +190,7 @@ void RenderTableRow::paint(PaintInfo& paintInfo, int tx, int ty) if (child->isTableCell()) { // Paint the row background behind the cell. if (paintInfo.phase == PaintPhaseBlockBackground || paintInfo.phase == PaintPhaseChildBlockBackground) { - RenderTableCell* cell = static_cast<RenderTableCell*>(child); + RenderTableCell* cell = toRenderTableCell(child); cell->paintBackgroundsBehindCell(paintInfo, tx, ty, this); } if (!toRenderBox(child)->hasSelfPaintingLayer()) diff --git a/WebCore/rendering/RenderTableRow.h b/WebCore/rendering/RenderTableRow.h index 9622480..588252b 100644 --- a/WebCore/rendering/RenderTableRow.h +++ b/WebCore/rendering/RenderTableRow.h @@ -1,12 +1,10 @@ /* - * This file is part of the DOM implementation for KDE. - * * Copyright (C) 1997 Martin Jones (mjones@kde.org) * (C) 1997 Torben Weis (weis@kde.org) * (C) 1998 Waldo Bastian (bastian@kde.org) * (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) - * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc. + * Copyright (C) 2003, 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 @@ -35,15 +33,16 @@ class RenderTableRow : public RenderBox { public: RenderTableRow(Node*); - virtual RenderObjectChildList* virtualChildren() { return children(); } - virtual const RenderObjectChildList* virtualChildren() const { return children(); } const RenderObjectChildList* children() const { return &m_children; } RenderObjectChildList* children() { return &m_children; } - RenderTableSection* section() const { return static_cast<RenderTableSection*>(parent()); } - RenderTable* table() const { return static_cast<RenderTable*>(parent()->parent()); } + RenderTableSection* section() const { return toRenderTableSection(parent()); } + RenderTable* table() const { return toRenderTable(parent()->parent()); } private: + virtual RenderObjectChildList* virtualChildren() { return children(); } + virtual const RenderObjectChildList* virtualChildren() const { return children(); } + virtual const char* renderName() const { return isAnonymous() ? "RenderTableRow (anonymous)" : "RenderTableRow"; } virtual bool isTableRow() const { return true; } @@ -65,10 +64,24 @@ private: virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle); -private: RenderObjectChildList m_children; }; +inline RenderTableRow* toRenderTableRow(RenderObject* object) +{ + ASSERT(!object || object->isTableRow()); + return static_cast<RenderTableRow*>(object); +} + +inline const RenderTableRow* toRenderTableRow(const RenderObject* object) +{ + ASSERT(!object || object->isTableRow()); + return static_cast<const RenderTableRow*>(object); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderTableRow(const RenderTableRow*); + } // namespace WebCore #endif // RenderTableRow_h diff --git a/WebCore/rendering/RenderTableSection.cpp b/WebCore/rendering/RenderTableSection.cpp index efa8850..5d47357 100644 --- a/WebCore/rendering/RenderTableSection.cpp +++ b/WebCore/rendering/RenderTableSection.cpp @@ -128,7 +128,7 @@ void RenderTableSection::addChild(RenderObject* child, RenderObject* beforeChild if (!ensureRows(m_cRow + 1)) return; - m_grid[m_cRow].rowRenderer = static_cast<RenderTableRow*>(child); + m_grid[m_cRow].rowRenderer = toRenderTableRow(child); if (!beforeChild) { m_grid[m_cRow].height = child->style()->height(); @@ -612,7 +612,7 @@ int RenderTableSection::layoutRows(int toAdd) for (RenderObject* o = cell->firstChild(); o; o = o->nextSibling()) { if (!o->isText() && o->style()->height().isPercent() && (flexAllChildren || o->isReplaced() || (o->isBox() && toRenderBox(o)->scrollsOverflow()))) { // Tables with no sections do not flex. - if (!o->isTable() || static_cast<RenderTable*>(o)->hasSections()) { + if (!o->isTable() || toRenderTable(o)->hasSections()) { o->setNeedsLayout(true, false); cellChildrenFlex = true; } @@ -741,7 +741,7 @@ int RenderTableSection::lowestPosition(bool includeOverflowInterior, bool includ for (RenderObject* row = firstChild(); row; row = row->nextSibling()) { for (RenderObject* curr = row->firstChild(); curr; curr = curr->nextSibling()) { if (curr->isTableCell()) { - RenderTableCell* cell = static_cast<RenderTableCell*>(curr); + RenderTableCell* cell = toRenderTableCell(curr); bottom = max(bottom, cell->y() + cell->lowestPosition(false)); } } @@ -759,7 +759,7 @@ int RenderTableSection::rightmostPosition(bool includeOverflowInterior, bool inc for (RenderObject* row = firstChild(); row; row = row->nextSibling()) { for (RenderObject* curr = row->firstChild(); curr; curr = curr->nextSibling()) { if (curr->isTableCell()) { - RenderTableCell* cell = static_cast<RenderTableCell*>(curr); + RenderTableCell* cell = toRenderTableCell(curr); right = max(right, cell->x() + cell->rightmostPosition(false)); } } @@ -777,7 +777,7 @@ int RenderTableSection::leftmostPosition(bool includeOverflowInterior, bool incl for (RenderObject* row = firstChild(); row; row = row->nextSibling()) { for (RenderObject* curr = row->firstChild(); curr; curr = curr->nextSibling()) { if (curr->isTableCell()) { - RenderTableCell* cell = static_cast<RenderTableCell*>(curr); + RenderTableCell* cell = toRenderTableCell(curr); left = min(left, cell->x() + cell->leftmostPosition(false)); } } @@ -1129,7 +1129,7 @@ void RenderTableSection::paintObject(PaintInfo& paintInfo, int tx, int ty) if (!cell || (r > startrow && (cellAt(r - 1, c).cell == cell))) continue; - RenderTableRow* row = static_cast<RenderTableRow*>(cell->parent()); + RenderTableRow* row = toRenderTableRow(cell->parent()); if (paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) { // We need to handle painting a stack of backgrounds. This stack (from bottom to top) consists of @@ -1182,12 +1182,12 @@ void RenderTableSection::recalcCells() if (!ensureRows(m_cRow + 1)) break; - RenderTableRow* tableRow = static_cast<RenderTableRow*>(row); + RenderTableRow* tableRow = toRenderTableRow(row); m_grid[m_cRow].rowRenderer = tableRow; for (RenderObject* cell = row->firstChild(); cell; cell = cell->nextSibling()) { if (cell->isTableCell()) - addCell(static_cast<RenderTableCell*>(cell), tableRow); + addCell(toRenderTableCell(cell), tableRow); } } } diff --git a/WebCore/rendering/RenderTableSection.h b/WebCore/rendering/RenderTableSection.h index 30614f0..c0098bc 100644 --- a/WebCore/rendering/RenderTableSection.h +++ b/WebCore/rendering/RenderTableSection.h @@ -1,12 +1,10 @@ /* - * This file is part of the DOM implementation for KDE. - * * Copyright (C) 1997 Martin Jones (mjones@kde.org) * (C) 1997 Torben Weis (weis@kde.org) * (C) 1998 Waldo Bastian (bastian@kde.org) * (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) - * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc. + * Copyright (C) 2003, 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 @@ -38,23 +36,12 @@ class RenderTableRow; class RenderTableSection : public RenderBox { public: RenderTableSection(Node*); - ~RenderTableSection(); + virtual ~RenderTableSection(); - virtual RenderObjectChildList* virtualChildren() { return children(); } - virtual const RenderObjectChildList* virtualChildren() const { return children(); } const RenderObjectChildList* children() const { return &m_children; } RenderObjectChildList* children() { return &m_children; } - virtual const char* renderName() const { return isAnonymous() ? "RenderTableSection (anonymous)" : "RenderTableSection"; } - - virtual bool isTableSection() const { return true; } - - virtual void destroy(); - - virtual void layout(); - virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0); - virtual void removeChild(RenderObject* oldChild); virtual int firstLineBoxBaseline() const; @@ -64,7 +51,7 @@ public: int calcRowHeight(); int layoutRows(int height); - RenderTable* table() const { return static_cast<RenderTable*>(parent()); } + RenderTable* table() const { return toRenderTable(parent()); } struct CellStruct { RenderTableCell* cell; @@ -91,10 +78,6 @@ public: 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; - virtual int rightmostPosition(bool includeOverflowInterior, bool includeSelf) const; - virtual int leftmostPosition(bool includeOverflowInterior, bool includeSelf) const; - int calcOuterBorderTop() const; int calcOuterBorderBottom() const; int calcOuterBorderLeft(bool rtl) const; @@ -106,11 +89,6 @@ public: int outerBorderLeft() const { return m_outerBorderLeft; } int outerBorderRight() const { return m_outerBorderRight; } - virtual void paint(PaintInfo&, int tx, int ty); - virtual void paintObject(PaintInfo&, int tx, int ty); - - virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); - int numRows() const { return m_gridRows; } int numColumns() const; void recalcCells(); @@ -129,9 +107,31 @@ public: int getBaseline(int row) { return m_grid[row].baseline; } +private: + virtual RenderObjectChildList* virtualChildren() { return children(); } + virtual const RenderObjectChildList* virtualChildren() const { return children(); } + + virtual const char* renderName() const { return isAnonymous() ? "RenderTableSection (anonymous)" : "RenderTableSection"; } + + virtual bool isTableSection() const { return true; } + + virtual void destroy(); + + virtual void layout(); + + virtual void removeChild(RenderObject* oldChild); + + virtual int lowestPosition(bool includeOverflowInterior, bool includeSelf) const; + virtual int rightmostPosition(bool includeOverflowInterior, bool includeSelf) const; + virtual int leftmostPosition(bool includeOverflowInterior, bool includeSelf) const; + + virtual void paint(PaintInfo&, int tx, int ty); + virtual void paintObject(PaintInfo&, int tx, int ty); + + virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); -private: virtual int lineHeight(bool, bool) const { return 0; } bool ensureRows(int); @@ -161,6 +161,21 @@ private: bool m_hasOverflowingCell; }; +inline RenderTableSection* toRenderTableSection(RenderObject* object) +{ + ASSERT(!object || object->isTableSection()); + return static_cast<RenderTableSection*>(object); +} + +inline const RenderTableSection* toRenderTableSection(const RenderObject* object) +{ + ASSERT(!object || object->isTableSection()); + return static_cast<const RenderTableSection*>(object); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderTableSection(const RenderTableSection*); + } // namespace WebCore #endif // RenderTableSection_h diff --git a/WebCore/rendering/RenderText.h b/WebCore/rendering/RenderText.h index 2e04a9e..915ff40 100644 --- a/WebCore/rendering/RenderText.h +++ b/WebCore/rendering/RenderText.h @@ -173,16 +173,16 @@ private: mutable bool m_knownNotToUseFallbackFonts : 1; }; -inline RenderText* toRenderText(RenderObject* o) +inline RenderText* toRenderText(RenderObject* object) { - ASSERT(!o || o->isText()); - return static_cast<RenderText*>(o); + ASSERT(!object || object->isText()); + return static_cast<RenderText*>(object); } -inline const RenderText* toRenderText(const RenderObject* o) +inline const RenderText* toRenderText(const RenderObject* object) { - ASSERT(!o || o->isText()); - return static_cast<const RenderText*>(o); + ASSERT(!object || object->isText()); + return static_cast<const RenderText*>(object); } // This will catch anyone doing an unnecessary cast. diff --git a/WebCore/rendering/RenderTextControl.cpp b/WebCore/rendering/RenderTextControl.cpp index 752ad7b..70b6518 100644 --- a/WebCore/rendering/RenderTextControl.cpp +++ b/WebCore/rendering/RenderTextControl.cpp @@ -235,7 +235,7 @@ void RenderTextControl::setSelectionRange(int start, int end) end = max(end, 0); start = min(max(start, 0), end); - document()->updateLayout(); + ASSERT(!document()->childNeedsAndNotInStyleRecalc()); if (style()->visibility() == HIDDEN || !m_innerText || !m_innerText->renderer() || !m_innerText->renderBox()->height()) { cacheSelection(start, end); @@ -248,9 +248,11 @@ void RenderTextControl::setSelectionRange(int start, int end) else endPosition = visiblePositionForIndex(end); - ASSERT(startPosition.isNotNull() && endPosition.isNotNull()); - ASSERT(startPosition.deepEquivalent().node()->shadowAncestorNode() == node() && endPosition.deepEquivalent().node()->shadowAncestorNode() == node()); - + // startPosition and endPosition can be null position for example when + // "-webkit-user-select: none" style attribute is specified. + if (startPosition.isNotNull() && endPosition.isNotNull()) { + ASSERT(startPosition.deepEquivalent().node()->shadowAncestorNode() == node() && endPosition.deepEquivalent().node()->shadowAncestorNode() == node()); + } VisibleSelection newSelection = VisibleSelection(startPosition, endPosition); if (Frame* frame = document()->frame()) @@ -326,26 +328,14 @@ String RenderTextControl::text() if (!m_innerText) return ""; - Frame* frame = document()->frame(); - Text* compositionNode = frame ? frame->editor()->compositionNode() : 0; - Vector<UChar> result; for (Node* n = m_innerText.get(); n; n = n->traverseNextNode(m_innerText.get())) { 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(); - if (text != compositionNode) - result.append(data.characters(), length); - else { - unsigned compositionStart = min(frame->editor()->compositionStart(), length); - unsigned compositionEnd = min(max(compositionStart, frame->editor()->compositionEnd()), length); - result.append(data.characters(), compositionStart); - result.append(data.characters() + compositionEnd, length - compositionEnd); - } + String data = static_cast<Text*>(n)->data(); + result.append(data.characters(), data.length()); } } @@ -387,9 +377,6 @@ String RenderTextControl::textWithHardLineBreaks() if (!box) return ""; - Frame* frame = document()->frame(); - Text* compositionNode = frame ? frame->editor()->compositionNode() : 0; - Node* breakNode; unsigned breakOffset; RootInlineBox* line = box->root(); @@ -404,19 +391,7 @@ String RenderTextControl::textWithHardLineBreaks() Text* text = static_cast<Text*>(n); String data = text->data(); unsigned length = data.length(); - unsigned compositionStart = (text == compositionNode) - ? min(frame->editor()->compositionStart(), length) : 0; - unsigned compositionEnd = (text == compositionNode) - ? min(max(compositionStart, frame->editor()->compositionEnd()), length) : 0; unsigned position = 0; - while (breakNode == n && breakOffset < compositionStart) { - result.append(data.characters() + position, breakOffset - position); - position = breakOffset; - result.append(&newlineCharacter, 1); - getNextSoftBreak(line, breakNode, breakOffset); - } - result.append(data.characters() + position, compositionStart - position); - position = compositionEnd; while (breakNode == n && breakOffset <= length) { if (breakOffset > position) { result.append(data.characters() + position, breakOffset - position); diff --git a/WebCore/rendering/RenderTextControl.h b/WebCore/rendering/RenderTextControl.h index bce9619..c0fc343 100644 --- a/WebCore/rendering/RenderTextControl.h +++ b/WebCore/rendering/RenderTextControl.h @@ -34,17 +34,6 @@ class RenderTextControl : public RenderBlock { public: virtual ~RenderTextControl(); - virtual const char* renderName() const { return "RenderTextControl"; } - virtual bool isTextControl() const { return true; } - 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 bool avoidsFloats() const { return true; } - bool isEdited() const { return m_edited; } void setEdited(bool isEdited) { m_edited = isEdited; } @@ -64,10 +53,6 @@ public: String textWithHardLineBreaks(); void selectionChanged(bool userTriggered); - virtual void addFocusRingRects(GraphicsContext*, int tx, int ty); - - virtual bool canBeProgramaticallyScrolled(bool) const { return true; } - VisiblePosition visiblePositionForIndex(int index); int indexForVisiblePosition(const VisiblePosition&); @@ -92,10 +77,26 @@ protected: virtual void cacheSelection(int start, int end) = 0; virtual PassRefPtr<RenderStyle> createInnerTextStyle(const RenderStyle* startStyle) const = 0; + virtual void updateFromElement(); + virtual void calcHeight(); + friend class TextIterator; HTMLElement* innerTextElement() const; private: + virtual const char* renderName() const { return "RenderTextControl"; } + virtual bool isTextControl() const { return true; } + virtual bool hasControlClip() const { return false; } + virtual IntRect controlClipRect(int tx, int ty) const; + virtual void calcPrefWidths(); + virtual void removeLeftoverAnonymousBlock(RenderBlock*) { } + virtual bool canHaveChildren() const { return false; } + virtual bool avoidsFloats() const { return true; } + + virtual void addFocusRingRects(GraphicsContext*, int tx, int ty); + + virtual bool canBeProgramaticallyScrolled(bool) const { return true; } + String finishText(Vector<UChar>&) const; bool m_edited; @@ -103,16 +104,16 @@ private: RefPtr<TextControlInnerTextElement> m_innerText; }; -inline RenderTextControl* toRenderTextControl(RenderObject* o) +inline RenderTextControl* toRenderTextControl(RenderObject* object) { - ASSERT(!o || o->isTextControl()); - return static_cast<RenderTextControl*>(o); + ASSERT(!object || object->isTextControl()); + return static_cast<RenderTextControl*>(object); } -inline const RenderTextControl* toRenderTextControl(const RenderObject* o) +inline const RenderTextControl* toRenderTextControl(const RenderObject* object) { - ASSERT(!o || o->isTextControl()); - return static_cast<const RenderTextControl*>(o); + ASSERT(!object || object->isTextControl()); + return static_cast<const RenderTextControl*>(object); } // This will catch anyone doing an unnecessary cast. diff --git a/WebCore/rendering/RenderTextControlMultiLine.cpp b/WebCore/rendering/RenderTextControlMultiLine.cpp index 516d812..ac790e2 100644 --- a/WebCore/rendering/RenderTextControlMultiLine.cpp +++ b/WebCore/rendering/RenderTextControlMultiLine.cpp @@ -51,6 +51,9 @@ void RenderTextControlMultiLine::subtreeHasChanged() if (!node()->focused()) return; + // Fire the "input" DOM event + node()->dispatchEvent(eventNames().inputEvent, true, false); + if (Frame* frame = document()->frame()) frame->textDidChangeInTextArea(static_cast<Element*>(node())); } @@ -106,19 +109,6 @@ PassRefPtr<RenderStyle> RenderTextControlMultiLine::createInnerTextStyle(const R textBlockStyle->inheritFrom(startStyle); adjustInnerTextStyle(startStyle, textBlockStyle.get()); - - // FIXME: This code should just map wrap into CSS in the DOM code. - // Then here we should set the textBlockStyle appropriately based off this - // object's style()->whiteSpace() and style->wordWrap(). - // 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); return textBlockStyle.release(); diff --git a/WebCore/rendering/RenderTextControlMultiLine.h b/WebCore/rendering/RenderTextControlMultiLine.h index 579047d..7296653 100644 --- a/WebCore/rendering/RenderTextControlMultiLine.h +++ b/WebCore/rendering/RenderTextControlMultiLine.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) + * Copyright (C) 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 @@ -30,14 +31,15 @@ public: RenderTextControlMultiLine(Node*); virtual ~RenderTextControlMultiLine(); + void forwardEvent(Event*); + +private: virtual bool isTextArea() const { return true; } virtual void subtreeHasChanged(); 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; @@ -48,6 +50,15 @@ private: virtual PassRefPtr<RenderStyle> createInnerTextStyle(const RenderStyle* startStyle) const; }; +inline RenderTextControlMultiLine* toRenderTextControlMultiLine(RenderObject* object) +{ + ASSERT(!object || object->isTextArea()); + return static_cast<RenderTextControlMultiLine*>(object); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderTextControlMultiLine(const RenderTextControlMultiLine*); + } #endif diff --git a/WebCore/rendering/RenderTextControlSingleLine.cpp b/WebCore/rendering/RenderTextControlSingleLine.cpp index 0d0a5fe..b448eb7 100644 --- a/WebCore/rendering/RenderTextControlSingleLine.cpp +++ b/WebCore/rendering/RenderTextControlSingleLine.cpp @@ -234,17 +234,12 @@ void RenderTextControlSingleLine::layout() int desiredHeight = textBlockHeight(); int currentHeight = innerTextRenderer->height(); - if (m_innerBlock || currentHeight > height()) { + if (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)); + if (m_innerBlock) + innerBlockRenderer->style()->setHeight(Length(desiredHeight, Fixed)); } // Set the text block width @@ -262,13 +257,11 @@ void RenderTextControlSingleLine::layout() 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); - } + // Center the child block vertically + RenderBox* childBlock = innerBlockRenderer ? innerBlockRenderer : innerTextRenderer; + currentHeight = childBlock->height(); + if (currentHeight < height()) + childBlock->setLocation(childBlock->x(), (height() - currentHeight) / 2); } bool RenderTextControlSingleLine::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int xPos, int yPos, int tx, int ty, HitTestAction hitTestAction) @@ -762,8 +755,8 @@ int RenderTextControlSingleLine::selectedIndex() const 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); + // 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 diff --git a/WebCore/rendering/RenderTextControlSingleLine.h b/WebCore/rendering/RenderTextControlSingleLine.h index 23352b4..da9838f 100644 --- a/WebCore/rendering/RenderTextControlSingleLine.h +++ b/WebCore/rendering/RenderTextControlSingleLine.h @@ -1,4 +1,5 @@ /* + * Copyright (C) 2006, 2007, 2009 Apple Inc. All rights reserved. * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) * * This library is free software; you can redistribute it and/or @@ -38,9 +39,6 @@ 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(); @@ -52,14 +50,19 @@ public: void showPopup(); virtual void hidePopup(); // PopupMenuClient method + void forwardEvent(Event*); + + void capsLockStateMayHaveChanged(); + +private: + virtual bool hasControlClip() const { return m_cancelButton; } + virtual bool isTextField() const { return true; } + 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*); - - void capsLockStateMayHaveChanged(); virtual void autoscroll(); @@ -72,7 +75,6 @@ public: virtual void setScrollTop(int); virtual bool scroll(ScrollDirection, ScrollGranularity, float multiplier = 1.0f); -private: int textBlockWidth() const; virtual int preferredContentWidth(float charWidth) const; virtual void adjustControlHeightBasedOnLineHeight(int lineHeight); @@ -94,10 +96,10 @@ private: void startSearchEventTimer(); void searchEventTimerFired(Timer<RenderTextControlSingleLine>*); -private: // PopupMenuClient methods virtual void valueChanged(unsigned listIndex, bool fireEvents = true); virtual String itemText(unsigned listIndex) const; + virtual String itemToolTip(unsigned) const { return String(); } virtual bool itemIsEnabled(unsigned listIndex) const; virtual PopupMenuStyle itemStyle(unsigned listIndex) const; virtual PopupMenuStyle menuStyle() const; @@ -119,7 +121,6 @@ private: InputElement* inputElement() const; -private: bool m_placeholderVisible; bool m_searchPopupIsVisible; bool m_shouldDrawCapsLockIndicator; @@ -133,6 +134,15 @@ private: Vector<String> m_recentSearches; }; +inline RenderTextControlSingleLine* toRenderTextControlSingleLine(RenderObject* object) +{ + ASSERT(!object || object->isTextField()); + return static_cast<RenderTextControlSingleLine*>(object); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderTextControlSingleLine(const RenderTextControlSingleLine*); + } #endif diff --git a/WebCore/rendering/RenderTheme.cpp b/WebCore/rendering/RenderTheme.cpp index 4aaf9be..63e7d45 100644 --- a/WebCore/rendering/RenderTheme.cpp +++ b/WebCore/rendering/RenderTheme.cpp @@ -42,6 +42,12 @@ namespace WebCore { using namespace HTMLNames; +static Color& customFocusRingColor() +{ + DEFINE_STATIC_LOCAL(Color, color, ()); + return color; +} + RenderTheme::RenderTheme() #if USE(NEW_THEME) : m_theme(platformTheme()) @@ -62,7 +68,7 @@ void RenderTheme::adjustStyle(CSSStyleSelector* selector, RenderStyle* style, El else if (style->display() == COMPACT || style->display() == RUN_IN || style->display() == LIST_ITEM || style->display() == TABLE) style->setDisplay(BLOCK); - if (UAHasAppearance && theme()->isControlStyled(style, border, background, backgroundColor)) { + if (UAHasAppearance && isControlStyled(style, border, background, backgroundColor)) { if (part == MenulistPart) { style->setAppearance(MenulistButtonPart); part = MenulistButtonPart; @@ -266,6 +272,10 @@ bool RenderTheme::paint(RenderObject* o, const RenderObject::PaintInfo& paintInf return paintMediaSeekBackButton(o, paintInfo, r); case MediaSeekForwardButtonPart: return paintMediaSeekForwardButton(o, paintInfo, r); + case MediaRewindButtonPart: + return paintMediaRewindButton(o, paintInfo, r); + case MediaReturnToRealtimeButtonPart: + return paintMediaReturnToRealtimeButton(o, paintInfo, r); case MediaSliderPart: return paintMediaSliderTrack(o, paintInfo, r); case MediaSliderThumbPart: @@ -276,8 +286,8 @@ bool RenderTheme::paint(RenderObject* o, const RenderObject::PaintInfo& paintInf return paintMediaTimeRemaining(o, paintInfo, r); case MediaCurrentTimePart: return paintMediaCurrentTime(o, paintInfo, r); - case MediaTimelineContainerPart: - return paintMediaTimelineContainer(o, paintInfo, r); + case MediaControlsBackgroundPart: + return paintMediaControlsBackground(o, paintInfo, r); case MenulistButtonPart: case TextFieldPart: case TextAreaPart: @@ -313,6 +323,7 @@ bool RenderTheme::paintBorderOnly(RenderObject* o, const RenderObject::PaintInfo case TextAreaPart: return paintTextArea(o, paintInfo, r); case MenulistButtonPart: + case SearchFieldPart: return true; case CheckboxPart: case RadioPart: @@ -325,7 +336,6 @@ bool RenderTheme::paintBorderOnly(RenderObject* o, const RenderObject::PaintInfo case SliderVerticalPart: case SliderThumbHorizontalPart: case SliderThumbVerticalPart: - case SearchFieldPart: case SearchFieldCancelButtonPart: case SearchFieldDecorationPart: case SearchFieldResultsDecorationPart: @@ -853,4 +863,14 @@ Color RenderTheme::platformInactiveTextSearchHighlightColor() const return Color(255, 255, 0); // Yellow. } +void RenderTheme::setCustomFocusRingColor(const Color& c) +{ + customFocusRingColor() = c; +} + +Color RenderTheme::focusRingColor() +{ + return customFocusRingColor().isValid() ? customFocusRingColor() : defaultTheme()->platformFocusRingColor(); +} + } // namespace WebCore diff --git a/WebCore/rendering/RenderTheme.h b/WebCore/rendering/RenderTheme.h index 450e2f6..4f37015 100644 --- a/WebCore/rendering/RenderTheme.h +++ b/WebCore/rendering/RenderTheme.h @@ -23,13 +23,16 @@ #ifndef RenderTheme_h #define RenderTheme_h -#include "RenderObject.h" #if USE(NEW_THEME) #include "Theme.h" #else #include "ThemeTypes.h" #endif +#include "RenderObject.h" +#include "RenderTheme.h" #include "ScrollTypes.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> namespace WebCore { @@ -38,11 +41,24 @@ class PopupMenu; class RenderMenuList; class CSSStyleSheet; -class RenderTheme { -public: +class RenderTheme : public RefCounted<RenderTheme> { +protected: RenderTheme(); + +public: virtual ~RenderTheme() { } + // This function is to be implemented in your platform-specific theme implementation to hand back the + // appropriate platform theme. When the theme is needed in non-page dependent code, a default theme is + // used as fallback, which is returned for a nulled page, so the platform code needs to account for this. + static PassRefPtr<RenderTheme> themeForPage(Page* page); + + // When the theme is needed in non-page dependent code, the defaultTheme() is used as fallback. + static inline PassRefPtr<RenderTheme> defaultTheme() + { + return themeForPage(0); + }; + // This method is called whenever style has been computed for an element and the appearance // property has been set to a value other than "none". The theme should map in all of the appropriate // metrics and defaults given the contents of the style. This includes sophisticated operations like @@ -62,7 +78,7 @@ public: // 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 + // adjust the default CSS rules in html.css, quirks.css, or mediaControls.css virtual String extraDefaultStyleSheet() { return String(); } virtual String extraQuirksStyleSheet() { return String(); } #if ENABLE(VIDEO) @@ -121,6 +137,10 @@ public: virtual Color platformActiveTextSearchHighlightColor() const; virtual Color platformInactiveTextSearchHighlightColor() const; + static Color focusRingColor(); + virtual Color platformFocusRingColor() const { return Color(0, 0, 0); } + static void setCustomFocusRingColor(const Color&); + virtual void platformColorsDidChange(); virtual double caretBlinkInterval() const { return 0.5; } @@ -227,7 +247,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 paintMediaRewindButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; } + virtual bool paintMediaReturnToRealtimeButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; } + virtual bool paintMediaControlsBackground(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; } @@ -260,10 +282,6 @@ private: #endif }; -// Function to obtain the theme. This is implemented in your platform-specific theme implementation to hand -// back the appropriate platform theme. -RenderTheme* theme(); - } // namespace WebCore #endif // RenderTheme_h diff --git a/WebCore/rendering/RenderThemeChromiumLinux.cpp b/WebCore/rendering/RenderThemeChromiumLinux.cpp index 8049403..c4020d3 100644 --- a/WebCore/rendering/RenderThemeChromiumLinux.cpp +++ b/WebCore/rendering/RenderThemeChromiumLinux.cpp @@ -3,6 +3,7 @@ * Copyright (C) 2007 Alp Toker <alp@atoker.com> * Copyright (C) 2008 Collabora Ltd. * Copyright (C) 2008, 2009 Google Inc. + * Copyright (C) 2009 Kenneth Rohde Christiansen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -24,102 +25,29 @@ #include "config.h" #include "RenderThemeChromiumLinux.h" -#include "ChromiumBridge.h" +#include "Color.h" #include "CSSValueKeywords.h" -#include "GraphicsContext.h" -#include "HTMLMediaElement.h" -#include "HTMLNames.h" -#include "Image.h" -#include "MediaControlElements.h" -#include "PlatformContextSkia.h" -#include "RenderBox.h" #include "RenderObject.h" -#include "ScrollbarTheme.h" -#include "TransformationMatrix.h" #include "UserAgentStyleSheets.h" -#include "SkShader.h" -#include "SkGradientShader.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 const float defaultFontSize = 16.0; - -// The background for the media player controls should be a 60% opaque black rectangle. This -// matches the UI mockups for the default UI theme. -static const float defaultMediaControlOpacity = 0.6f; - -// These values all match Safari/Win. -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 supportsFocus(ControlPart appearance) +PassRefPtr<RenderTheme> RenderThemeChromiumLinux::create() { - // This causes WebKit to draw the focus rings for us. - return false; + return adoptRef(new RenderThemeChromiumLinux()); } -static void setSizeIfAuto(RenderStyle* style, const IntSize& size) +PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page) { - if (style->width().isIntrinsicOrAuto()) - style->setWidth(Length(size.width(), Fixed)); - if (style->height().isAuto()) - style->setHeight(Length(size.height(), Fixed)); + static RenderTheme* rt = RenderThemeChromiumLinux::create().releaseRef(); + return rt; } -// 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() -{ - return "Arial"; -} - -#if ENABLE(VIDEO) -// Attempt to retrieve a HTMLMediaElement from a Node. Returns NULL if one cannot be found. -static HTMLMediaElement* mediaElementParent(Node* node) -{ - if (!node) - return 0; - Node* mediaNode = node->shadowAncestorNode(); - if (!mediaNode || (!mediaNode->hasTagName(HTMLNames::videoTag) && !mediaNode->hasTagName(HTMLNames::audioTag))) - return 0; - - return static_cast<HTMLMediaElement*>(mediaNode); -} -#endif - -RenderTheme* theme() +RenderThemeChromiumLinux::RenderThemeChromiumLinux() { - static RenderThemeChromiumLinux theme; - return &theme; } -RenderThemeChromiumLinux::RenderThemeChromiumLinux() +RenderThemeChromiumLinux::~RenderThemeChromiumLinux() { } @@ -132,465 +60,12 @@ Color RenderThemeChromiumLinux::systemColor(int cssValueId) const return RenderTheme::systemColor(cssValueId); } -// Use the Windows style sheets to match their metrics. String RenderThemeChromiumLinux::extraDefaultStyleSheet() { - return String(themeWinUserAgentStyleSheet, sizeof(themeWinUserAgentStyleSheet)) + + return RenderThemeChromiumSkia::extraDefaultStyleSheet() + String(themeChromiumLinuxUserAgentStyleSheet, sizeof(themeChromiumLinuxUserAgentStyleSheet)); } -String RenderThemeChromiumLinux::extraQuirksStyleSheet() -{ - return String(themeWinQuirksUserAgentStyleSheet, sizeof(themeWinQuirksUserAgentStyleSheet)); -} - -#if ENABLE(VIDEO) -String RenderThemeChromiumLinux::extraMediaControlsStyleSheet() -{ - return String(mediaControlsChromiumUserAgentStyleSheet, sizeof(mediaControlsChromiumUserAgentStyleSheet)); -} -#endif - -bool RenderThemeChromiumLinux::supportsFocusRing(const RenderStyle* style) const -{ - return supportsFocus(style->appearance()); -} - -Color RenderThemeChromiumLinux::platformActiveSelectionBackgroundColor() const -{ - return Color(0x1e, 0x90, 0xff); -} - -Color RenderThemeChromiumLinux::platformInactiveSelectionBackgroundColor() const -{ - return Color(0xc8, 0xc8, 0xc8); -} - -Color RenderThemeChromiumLinux::platformActiveSelectionForegroundColor() const -{ - return Color::black; -} - -Color RenderThemeChromiumLinux::platformInactiveSelectionForegroundColor() const -{ - return Color(0x32, 0x32, 0x32); -} - -Color RenderThemeChromiumLinux::platformTextSearchHighlightColor() const -{ - return Color(0xff, 0xff, 0x96); -} - -double RenderThemeChromiumLinux::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. - return 0.5; -} - -void RenderThemeChromiumLinux::systemFont(int propId, FontDescription& fontDescription) const -{ - float fontSize = defaultFontSize; - - switch (propId) { - case CSSValueWebkitMiniControl: - case CSSValueWebkitSmallControl: - case CSSValueWebkitControl: - // Why 2 points smaller? Because that's what Gecko does. Note that we - // are assuming a 96dpi screen, which is the default that we use on - // Windows. - static const float pointsPerInch = 72.0f; - static const float pixelsPerInch = 96.0f; - fontSize -= (2.0f / pointsPerInch) * pixelsPerInch; - break; - } - - fontDescription.firstFamily().setFamily(defaultGUIFont()); - fontDescription.setSpecifiedSize(fontSize); - fontDescription.setIsAbsoluteSize(true); - fontDescription.setGenericFamily(FontDescription::NoFamily); - fontDescription.setWeight(FontWeightNormal); - fontDescription.setItalic(false); -} - -int RenderThemeChromiumLinux::minimumMenuListSize(RenderStyle* style) const -{ - return 0; -} - -bool RenderThemeChromiumLinux::paintCheckbox(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) -{ - static Image* const checkedImage = Image::loadPlatformResource("linuxCheckboxOn").releaseRef(); - static Image* const uncheckedImage = Image::loadPlatformResource("linuxCheckboxOff").releaseRef(); - - Image* image = this->isChecked(o) ? checkedImage : uncheckedImage; - i.context->drawImage(image, rect); - return false; -} - -void RenderThemeChromiumLinux::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 RenderThemeChromiumLinux::paintRadio(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) -{ - static Image* const checkedImage = Image::loadPlatformResource("linuxRadioOn").releaseRef(); - static Image* const uncheckedImage = Image::loadPlatformResource("linuxRadioOff").releaseRef(); - - Image* image = this->isChecked(o) ? checkedImage : uncheckedImage; - i.context->drawImage(image, rect); - return false; -} - -void RenderThemeChromiumLinux::setRadioSize(RenderStyle* style) const -{ - // Use same sizing for radio box as checkbox. - setCheckboxSize(style); -} - -static SkColor brightenColor(double h, double s, double l, float brightenAmount) -{ - l += brightenAmount; - if (l > 1.0) - l = 1.0; - if (l < 0.0) - l = 0.0; - - return makeRGBAFromHSLA(h, s, l, 1.0); -} - -static void paintButtonLike(RenderTheme* theme, RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) -{ - SkCanvas* const canvas = i.context->platformContext()->canvas(); - SkPaint paint; - SkRect skrect; - const int right = rect.x() + rect.width(); - const int bottom = rect.y() + rect.height(); - SkColor baseColor = SkColorSetARGB(0xff, 0xdd, 0xdd, 0xdd); - if (o->style()->hasBackground()) - baseColor = o->style()->backgroundColor().rgb(); - double h, s, l; - Color(baseColor).getHSL(h, s, l); - // Our standard gradient is from 0xdd to 0xf8. This is the amount of - // increased luminance between those values. - SkColor lightColor(brightenColor(h, s, l, 0.105)); - - // If the button is too small, fallback to drawing a single, solid color - if (rect.width() < 5 || rect.height() < 5) { - paint.setColor(baseColor); - skrect.set(rect.x(), rect.y(), right, bottom); - canvas->drawRect(skrect, paint); - return; - } - - const int borderAlpha = theme->isHovered(o) ? 0x80 : 0x55; - paint.setARGB(borderAlpha, 0, 0, 0); - canvas->drawLine(rect.x() + 1, rect.y(), right - 1, rect.y(), paint); - canvas->drawLine(right - 1, rect.y() + 1, right - 1, bottom - 1, paint); - canvas->drawLine(rect.x() + 1, bottom - 1, right - 1, bottom - 1, paint); - canvas->drawLine(rect.x(), rect.y() + 1, rect.x(), bottom - 1, paint); - - paint.setARGB(0xff, 0, 0, 0); - SkPoint p[2]; - const int lightEnd = theme->isPressed(o) ? 1 : 0; - const int darkEnd = !lightEnd; - p[lightEnd].set(SkIntToScalar(rect.x()), SkIntToScalar(rect.y())); - p[darkEnd].set(SkIntToScalar(rect.x()), SkIntToScalar(bottom - 1)); - SkColor colors[2]; - colors[0] = lightColor; - colors[1] = baseColor; - - SkShader* shader = SkGradientShader::CreateLinear( - p, colors, NULL, 2, SkShader::kClamp_TileMode, NULL); - paint.setStyle(SkPaint::kFill_Style); - paint.setShader(shader); - shader->unref(); - - skrect.set(rect.x() + 1, rect.y() + 1, right - 1, bottom - 1); - canvas->drawRect(skrect, paint); - - paint.setShader(NULL); - paint.setColor(brightenColor(h, s, l, -0.0588)); - canvas->drawPoint(rect.x() + 1, rect.y() + 1, paint); - canvas->drawPoint(right - 2, rect.y() + 1, paint); - canvas->drawPoint(rect.x() + 1, bottom - 2, paint); - canvas->drawPoint(right - 2, bottom - 2, paint); -} - -bool RenderThemeChromiumLinux::paintButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) -{ - paintButtonLike(this, o, i, rect); - return false; -} - -bool RenderThemeChromiumLinux::paintTextField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) -{ - return true; -} - -void RenderThemeChromiumLinux::adjustSearchFieldCancelButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const -{ - // Scale the button size based on the font size - float fontScale = style->fontSize() / defaultControlFontPixelSize; - int cancelButtonSize = lroundf(std::min(std::max(minCancelButtonSize, defaultCancelButtonSize * fontScale), maxCancelButtonSize)); - style->setWidth(Length(cancelButtonSize, Fixed)); - style->setHeight(Length(cancelButtonSize, Fixed)); -} - -bool RenderThemeChromiumLinux::paintSearchFieldCancelButton(RenderObject* o, const RenderObject::PaintInfo& i, 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 button stays square and will fit in its parent's box - bounds.setHeight(std::min(parentBox.width(), std::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(); - i.context->drawImage(isPressed(o) ? cancelPressedImage : cancelImage, bounds); - return false; -} - -void RenderThemeChromiumLinux::adjustSearchFieldDecorationStyle(CSSStyleSelector*, RenderStyle* style, Element*) const -{ - IntSize emptySize(1, 11); - style->setWidth(Length(emptySize.width(), Fixed)); - style->setHeight(Length(emptySize.height(), Fixed)); -} - -void RenderThemeChromiumLinux::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector*, RenderStyle* style, Element*) const -{ - // Scale the decoration size based on the font size - float fontScale = style->fontSize() / defaultControlFontPixelSize; - int magnifierSize = lroundf(std::min(std::max(minSearchFieldResultsDecorationSize, defaultSearchFieldResultsDecorationSize * fontScale), - maxSearchFieldResultsDecorationSize)); - style->setWidth(Length(magnifierSize, Fixed)); - style->setHeight(Length(magnifierSize, Fixed)); -} - -bool RenderThemeChromiumLinux::paintSearchFieldResultsDecoration(RenderObject* o, const RenderObject::PaintInfo& i, 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(std::min(parentBox.width(), std::min(parentBox.height(), bounds.height()))); - bounds.setWidth(bounds.height()); - - // 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); - - static Image* magnifierImage = Image::loadPlatformResource("searchMagnifier").releaseRef(); - i.context->drawImage(magnifierImage, bounds); - return false; -} - -void RenderThemeChromiumLinux::adjustSearchFieldResultsButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const -{ - // Scale the button size based on the font size - float fontScale = style->fontSize() / defaultControlFontPixelSize; - int magnifierHeight = lroundf(std::min(std::max(minSearchFieldResultsDecorationSize, defaultSearchFieldResultsDecorationSize * fontScale), - maxSearchFieldResultsDecorationSize)); - int magnifierWidth = lroundf(magnifierHeight * defaultSearchFieldResultsButtonWidth / defaultSearchFieldResultsDecorationSize); - style->setWidth(Length(magnifierWidth, Fixed)); - style->setHeight(Length(magnifierHeight, Fixed)); -} - -bool RenderThemeChromiumLinux::paintSearchFieldResultsButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& 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(std::min(parentBox.height(), bounds.height())); - bounds.setWidth(std::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(); - i.context->drawImage(magnifierImage, bounds); - return false; -} - -bool RenderThemeChromiumLinux::paintMediaButtonInternal(GraphicsContext* context, const IntRect& rect, Image* image) -{ - context->beginTransparencyLayer(defaultMediaControlOpacity); - - // Draw background. - Color oldFill = context->fillColor(); - Color oldStroke = context->strokeColor(); - - context->setFillColor(Color::black); - context->setStrokeColor(Color::black); - context->drawRect(rect); - - context->setFillColor(oldFill); - context->setStrokeColor(oldStroke); - - // Create a destination rectangle for the image that is centered in the drawing rectangle, rounded left, and down. - IntRect imageRect = image->rect(); - imageRect.setY(rect.y() + (rect.height() - image->height() + 1) / 2); - imageRect.setX(rect.x() + (rect.width() - image->width() + 1) / 2); - - context->drawImage(image, imageRect, CompositeSourceAtop); - context->endTransparencyLayer(); - - return false; -} - -bool RenderThemeChromiumLinux::paintMediaPlayButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& rect) -{ -#if ENABLE(VIDEO) - HTMLMediaElement* mediaElement = mediaElementParent(o->node()); - if (!mediaElement) - return false; - - static Image* mediaPlay = Image::loadPlatformResource("mediaPlay").releaseRef(); - static Image* mediaPause = Image::loadPlatformResource("mediaPause").releaseRef(); - - return paintMediaButtonInternal(paintInfo.context, rect, mediaElement->paused() ? mediaPlay : mediaPause); -#else - return false; -#endif -} - -bool RenderThemeChromiumLinux::paintMediaMuteButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& rect) -{ -#if ENABLE(VIDEO) - HTMLMediaElement* mediaElement = mediaElementParent(o->node()); - if (!mediaElement) - return false; - - static Image* soundFull = Image::loadPlatformResource("mediaSoundFull").releaseRef(); - static Image* soundNone = Image::loadPlatformResource("mediaSoundNone").releaseRef(); - - return paintMediaButtonInternal(paintInfo.context, rect, mediaElement->muted() ? soundNone: soundFull); -#else - return false; -#endif -} - -void RenderThemeChromiumLinux::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, WebCore::Element* e) const -{ - // Height is locked to auto on all browsers. - style->setLineHeight(RenderStyle::initialLineHeight()); -} - -bool RenderThemeChromiumLinux::paintMenuList(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) -{ - SkCanvas* const canvas = i.context->platformContext()->canvas(); - const int right = rect.x() + rect.width(); - const int middle = rect.y() + rect.height() / 2; - - paintButtonLike(this, o, i, rect); - - SkPaint paint; - paint.setARGB(0xff, 0, 0, 0); - paint.setAntiAlias(true); - paint.setStyle(SkPaint::kFill_Style); - - SkPath path; - path.moveTo(right - 13, middle - 3); - path.rLineTo(6, 0); - path.rLineTo(-3, 6); - path.close(); - canvas->drawPath(path, paint); - - return false; -} - -void RenderThemeChromiumLinux::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 RenderThemeChromiumLinux::paintMenuListButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) -{ - return paintMenuList(o, i, rect); -} - -int RenderThemeChromiumLinux::popupInternalPaddingLeft(RenderStyle* style) const -{ - return menuListInternalPadding(style, LeftPadding); -} - -int RenderThemeChromiumLinux::popupInternalPaddingRight(RenderStyle* style) const -{ - return menuListInternalPadding(style, RightPadding); -} - -int RenderThemeChromiumLinux::popupInternalPaddingTop(RenderStyle* style) const -{ - return menuListInternalPadding(style, TopPadding); -} - -int RenderThemeChromiumLinux::popupInternalPaddingBottom(RenderStyle* style) const -{ - return menuListInternalPadding(style, BottomPadding); -} - -int RenderThemeChromiumLinux::buttonInternalPaddingLeft() const -{ - return 3; -} - -int RenderThemeChromiumLinux::buttonInternalPaddingRight() const -{ - return 3; -} - -int RenderThemeChromiumLinux::buttonInternalPaddingTop() const -{ - return 1; -} - -int RenderThemeChromiumLinux::buttonInternalPaddingBottom() const -{ - return 1; -} - bool RenderThemeChromiumLinux::controlSupportsTints(const RenderObject* o) const { return isEnabled(o); @@ -616,22 +91,9 @@ Color RenderThemeChromiumLinux::inactiveListBoxSelectionForegroundColor() const return Color(0x32, 0x32, 0x32); } -int RenderThemeChromiumLinux::menuListInternalPadding(RenderStyle* style, int paddingType) const +bool RenderThemeChromiumLinux::supportsControlTints() 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; + return true; } -} // namespace WebCore +} // namespace WebCore diff --git a/WebCore/rendering/RenderThemeChromiumLinux.h b/WebCore/rendering/RenderThemeChromiumLinux.h index 11239d9..e75ddd5 100644 --- a/WebCore/rendering/RenderThemeChromiumLinux.h +++ b/WebCore/rendering/RenderThemeChromiumLinux.h @@ -7,6 +7,7 @@ * Copyright (C) 2007 Alp Toker <alp@atoker.com> * Copyright (C) 2008, 2009 Google, Inc. * All rights reserved. + * Copyright (C) 2009 Kenneth Rohde Christiansen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -28,101 +29,20 @@ #ifndef RenderThemeChromiumLinux_h #define RenderThemeChromiumLinux_h -#include "RenderTheme.h" +#include "RenderThemeChromiumSkia.h" namespace WebCore { - class RenderThemeChromiumLinux : public RenderTheme { + class RenderThemeChromiumLinux : public RenderThemeChromiumSkia { public: - RenderThemeChromiumLinux(); - ~RenderThemeChromiumLinux() { } - + static PassRefPtr<RenderTheme> create(); virtual String extraDefaultStyleSheet(); - virtual String extraQuirksStyleSheet(); -#if ENABLE(VIDEO) - virtual String extraMediaControlsStyleSheet(); -#endif - - // 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, FontDescription&) const; virtual Color systemColor(int cssValidId) 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* o, const RenderObject::PaintInfo& i, const IntRect& r) { return paintTextField(o, i, r); } - - virtual void adjustSearchFieldCancelButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; - virtual bool paintSearchFieldCancelButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); - - virtual void adjustSearchFieldDecorationStyle(CSSStyleSelector*, RenderStyle*, Element*) const; - - 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 paintMediaPlayButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); - virtual bool paintMediaMuteButton(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 int buttonInternalPaddingLeft() const; - virtual int buttonInternalPaddingRight() const; - virtual int buttonInternalPaddingTop() const; - virtual int buttonInternalPaddingBottom() 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; @@ -130,10 +50,13 @@ namespace WebCore { virtual Color inactiveListBoxSelectionForegroundColor() const; private: - int menuListInternalPadding(RenderStyle*, int paddingType) const; - bool paintMediaButtonInternal(GraphicsContext*, const IntRect&, Image*); + RenderThemeChromiumLinux(); + virtual ~RenderThemeChromiumLinux(); + + // A general method asking if any control tinting is supported at all. + virtual bool supportsControlTints() const; }; } // namespace WebCore -#endif +#endif // RenderThemeChromiumLinux_h diff --git a/WebCore/rendering/RenderThemeChromiumMac.h b/WebCore/rendering/RenderThemeChromiumMac.h index f072000..ffb2548 100644 --- a/WebCore/rendering/RenderThemeChromiumMac.h +++ b/WebCore/rendering/RenderThemeChromiumMac.h @@ -3,6 +3,7 @@ * * Copyright (C) 2005 Apple Computer, Inc. * Copyright (C) 2008, 2009 Google, Inc. + * Copyright (C) 2009 Kenneth Rohde Christiansen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -41,8 +42,7 @@ namespace WebCore { class RenderThemeChromiumMac : public RenderTheme { public: - RenderThemeChromiumMac(); - virtual ~RenderThemeChromiumMac(); + static PassRefPtr<RenderTheme> create(); // 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 @@ -62,7 +62,9 @@ namespace WebCore { virtual Color platformActiveSelectionBackgroundColor() const; virtual Color platformInactiveSelectionBackgroundColor() const; - virtual Color activeListBoxSelectionBackgroundColor() const; + virtual Color platformActiveListBoxSelectionBackgroundColor() const; + + virtual Color platformFocusRingColor() const; virtual void platformColorsDidChange(); @@ -140,6 +142,9 @@ namespace WebCore { virtual bool paintMediaSliderThumb(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); private: + RenderThemeChromiumMac(); + virtual ~RenderThemeChromiumMac(); + 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). diff --git a/WebCore/rendering/RenderThemeChromiumMac.mm b/WebCore/rendering/RenderThemeChromiumMac.mm index f6081a5..23201c9 100644 --- a/WebCore/rendering/RenderThemeChromiumMac.mm +++ b/WebCore/rendering/RenderThemeChromiumMac.mm @@ -1,6 +1,7 @@ /* * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. * Copyright (C) 2008, 2009 Google, Inc. + * Copyright (C) 2009 Kenneth Rohde Christiansen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -31,6 +32,8 @@ #import <math.h> #import "BitmapImage.h" +#import "ChromiumBridge.h" +#import "ColorMac.h" #import "CSSStyleSelector.h" #import "CSSValueKeywords.h" #import "Element.h" @@ -43,6 +46,7 @@ #import "Image.h" #import "LocalCurrentGraphicsContext.h" #import "MediaControlElements.h" +#import "RenderMedia.h" #import "RenderSlider.h" #import "RenderView.h" #import "SharedBuffer.h" @@ -124,10 +128,15 @@ IntRect NSRectToIntRect(const NSRect & rect) return IntRect(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height); } -RenderTheme* theme() +PassRefPtr<RenderTheme> RenderThemeChromiumMac::create() { - static RenderThemeChromiumMac* macTheme = new RenderThemeChromiumMac; - return macTheme; + return adoptRef(new RenderThemeChromiumMac); +} + +PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page) +{ + static RenderTheme* rt = RenderThemeChromiumMac::create().releaseRef(); + return rt; } RenderThemeChromiumMac::RenderThemeChromiumMac() @@ -158,12 +167,20 @@ Color RenderThemeChromiumMac::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 RenderThemeChromiumMac::activeListBoxSelectionBackgroundColor() const +Color RenderThemeChromiumMac::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 RenderThemeChromiumMac::platformFocusRingColor() const +{ + if (ChromiumBridge::layoutTestMode()) + return oldAquaFocusRingColor(); + + return systemColor(CSSValueWebkitFocusRingColor); +} + static FontWeight toFontWeight(NSInteger appKitFontWeight) { ASSERT(appKitFontWeight > 0 && appKitFontWeight < 15); @@ -416,6 +433,9 @@ Color RenderThemeChromiumMac::systemColor(int cssValueId) const case CSSValueThreedlightshadow: color = convertNSColorToColor([NSColor controlLightHighlightColor]); break; + case CSSValueWebkitFocusRingColor: + color = convertNSColorToColor([NSColor keyboardFocusIndicatorColor]); + break; case CSSValueWindow: color = convertNSColorToColor([NSColor windowBackgroundColor]); break; @@ -1486,7 +1506,7 @@ bool RenderThemeChromiumMac::paintSliderThumb(RenderObject* o, const RenderObjec else oldPressed = m_isSliderThumbHorizontalPressed; - bool pressed = static_cast<RenderSlider*>(o->parent())->inDragMode(); + bool pressed = toRenderSlider(o->parent())->inDragMode(); if (o->style()->appearance() == SliderThumbVerticalPart) m_isSliderThumbVerticalPressed = pressed; @@ -1781,6 +1801,12 @@ typedef enum { MediaControllerThemeClassic = 1, MediaControllerThemeQT = 2 } MediaControllerThemeStyle; + +enum WKMediaControllerThemeState { + MediaUIPartDisabledFlag = 1 << 0, + MediaUIPartPressedFlag = 1 << 1, + MediaUIPartDrawEndCapsFlag = 1 << 3, +}; #endif bool RenderThemeChromiumMac::paintMediaFullscreenButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) @@ -1791,7 +1817,8 @@ bool RenderThemeChromiumMac::paintMediaFullscreenButton(RenderObject* o, const R return false; LocalCurrentGraphicsContext localContext(paintInfo.context); - wkDrawMediaUIPart(MediaFullscreenButton, MediaControllerThemeClassic, paintInfo.context->platformContext(), r, node->active()); + wkDrawMediaUIPart(MediaFullscreenButton, MediaControllerThemeClassic, paintInfo.context->platformContext(), r, + node->active() ? MediaUIPartPressedFlag : 0); #endif return false; } @@ -1809,7 +1836,8 @@ bool RenderThemeChromiumMac::paintMediaMuteButton(RenderObject* o, const RenderO return false; LocalCurrentGraphicsContext localContext(paintInfo.context); - wkDrawMediaUIPart(mediaElement->muted() ? MediaUnMuteButton : MediaMuteButton, MediaControllerThemeClassic, paintInfo.context->platformContext(), r, node->active()); + wkDrawMediaUIPart(mediaElement->muted() ? MediaUnMuteButton : MediaMuteButton, MediaControllerThemeClassic, paintInfo.context->platformContext(), r, + node->active() ? MediaUIPartPressedFlag : 0); #endif return false; } @@ -1827,7 +1855,8 @@ bool RenderThemeChromiumMac::paintMediaPlayButton(RenderObject* o, const RenderO return false; LocalCurrentGraphicsContext localContext(paintInfo.context); - wkDrawMediaUIPart(mediaElement->canPlay() ? MediaPlayButton : MediaPauseButton, MediaControllerThemeClassic, paintInfo.context->platformContext(), r, node->active()); + wkDrawMediaUIPart(mediaElement->canPlay() ? MediaPlayButton : MediaPauseButton, MediaControllerThemeClassic, paintInfo.context->platformContext(), r, + node->active() ? MediaUIPartPressedFlag : 0); #endif return false; } @@ -1840,7 +1869,8 @@ bool RenderThemeChromiumMac::paintMediaSeekBackButton(RenderObject* o, const Ren return false; LocalCurrentGraphicsContext localContext(paintInfo.context); - wkDrawMediaUIPart(MediaSeekBackButton, MediaControllerThemeClassic, paintInfo.context->platformContext(), r, node->active()); + wkDrawMediaUIPart(MediaSeekBackButton, MediaControllerThemeClassic, paintInfo.context->platformContext(), r, + node->active() ? MediaUIPartPressedFlag : 0); #endif return false; } @@ -1853,7 +1883,8 @@ bool RenderThemeChromiumMac::paintMediaSeekForwardButton(RenderObject* o, const return false; LocalCurrentGraphicsContext localContext(paintInfo.context); - wkDrawMediaUIPart(MediaSeekForwardButton, MediaControllerThemeClassic, paintInfo.context->platformContext(), r, node->active()); + wkDrawMediaUIPart(MediaSeekForwardButton, MediaControllerThemeClassic, paintInfo.context->platformContext(), r, + node->active() ? MediaUIPartPressedFlag : 0); #endif return false; } @@ -1879,7 +1910,8 @@ bool RenderThemeChromiumMac::paintMediaSliderTrack(RenderObject* o, const Render currentTime = player->currentTime(); } - wkDrawMediaSliderTrack(MediaControllerThemeClassic, paintInfo.context->platformContext(), r, timeLoaded, currentTime, duration); + bool shouldDrawEndCaps = !toRenderMedia(mediaElement->renderer())->shouldShowTimeDisplayControls(); + wkDrawMediaSliderTrack(MediaControllerThemeClassic, paintInfo.context->platformContext(), r, timeLoaded, currentTime, duration, shouldDrawEndCaps ? MediaUIPartDrawEndCapsFlag : 0); #endif return false; } @@ -1892,7 +1924,8 @@ bool RenderThemeChromiumMac::paintMediaSliderThumb(RenderObject* o, const Render return false; LocalCurrentGraphicsContext localContext(paintInfo.context); - wkDrawMediaUIPart(MediaSliderThumb, MediaControllerThemeClassic, paintInfo.context->platformContext(), r, node->active()); + wkDrawMediaUIPart(MediaSliderThumb, MediaControllerThemeClassic, paintInfo.context->platformContext(), r, + node->active() ? MediaUIPartPressedFlag : 0); #endif return false; } diff --git a/WebCore/rendering/RenderThemeChromiumSkia.cpp b/WebCore/rendering/RenderThemeChromiumSkia.cpp index bf217c8..79804ac 100644 --- a/WebCore/rendering/RenderThemeChromiumSkia.cpp +++ b/WebCore/rendering/RenderThemeChromiumSkia.cpp @@ -1,2 +1,751 @@ -// FIXME: This is a placeholder to avoid some issues with webkit.gyp in the chromium tree. Having this placeholder until we can factor out -// RenderThemeChromiumSkia from RenderThemeChromiumLinux will keep the HEAD of both trees compatible. +/* + * 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 "RenderThemeChromiumSkia.h" + +#include "ChromiumBridge.h" +#include "CSSValueKeywords.h" +#include "GraphicsContext.h" +#include "HTMLMediaElement.h" +#include "HTMLNames.h" +#include "Image.h" +#include "MediaControlElements.h" +#include "PlatformContextSkia.h" +#include "RenderBox.h" +#include "RenderObject.h" +#include "ScrollbarTheme.h" +#include "TransformationMatrix.h" +#include "UserAgentStyleSheets.h" + +#include "SkShader.h" +#include "SkGradientShader.h" + +namespace WebCore { + +enum PaddingType { + TopPadding, + RightPadding, + BottomPadding, + LeftPadding +}; + +static const int styledMenuListInternalPadding[4] = { 1, 4, 1, 4 }; + +// These values all match Safari/Win. +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 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)); +} + +#if ENABLE(VIDEO) +// Attempt to retrieve a HTMLMediaElement from a Node. Returns NULL if one cannot be found. +static HTMLMediaElement* mediaElementParent(Node* node) +{ + if (!node) + return 0; + Node* mediaNode = node->shadowAncestorNode(); + if (!mediaNode || (!mediaNode->hasTagName(HTMLNames::videoTag) && !mediaNode->hasTagName(HTMLNames::audioTag))) + return 0; + + return static_cast<HTMLMediaElement*>(mediaNode); +} +#endif + +// 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. +const String& RenderThemeChromiumSkia::defaultGUIFont() +{ + DEFINE_STATIC_LOCAL(String, fontFace, ("Arial")); + return fontFace; +} + +float RenderThemeChromiumSkia::defaultFontSize = 16.0; + +RenderThemeChromiumSkia::RenderThemeChromiumSkia() +{ +} + +RenderThemeChromiumSkia::~RenderThemeChromiumSkia() +{ +} + +// Use the Windows style sheets to match their metrics. +String RenderThemeChromiumSkia::extraDefaultStyleSheet() +{ + return String(themeWinUserAgentStyleSheet, sizeof(themeWinUserAgentStyleSheet)); +} + +String RenderThemeChromiumSkia::extraQuirksStyleSheet() +{ + return String(themeWinQuirksUserAgentStyleSheet, sizeof(themeWinQuirksUserAgentStyleSheet)); +} + +#if ENABLE(VIDEO) +String RenderThemeChromiumSkia::extraMediaControlsStyleSheet() +{ + return String(mediaControlsChromiumUserAgentStyleSheet, sizeof(mediaControlsChromiumUserAgentStyleSheet)); +} +#endif + +bool RenderThemeChromiumSkia::supportsHover(const RenderStyle* style) const +{ + return true; +} + +bool RenderThemeChromiumSkia::supportsFocusRing(const RenderStyle* style) const +{ + // This causes WebKit to draw the focus rings for us. + return false; +} + +Color RenderThemeChromiumSkia::platformActiveSelectionBackgroundColor() const +{ + return Color(0x1e, 0x90, 0xff); +} + +Color RenderThemeChromiumSkia::platformInactiveSelectionBackgroundColor() const +{ + return Color(0xc8, 0xc8, 0xc8); +} + +Color RenderThemeChromiumSkia::platformActiveSelectionForegroundColor() const +{ + return Color::black; +} + +Color RenderThemeChromiumSkia::platformInactiveSelectionForegroundColor() const +{ + return Color(0x32, 0x32, 0x32); +} + +Color RenderThemeChromiumSkia::platformFocusRingColor() const +{ + static Color focusRingColor(229, 151, 0, 255); + return focusRingColor; +} + +double RenderThemeChromiumSkia::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; + + return caretBlinkIntervalInternal(); +} + +void RenderThemeChromiumSkia::systemFont(int propId, FontDescription& fontDescription) const +{ + float fontSize = defaultFontSize; + + switch (propId) { + case CSSValueWebkitMiniControl: + case CSSValueWebkitSmallControl: + case CSSValueWebkitControl: + // Why 2 points smaller? Because that's what Gecko does. Note that we + // are assuming a 96dpi screen, which is the default that we use on + // Windows. + static const float pointsPerInch = 72.0f; + static const float pixelsPerInch = 96.0f; + fontSize -= (2.0f / pointsPerInch) * pixelsPerInch; + break; + } + + fontDescription.firstFamily().setFamily(defaultGUIFont()); + fontDescription.setSpecifiedSize(fontSize); + fontDescription.setIsAbsoluteSize(true); + fontDescription.setGenericFamily(FontDescription::NoFamily); + fontDescription.setWeight(FontWeightNormal); + fontDescription.setItalic(false); +} + +int RenderThemeChromiumSkia::minimumMenuListSize(RenderStyle* style) const +{ + return 0; +} + +bool RenderThemeChromiumSkia::paintCheckbox(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) +{ + static Image* const checkedImage = Image::loadPlatformResource("linuxCheckboxOn").releaseRef(); + static Image* const uncheckedImage = Image::loadPlatformResource("linuxCheckboxOff").releaseRef(); + static Image* const disabledCheckedImage = Image::loadPlatformResource("linuxCheckboxDisabledOn").releaseRef(); + static Image* const disabledUncheckedImage = Image::loadPlatformResource("linuxCheckboxDisabledOff").releaseRef(); + + Image* image; + + if (this->isEnabled(o)) + image = this->isChecked(o) ? checkedImage : uncheckedImage; + else + image = this->isChecked(o) ? disabledCheckedImage : disabledUncheckedImage; + + i.context->drawImage(image, rect); + return false; +} + +void RenderThemeChromiumSkia::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 RenderThemeChromiumSkia::paintRadio(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) +{ + static Image* const checkedImage = Image::loadPlatformResource("linuxRadioOn").releaseRef(); + static Image* const uncheckedImage = Image::loadPlatformResource("linuxRadioOff").releaseRef(); + static Image* const disabledCheckedImage = Image::loadPlatformResource("linuxRadioDisabledOn").releaseRef(); + static Image* const disabledUncheckedImage = Image::loadPlatformResource("linuxRadioDisabledOff").releaseRef(); + + Image* image; + if (this->isEnabled(o)) + image = this->isChecked(o) ? checkedImage : uncheckedImage; + else + image = this->isChecked(o) ? disabledCheckedImage : disabledUncheckedImage; + + i.context->drawImage(image, rect); + return false; +} + +void RenderThemeChromiumSkia::setRadioSize(RenderStyle* style) const +{ + // Use same sizing for radio box as checkbox. + setCheckboxSize(style); +} + +static SkColor brightenColor(double h, double s, double l, float brightenAmount) +{ + l += brightenAmount; + if (l > 1.0) + l = 1.0; + if (l < 0.0) + l = 0.0; + + return makeRGBAFromHSLA(h, s, l, 1.0); +} + +static void paintButtonLike(RenderTheme* theme, RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) +{ + SkCanvas* const canvas = i.context->platformContext()->canvas(); + SkPaint paint; + SkRect skrect; + const int right = rect.x() + rect.width(); + const int bottom = rect.y() + rect.height(); + SkColor baseColor = SkColorSetARGB(0xff, 0xdd, 0xdd, 0xdd); + if (o->style()->hasBackground()) + baseColor = o->style()->backgroundColor().rgb(); + double h, s, l; + Color(baseColor).getHSL(h, s, l); + // Our standard gradient is from 0xdd to 0xf8. This is the amount of + // increased luminance between those values. + SkColor lightColor(brightenColor(h, s, l, 0.105)); + + // If the button is too small, fallback to drawing a single, solid color + if (rect.width() < 5 || rect.height() < 5) { + paint.setColor(baseColor); + skrect.set(rect.x(), rect.y(), right, bottom); + canvas->drawRect(skrect, paint); + return; + } + + const int borderAlpha = theme->isHovered(o) ? 0x80 : 0x55; + paint.setARGB(borderAlpha, 0, 0, 0); + canvas->drawLine(rect.x() + 1, rect.y(), right - 1, rect.y(), paint); + canvas->drawLine(right - 1, rect.y() + 1, right - 1, bottom - 1, paint); + canvas->drawLine(rect.x() + 1, bottom - 1, right - 1, bottom - 1, paint); + canvas->drawLine(rect.x(), rect.y() + 1, rect.x(), bottom - 1, paint); + + paint.setARGB(0xff, 0, 0, 0); + SkPoint p[2]; + const int lightEnd = theme->isPressed(o) ? 1 : 0; + const int darkEnd = !lightEnd; + p[lightEnd].set(SkIntToScalar(rect.x()), SkIntToScalar(rect.y())); + p[darkEnd].set(SkIntToScalar(rect.x()), SkIntToScalar(bottom - 1)); + SkColor colors[2]; + colors[0] = lightColor; + colors[1] = baseColor; + + SkShader* shader = SkGradientShader::CreateLinear( + p, colors, NULL, 2, SkShader::kClamp_TileMode, NULL); + paint.setStyle(SkPaint::kFill_Style); + paint.setShader(shader); + shader->unref(); + + skrect.set(rect.x() + 1, rect.y() + 1, right - 1, bottom - 1); + canvas->drawRect(skrect, paint); + + paint.setShader(NULL); + paint.setColor(brightenColor(h, s, l, -0.0588)); + canvas->drawPoint(rect.x() + 1, rect.y() + 1, paint); + canvas->drawPoint(right - 2, rect.y() + 1, paint); + canvas->drawPoint(rect.x() + 1, bottom - 2, paint); + canvas->drawPoint(right - 2, bottom - 2, paint); +} + +bool RenderThemeChromiumSkia::paintButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) +{ + paintButtonLike(this, o, i, rect); + return false; +} + +bool RenderThemeChromiumSkia::paintTextField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) +{ + return true; +} + +bool RenderThemeChromiumSkia::paintTextArea(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) +{ + return paintTextField(o, i, r); +} + +bool RenderThemeChromiumSkia::paintSearchField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) +{ + return paintTextField(o, i, r); +} + +void RenderThemeChromiumSkia::adjustSearchFieldCancelButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const +{ + // Scale the button size based on the font size + float fontScale = style->fontSize() / defaultControlFontPixelSize; + int cancelButtonSize = lroundf(std::min(std::max(minCancelButtonSize, defaultCancelButtonSize * fontScale), maxCancelButtonSize)); + style->setWidth(Length(cancelButtonSize, Fixed)); + style->setHeight(Length(cancelButtonSize, Fixed)); +} + +bool RenderThemeChromiumSkia::paintSearchFieldCancelButton(RenderObject* o, const RenderObject::PaintInfo& i, 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 button stays square and will fit in its parent's box + bounds.setHeight(std::min(parentBox.width(), std::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(); + i.context->drawImage(isPressed(o) ? cancelPressedImage : cancelImage, bounds); + return false; +} + +void RenderThemeChromiumSkia::adjustSearchFieldDecorationStyle(CSSStyleSelector*, RenderStyle* style, Element*) const +{ + IntSize emptySize(1, 11); + style->setWidth(Length(emptySize.width(), Fixed)); + style->setHeight(Length(emptySize.height(), Fixed)); +} + +void RenderThemeChromiumSkia::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector*, RenderStyle* style, Element*) const +{ + // Scale the decoration size based on the font size + float fontScale = style->fontSize() / defaultControlFontPixelSize; + int magnifierSize = lroundf(std::min(std::max(minSearchFieldResultsDecorationSize, defaultSearchFieldResultsDecorationSize * fontScale), + maxSearchFieldResultsDecorationSize)); + style->setWidth(Length(magnifierSize, Fixed)); + style->setHeight(Length(magnifierSize, Fixed)); +} + +bool RenderThemeChromiumSkia::paintSearchFieldResultsDecoration(RenderObject* o, const RenderObject::PaintInfo& i, 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(std::min(parentBox.width(), std::min(parentBox.height(), bounds.height()))); + bounds.setWidth(bounds.height()); + + // 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); + + static Image* magnifierImage = Image::loadPlatformResource("searchMagnifier").releaseRef(); + i.context->drawImage(magnifierImage, bounds); + return false; +} + +void RenderThemeChromiumSkia::adjustSearchFieldResultsButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const +{ + // Scale the button size based on the font size + float fontScale = style->fontSize() / defaultControlFontPixelSize; + int magnifierHeight = lroundf(std::min(std::max(minSearchFieldResultsDecorationSize, defaultSearchFieldResultsDecorationSize * fontScale), + maxSearchFieldResultsDecorationSize)); + int magnifierWidth = lroundf(magnifierHeight * defaultSearchFieldResultsButtonWidth / defaultSearchFieldResultsDecorationSize); + style->setWidth(Length(magnifierWidth, Fixed)); + style->setHeight(Length(magnifierHeight, Fixed)); +} + +bool RenderThemeChromiumSkia::paintSearchFieldResultsButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& 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(std::min(parentBox.height(), bounds.height())); + bounds.setWidth(std::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(); + i.context->drawImage(magnifierImage, bounds); + return false; +} + +bool RenderThemeChromiumSkia::paintMediaButtonInternal(GraphicsContext* context, const IntRect& rect, Image* image) +{ + // Create a destination rectangle for the image that is centered in the drawing rectangle, rounded left, and down. + IntRect imageRect = image->rect(); + imageRect.setY(rect.y() + (rect.height() - image->height() + 1) / 2); + imageRect.setX(rect.x() + (rect.width() - image->width() + 1) / 2); + + context->drawImage(image, imageRect); + return true; +} + +bool RenderThemeChromiumSkia::paintMediaControlsBackground(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect) +{ +#if ENABLE(VIDEO) + HTMLMediaElement* mediaElement = mediaElementParent(object->node()); + if (!mediaElement) + return false; + + if (!rect.isEmpty()) + { + SkCanvas* canvas = paintInfo.context->platformContext()->canvas(); + SkPaint paint; + + // Draws the left border, it is always 1px wide. + paint.setColor(object->style()->borderLeftColor().rgb()); + canvas->drawLine(rect.x() + 1, rect.y(), + rect.x() + 1, rect.y() + rect.height(), + paint); + + // Draws the right border, it is always 1px wide. + paint.setColor(object->style()->borderRightColor().rgb()); + canvas->drawLine(rect.x() + rect.width() - 1, rect.y(), + rect.x() + rect.width() - 1, rect.y() + rect.height(), + paint); + } + return true; +#else + UNUSED_PARAM(object); + UNUSED_PARAM(paintInfo); + UNUSED_PARAM(rect); + return false; +#endif +} + +bool RenderThemeChromiumSkia::paintMediaSliderTrack(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect) +{ +#if ENABLE(VIDEO) + HTMLMediaElement* mediaElement = mediaElementParent(object->node()); + if (!mediaElement) + return false; + + SkCanvas* canvas = paintInfo.context->platformContext()->canvas(); + SkRect backgroundRect; + backgroundRect.set(rect.x(), rect.y(), rect.x() + rect.width(), rect.y() + rect.height()); + + SkPaint paint; + paint.setAntiAlias(true); + + // Draw the border of the time bar. The border only has one single color, + // width and radius. So use the property of the left border. + SkColor borderColor = object->style()->borderLeftColor().rgb(); + int borderWidth = object->style()->borderLeftWidth(); + IntSize borderRadius = object->style()->borderTopLeftRadius(); + paint.setStyle(SkPaint::kStroke_Style); + paint.setStrokeWidth(borderWidth); + paint.setColor(borderColor); + canvas->drawRoundRect(backgroundRect, borderRadius.width(), borderRadius.height(), paint); + + // Draw the background of the time bar. + SkColor backgroundColor = object->style()->backgroundColor().rgb(); + paint.setStyle(SkPaint::kFill_Style); + paint.setColor(backgroundColor); + canvas->drawRoundRect(backgroundRect, borderRadius.width(), borderRadius.height(), paint); + + if (backgroundRect.width() >= 3 && backgroundRect.height() >= 3) + { + // Draw the buffered ranges. + // FIXME: Draw multiple ranges if there are multiple buffered ranges. + SkRect bufferedRect; + bufferedRect.set(backgroundRect.fLeft + 2, backgroundRect.fTop + 2, + backgroundRect.fRight - 1, backgroundRect.fBottom - 1); + int width = static_cast<int>(bufferedRect.width() * mediaElement->percentLoaded()); + bufferedRect.fRight = bufferedRect.fLeft + width; + + SkPoint points[2] = { { 0, bufferedRect.fTop }, { 0, bufferedRect.fBottom } }; + SkColor startColor = object->style()->color().rgb(); + SkColor endColor = SkColorSetRGB(SkColorGetR(startColor) / 2, + SkColorGetG(startColor) / 2, + SkColorGetB(startColor) / 2); + SkColor colors[2] = { startColor, endColor }; + SkShader* gradient = SkGradientShader::CreateLinear(points, colors, 0, + sizeof(points) / sizeof(points[0]), + SkShader::kMirror_TileMode, 0); + + paint.reset(); + paint.setShader(gradient); + paint.setAntiAlias(true); + // Check for round rect with zero width or height, otherwise Skia will assert + if (bufferedRect.width() > 0 && bufferedRect.height() > 0) + canvas->drawRoundRect(bufferedRect, borderRadius.width(), borderRadius.height(), paint); + gradient->unref(); + } + return true; +#else + UNUSED_PARAM(object); + UNUSED_PARAM(paintInfo); + UNUSED_PARAM(rect); + return false; +#endif +} + +void RenderThemeChromiumSkia::adjustSliderThumbSize(RenderObject* object) const { +#if ENABLE(VIDEO) + if (object->style()->appearance() == MediaSliderThumbPart) { + static Image* mediaSliderThumb = Image::loadPlatformResource("mediaSliderThumb").releaseRef(); + + object->style()->setWidth(Length(mediaSliderThumb->width(), Fixed)); + object->style()->setHeight(Length(mediaSliderThumb->height(), Fixed)); + } +#else + UNUSED_PARAM(object); +#endif +} + +bool RenderThemeChromiumSkia::paintMediaSliderThumb(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect) +{ +#if ENABLE(VIDEO) + if (!object->parent()->isSlider()) + return false; + + static Image* mediaSliderThumb = Image::loadPlatformResource("mediaSliderThumb").releaseRef(); + + return paintMediaButtonInternal(paintInfo.context, rect, mediaSliderThumb); +#else + UNUSED_PARAM(object); + UNUSED_PARAM(paintInfo); + UNUSED_PARAM(rect); + return false; +#endif +} + +bool RenderThemeChromiumSkia::paintMediaPlayButton(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect) +{ +#if ENABLE(VIDEO) + HTMLMediaElement* mediaElement = mediaElementParent(object->node()); + if (!mediaElement) + return false; + + static Image* mediaPlay = Image::loadPlatformResource("mediaPlay").releaseRef(); + static Image* mediaPause = Image::loadPlatformResource("mediaPause").releaseRef(); + + return paintMediaButtonInternal(paintInfo.context, rect, mediaElement->paused() ? mediaPlay : mediaPause); +#else + UNUSED_PARAM(object); + UNUSED_PARAM(paintInfo); + UNUSED_PARAM(rect); + return false; +#endif +} + +bool RenderThemeChromiumSkia::paintMediaMuteButton(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect) +{ +#if ENABLE(VIDEO) + HTMLMediaElement* mediaElement = mediaElementParent(object->node()); + if (!mediaElement) + return false; + + static Image* soundFull = Image::loadPlatformResource("mediaSoundFull").releaseRef(); + static Image* soundNone = Image::loadPlatformResource("mediaSoundNone").releaseRef(); + + return paintMediaButtonInternal(paintInfo.context, rect, mediaElement->muted() ? soundNone: soundFull); +#else + UNUSED_PARAM(object); + UNUSED_PARAM(paintInfo); + UNUSED_PARAM(rect); + return false; +#endif +} + +void RenderThemeChromiumSkia::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, WebCore::Element* e) const +{ + // Height is locked to auto on all browsers. + style->setLineHeight(RenderStyle::initialLineHeight()); +} + +bool RenderThemeChromiumSkia::paintMenuList(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) +{ + SkCanvas* const canvas = i.context->platformContext()->canvas(); + const int right = rect.x() + rect.width(); + const int middle = rect.y() + rect.height() / 2; + + paintButtonLike(this, o, i, rect); + + SkPaint paint; + paint.setARGB(0xff, 0, 0, 0); + paint.setAntiAlias(true); + paint.setStyle(SkPaint::kFill_Style); + + SkPath path; + path.moveTo(right - 13, middle - 3); + path.rLineTo(6, 0); + path.rLineTo(-3, 6); + path.close(); + canvas->drawPath(path, paint); + + return false; +} + +void RenderThemeChromiumSkia::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 RenderThemeChromiumSkia::paintMenuListButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) +{ + return paintMenuList(o, i, rect); +} + +int RenderThemeChromiumSkia::popupInternalPaddingLeft(RenderStyle* style) const +{ + return menuListInternalPadding(style, LeftPadding); +} + +int RenderThemeChromiumSkia::popupInternalPaddingRight(RenderStyle* style) const +{ + return menuListInternalPadding(style, RightPadding); +} + +int RenderThemeChromiumSkia::popupInternalPaddingTop(RenderStyle* style) const +{ + return menuListInternalPadding(style, TopPadding); +} + +int RenderThemeChromiumSkia::popupInternalPaddingBottom(RenderStyle* style) const +{ + return menuListInternalPadding(style, BottomPadding); +} + +int RenderThemeChromiumSkia::buttonInternalPaddingLeft() const +{ + return 3; +} + +int RenderThemeChromiumSkia::buttonInternalPaddingRight() const +{ + return 3; +} + +int RenderThemeChromiumSkia::buttonInternalPaddingTop() const +{ + return 1; +} + +int RenderThemeChromiumSkia::buttonInternalPaddingBottom() const +{ + return 1; +} + +// static +void RenderThemeChromiumSkia::setDefaultFontSize(int fontSize) +{ + defaultFontSize = static_cast<float>(fontSize); +} + +double RenderThemeChromiumSkia::caretBlinkIntervalInternal() const +{ + return RenderTheme::caretBlinkInterval(); +} + +int RenderThemeChromiumSkia::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 barType = style->direction() == LTR ? RightPadding : LeftPadding; + if (paddingType == barType && style->appearance() != NoControlPart) + padding += ScrollbarTheme::nativeTheme()->scrollbarThickness(); + + return padding; +} + +} // namespace WebCore diff --git a/WebCore/rendering/RenderThemeChromiumSkia.h b/WebCore/rendering/RenderThemeChromiumSkia.h index bf217c8..7544c22 100644 --- a/WebCore/rendering/RenderThemeChromiumSkia.h +++ b/WebCore/rendering/RenderThemeChromiumSkia.h @@ -1,2 +1,148 @@ -// FIXME: This is a placeholder to avoid some issues with webkit.gyp in the chromium tree. Having this placeholder until we can factor out -// RenderThemeChromiumSkia from RenderThemeChromiumLinux will keep the HEAD of both trees compatible. +/* + * 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 RenderThemeChromiumSkia_h +#define RenderThemeChromiumSkia_h + +#include "RenderTheme.h" + +namespace WebCore { + + class RenderThemeChromiumSkia : public RenderTheme { + public: + RenderThemeChromiumSkia(); + virtual ~RenderThemeChromiumSkia(); + + virtual String extraDefaultStyleSheet(); + virtual String extraQuirksStyleSheet(); +#if ENABLE(VIDEO) + virtual String extraMediaControlsStyleSheet(); +#endif + + // A method asking if the theme's controls actually care about redrawing when hovered. + virtual bool supportsHover(const RenderStyle*) const; + + // 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 platformFocusRingColor() const; + + // To change the blink interval, override caretBlinkIntervalInternal instead of this one so that we may share layout test code an intercepts. + virtual double caretBlinkInterval() const; + + // System fonts. + virtual void systemFont(int propId, 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*, const RenderObject::PaintInfo&, const IntRect&); + + virtual bool paintSearchField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + virtual void adjustSearchFieldCancelButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual bool paintSearchFieldCancelButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + virtual void adjustSearchFieldDecorationStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + + 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 paintMediaControlsBackground(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual bool paintMediaSliderTrack(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual void adjustSliderThumbSize(RenderObject*) const; + virtual bool paintMediaSliderThumb(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual bool paintMediaPlayButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual bool paintMediaMuteButton(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 int buttonInternalPaddingLeft() const; + virtual int buttonInternalPaddingRight() const; + virtual int buttonInternalPaddingTop() const; + virtual int buttonInternalPaddingBottom() 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); + + protected: + static const String& defaultGUIFont(); + + // 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; + + virtual double caretBlinkIntervalInternal() const; + + private: + int menuListInternalPadding(RenderStyle*, int paddingType) const; + bool paintMediaButtonInternal(GraphicsContext*, const IntRect&, Image*); + }; + +} // namespace WebCore + +#endif // RenderThemeChromiumSkia_h diff --git a/WebCore/rendering/RenderThemeChromiumWin.cpp b/WebCore/rendering/RenderThemeChromiumWin.cpp index 5288191..35d1580 100644 --- a/WebCore/rendering/RenderThemeChromiumWin.cpp +++ b/WebCore/rendering/RenderThemeChromiumWin.cpp @@ -3,6 +3,7 @@ * * Copyright (C) 2006 Apple Computer, Inc. * Copyright (C) 2008, 2009 Google, Inc. + * Copyright (C) 2009 Kenneth Rohde Christiansen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -29,7 +30,6 @@ #include <vssym32.h> #include "ChromiumBridge.h" -#include "CSSStyleSheet.h" #include "CSSValueKeywords.h" #include "FontSelector.h" #include "FontUtilsChromiumWin.h" @@ -40,9 +40,7 @@ #include "RenderBox.h" #include "RenderSlider.h" #include "ScrollbarTheme.h" -#include "SkiaUtils.h" #include "TransparencyWin.h" -#include "UserAgentStyleSheets.h" #include "WindowsVersion.h" // FIXME: This dependency should eventually be removed. @@ -57,28 +55,6 @@ namespace WebCore { namespace { - -// The background for the media player controls should be a 60% opaque black rectangle. This -// matches the UI mockups for the default UI theme. -static const float defaultMediaControlOpacity = 0.6f; - -// These values all match Safari/Win. -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; - -bool canvasHasMultipleLayers(const SkCanvas* canvas) -{ - SkCanvas::LayerIter iter(const_cast<SkCanvas*>(canvas), false); - iter.next(); // There is always at least one layer. - return !iter.done(); // There is > 1 layer if the the iterator can stil advance. -} - class ThemePainter : public TransparencyWin { public: ThemePainter(GraphicsContext* context, const IntRect& r) @@ -93,6 +69,13 @@ public: } private: + static bool canvasHasMultipleLayers(const SkCanvas* canvas) + { + SkCanvas::LayerIter iter(const_cast<SkCanvas*>(canvas), false); + iter.next(); // There is always at least one layer. + return !iter.done(); // There is > 1 layer if the the iterator can stil advance. + } + static LayerMode getLayerMode(GraphicsContext* context, TransformMode transformMode) { if (context->platformContext()->isDrawingToImageBuffer()) // Might have transparent background. @@ -116,7 +99,8 @@ private: } // namespace -static void getNonClientMetrics(NONCLIENTMETRICS* metrics) { +static void getNonClientMetrics(NONCLIENTMETRICS* metrics) +{ static UINT size = WebCore::isVistaOrNewer() ? sizeof(NONCLIENTMETRICS) : NONCLIENTMETRICS_SIZE_PRE_VISTA; metrics->cbSize = size; @@ -124,20 +108,6 @@ static void getNonClientMetrics(NONCLIENTMETRICS* metrics) { 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; @@ -159,14 +129,6 @@ static bool supportsFocus(ControlPart appearance) 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) @@ -201,20 +163,6 @@ static float systemFontSize(const LOGFONT& font) 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() -{ - return L"Arial"; -} - // Converts |points| to pixels. One point is 1/72 of an inch. static float pointsToPixels(float points) { @@ -233,14 +181,6 @@ static float pointsToPixels(float points) 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(); @@ -251,51 +191,24 @@ static double querySystemBlinkInterval(double defaultInterval) return blinkTime / 1000.0; } -#if ENABLE(VIDEO) -// Attempt to retrieve a HTMLMediaElement from a Node. Returns NULL if one cannot be found. -static HTMLMediaElement* mediaElementParent(Node* node) -{ - if (!node) - return 0; - Node* mediaNode = node->shadowAncestorNode(); - if (!mediaNode || (!mediaNode->hasTagName(HTMLNames::videoTag) && !mediaNode->hasTagName(HTMLNames::audioTag))) - return 0; - - return static_cast<HTMLMediaElement*>(mediaNode); -} -#endif - -// Implement WebCore::theme() for getting the global RenderTheme. -RenderTheme* theme() +PassRefPtr<RenderTheme> RenderThemeChromiumWin::create() { - static RenderThemeChromiumWin winTheme; - return &winTheme; + return adoptRef(new RenderThemeChromiumWin); } -String RenderThemeChromiumWin::extraDefaultStyleSheet() +PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page) { - return String(themeWinUserAgentStyleSheet, sizeof(themeWinUserAgentStyleSheet)); + static RenderTheme* rt = RenderThemeChromiumWin::create().releaseRef(); + return rt; } -String RenderThemeChromiumWin::extraQuirksStyleSheet() -{ - return String(themeWinQuirksUserAgentStyleSheet, sizeof(themeWinQuirksUserAgentStyleSheet)); -} - -#if ENABLE(VIDEO) -String RenderThemeChromiumWin::extraMediaControlsStyleSheet() -{ - return String(mediaControlsChromiumUserAgentStyleSheet, sizeof(mediaControlsChromiumUserAgentStyleSheet)); -} -#endif - 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; + // 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 @@ -337,23 +250,11 @@ Color RenderThemeChromiumWin::platformInactiveTextSearchHighlightColor() const return Color(0xff, 0xff, 0x96); // Yellow. } -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, FontDescription& fontDescription) const { // This logic owes much to RenderThemeSafari.cpp. - FontDescription* cachedDesc = NULL; - wchar_t* faceName = 0; + FontDescription* cachedDesc = 0; + AtomicString faceName; float fontSize = 0; switch (propId) { case CSSValueSmallCaption: @@ -361,7 +262,7 @@ void RenderThemeChromiumWin::systemFont(int propId, FontDescription& fontDescrip if (!smallSystemFont.isAbsoluteSize()) { NONCLIENTMETRICS metrics; getNonClientMetrics(&metrics); - faceName = metrics.lfSmCaptionFont.lfFaceName; + faceName = AtomicString(metrics.lfSmCaptionFont.lfFaceName, wcslen(metrics.lfSmCaptionFont.lfFaceName)); fontSize = systemFontSize(metrics.lfSmCaptionFont); } break; @@ -370,7 +271,7 @@ void RenderThemeChromiumWin::systemFont(int propId, FontDescription& fontDescrip if (!menuFont.isAbsoluteSize()) { NONCLIENTMETRICS metrics; getNonClientMetrics(&metrics); - faceName = metrics.lfMenuFont.lfFaceName; + faceName = AtomicString(metrics.lfMenuFont.lfFaceName, wcslen(metrics.lfMenuFont.lfFaceName)); fontSize = systemFontSize(metrics.lfMenuFont); } break; @@ -400,9 +301,7 @@ void RenderThemeChromiumWin::systemFont(int propId, FontDescription& fontDescrip cachedDesc = &fontDescription; if (fontSize) { - ASSERT(faceName); - cachedDesc->firstFamily().setFamily(AtomicString(faceName, - wcslen(faceName))); + cachedDesc->firstFamily().setFamily(faceName); cachedDesc->setIsAbsoluteSize(true); cachedDesc->setGenericFamily(FontDescription::NoFamily); cachedDesc->setSpecifiedSize(fontSize); @@ -412,44 +311,28 @@ void RenderThemeChromiumWin::systemFont(int propId, FontDescription& fontDescrip fontDescription = *cachedDesc; } -int RenderThemeChromiumWin::minimumMenuListSize(RenderStyle* style) const -{ - return 0; -} - void RenderThemeChromiumWin::adjustSliderThumbSize(RenderObject* o) const { // These sizes match what WinXP draws for various menus. const int sliderThumbAlongAxis = 11; const int sliderThumbAcrossAxis = 21; - if (o->style()->appearance() == SliderThumbHorizontalPart || o->style()->appearance() == MediaSliderThumbPart) { + if (o->style()->appearance() == SliderThumbHorizontalPart) { o->style()->setWidth(Length(sliderThumbAlongAxis, Fixed)); o->style()->setHeight(Length(sliderThumbAcrossAxis, Fixed)); } else if (o->style()->appearance() == SliderThumbVerticalPart) { o->style()->setWidth(Length(sliderThumbAcrossAxis, Fixed)); o->style()->setHeight(Length(sliderThumbAlongAxis, Fixed)); - } + } else + RenderThemeChromiumSkia::adjustSliderThumbSize(o); } -void RenderThemeChromiumWin::setCheckboxSize(RenderStyle* style) const +bool RenderThemeChromiumWin::paintCheckbox(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) { - // 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); + return paintButton(o, i, r); } - -void RenderThemeChromiumWin::setRadioSize(RenderStyle* style) const +bool RenderThemeChromiumWin::paintRadio(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) { - // Use same sizing for radio box as checkbox. - setCheckboxSize(style); + return paintButton(o, i, r); } bool RenderThemeChromiumWin::paintButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) @@ -483,178 +366,9 @@ bool RenderThemeChromiumWin::paintSliderTrack(RenderObject* o, const RenderObjec return false; } -void RenderThemeChromiumWin::adjustSearchFieldCancelButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const -{ - // Scale the button size based on the font size - float fontScale = style->fontSize() / defaultControlFontPixelSize; - int cancelButtonSize = lroundf(std::min(std::max(minCancelButtonSize, defaultCancelButtonSize * fontScale), maxCancelButtonSize)); - style->setWidth(Length(cancelButtonSize, Fixed)); - style->setHeight(Length(cancelButtonSize, Fixed)); -} - -bool RenderThemeChromiumWin::paintSearchFieldCancelButton(RenderObject* o, const RenderObject::PaintInfo& i, 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 button stays square and will fit in its parent's box - bounds.setHeight(std::min(parentBox.width(), std::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(); - i.context->drawImage(isPressed(o) ? cancelPressedImage : cancelImage, bounds); - return false; -} - -void RenderThemeChromiumWin::adjustSearchFieldDecorationStyle(CSSStyleSelector*, RenderStyle* style, Element*) const -{ - IntSize emptySize(1, 11); - style->setWidth(Length(emptySize.width(), Fixed)); - style->setHeight(Length(emptySize.height(), Fixed)); -} - -void RenderThemeChromiumWin::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector*, RenderStyle* style, Element*) const -{ - // Scale the decoration size based on the font size - float fontScale = style->fontSize() / defaultControlFontPixelSize; - int magnifierSize = lroundf(std::min(std::max(minSearchFieldResultsDecorationSize, defaultSearchFieldResultsDecorationSize * fontScale), - maxSearchFieldResultsDecorationSize)); - style->setWidth(Length(magnifierSize, Fixed)); - style->setHeight(Length(magnifierSize, Fixed)); -} - -bool RenderThemeChromiumWin::paintSearchFieldResultsDecoration(RenderObject* o, const RenderObject::PaintInfo& i, 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(std::min(parentBox.width(), std::min(parentBox.height(), bounds.height()))); - bounds.setWidth(bounds.height()); - - // 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); - - static Image* magnifierImage = Image::loadPlatformResource("searchMagnifier").releaseRef(); - i.context->drawImage(magnifierImage, bounds); - return false; -} - -void RenderThemeChromiumWin::adjustSearchFieldResultsButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const -{ - // Scale the button size based on the font size - float fontScale = style->fontSize() / defaultControlFontPixelSize; - int magnifierHeight = lroundf(std::min(std::max(minSearchFieldResultsDecorationSize, defaultSearchFieldResultsDecorationSize * fontScale), - maxSearchFieldResultsDecorationSize)); - int magnifierWidth = lroundf(magnifierHeight * defaultSearchFieldResultsButtonWidth / defaultSearchFieldResultsDecorationSize); - style->setWidth(Length(magnifierWidth, Fixed)); - style->setHeight(Length(magnifierHeight, Fixed)); -} - -bool RenderThemeChromiumWin::paintSearchFieldResultsButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& 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(std::min(parentBox.height(), bounds.height())); - bounds.setWidth(std::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(); - i.context->drawImage(magnifierImage, bounds); - return false; -} - -bool RenderThemeChromiumWin::paintMediaButtonInternal(GraphicsContext* context, const IntRect& rect, Image* image) +bool RenderThemeChromiumWin::paintSliderThumb(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) { - context->beginTransparencyLayer(defaultMediaControlOpacity); - - // Draw background. - Color oldFill = context->fillColor(); - Color oldStroke = context->strokeColor(); - - context->setFillColor(Color::black); - context->setStrokeColor(Color::black); - context->drawRect(rect); - - context->setFillColor(oldFill); - context->setStrokeColor(oldStroke); - - // Create a destination rectangle for the image that is centered in the drawing rectangle, rounded left, and down. - IntRect imageRect = image->rect(); - imageRect.setY(rect.y() + (rect.height() - image->height() + 1) / 2); - imageRect.setX(rect.x() + (rect.width() - image->width() + 1) / 2); - - context->drawImage(image, imageRect, CompositeSourceAtop); - context->endTransparencyLayer(); - - return false; -} - -bool RenderThemeChromiumWin::paintMediaPlayButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& rect) -{ -#if ENABLE(VIDEO) - HTMLMediaElement* mediaElement = mediaElementParent(o->node()); - if (!mediaElement) - return false; - - static Image* mediaPlay = Image::loadPlatformResource("mediaPlay").releaseRef(); - static Image* mediaPause = Image::loadPlatformResource("mediaPause").releaseRef(); - - return paintMediaButtonInternal(paintInfo.context, rect, mediaElement->paused() ? mediaPlay : mediaPause); -#else - return false; -#endif -} - -bool RenderThemeChromiumWin::paintMediaMuteButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& rect) -{ -#if ENABLE(VIDEO) - HTMLMediaElement* mediaElement = mediaElementParent(o->node()); - if (!mediaElement) - return false; - - static Image* soundFull = Image::loadPlatformResource("mediaSoundFull").releaseRef(); - static Image* soundNone = Image::loadPlatformResource("mediaSoundNone").releaseRef(); - - return paintMediaButtonInternal(paintInfo.context, rect, mediaElement->muted() ? soundNone: soundFull); -#else - return false; -#endif -} - -void RenderThemeChromiumWin::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const -{ - // Height is locked to auto on all browsers. - style->setLineHeight(RenderStyle::initialLineHeight()); + return paintSliderTrack(o, i, r); } // Used to paint unstyled menulists (i.e. with the default border) @@ -709,66 +423,22 @@ bool RenderThemeChromiumWin::paintMenuList(RenderObject* o, const RenderObject:: 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); -} - -int RenderThemeChromiumWin::buttonInternalPaddingLeft() const -{ - return 3; -} - -int RenderThemeChromiumWin::buttonInternalPaddingRight() const -{ - return 3; -} - -int RenderThemeChromiumWin::buttonInternalPaddingTop() const -{ - return 1; -} - -int RenderThemeChromiumWin::buttonInternalPaddingBottom() const -{ - return 1; -} - // static void RenderThemeChromiumWin::setDefaultFontSize(int fontSize) { - defaultFontSize = static_cast<float>(fontSize); + RenderThemeChromiumSkia::setDefaultFontSize(fontSize); // Reset cached fonts. smallSystemFont = menuFont = labelFont = FontDescription(); } +double RenderThemeChromiumWin::caretBlinkIntervalInternal() const +{ + // This involves a system call, so we cache the result. + static double blinkInterval = querySystemBlinkInterval(RenderTheme::caretBlinkInterval()); + return blinkInterval; +} + unsigned RenderThemeChromiumWin::determineState(RenderObject* o) { unsigned result = TS_NORMAL; @@ -795,7 +465,7 @@ unsigned RenderThemeChromiumWin::determineSliderThumbState(RenderObject* o) result = TUS_DISABLED; else if (supportsFocus(o->style()->appearance()) && isFocused(o->parent())) result = TUS_FOCUSED; - else if (static_cast<RenderSlider*>(o->parent())->inDragMode()) + else if (toRenderSlider(o->parent())->inDragMode()) result = TUS_PRESSED; else if (isHovered(o)) result = TUS_HOT; @@ -909,22 +579,4 @@ bool RenderThemeChromiumWin::paintTextFieldInternal(RenderObject* o, 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; -} - } // namespace WebCore diff --git a/WebCore/rendering/RenderThemeChromiumWin.h b/WebCore/rendering/RenderThemeChromiumWin.h index 6ba6595..5e98c9b 100644 --- a/WebCore/rendering/RenderThemeChromiumWin.h +++ b/WebCore/rendering/RenderThemeChromiumWin.h @@ -24,7 +24,7 @@ #ifndef RenderThemeChromiumWin_h #define RenderThemeChromiumWin_h -#include "RenderTheme.h" +#include "RenderThemeChromiumSkia.h" #if WIN32 typedef void* HANDLE; @@ -42,19 +42,9 @@ namespace WebCore { unsigned m_classicState; }; - class RenderThemeChromiumWin : public RenderTheme { + class RenderThemeChromiumWin : public RenderThemeChromiumSkia { public: - RenderThemeChromiumWin() { } - ~RenderThemeChromiumWin() { } - - virtual String extraDefaultStyleSheet(); - virtual String extraQuirksStyleSheet(); -#if ENABLE(VIDEO) - virtual String extraMediaControlsStyleSheet(); -#endif - - // A method asking if the theme's controls actually care about redrawing when hovered. - virtual bool supportsHover(const RenderStyle*) const { return true; } + static PassRefPtr<RenderTheme> create(); // A method asking if the theme is able to draw the focus ring. virtual bool supportsFocusRing(const RenderStyle*) const; @@ -67,46 +57,18 @@ namespace WebCore { virtual Color platformActiveTextSearchHighlightColor() const; virtual Color platformInactiveTextSearchHighlightColor() const; - virtual double caretBlinkInterval() const; - // System fonts. virtual void systemFont(int propId, FontDescription&) const; - virtual int minimumMenuListSize(RenderStyle*) const; - virtual void adjustSliderThumbSize(RenderObject*) 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; - + // Various paint functions. + virtual bool paintCheckbox(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual bool paintRadio(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); 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 paintSliderTrack(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); - - virtual bool paintSliderThumb(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) { return paintSliderTrack(o, i, r); } - - virtual bool paintSearchField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) { return paintTextField(o, i, r); } - - virtual void adjustSearchFieldCancelButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; - virtual bool paintSearchFieldCancelButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); - - virtual void adjustSearchFieldDecorationStyle(CSSStyleSelector*, RenderStyle*, Element*) const; - - 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 paintMediaPlayButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); - virtual bool paintMediaMuteButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual bool paintSliderThumb(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 @@ -117,30 +79,19 @@ namespace WebCore { // 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 int buttonInternalPaddingLeft() const; - virtual int buttonInternalPaddingRight() const; - virtual int buttonInternalPaddingTop() const; - virtual int buttonInternalPaddingBottom() 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. + + // Override RenderThemeChromiumSkia's setDefaultFontSize method to also reset the local font property caches. + // See comment in RenderThemeChromiumSkia::setDefaultFontSize() regarding ugliness of this hack. static void setDefaultFontSize(int); + protected: + virtual double caretBlinkIntervalInternal() const; + private: + RenderThemeChromiumWin() { } + virtual ~RenderThemeChromiumWin() { } + unsigned determineState(RenderObject*); unsigned determineSliderThumbState(RenderObject*); unsigned determineClassicState(RenderObject*); @@ -148,9 +99,6 @@ namespace WebCore { ThemeData getThemeData(RenderObject*); bool paintTextFieldInternal(RenderObject*, const RenderObject::PaintInfo&, const IntRect&, bool); - bool paintMediaButtonInternal(GraphicsContext*, const IntRect&, Image*); - - int menuListInternalPadding(RenderStyle*, int paddingType) const; }; } // namespace WebCore diff --git a/WebCore/rendering/RenderThemeMac.h b/WebCore/rendering/RenderThemeMac.h index 63f1d97..85f141f 100644 --- a/WebCore/rendering/RenderThemeMac.h +++ b/WebCore/rendering/RenderThemeMac.h @@ -39,8 +39,7 @@ class RenderStyle; class RenderThemeMac : public RenderTheme { public: - RenderThemeMac(); - virtual ~RenderThemeMac(); + static PassRefPtr<RenderTheme> create(); // A method asking if the control changes its tint when the window has focus or not. virtual bool controlSupportsTints(const RenderObject*) const; @@ -59,6 +58,7 @@ public: virtual Color platformActiveListBoxSelectionForegroundColor() const; virtual Color platformInactiveListBoxSelectionBackgroundColor() const; virtual Color platformInactiveListBoxSelectionForegroundColor() const; + virtual Color platformFocusRingColor() const; virtual ScrollbarControlSize scrollbarControlSizeForPart(ControlPart) { return SmallScrollbar; } @@ -124,16 +124,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 paintMediaRewindButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual bool paintMediaReturnToRealtimeButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual bool paintMediaControlsBackground(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: + RenderThemeMac(); + virtual ~RenderThemeMac(); + 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; diff --git a/WebCore/rendering/RenderThemeMac.mm b/WebCore/rendering/RenderThemeMac.mm index c3ec91a..6315f9f 100644 --- a/WebCore/rendering/RenderThemeMac.mm +++ b/WebCore/rendering/RenderThemeMac.mm @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 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 @@ -21,6 +21,7 @@ #import "RenderThemeMac.h" #import "BitmapImage.h" +#import "ColorMac.h" #import "CSSStyleSelector.h" #import "CSSValueKeywords.h" #import "Document.h" @@ -33,6 +34,7 @@ #import "Image.h" #import "LocalCurrentGraphicsContext.h" #import "MediaControlElements.h" +#import "RenderMedia.h" #import "RenderSlider.h" #import "RenderView.h" #import "SharedBuffer.h" @@ -101,10 +103,15 @@ enum { leftPadding }; -RenderTheme* theme() +PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page*) { - static RenderThemeMac* macTheme = new RenderThemeMac; - return macTheme; + static RenderTheme* rt = RenderThemeMac::create().releaseRef(); + return rt; +} + +PassRefPtr<RenderTheme> RenderThemeMac::create() +{ + return adoptRef(new RenderThemeMac); } RenderThemeMac::RenderThemeMac() @@ -151,6 +158,14 @@ Color RenderThemeMac::platformInactiveListBoxSelectionForegroundColor() const return Color::black; } +Color RenderThemeMac::platformFocusRingColor() const +{ + if (usesTestModeFocusRingColor()) + return oldAquaFocusRingColor(); + + return systemColor(CSSValueWebkitFocusRingColor); +} + Color RenderThemeMac::platformInactiveListBoxSelectionBackgroundColor() const { return platformInactiveSelectionBackgroundColor(); @@ -408,6 +423,9 @@ Color RenderThemeMac::systemColor(int cssValueId) const case CSSValueThreedlightshadow: color = convertNSColorToColor([NSColor controlLightHighlightColor]); break; + case CSSValueWebkitFocusRingColor: + color = convertNSColorToColor([NSColor keyboardFocusIndicatorColor]); + break; case CSSValueWindow: color = convertNSColorToColor([NSColor windowBackgroundColor]); break; @@ -1116,7 +1134,7 @@ bool RenderThemeMac::paintSliderThumb(RenderObject* o, const RenderObject::Paint else oldPressed = m_isSliderThumbHorizontalPressed; - bool pressed = static_cast<RenderSlider*>(o->parent())->inDragMode(); + bool pressed = toRenderSlider(o->parent())->inDragMode(); if (o->style()->appearance() == SliderThumbVerticalPart) m_isSliderThumbVerticalPressed = pressed; @@ -1403,25 +1421,37 @@ typedef enum { static int mediaControllerTheme() { - static const long minimumQuickTimeVersion = 0x07600000; // 7.6 + static const long minimumQuickTimeVersion = 0x07630000; // 7.6.3 static SInt32 quickTimeVersion = 0; + static int controllerTheme = -1; + + if (controllerTheme != -1) + return controllerTheme; + + controllerTheme = MediaControllerThemeClassic; if (!quickTimeVersion) { OSErr err; err = Gestalt(gestaltQuickTime, &quickTimeVersion); if (err != noErr) - return MediaControllerThemeClassic; + return controllerTheme; } if (quickTimeVersion < minimumQuickTimeVersion) - return MediaControllerThemeClassic; + return controllerTheme; - // keep the feature off for now without an explicit opt-in Boolean validKey; Boolean useQTMediaUI = CFPreferencesGetAppBooleanValue(CFSTR("UseQuickTimeMediaUI"), CFSTR("com.apple.WebCore"), &validKey); + +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + if (validKey && !useQTMediaUI) + return controllerTheme; +#else if (!validKey || !useQTMediaUI) - return MediaControllerThemeClassic; + return controllerTheme; +#endif - return MediaControllerThemeQT; + controllerTheme = MediaControllerThemeQT; + return controllerTheme; } #endif @@ -1460,6 +1490,37 @@ void RenderThemeMac::adjustSliderThumbSize(RenderObject* o) const #if ENABLE(VIDEO) +enum WKMediaControllerThemeState { + MediaUIPartDisabledFlag = 1 << 0, + MediaUIPartPressedFlag = 1 << 1, + MediaUIPartDrawEndCapsFlag = 1 << 3, +}; + +static unsigned getMediaUIPartStateFlags(Node* node) +{ + unsigned flags = 0; + + if (node->active()) + flags |= MediaUIPartPressedFlag; + return flags; +} + +// Utility to scale when the UI part are not scaled by wkDrawMediaUIPart +static FloatRect getUnzoomedRectAndAdjustCurrentContext(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect &originalRect) +{ + float zoomLevel = o->style()->effectiveZoom(); + FloatRect unzoomedRect(originalRect); + if (zoomLevel != 1.0f && mediaControllerTheme() == MediaControllerThemeQT) { + 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()); + } + return unzoomedRect; +} + + bool RenderThemeMac::paintMediaFullscreenButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) { Node* node = o->node(); @@ -1467,7 +1528,7 @@ bool RenderThemeMac::paintMediaFullscreenButton(RenderObject* o, const RenderObj return false; LocalCurrentGraphicsContext localContext(paintInfo.context); - wkDrawMediaUIPart(MediaFullscreenButton, mediaControllerTheme(), paintInfo.context->platformContext(), r, node->active()); + wkDrawMediaUIPart(MediaFullscreenButton, mediaControllerTheme(), paintInfo.context->platformContext(), r, getMediaUIPartStateFlags(node)); return false; } @@ -1478,12 +1539,11 @@ bool RenderThemeMac::paintMediaMuteButton(RenderObject* o, const RenderObject::P 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, mediaControllerTheme(), paintInfo.context->platformContext(), r, node->active()); + if (MediaControlPlayButtonElement* btn = static_cast<MediaControlPlayButtonElement*>(node)) { + LocalCurrentGraphicsContext localContext(paintInfo.context); + wkDrawMediaUIPart(btn->displayType(), mediaControllerTheme(), paintInfo.context->platformContext(), r, getMediaUIPartStateFlags(node)); + + } return false; } @@ -1494,12 +1554,10 @@ bool RenderThemeMac::paintMediaPlayButton(RenderObject* o, const RenderObject::P 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, mediaControllerTheme(), paintInfo.context->platformContext(), r, node->active()); + if (MediaControlPlayButtonElement* btn = static_cast<MediaControlPlayButtonElement*>(node)) { + LocalCurrentGraphicsContext localContext(paintInfo.context); + wkDrawMediaUIPart(btn->displayType(), mediaControllerTheme(), paintInfo.context->platformContext(), r, getMediaUIPartStateFlags(node)); + } return false; } @@ -1510,7 +1568,7 @@ bool RenderThemeMac::paintMediaSeekBackButton(RenderObject* o, const RenderObjec return false; LocalCurrentGraphicsContext localContext(paintInfo.context); - wkDrawMediaUIPart(MediaSeekBackButton, mediaControllerTheme(), paintInfo.context->platformContext(), r, node->active()); + wkDrawMediaUIPart(MediaSeekBackButton, mediaControllerTheme(), paintInfo.context->platformContext(), r, getMediaUIPartStateFlags(node)); return false; } @@ -1521,7 +1579,7 @@ bool RenderThemeMac::paintMediaSeekForwardButton(RenderObject* o, const RenderOb return false; LocalCurrentGraphicsContext localContext(paintInfo.context); - wkDrawMediaUIPart(MediaSeekForwardButton, mediaControllerTheme(), paintInfo.context->platformContext(), r, node->active()); + wkDrawMediaUIPart(MediaSeekForwardButton, mediaControllerTheme(), paintInfo.context->platformContext(), r, getMediaUIPartStateFlags(node)); return false; } @@ -1545,7 +1603,12 @@ bool RenderThemeMac::paintMediaSliderTrack(RenderObject* o, const RenderObject:: currentTime = player->currentTime(); } - wkDrawMediaSliderTrack(mediaControllerTheme(), paintInfo.context->platformContext(), r, timeLoaded, currentTime, duration); + paintInfo.context->save(); + FloatRect unzoomedRect = getUnzoomedRectAndAdjustCurrentContext(o, paintInfo, r); + wkDrawMediaSliderTrack(mediaControllerTheme(), paintInfo.context->platformContext(), unzoomedRect, + timeLoaded, currentTime, duration, getMediaUIPartStateFlags(node)); + + paintInfo.context->restore(); return false; } @@ -1556,18 +1619,41 @@ bool RenderThemeMac::paintMediaSliderThumb(RenderObject* o, const RenderObject:: return false; LocalCurrentGraphicsContext localContext(paintInfo.context); - wkDrawMediaUIPart(MediaSliderThumb, mediaControllerTheme(), paintInfo.context->platformContext(), r, node->active()); + wkDrawMediaUIPart(MediaSliderThumb, mediaControllerTheme(), paintInfo.context->platformContext(), r, getMediaUIPartStateFlags(node)); + return false; +} + +bool RenderThemeMac::paintMediaRewindButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + Node* node = o->node(); + if (!node) + return false; + + LocalCurrentGraphicsContext localContext(paintInfo.context); + wkDrawMediaUIPart(MediaRewindButton, mediaControllerTheme(), paintInfo.context->platformContext(), r, getMediaUIPartStateFlags(node)); return false; } -bool RenderThemeMac::paintMediaTimelineContainer(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +bool RenderThemeMac::paintMediaReturnToRealtimeButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + Node* node = o->node(); + if (!node) + return false; + + LocalCurrentGraphicsContext localContext(paintInfo.context); + wkDrawMediaUIPart(MediaReturnToRealtimeButton, mediaControllerTheme(), paintInfo.context->platformContext(), r, getMediaUIPartStateFlags(node)); + return false; +} + + +bool RenderThemeMac::paintMediaControlsBackground(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) { Node* node = o->node(); if (!node) return false; LocalCurrentGraphicsContext localContext(paintInfo.context); - wkDrawMediaUIPart(MediaTimelineContainer, mediaControllerTheme(), paintInfo.context->platformContext(), r, node->active()); + wkDrawMediaUIPart(MediaTimelineContainer, mediaControllerTheme(), paintInfo.context->platformContext(), r, getMediaUIPartStateFlags(node)); return false; } @@ -1577,8 +1663,10 @@ bool RenderThemeMac::paintMediaCurrentTime(RenderObject* o, const RenderObject:: if (!node) return false; - LocalCurrentGraphicsContext localContext(paintInfo.context); - wkDrawMediaUIPart(MediaCurrentTimeDisplay, mediaControllerTheme(), paintInfo.context->platformContext(), r, node->active()); + paintInfo.context->save(); + FloatRect unzoomedRect = getUnzoomedRectAndAdjustCurrentContext(o, paintInfo, r); + wkDrawMediaUIPart(MediaCurrentTimeDisplay, mediaControllerTheme(), paintInfo.context->platformContext(), unzoomedRect, getMediaUIPartStateFlags(node)); + paintInfo.context->restore(); return false; } @@ -1588,8 +1676,10 @@ bool RenderThemeMac::paintMediaTimeRemaining(RenderObject* o, const RenderObject if (!node) return false; - LocalCurrentGraphicsContext localContext(paintInfo.context); - wkDrawMediaUIPart(MediaTimeRemainingDisplay, mediaControllerTheme(), paintInfo.context->platformContext(), r, node->active()); + paintInfo.context->save(); + FloatRect unzoomedRect = getUnzoomedRectAndAdjustCurrentContext(o, paintInfo, r); + wkDrawMediaUIPart(MediaTimeRemainingDisplay, mediaControllerTheme(), paintInfo.context->platformContext(), unzoomedRect, getMediaUIPartStateFlags(node)); + paintInfo.context->restore(); return false; } @@ -1600,20 +1690,6 @@ String RenderThemeMac::extraMediaControlsStyleSheet() 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 diff --git a/WebCore/rendering/RenderThemeSafari.cpp b/WebCore/rendering/RenderThemeSafari.cpp index 3affd1f..23998d4 100644 --- a/WebCore/rendering/RenderThemeSafari.cpp +++ b/WebCore/rendering/RenderThemeSafari.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2007, 2008 Apple Inc. + * Copyright (C) 2009 Kenneth Rohde Christiansen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -65,13 +66,24 @@ enum { leftPadding }; -RenderTheme* theme() +PassRefPtr<RenderTheme> RenderThemeSafari::create() { - static RenderThemeSafari safariTheme; - static RenderThemeWin windowsTheme; - if (Settings::shouldPaintNativeControls()) - return &windowsTheme; - return &safariTheme; + return adoptRef(new RenderThemeSafari); +} + +PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page) +{ + static RenderTheme* safariTheme = RenderThemeSafari::create().releaseRef(); + static RenderTheme* windowsTheme = RenderThemeWin::create().releaseRef(); + + // FIXME: This is called before Settings has been initialized by WebKit, so will return a + // potentially wrong answer the very first time it's called (see + // <https://bugs.webkit.org/show_bug.cgi?id=26493>). + if (Settings::shouldPaintNativeControls()) { + RenderTheme::setCustomFocusRingColor(safariTheme->platformFocusRingColor()); + return windowsTheme; // keep the reference of one. + } + return safariTheme; // keep the reference of one. } #if !defined(NDEBUG) && defined(USE_DEBUG_SAFARI_THEME) @@ -84,6 +96,17 @@ SOFT_LINK(SafariTheme, paintThemePart, void, __stdcall, (ThemePart part, CGConte #if defined(SAFARI_THEME_VERSION) && SAFARI_THEME_VERSION >= 2 SOFT_LINK(SafariTheme, STPaintProgressIndicator, void, APIENTRY, (ProgressIndicatorType type, CGContextRef context, const CGRect& rect, NSControlSize size, ThemeControlState state, float value), (type, context, rect, size, state, value)) #endif +SOFT_LINK_OPTIONAL(SafariTheme, STCopyThemeColor, CGColorRef, APIENTRY, (unsigned color, SafariTheme::ThemeControlState)); + +static const unsigned stFocusRingColorID = 4; + +static const unsigned aquaFocusRingColor = 0xFF7DADD9; + +static RGBA32 makeRGBAFromCGColor(CGColorRef color) +{ + const CGFloat* components = CGColorGetComponents(color); + return makeRGBA(255 * components[0], 255 * components[1], 255 * components[2], 255 * components[3]); +} ThemeControlState RenderThemeSafari::determineState(RenderObject* o) const { @@ -139,6 +162,22 @@ Color RenderThemeSafari::activeListBoxSelectionBackgroundColor() const return Color(56, 117, 215); } +Color RenderThemeSafari::platformFocusRingColor() const +{ + static Color focusRingColor; + + if (!focusRingColor.isValid()) { + if (STCopyThemeColorPtr()) { + RetainPtr<CGColorRef> color(AdoptCF, STCopyThemeColorPtr()(stFocusRingColorID, SafariTheme::ActiveState)); + focusRingColor = makeRGBAFromCGColor(color.get()); + } + if (!focusRingColor.isValid()) + focusRingColor = aquaFocusRingColor; + } + + return focusRingColor; +} + static float systemFontSizeForControlSize(NSControlSize controlSize) { static float sizes[] = { 13.0f, 11.0f, 9.0f }; @@ -961,7 +1000,7 @@ bool RenderThemeSafari::paintSliderThumb(RenderObject* o, const RenderObject::Pa ASSERT(o->parent()->isSlider()); - bool pressed = static_cast<RenderSlider*>(o->parent())->inDragMode(); + bool pressed = toRenderSlider(o->parent())->inDragMode(); ThemeControlState state = determineState(o->parent()); state &= ~SafariTheme::PressedState; if (pressed) diff --git a/WebCore/rendering/RenderThemeSafari.h b/WebCore/rendering/RenderThemeSafari.h index 8ac5acf..fb8ffb0 100644 --- a/WebCore/rendering/RenderThemeSafari.h +++ b/WebCore/rendering/RenderThemeSafari.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2007, 2008 Apple Inc. + * Copyright (C) 2009 Kenneth Rohde Christiansen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -46,8 +47,7 @@ class RenderStyle; class RenderThemeSafari : public RenderTheme { public: - RenderThemeSafari(); - virtual ~RenderThemeSafari(); + static PassRefPtr<RenderTheme> create(); // 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 @@ -69,6 +69,8 @@ public: virtual Color platformInactiveSelectionBackgroundColor() const; virtual Color activeListBoxSelectionBackgroundColor() const; + virtual Color platformFocusRingColor() const; + // System fonts. virtual void systemFont(int propId, FontDescription&) const; @@ -137,6 +139,9 @@ protected: #endif private: + RenderThemeSafari(); + virtual ~RenderThemeSafari(); + IntRect inflateRect(const IntRect&, const IntSize&, const int* margins) const; // Get the control size based off the font. Used by some of the controls (like buttons). diff --git a/WebCore/rendering/RenderThemeWin.cpp b/WebCore/rendering/RenderThemeWin.cpp index 1fa5162..92bfd03 100644 --- a/WebCore/rendering/RenderThemeWin.cpp +++ b/WebCore/rendering/RenderThemeWin.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2006, 2007 Apple Inc. + * Copyright (C) 2009 Kenneth Rohde Christiansen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -134,11 +135,16 @@ void RenderThemeWin::setWebKitIsBeingUnloaded() gWebKitIsBeingUnloaded = true; } +PassRefPtr<RenderTheme> RenderThemeWin::create() +{ + return adoptRef(new RenderThemeWin); +} + #if !USE(SAFARI_THEME) -RenderTheme* theme() +PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page) { - static RenderThemeWin winTheme; - return &winTheme; + static RenderTheme* winTheme = RenderThemeWin::create().releaseRef(); + return winTheme; } #endif @@ -422,7 +428,7 @@ unsigned RenderThemeWin::determineSliderThumbState(RenderObject* o) result = TUS_DISABLED; else if (supportsFocus(o->style()->appearance()) && isFocused(o->parent())) result = TUS_FOCUSED; - else if (static_cast<RenderSlider*>(o->parent())->inDragMode()) + else if (toRenderSlider(o->parent())->inDragMode()) result = TUS_PRESSED; else if (isHovered(o)) result = TUS_HOT; diff --git a/WebCore/rendering/RenderThemeWin.h b/WebCore/rendering/RenderThemeWin.h index 25473a1..99c2004 100644 --- a/WebCore/rendering/RenderThemeWin.h +++ b/WebCore/rendering/RenderThemeWin.h @@ -2,6 +2,7 @@ * This file is part of the WebKit project. * * Copyright (C) 2006, 2008 Apple Computer, Inc. + * Copyright (C) 2009 Kenneth Rohde Christiansen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -48,8 +49,7 @@ struct ThemeData { class RenderThemeWin : public RenderTheme { public: - RenderThemeWin(); - ~RenderThemeWin(); + static PassRefPtr<RenderTheme> create(); virtual String extraDefaultStyleSheet(); virtual String extraQuirksStyleSheet(); @@ -135,6 +135,9 @@ public: #endif private: + RenderThemeWin(); + ~RenderThemeWin(); + void addIntrinsicMargins(RenderStyle*) const; void close(); diff --git a/WebCore/rendering/RenderThemeWince.cpp b/WebCore/rendering/RenderThemeWince.cpp new file mode 100644 index 0000000..fb89678 --- /dev/null +++ b/WebCore/rendering/RenderThemeWince.cpp @@ -0,0 +1,667 @@ +/* + * This file is part of the WebKit project. + * + * Copyright (C) 2006, 2007 Apple Computer, Inc. + * Copyright (C) 2007-2009 Torch Mobile, 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 "RenderThemeWince.h" + +#include "CSSStyleSheet.h" +#include "CSSValueKeywords.h" +#include "Document.h" +#include "GraphicsContext.h" +#if ENABLE(VIDEO) +#include "HTMLMediaElement.h" +#endif + +#include <windows.h> + +/* + * The following constants are used to determine how a widget is drawn using + * Windows' Theme API. For more information on theme parts and states see + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/commctls/userex/topics/partsandstates.asp + */ +#define THEME_COLOR 204 +#define THEME_FONT 210 + +// Generic state constants +#define TS_NORMAL 1 +#define TS_HOVER 2 +#define TS_ACTIVE 3 +#define TS_DISABLED 4 +#define TS_FOCUSED 5 + +// Button constants +#define BP_BUTTON 1 +#define BP_RADIO 2 +#define BP_CHECKBOX 3 + +// Textfield constants +#define TFP_TEXTFIELD 1 +#define TFS_READONLY 6 + +typedef HANDLE (WINAPI*openThemeDataPtr)(HWND hwnd, LPCWSTR pszClassList); +typedef HRESULT (WINAPI*closeThemeDataPtr)(HANDLE hTheme); +typedef HRESULT (WINAPI*drawThemeBackgroundPtr)(HANDLE hTheme, HDC hdc, int iPartId, + int iStateId, const RECT *pRect, + const RECT* pClipRect); +typedef HRESULT (WINAPI*drawThemeEdgePtr)(HANDLE hTheme, HDC hdc, int iPartId, + int iStateId, const RECT *pRect, + unsigned uEdge, unsigned uFlags, + const RECT* pClipRect); +typedef HRESULT (WINAPI*getThemeContentRectPtr)(HANDLE hTheme, HDC hdc, int iPartId, + int iStateId, const RECT* pRect, + RECT* pContentRect); +typedef HRESULT (WINAPI*getThemePartSizePtr)(HANDLE hTheme, HDC hdc, int iPartId, + int iStateId, RECT* prc, int ts, + SIZE* psz); +typedef HRESULT (WINAPI*getThemeSysFontPtr)(HANDLE hTheme, int iFontId, OUT LOGFONT* pFont); +typedef HRESULT (WINAPI*getThemeColorPtr)(HANDLE hTheme, HDC hdc, int iPartId, + int iStateId, int iPropId, OUT COLORREF* pFont); + +namespace WebCore { + +static const int dropDownButtonWidth = 17; +static const int trackWidth = 4; + +PassRefPtr<RenderTheme> RenderThemeWince::create() +{ + return adoptRef(new RenderThemeWince); +} + +PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page) +{ + static RenderTheme* winceTheme = RenderThemeWince::create().releaseRef(); + return winceTheme; +} + +RenderThemeWince::RenderThemeWince() +{ +} + +RenderThemeWince::~RenderThemeWince() +{ +} + +Color RenderThemeWince::platformActiveSelectionBackgroundColor() const +{ + COLORREF color = GetSysColor(COLOR_HIGHLIGHT); + return Color(GetRValue(color), GetGValue(color), GetBValue(color), 255); +} + +Color RenderThemeWince::platformInactiveSelectionBackgroundColor() const +{ + COLORREF color = GetSysColor(COLOR_GRAYTEXT); + return Color(GetRValue(color), GetGValue(color), GetBValue(color), 255); +} + +Color RenderThemeWince::platformActiveSelectionForegroundColor() const +{ + COLORREF color = GetSysColor(COLOR_HIGHLIGHTTEXT); + return Color(GetRValue(color), GetGValue(color), GetBValue(color), 255); +} + +Color RenderThemeWince::platformInactiveSelectionForegroundColor() const +{ + return Color::white; +} + +bool RenderThemeWince::supportsFocus(ControlPart appearance) const +{ + switch (appearance) { + case PushButtonPart: + case ButtonPart: + case TextFieldPart: + case TextAreaPart: + return true; + default: + return false; + } + + return false; +} + +bool RenderThemeWince::supportsFocusRing(const RenderStyle *style) const +{ + return supportsFocus(style->appearance()); +} + +unsigned RenderThemeWince::determineClassicState(RenderObject* o) +{ + unsigned result = 0; + if (!isEnabled(o) || isReadOnlyControl(o)) + result = DFCS_INACTIVE; + else if (isPressed(o)) // Active supersedes hover + result = DFCS_PUSHED; + + if (isChecked(o)) + result |= DFCS_CHECKED; + return result; +} + +ThemeData RenderThemeWince::getThemeData(RenderObject* o) +{ + ThemeData result; + switch (o->style()->appearance()) { + case PushButtonPart: + case ButtonPart: + result.m_part = BP_BUTTON; + 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_RADIO; + result.m_classicState = DFCS_BUTTONRADIO; + break; + case ListboxPart: + case MenulistPart: + case TextFieldPart: + case TextAreaPart: + result.m_part = TFP_TEXTFIELD; + break; + } + + result.m_classicState |= determineClassicState(o); + + return result; +} + +bool RenderThemeWince::paintButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) +{ + // Get the correct theme data for a button + ThemeData themeData = getThemeData(o); + + // Now paint the button. + i.context->drawFrameControl(r, DFC_BUTTON, themeData.m_classicState); + if (isFocused(o)) { + if (themeData.m_part == BP_BUTTON) { + IntRect focusRect(r); + focusRect.inflate(-2); + i.context->drawFocusRect(focusRect); + } else + i.context->drawFocusRect(r); + } + + return false; +} + +void RenderThemeWince::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. + if (style->width().isIntrinsicOrAuto()) + style->setWidth(Length(13, Fixed)); + if (style->height().isAuto()) + style->setHeight(Length(13, Fixed)); +} + +bool RenderThemeWince::paintTextField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) +{ + // Get the correct theme data for a textfield + ThemeData themeData = getThemeData(o); + + // Now paint the text field. + i.context->paintTextField(r, themeData.m_classicState); + + return false; +} + +void RenderThemeWince::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +{ + style->resetBorder(); + adjustMenuListButtonStyle(selector, style, e); +} + +bool RenderThemeWince::paintMenuList(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) +{ + paintTextField(o, i, r); + paintMenuListButton(o, i, r); + return true; +} + +bool RenderThemeWince::paintMenuListButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) +{ + IntRect buttonRect(r.right() - dropDownButtonWidth - 1, r.y(), dropDownButtonWidth, r.height()); + buttonRect.inflateY(-1); + i.context->drawFrameControl(buttonRect, DFC_SCROLL, DFCS_SCROLLCOMBOBOX | determineClassicState(o)); + return true; +} + +void RenderThemeWince::systemFont(int propId, FontDescription& fontDescription) const +{ + notImplemented(); +} + +void RenderThemeWince::themeChanged() +{ +} + +String RenderThemeWince::extraDefaultStyleSheet() +{ + notImplemented(); + return String(); +} + +String RenderThemeWince::extraQuirksStyleSheet() +{ + notImplemented(); + return String(); +} + +bool RenderThemeWince::supportsHover(const RenderStyle*) const +{ + return false; +} + +// Map a CSSValue* system color to an index understood by GetSysColor +static int cssValueIdToSysColorIndex(int cssValueId) +{ + switch (cssValueId) { + case CSSValueActiveborder: return COLOR_ACTIVEBORDER; + case CSSValueActivecaption: return COLOR_ACTIVECAPTION; + case CSSValueAppworkspace: return COLOR_APPWORKSPACE; + case CSSValueBackground: return COLOR_BACKGROUND; + case CSSValueButtonface: return COLOR_BTNFACE; + case CSSValueButtonhighlight: return COLOR_BTNHIGHLIGHT; + case CSSValueButtonshadow: return COLOR_BTNSHADOW; + case CSSValueButtontext: return COLOR_BTNTEXT; + case CSSValueCaptiontext: return COLOR_CAPTIONTEXT; + case CSSValueGraytext: return COLOR_GRAYTEXT; + case CSSValueHighlight: return COLOR_HIGHLIGHT; + case CSSValueHighlighttext: return COLOR_HIGHLIGHTTEXT; + case CSSValueInactiveborder: return COLOR_INACTIVEBORDER; + case CSSValueInactivecaption: return COLOR_INACTIVECAPTION; + case CSSValueInactivecaptiontext: return COLOR_INACTIVECAPTIONTEXT; + case CSSValueInfobackground: return COLOR_INFOBK; + case CSSValueInfotext: return COLOR_INFOTEXT; + case CSSValueMenu: return COLOR_MENU; + case CSSValueMenutext: return COLOR_MENUTEXT; + case CSSValueScrollbar: return COLOR_SCROLLBAR; + case CSSValueThreeddarkshadow: return COLOR_3DDKSHADOW; + case CSSValueThreedface: return COLOR_3DFACE; + case CSSValueThreedhighlight: return COLOR_3DHIGHLIGHT; + case CSSValueThreedlightshadow: return COLOR_3DLIGHT; + case CSSValueThreedshadow: return COLOR_3DSHADOW; + case CSSValueWindow: return COLOR_WINDOW; + case CSSValueWindowframe: return COLOR_WINDOWFRAME; + case CSSValueWindowtext: return COLOR_WINDOWTEXT; + default: return -1; // Unsupported CSSValue + } +} + +Color RenderThemeWince::systemColor(int cssValueId) const +{ + int sysColorIndex = cssValueIdToSysColorIndex(cssValueId); + if (sysColorIndex == -1) + return RenderTheme::systemColor(cssValueId); + + COLORREF color = GetSysColor(sysColorIndex); + return Color(GetRValue(color), GetGValue(color), GetBValue(color)); +} + +const int sliderThumbWidth = 7; +const int sliderThumbHeight = 15; + +void RenderThemeWince::adjustSliderThumbSize(RenderObject* o) const +{ + if (o->style()->appearance() == SliderThumbVerticalPart) { + o->style()->setWidth(Length(sliderThumbHeight, Fixed)); + o->style()->setHeight(Length(sliderThumbWidth, Fixed)); + } else if (o->style()->appearance() == SliderThumbHorizontalPart) { + o->style()->setWidth(Length(sliderThumbWidth, Fixed)); + o->style()->setHeight(Length(sliderThumbHeight, Fixed)); + } +} + +#if 0 +void RenderThemeWince::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)); +} + +void RenderThemeWince::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +{ + // Override padding size to match AppKit text positioning. + const int padding = 1; + style->setPaddingLeft(Length(padding, Fixed)); + style->setPaddingRight(Length(padding, Fixed)); + style->setPaddingTop(Length(padding, Fixed)); + style->setPaddingBottom(Length(padding, Fixed)); +} +#endif + +bool RenderThemeWince::paintSearchField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) +{ + return paintTextField(o, i, r); +} + +bool RenderThemeWince::paintSearchFieldCancelButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + Color buttonColor = (o->node() && o->node()->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(); + return false; +} + +void RenderThemeWince::adjustSearchFieldCancelButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +{ + IntSize cancelSize(13, 11); + style->setWidth(Length(cancelSize.width(), Fixed)); + style->setHeight(Length(cancelSize.height(), Fixed)); +} + +void RenderThemeWince::adjustSearchFieldDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +{ + IntSize emptySize(1, 11); + style->setWidth(Length(emptySize.width(), Fixed)); + style->setHeight(Length(emptySize.height(), Fixed)); +} + +void RenderThemeWince::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +{ + IntSize magnifierSize(15, 11); + style->setWidth(Length(magnifierSize.width(), Fixed)); + style->setHeight(Length(magnifierSize.height(), Fixed)); +} + +bool RenderThemeWince::paintSearchFieldResultsDecoration(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + notImplemented(); + return false; +} + +void RenderThemeWince::adjustSearchFieldResultsButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +{ + IntSize magnifierSize(15, 11); + style->setWidth(Length(magnifierSize.width(), Fixed)); + style->setHeight(Length(magnifierSize.height(), Fixed)); +} + +bool RenderThemeWince::paintSearchFieldResultsButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + paintSearchFieldResultsDecoration(o, paintInfo, r); + return false; +} + +void RenderThemeWince::adjustMenuListButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +{ + // These are the paddings needed to place the text correctly in the <select> box + const int dropDownBoxPaddingTop = 2; + const int dropDownBoxPaddingRight = style->direction() == LTR ? 4 + dropDownButtonWidth : 4; + const int dropDownBoxPaddingBottom = 2; + const int dropDownBoxPaddingLeft = style->direction() == LTR ? 4 : 4 + dropDownButtonWidth; + // The <select> box must be at least 12px high for the button to render nicely on Windows + const int dropDownBoxMinHeight = 12; + + // Position the text correctly within the select box and make the box wide enough to fit the dropdown button + style->setPaddingTop(Length(dropDownBoxPaddingTop, Fixed)); + style->setPaddingRight(Length(dropDownBoxPaddingRight, Fixed)); + style->setPaddingBottom(Length(dropDownBoxPaddingBottom, Fixed)); + style->setPaddingLeft(Length(dropDownBoxPaddingLeft, Fixed)); + + // Height is locked to auto + style->setHeight(Length(Auto)); + + // Calculate our min-height + int minHeight = style->font().height(); + minHeight = max(minHeight, dropDownBoxMinHeight); + + style->setMinHeight(Length(minHeight, Fixed)); + + // White-space is locked to pre + style->setWhiteSpace(PRE); + + DWORD colorMenu = GetSysColor(COLOR_MENU); + DWORD colorMenuText = GetSysColor(COLOR_MENUTEXT); + Color bgColor(GetRValue(colorMenu), GetGValue(colorMenu), GetBValue(colorMenu), 255); + Color textColor(GetRValue(colorMenuText), GetGValue(colorMenuText), GetBValue(colorMenuText), 255); + if (bgColor == textColor) + textColor.setRGB((~bgColor.rgb()) | 0xFF000000); + style->clearBackgroundLayers(); + style->accessBackgroundLayers()->setClip(ContentFillBox); + style->setBackgroundColor(bgColor); + style->setColor(textColor); +} + +#if ENABLE(VIDEO) +// Attempt to retrieve a HTMLMediaElement from a Node. Returns 0 if one cannot be found. +static HTMLMediaElement* mediaElementParent(Node* node) +{ + if (!node) + return 0; + Node* mediaNode = node->shadowAncestorNode(); + if (!mediaNode || (!mediaNode->hasTagName(HTMLNames::videoTag) && !mediaNode->hasTagName(HTMLNames::audioTag))) + return 0; + + return static_cast<HTMLMediaElement*>(mediaNode); +} +#endif + +bool RenderThemeWince::paintSliderTrack(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) +{ + bool rc = RenderTheme::paintSliderTrack(o, i, r); + IntPoint left = IntPoint(r.x() + 2, (r.y() + r.bottom()) / 2); + i.context->save(); + i.context->setStrokeColor(Color::gray); + i.context->setFillColor(Color::gray); + i.context->fillRect(r); +#if ENABLE(VIDEO) + HTMLMediaElement *mediaElement = mediaElementParent(o->node()); + if (mediaElement) { + i.context->setStrokeColor(Color(0, 0xff, 0)); + IntPoint right = IntPoint(left.x() + mediaElement->percentLoaded() * (r.right() - r.x() - 4), (r.y() + r.bottom()) / 2); + i.context->drawLine(left, right); + left = right; + } +#endif + i.context->setStrokeColor(Color::black); + i.context->drawLine(left, IntPoint(r.right() - 2, left.y())); + i.context->restore(); + return rc; +} + +bool RenderThemeWince::paintSliderThumb(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) +{ + bool rc = RenderTheme::paintSliderThumb(o, i, r); + i.context->save(); + i.context->setStrokeColor(Color::black); + i.context->setFillColor(Color::black); +#if ENABLE(VIDEO) + HTMLMediaElement *mediaElement = mediaElementParent(o->node()); + if (mediaElement) { + float pt = (mediaElement->currentTime() - mediaElement->startTime()) / mediaElement->duration(); + FloatRect intRect = r; + intRect.setX(intRect.x() + intRect.width() * pt - 2); + intRect.setWidth(5); + i.context->fillRect(intRect); + } +#endif + i.context->restore(); + return rc; +} + +int RenderThemeWince::buttonInternalPaddingLeft() const +{ + return 3; +} + +int RenderThemeWince::buttonInternalPaddingRight() const +{ + return 3; +} + +int RenderThemeWince::buttonInternalPaddingTop() const +{ + return 1; +} + +int RenderThemeWince::buttonInternalPaddingBottom() const +{ + return 1; +} + +void RenderThemeWince::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +{ + const int padding = 1; + style->setPaddingLeft(Length(padding, Fixed)); + style->setPaddingRight(Length(padding, Fixed)); + style->setPaddingTop(Length(padding, Fixed)); + style->setPaddingBottom(Length(padding, Fixed)); +} + +#if ENABLE(VIDEO) + +bool RenderThemeWince::paintMediaFullscreenButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + bool rc = paintButton(o, paintInfo, r); + FloatRect imRect = r; + imRect.inflate(-2); + paintInfo.context->save(); + paintInfo.context->setStrokeColor(Color::black); + paintInfo.context->setFillColor(Color::gray); + paintInfo.context->fillRect(imRect); + paintInfo.context->restore(); + return rc; +} + +bool RenderThemeWince::paintMediaMuteButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + bool rc = paintButton(o, paintInfo, r); + HTMLMediaElement *mediaElement = mediaElementParent(o->node()); + bool muted = !mediaElement || mediaElement->muted(); + FloatRect imRect = r; + imRect.inflate(-2); + paintInfo.context->save(); + paintInfo.context->setStrokeColor(Color::black); + paintInfo.context->setFillColor(Color::black); + FloatPoint pts[6] = { + FloatPoint(imRect.x() + 1, imRect.y() + imRect.height() / 3.0), + FloatPoint(imRect.x() + 1 + imRect.width() / 2.0, imRect.y() + imRect.height() / 3.0), + FloatPoint(imRect.right() - 1, imRect.y()), + FloatPoint(imRect.right() - 1, imRect.bottom()), + FloatPoint(imRect.x() + 1 + imRect.width() / 2.0, imRect.y() + 2.0 * imRect.height() / 3.0), + FloatPoint(imRect.x() + 1, imRect.y() + 2.0 * imRect.height() / 3.0) + }; + paintInfo.context->drawConvexPolygon(6, pts); + if (muted) + paintInfo.context->drawLine(IntPoint(imRect.right(), imRect.y()), IntPoint(imRect.x(), imRect.bottom())); + paintInfo.context->restore(); + return rc; +} + +bool RenderThemeWince::paintMediaPlayButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + bool rc = paintButton(o, paintInfo, r); + FloatRect imRect = r; + imRect.inflate(-3); + paintInfo.context->save(); + paintInfo.context->setStrokeColor(Color::black); + paintInfo.context->setFillColor(Color::black); + HTMLMediaElement *mediaElement = mediaElementParent(o->node()); + bool paused = !mediaElement || mediaElement->paused(); + if (paused) { + float width = imRect.width(); + imRect.setWidth(width / 3.0); + paintInfo.context->fillRect(imRect); + imRect.move(2.0 * width / 3.0, 0); + paintInfo.context->fillRect(imRect); + } else { + FloatPoint pts[3] = { FloatPoint(imRect.x(), imRect.y()), FloatPoint(imRect.right(), (imRect.y() + imRect.bottom()) / 2.0), FloatPoint(imRect.x(), imRect.bottom()) }; + paintInfo.context->drawConvexPolygon(3, pts); + } + paintInfo.context->restore(); + return rc; +} + +bool RenderThemeWince::paintMediaSeekBackButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + bool rc = paintButton(o, paintInfo, r); + FloatRect imRect = r; + imRect.inflate(-3); + FloatPoint pts[3] = { FloatPoint((imRect.x() + imRect.right()) / 2.0, imRect.y()), FloatPoint(imRect.x(), (imRect.y() + imRect.bottom()) / 2.0), FloatPoint((imRect.x() + imRect.right()) / 2.0, imRect.bottom()) }; + FloatPoint pts2[3] = { FloatPoint(imRect.right(), imRect.y()), FloatPoint((imRect.x() + imRect.right()) / 2.0, (imRect.y() + imRect.bottom()) / 2.0), FloatPoint(imRect.right(), imRect.bottom()) }; + paintInfo.context->save(); + paintInfo.context->setStrokeColor(Color::black); + paintInfo.context->setFillColor(Color::black); + paintInfo.context->drawConvexPolygon(3, pts); + paintInfo.context->drawConvexPolygon(3, pts2); + paintInfo.context->restore(); + return rc; +} + +bool RenderThemeWince::paintMediaSeekForwardButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + bool rc = paintButton(o, paintInfo, r); + FloatRect imRect = r; + imRect.inflate(-3); + FloatPoint pts[3] = { FloatPoint(imRect.x(), imRect.y()), FloatPoint((imRect.x() + imRect.right()) / 2.0, (imRect.y() + imRect.bottom()) / 2.0), FloatPoint(imRect.x(), imRect.bottom()) }; + FloatPoint pts2[3] = { FloatPoint((imRect.x() + imRect.right()) / 2.0, imRect.y()), FloatPoint(imRect.right(), (imRect.y() + imRect.bottom()) / 2.0), FloatPoint((imRect.x() + imRect.right()) / 2.0, imRect.bottom()) }; + paintInfo.context->save(); + paintInfo.context->setStrokeColor(Color::black); + paintInfo.context->setFillColor(Color::black); + paintInfo.context->drawConvexPolygon(3, pts); + paintInfo.context->drawConvexPolygon(3, pts2); + paintInfo.context->restore(); + return rc; +} + +bool RenderThemeWince::paintMediaSliderTrack(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + return paintSliderTrack(o, paintInfo, r); +} + +bool RenderThemeWince::paintMediaSliderThumb(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +{ + return paintSliderThumb(o, paintInfo, r); +} +#endif + +} + diff --git a/WebCore/rendering/RenderThemeWince.h b/WebCore/rendering/RenderThemeWince.h new file mode 100644 index 0000000..a2d04e1 --- /dev/null +++ b/WebCore/rendering/RenderThemeWince.h @@ -0,0 +1,147 @@ +/* + * This file is part of the WebKit project. + * + * Copyright (C) 2006, 2008 Apple Computer, Inc. + * Copyright (C) 2009 Torch Mobile, 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 RenderThemeWince_h +#define RenderThemeWince_h + +#include "RenderTheme.h" + +typedef void* HANDLE; +typedef struct HINSTANCE__* HINSTANCE; +typedef HINSTANCE HMODULE; + +namespace WebCore { + + struct ThemeData { + ThemeData() :m_part(0), m_state(0), m_classicState(0) {} + ThemeData(int part, int state) + : m_part(part) + , m_state(state) + , m_classicState(0) + { } + + unsigned m_part; + unsigned m_state; + unsigned m_classicState; + }; + + class RenderThemeWince : public RenderTheme { + public: + static PassRefPtr<RenderTheme> create(); + ~RenderThemeWince(); + + 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; + + virtual Color platformActiveSelectionBackgroundColor() const; + virtual Color platformInactiveSelectionBackgroundColor() const; + virtual Color platformActiveSelectionForegroundColor() const; + virtual Color platformInactiveSelectionForegroundColor() const; + + // System fonts. + virtual void systemFont(int propId, FontDescription&) const; + virtual Color systemColor(int cssValueId) 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* style) const + { return setCheckboxSize(style); } + + 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 void adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const; + virtual bool paintMenuList(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual void adjustMenuListButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const; + + virtual bool paintMenuListButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + virtual bool paintSliderTrack(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r); + virtual bool paintSliderThumb(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r); + virtual void adjustSliderThumbSize(RenderObject*) const; + + virtual bool popupOptionSupportsTextIndent() const { return true; } + + virtual int buttonInternalPaddingLeft() const; + virtual int buttonInternalPaddingRight() const; + virtual int buttonInternalPaddingTop() const; + virtual int buttonInternalPaddingBottom() const; + + virtual void adjustSearchFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual bool paintSearchField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + 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&) { return false; } + + 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 void themeChanged(); + + virtual void adjustButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const {} + virtual void adjustTextFieldStyle(CSSStyleSelector*, RenderStyle* style, Element*) const {} + virtual void adjustTextAreaStyle(CSSStyleSelector*, RenderStyle* style, Element*) const {} + + static void setWebKitIsBeingUnloaded(); + + virtual bool supportsFocusRing(const RenderStyle*) const; + + #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&); + 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&); + #endif + + private: + RenderThemeWince(); + + unsigned determineClassicState(RenderObject*); + bool supportsFocus(ControlPart) const; + + ThemeData getThemeData(RenderObject*); + }; + +}; + +#endif diff --git a/WebCore/rendering/RenderTreeAsText.cpp b/WebCore/rendering/RenderTreeAsText.cpp index 79d1724..5c6e738 100644 --- a/WebCore/rendering/RenderTreeAsText.cpp +++ b/WebCore/rendering/RenderTreeAsText.cpp @@ -204,14 +204,14 @@ static TextStream &operator<<(TextStream& ts, const RenderObject& o) // 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); + const RenderTableCell& cell = *toRenderTableCell(&o); r = IntRect(cell.x(), cell.y() + cell.intrinsicPaddingTop(), cell.width(), cell.height() - cell.intrinsicPaddingTop() - cell.intrinsicPaddingBottom()); } else if (o.isBox()) 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()); + r.move(0, -toRenderTableCell(o.containingBlock())->intrinsicPaddingTop()); ts << " " << r; @@ -307,12 +307,12 @@ static TextStream &operator<<(TextStream& ts, const RenderObject& o) } if (o.isTableCell()) { - const RenderTableCell& c = static_cast<const RenderTableCell&>(o); + const RenderTableCell& c = *toRenderTableCell(&o); ts << " [r=" << c.row() << " c=" << c.col() << " rs=" << c.rowSpan() << " cs=" << c.colSpan() << "]"; } if (o.isListMarker()) { - String text = static_cast<const RenderListMarker&>(o).text(); + String text = toRenderListMarker(&o)->text(); if (!text.isEmpty()) { if (text.length() != 1) text = quoteAndEscapeNonPrintables(text); @@ -343,7 +343,7 @@ static void writeTextRun(TextStream& ts, const RenderText& o, const InlineTextBo // 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(); + y -= toRenderTableCell(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"); @@ -359,26 +359,26 @@ void write(TextStream& ts, const RenderObject& o, int indent) { #if ENABLE(SVG) if (o.isRenderPath()) { - write(ts, static_cast<const RenderPath&>(o), indent); + write(ts, *toRenderPath(&o), indent); return; } if (o.isSVGContainer()) { - write(ts, static_cast<const RenderSVGContainer&>(o), indent); + writeSVGContainer(ts, o, indent); return; } if (o.isSVGRoot()) { - write(ts, static_cast<const RenderSVGRoot&>(o), indent); + write(ts, *toRenderSVGRoot(&o), indent); return; } if (o.isSVGText()) { if (!o.isText()) - write(ts, static_cast<const RenderSVGText&>(o), indent); + writeSVGText(ts, *toRenderBlock(&o), indent); else - write(ts, static_cast<const RenderSVGInlineText&>(o), indent); + writeSVGInlineText(ts, *toRenderText(&o), indent); return; } if (o.isSVGImage()) { - write(ts, static_cast<const RenderSVGImage&>(o), indent); + writeSVGImage(ts, *toRenderImage(&o), indent); return; } #endif @@ -402,7 +402,7 @@ void write(TextStream& ts, const RenderObject& o, int indent) } if (o.isWidget()) { - Widget* widget = static_cast<const RenderWidget&>(o).widget(); + Widget* widget = toRenderWidget(&o)->widget(); if (widget && widget->isFrameView()) { FrameView* view = static_cast<FrameView*>(widget); RenderView* root = view->frame()->contentRenderer(); diff --git a/WebCore/rendering/RenderVideo.cpp b/WebCore/rendering/RenderVideo.cpp index d47e2f3..246d0c0 100644 --- a/WebCore/rendering/RenderVideo.cpp +++ b/WebCore/rendering/RenderVideo.cpp @@ -35,6 +35,11 @@ #include "HTMLVideoElement.h" #include "MediaPlayer.h" +#if USE(ACCELERATED_COMPOSITING) +#include "RenderLayer.h" +#include "RenderLayerBacking.h" +#endif + using namespace std; namespace WebCore { @@ -139,6 +144,10 @@ void RenderVideo::updatePlayer() mediaPlayer->setVisible(false); return; } + +#if USE(ACCELERATED_COMPOSITING) + layer()->rendererContentChanged(); +#endif IntRect videoBounds = videoBox(); mediaPlayer->setFrameView(document()->view()); @@ -246,6 +255,32 @@ void RenderVideo::calcPrefWidths() setPrefWidthsDirty(false); } +#if USE(ACCELERATED_COMPOSITING) +bool RenderVideo::supportsAcceleratedRendering() const +{ + MediaPlayer* p = player(); + if (p) + return p->supportsAcceleratedRendering(); + + return false; +} + +void RenderVideo::acceleratedRenderingStateChanged() +{ + MediaPlayer* p = player(); + if (p) + p->acceleratedRenderingStateChanged(); +} + +GraphicsLayer* RenderVideo::videoGraphicsLayer() const +{ + if (hasLayer() && layer()->isComposited()) + return layer()->backing()->graphicsLayer(); + + return 0; +} +#endif // USE(ACCELERATED_COMPOSITING) + } // namespace WebCore #endif diff --git a/WebCore/rendering/RenderVideo.h b/WebCore/rendering/RenderVideo.h index 43c1e7b..79e5b4e 100644 --- a/WebCore/rendering/RenderVideo.h +++ b/WebCore/rendering/RenderVideo.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,15 +33,35 @@ namespace WebCore { class HTMLMediaElement; +#if USE(ACCELERATED_COMPOSITING) +class GraphicsLayer; +#endif class RenderVideo : public RenderMedia { public: RenderVideo(HTMLMediaElement*); virtual ~RenderVideo(); + void videoSizeChanged(); + IntRect videoBox() const; + +#if USE(ACCELERATED_COMPOSITING) + bool supportsAcceleratedRendering() const; + void acceleratedRenderingStateChanged(); + GraphicsLayer* videoGraphicsLayer() const; +#endif + +private: + virtual void updateFromElement(); + + virtual void intrinsicSizeChanged() { videoSizeChanged(); } + virtual const char* renderName() const { return "RenderVideo"; } - virtual void paintReplaced(PaintInfo& paintInfo, int tx, int ty); + virtual bool requiresLayer() const { return true; } + virtual bool isVideo() const { return true; } + + virtual void paintReplaced(PaintInfo&, int tx, int ty); virtual void layout(); @@ -50,25 +70,24 @@ public: virtual void calcPrefWidths(); - void videoSizeChanged(); - - void updateFromElement(); - -protected: - virtual void intrinsicSizeChanged() { videoSizeChanged(); } - -private: int calcAspectRatioWidth() const; int calcAspectRatioHeight() const; bool isWidthSpecified() const; bool isHeightSpecified() const; - IntRect videoBox() const; - void updatePlayer(); }; +inline RenderVideo* toRenderVideo(RenderObject* object) +{ + ASSERT(!object || object->isVideo()); + return static_cast<RenderVideo*>(object); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderVideo(const RenderVideo*); + } // namespace WebCore #endif diff --git a/WebCore/rendering/RenderView.cpp b/WebCore/rendering/RenderView.cpp index e110d80..584e38a 100644 --- a/WebCore/rendering/RenderView.cpp +++ b/WebCore/rendering/RenderView.cpp @@ -355,8 +355,8 @@ void RenderView::setMaximalOutlineSize(int o) if (o != m_maximalOutlineSize) { m_maximalOutlineSize = o; - if (m_frameView) - m_frameView->updateCompositingLayers(FrameView::ForcedCompositingUpdate); + // maximalOutlineSize affects compositing layer dimensions. + compositor()->setCompositingLayersNeedRebuild(); // FIXME: this really just needs to be a geometry update. } } #endif diff --git a/WebCore/rendering/RenderView.h b/WebCore/rendering/RenderView.h index bcade1a..089fe85 100644 --- a/WebCore/rendering/RenderView.h +++ b/WebCore/rendering/RenderView.h @@ -208,16 +208,16 @@ private: #endif }; -inline RenderView* toRenderView(RenderObject* o) +inline RenderView* toRenderView(RenderObject* object) { - ASSERT(!o || o->isRenderView()); - return static_cast<RenderView*>(o); + ASSERT(!object || object->isRenderView()); + return static_cast<RenderView*>(object); } -inline const RenderView* toRenderView(const RenderObject* o) +inline const RenderView* toRenderView(const RenderObject* object) { - ASSERT(!o || o->isRenderView()); - return static_cast<const RenderView*>(o); + ASSERT(!object || object->isRenderView()); + return static_cast<const RenderView*>(object); } // This will catch anyone doing an unnecessary cast. @@ -225,7 +225,7 @@ void toRenderView(const RenderView*); // Stack-based class to assist with LayoutState push/pop -class LayoutStateMaintainer : Noncopyable { +class LayoutStateMaintainer : public Noncopyable { public: // ctor to push now LayoutStateMaintainer(RenderView* view, RenderBox* root, IntSize offset, bool disableState = false) diff --git a/WebCore/rendering/RenderWidget.cpp b/WebCore/rendering/RenderWidget.cpp index ec2ee6a..16526ca 100644 --- a/WebCore/rendering/RenderWidget.cpp +++ b/WebCore/rendering/RenderWidget.cpp @@ -73,8 +73,8 @@ void RenderWidget::destroy() if (m_widget) { if (m_frameView) - m_frameView->removeChild(m_widget); - widgetRendererMap().remove(m_widget); + m_frameView->removeChild(m_widget.get()); + widgetRendererMap().remove(m_widget.get()); } // removes from override size map @@ -113,17 +113,17 @@ void RenderWidget::setWidgetGeometry(const IntRect& frame) } } -void RenderWidget::setWidget(Widget* widget) +void RenderWidget::setWidget(PassRefPtr<Widget> widget) { if (widget != m_widget) { if (m_widget) { m_widget->removeFromParent(); - widgetRendererMap().remove(m_widget); + widgetRendererMap().remove(m_widget.get()); clearWidget(); } m_widget = widget; if (m_widget) { - widgetRendererMap().add(m_widget, this); + widgetRendererMap().add(m_widget.get(), this); // if we've already received a layout, apply the calculated space to the // widget immediately, but we have to have really been full constructed (with a non-null // style pointer). @@ -135,7 +135,7 @@ void RenderWidget::setWidget(Widget* widget) else m_widget->show(); } - m_frameView->addChild(m_widget); + m_frameView->addChild(m_widget.get()); } } } @@ -182,8 +182,7 @@ void RenderWidget::paint(PaintInfo& paintInfo, int tx, int ty) paintCustomHighlight(tx - x(), ty - y(), style()->highlight(), true); #endif - bool clipToBorderRadius = style()->overflowX() != OVISIBLE && style()->hasBorderRadius(); - if (clipToBorderRadius) { + if (style()->hasBorderRadius()) { // Push a clip if we have a border radius, since we want to round the foreground content that gets painted. paintInfo.context->save(); @@ -204,13 +203,13 @@ void RenderWidget::paint(PaintInfo& paintInfo, int tx, int ty) // to paint itself. That way it will composite properly with z-indexed layers. m_widget->paint(paintInfo.context, paintInfo.rect); - if (m_widget->isFrameView() && paintInfo.overlapTestRequests && !static_cast<FrameView*>(m_widget)->useSlowRepaints()) { + if (m_widget->isFrameView() && paintInfo.overlapTestRequests && !static_cast<FrameView*>(m_widget.get())->useSlowRepaints()) { ASSERT(!paintInfo.overlapTestRequests->contains(this)); paintInfo.overlapTestRequests->set(this, m_widget->frameRect()); } } - if (clipToBorderRadius) + if (style()->hasBorderRadius()) paintInfo.context->restore(); // Paint a partially transparent wash over selected widgets. @@ -224,7 +223,7 @@ void RenderWidget::setOverlapTestResult(bool isOverlapped) { ASSERT(m_widget); ASSERT(m_widget->isFrameView()); - static_cast<FrameView*>(m_widget)->setIsOverlapped(isOverlapped); + static_cast<FrameView*>(m_widget.get())->setIsOverlapped(isOverlapped); } void RenderWidget::deref(RenderArena *arena) @@ -259,7 +258,7 @@ void RenderWidget::updateWidgetPosition() // if the frame bounds got changed, or if view needs layout (possibly indicating // content size is wrong) we have to do a layout to set the right widget size if (m_widget->isFrameView()) { - FrameView* frameView = static_cast<FrameView*>(m_widget); + FrameView* frameView = static_cast<FrameView*>(m_widget.get()); if (boundsChanged || frameView->needsLayout()) frameView->layout(); } @@ -276,15 +275,7 @@ void RenderWidget::setSelectionState(SelectionState state) void RenderWidget::clearWidget() { - Widget* widget = m_widget; m_widget = 0; - if (widget) - deleteWidget(widget); -} - -void RenderWidget::deleteWidget(Widget* widget) -{ - delete widget; } RenderWidget* RenderWidget::find(const Widget* widget) diff --git a/WebCore/rendering/RenderWidget.h b/WebCore/rendering/RenderWidget.h index d23dbb3..bb68143 100644 --- a/WebCore/rendering/RenderWidget.h +++ b/WebCore/rendering/RenderWidget.h @@ -33,8 +33,8 @@ class RenderWidget : public RenderReplaced, private OverlapTestRequestClient { public: virtual ~RenderWidget(); - Widget* widget() const { return m_widget; } - virtual void setWidget(Widget*); + Widget* widget() const { return m_widget.get(); } + virtual void setWidget(PassRefPtr<Widget>); static RenderWidget* find(const Widget*); @@ -57,7 +57,6 @@ private: virtual void destroy(); virtual void setSelectionState(SelectionState); virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); - virtual void deleteWidget(Widget*); virtual void setOverlapTestResult(bool); void setWidgetGeometry(const IntRect&); @@ -65,11 +64,26 @@ private: RenderArena* ref() { ++m_refCount; return renderArena(); } void deref(RenderArena*); - Widget* m_widget; + RefPtr<Widget> m_widget; FrameView* m_frameView; int m_refCount; }; +inline RenderWidget* toRenderWidget(RenderObject* object) +{ + ASSERT(!object || object->isWidget()); + return static_cast<RenderWidget*>(object); +} + +inline const RenderWidget* toRenderWidget(const RenderObject* object) +{ + ASSERT(!object || object->isWidget()); + return static_cast<const RenderWidget*>(object); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderWidget(const RenderWidget*); + } // namespace WebCore #endif // RenderWidget_h diff --git a/WebCore/rendering/RootInlineBox.cpp b/WebCore/rendering/RootInlineBox.cpp index ed125ee..e8f04da 100644 --- a/WebCore/rendering/RootInlineBox.cpp +++ b/WebCore/rendering/RootInlineBox.cpp @@ -355,8 +355,8 @@ static bool isEditableLeaf(InlineBox* leaf) InlineBox* RootInlineBox::closestLeafChildForXPos(int x, bool onlyEditableLeaves) { - InlineBox* firstLeaf = firstLeafChildAfterBox(); - InlineBox* lastLeaf = lastLeafChildBeforeBox(); + InlineBox* firstLeaf = firstLeafChild(); + InlineBox* lastLeaf = lastLeafChild(); if (firstLeaf == lastLeaf && (!onlyEditableLeaves || isEditableLeaf(firstLeaf))) return firstLeaf; diff --git a/WebCore/rendering/SVGCharacterLayoutInfo.cpp b/WebCore/rendering/SVGCharacterLayoutInfo.cpp index 8871a75..900e0ba 100644 --- a/WebCore/rendering/SVGCharacterLayoutInfo.cpp +++ b/WebCore/rendering/SVGCharacterLayoutInfo.cpp @@ -274,7 +274,7 @@ void SVGCharacterLayoutInfo::addLayoutInformation(InlineFlowBox* flowBox, float angleStack.isEmpty() && baselineShiftStack.isEmpty() && curx == 0.0f && cury == 0.0f; - RenderSVGTextPath* textPath = static_cast<RenderSVGTextPath*>(flowBox->renderer()); + RenderSVGTextPath* textPath = toRenderSVGTextPath(flowBox->renderer()); Path path = textPath->layoutPath(); float baselineShift = calculateBaselineShift(textPath); @@ -390,11 +390,11 @@ void SVGCharacterLayoutInfo::addStackContent(StackType type, const PositionedFlo dyStackChanged = true; dyStack.append(list); break; - case AngleStack: + case AngleStack: angleStackChanged = true; angleStack.append(list); break; - default: + default: ASSERT_NOT_REACHED(); } } diff --git a/WebCore/rendering/SVGCharacterLayoutInfo.h b/WebCore/rendering/SVGCharacterLayoutInfo.h index 0188b9d..b5b4f3e 100644 --- a/WebCore/rendering/SVGCharacterLayoutInfo.h +++ b/WebCore/rendering/SVGCharacterLayoutInfo.h @@ -44,8 +44,7 @@ class SVGNumberList; class SVGTextPositioningElement; template<class Type> -class PositionedVector : public Vector<Type> -{ +class PositionedVector : public Vector<Type> { public: PositionedVector<Type>() : m_position(0) diff --git a/WebCore/rendering/SVGInlineFlowBox.h b/WebCore/rendering/SVGInlineFlowBox.h index 1aa2637..f6eb87a 100644 --- a/WebCore/rendering/SVGInlineFlowBox.h +++ b/WebCore/rendering/SVGInlineFlowBox.h @@ -37,7 +37,7 @@ public: { } - virtual int svgBoxHeight() const { return m_height; } + virtual int virtualHeight() const { return m_height; } void setHeight(int h) { m_height = h; } virtual void paint(RenderObject::PaintInfo&, int tx, int ty); diff --git a/WebCore/rendering/SVGInlineTextBox.h b/WebCore/rendering/SVGInlineTextBox.h index 410218d..76837cc 100644 --- a/WebCore/rendering/SVGInlineTextBox.h +++ b/WebCore/rendering/SVGInlineTextBox.h @@ -38,7 +38,7 @@ namespace WebCore { public: SVGInlineTextBox(RenderObject* obj); - virtual int svgBoxHeight() const { return m_height; } + virtual int virtualHeight() const { return m_height; } void setHeight(int h) { m_height = h; } virtual int selectionTop(); diff --git a/WebCore/rendering/SVGRenderSupport.cpp b/WebCore/rendering/SVGRenderSupport.cpp index c2c8e0b..fb6866f 100644 --- a/WebCore/rendering/SVGRenderSupport.cpp +++ b/WebCore/rendering/SVGRenderSupport.cpp @@ -120,7 +120,7 @@ void SVGRenderBase::prepareToRenderSVGContent(RenderObject* object, RenderObject #if ENABLE(FILTERS) if (filter) { filter->addClient(styledElement); - filter->prepareFilter(paintInfo.context, object->objectBoundingBox()); + filter->prepareFilter(paintInfo.context, object); } else if (!filterId.isEmpty()) svgElement->document()->accessSVGExtensions()->addPendingResource(filterId, styledElement); #endif @@ -152,7 +152,7 @@ void SVGRenderBase::finishRenderSVGContent(RenderObject* object, RenderObject::P #if ENABLE(FILTERS) if (filter) { - filter->applyFilter(paintInfo.context, object->objectBoundingBox()); + filter->applyFilter(paintInfo.context, object); paintInfo.context = savedContext; } #endif @@ -169,9 +169,11 @@ void renderSubtreeToImage(ImageBuffer* image, RenderObject* item) ASSERT(image->context()); RenderObject::PaintInfo info(image->context(), IntRect(), PaintPhaseForeground, 0, 0, 0); + // FIXME: isSVGContainer returns true for RenderSVGViewportContainer, so if this is ever + // called with one of those, we will read from the wrong offset in an object due to a bad cast. RenderSVGContainer* svgContainer = 0; if (item && item->isSVGContainer()) - svgContainer = static_cast<RenderSVGContainer*>(item); + svgContainer = toRenderSVGContainer(item); bool drawsContents = svgContainer ? svgContainer->drawsContents() : false; if (svgContainer && !drawsContents) diff --git a/WebCore/rendering/SVGRenderTreeAsText.cpp b/WebCore/rendering/SVGRenderTreeAsText.cpp index 33baeba..28e506a 100644 --- a/WebCore/rendering/SVGRenderTreeAsText.cpp +++ b/WebCore/rendering/SVGRenderTreeAsText.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2004, 2005, 2007, 2009 Apple Inc. All rights reserved. * (C) 2005 Rob Buis <buis@kde.org> * (C) 2006 Alexander Kellett <lypanov@kde.org> * @@ -31,14 +31,15 @@ #include "SVGRenderTreeAsText.h" #include "GraphicsTypes.h" -#include "InlineTextBox.h" #include "HTMLNames.h" +#include "InlineTextBox.h" +#include "NodeRenderStyle.h" +#include "RenderImage.h" #include "RenderPath.h" #include "RenderSVGContainer.h" -#include "RenderSVGImage.h" #include "RenderSVGInlineText.h" -#include "RenderSVGText.h" #include "RenderSVGRoot.h" +#include "RenderSVGText.h" #include "RenderTreeAsText.h" #include "SVGCharacterLayoutInfo.h" #include "SVGInlineTextBox.h" @@ -272,7 +273,7 @@ static void writeStyle(TextStream& ts, const RenderObject& object) ts << s << *strokePaintServer; double dashOffset = SVGRenderStyle::cssPrimitiveToLength(&path, svgStyle->strokeDashOffset(), 0.0f); - const DashArray& dashArray = dashArrayFromRenderingStyle(style); + const DashArray& dashArray = dashArrayFromRenderingStyle(style, object.document()->documentElement()->renderStyle()); double strokeWidth = SVGRenderStyle::cssPrimitiveToLength(&path, svgStyle->strokeWidth(), 1.0f); writeIfNotDefault(ts, "opacity", svgStyle->strokeOpacity(), 1.0f); @@ -321,35 +322,23 @@ static TextStream& operator<<(TextStream& ts, const RenderPath& path) return ts; } -static TextStream& operator<<(TextStream& ts, const RenderSVGContainer& container) -{ - return writePositionAndStyle(ts, container); -} - static TextStream& operator<<(TextStream& ts, const RenderSVGRoot& root) { return writePositionAndStyle(ts, root); } -static TextStream& operator<<(TextStream& ts, const RenderSVGImage& root) -{ - return writePositionAndStyle(ts, root); -} - -static TextStream& operator<<(TextStream& ts, const RenderSVGText& text) +static void writeRenderSVGTextBox(TextStream& ts, const RenderBlock& text) { SVGRootInlineBox* box = static_cast<SVGRootInlineBox*>(text.firstRootBox()); if (!box) - return ts; + return; Vector<SVGTextChunk>& chunks = const_cast<Vector<SVGTextChunk>& >(box->svgTextChunks()); 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())) writeNameValuePair(ts, "color", text.style()->color().name()); - - return ts; } static inline bool containsInlineTextBox(SVGTextChunk& chunk, SVGInlineTextBox* box) @@ -454,7 +443,7 @@ static inline void writeSVGInlineTextBox(TextStream& ts, SVGInlineTextBox* textB } } -static inline void writeSVGInlineText(TextStream& ts, const RenderSVGInlineText& text, int indent) +static inline void writeSVGInlineTextBoxes(TextStream& ts, const RenderText& text, int indent) { for (InlineTextBox* box = text.firstTextBox(); box; box = box->nextTextBox()) writeSVGInlineTextBox(ts, static_cast<SVGInlineTextBox*>(box), indent); @@ -475,10 +464,11 @@ static void writeChildren(TextStream& ts, const RenderObject& object, int indent write(ts, *child, indent + 1); } -void write(TextStream& ts, const RenderSVGContainer& container, int indent) +void writeSVGContainer(TextStream& ts, const RenderObject& container, int indent) { writeStandardPrefix(ts, container, indent); - ts << container << "\n"; + writePositionAndStyle(ts, container); + ts << "\n"; writeChildren(ts, container, indent); } @@ -489,20 +479,21 @@ void write(TextStream& ts, const RenderSVGRoot& root, int indent) writeChildren(ts, root, indent); } -void write(TextStream& ts, const RenderSVGText& text, int indent) +void writeSVGText(TextStream& ts, const RenderBlock& text, int indent) { writeStandardPrefix(ts, text, indent); - ts << text << "\n"; + writeRenderSVGTextBox(ts, text); + ts << "\n"; writeChildren(ts, text, indent); } -void write(TextStream& ts, const RenderSVGInlineText& text, int indent) +void writeSVGInlineText(TextStream& ts, const RenderText& text, int indent) { writeStandardPrefix(ts, text, indent); // Why not just linesBoundingBox()? ts << " " << FloatRect(text.firstRunOrigin(), text.linesBoundingBox().size()) << "\n"; - writeSVGInlineText(ts, text, indent); + writeSVGInlineTextBoxes(ts, text, indent); } void write(TextStream& ts, const RenderPath& path, int indent) @@ -511,10 +502,11 @@ void write(TextStream& ts, const RenderPath& path, int indent) ts << path << "\n"; } -void write(TextStream& ts, const RenderSVGImage& image, int indent) +void writeSVGImage(TextStream& ts, const RenderImage& image, int indent) { writeStandardPrefix(ts, image, indent); - ts << image << "\n"; + writePositionAndStyle(ts, image); + ts << "\n"; } void writeRenderResources(TextStream& ts, Node* parent) diff --git a/WebCore/rendering/SVGRenderTreeAsText.h b/WebCore/rendering/SVGRenderTreeAsText.h index 35c3d5c..bee4f36 100644 --- a/WebCore/rendering/SVGRenderTreeAsText.h +++ b/WebCore/rendering/SVGRenderTreeAsText.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2004, 2005, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,7 +32,6 @@ namespace WebCore { - class TransformationMatrix; class Color; class FloatPoint; class FloatRect; @@ -40,20 +39,21 @@ namespace WebCore { class IntPoint; class IntRect; class Node; + class RenderBlock; + class RenderImage; + class RenderObject; class RenderPath; - class RenderSVGContainer; - class RenderSVGInlineText; class RenderSVGRoot; - class RenderSVGText; - class RenderSVGImage; + class RenderText; + class TransformationMatrix; // functions used by the main RenderTreeAsText code -void write(TextStream&, const RenderPath&, int indent = 0); -void write(TextStream&, const RenderSVGContainer&, int indent = 0); -void write(TextStream&, const RenderSVGInlineText&, int indent = 0); -void write(TextStream&, const RenderSVGRoot&, int indent = 0); -void write(TextStream&, const RenderSVGText&, int indent = 0); -void write(TextStream&, const RenderSVGImage&, int indent = 0); +void write(TextStream&, const RenderPath&, int indent); +void write(TextStream&, const RenderSVGRoot&, int indent); +void writeSVGContainer(TextStream&, const RenderObject&, int indent); +void writeSVGImage(TextStream&, const RenderImage&, int indent); +void writeSVGInlineText(TextStream&, const RenderText&, int indent); +void writeSVGText(TextStream&, const RenderBlock&, int indent); void writeRenderResources(TextStream&, Node* parent); diff --git a/WebCore/rendering/SVGRootInlineBox.cpp b/WebCore/rendering/SVGRootInlineBox.cpp index d92f54c..8319e7c 100644 --- a/WebCore/rendering/SVGRootInlineBox.cpp +++ b/WebCore/rendering/SVGRootInlineBox.cpp @@ -285,14 +285,11 @@ static inline void closeTextChunk(SVGTextChunkLayoutInfo& info) RenderSVGRoot* findSVGRootObject(RenderObject* start) { - // Find associated root inline box + // Find associated root inline box. while (start && !start->isSVGRoot()) start = start->parent(); - ASSERT(start); - ASSERT(start->isSVGRoot()); - - return static_cast<RenderSVGRoot*>(start); + return toRenderSVGRoot(start); } static inline FloatPoint topLeftPositionOfCharacterRange(Vector<SVGChar>& chars) diff --git a/WebCore/rendering/SVGRootInlineBox.h b/WebCore/rendering/SVGRootInlineBox.h index 735f755..65bade0 100644 --- a/WebCore/rendering/SVGRootInlineBox.h +++ b/WebCore/rendering/SVGRootInlineBox.h @@ -53,7 +53,7 @@ public: virtual bool isSVGRootInlineBox() { return true; } - virtual int svgBoxHeight() const { return m_height; } + virtual int virtualHeight() const { return m_height; } void setHeight(int h) { m_height = h; } virtual void paint(RenderObject::PaintInfo&, int tx, int ty); diff --git a/WebCore/rendering/TextControlInnerElements.cpp b/WebCore/rendering/TextControlInnerElements.cpp index cd067de..fc7f7f0 100644 --- a/WebCore/rendering/TextControlInnerElements.cpp +++ b/WebCore/rendering/TextControlInnerElements.cpp @@ -56,7 +56,7 @@ bool RenderTextControlInnerBlock::nodeAtPoint(const HitTestRequest& request, Hit bool placeholderIsVisible = false; if (renderer->isTextField()) - placeholderIsVisible = static_cast<RenderTextControlSingleLine*>(renderer)->placeholderIsVisible(); + placeholderIsVisible = toRenderTextControlSingleLine(renderer)->placeholderIsVisible(); return RenderBlock::nodeAtPoint(request, result, x, y, tx, ty, placeholderIsVisible ? HitTestBlockBackground : hitTestAction); } @@ -69,7 +69,7 @@ VisiblePosition RenderTextControlInnerBlock::positionForPoint(const IntPoint& po // Multiline text controls have the scroll on shadowAncestorNode, so we need to take that // into account here. if (m_multiLine) { - RenderTextControl* renderer = static_cast<RenderTextControl*>(node()->shadowAncestorNode()->renderer()); + RenderTextControl* renderer = toRenderTextControl(node()->shadowAncestorNode()->renderer()); if (renderer->hasOverflowClip()) renderer->layer()->addScrolledContentOffset(contentsX, contentsY); } @@ -155,7 +155,7 @@ void SearchFieldResultsButtonElement::defaultEventHandler(Event* evt) if (evt->type() == eventNames().mousedownEvent && evt->isMouseEvent() && static_cast<MouseEvent*>(evt)->button() == LeftButton) { input->focus(); input->select(); - RenderTextControlSingleLine* renderer = static_cast<RenderTextControlSingleLine*>(input->renderer()); + RenderTextControlSingleLine* renderer = toRenderTextControlSingleLine(input->renderer()); if (renderer->popupIsVisible()) renderer->hidePopup(); else if (input->maxResults() > 0) @@ -172,6 +172,16 @@ SearchFieldCancelButtonElement::SearchFieldCancelButtonElement(Document* doc) { } +void SearchFieldCancelButtonElement::detach() +{ + if (m_capturing) { + if (Frame* frame = document()->frame()) + frame->eventHandler()->setCapturingMouseEventsNode(0); + } + TextControlInnerElement::detach(); +} + + void SearchFieldCancelButtonElement::defaultEventHandler(Event* evt) { // If the element is visible, on mouseup, clear the value, and set selection diff --git a/WebCore/rendering/TextControlInnerElements.h b/WebCore/rendering/TextControlInnerElements.h index 9e81ada..f72ddf2 100644 --- a/WebCore/rendering/TextControlInnerElements.h +++ b/WebCore/rendering/TextControlInnerElements.h @@ -32,8 +32,7 @@ namespace WebCore { class String; -class TextControlInnerElement : public HTMLDivElement -{ +class TextControlInnerElement : public HTMLDivElement { public: TextControlInnerElement(Document*, Node* shadowParent = 0); @@ -64,6 +63,7 @@ class SearchFieldCancelButtonElement : public TextControlInnerElement { public: SearchFieldCancelButtonElement(Document*); virtual void defaultEventHandler(Event*); + virtual void detach(); private: bool m_capturing; }; diff --git a/WebCore/rendering/TransformState.h b/WebCore/rendering/TransformState.h index 92275f9..d2c962a 100644 --- a/WebCore/rendering/TransformState.h +++ b/WebCore/rendering/TransformState.h @@ -37,7 +37,7 @@ namespace WebCore { -class TransformState : Noncopyable { +class TransformState : public Noncopyable { public: enum TransformDirection { ApplyTransformDirection, UnapplyInverseTransformDirection }; enum TransformAccumulation { FlattenTransform, AccumulateTransform }; diff --git a/WebCore/rendering/bidi.h b/WebCore/rendering/bidi.h deleted file mode 100644 index 9058eeb..0000000 --- a/WebCore/rendering/bidi.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * This file is part of the html renderer for KDE. - * - * Copyright (C) 2000 Lars Knoll (knoll@kde.org) - * Copyright (C) 2003 Apple Computer, 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 bidi_h -#define bidi_h - -#include "BidiResolver.h" - -namespace WebCore { - -class RenderArena; -class RenderBlock; -class RenderObject; -class InlineBox; - -struct BidiRun : BidiCharacterRun { - BidiRun(int start, int stop, RenderObject* object, BidiContext* context, WTF::Unicode::Direction dir) - : BidiCharacterRun(start, stop, context, dir) - , m_object(object) - , m_box(0) - { - } - - void destroy(); - - // Overloaded new operator. - void* operator new(size_t, RenderArena*) throw(); - - // Overridden to prevent the normal delete from being called. - void operator delete(void*, size_t); - - BidiRun* next() { return static_cast<BidiRun*>(m_next); } - -private: - // The normal operator new is disallowed. - void* operator new(size_t) throw(); - -public: - RenderObject* m_object; - InlineBox* m_box; -}; - -} // namespace WebCore - -#endif // bidi_h diff --git a/WebCore/rendering/style/FillLayer.h b/WebCore/rendering/style/FillLayer.h index 2dc5871..c3944ad 100644 --- a/WebCore/rendering/style/FillLayer.h +++ b/WebCore/rendering/style/FillLayer.h @@ -42,7 +42,7 @@ public: StyleImage* image() const { return m_image.get(); } Length xPosition() const { return m_xPosition; } Length yPosition() const { return m_yPosition; } - bool attachment() const { return m_attachment; } + EFillAttachment attachment() const { return static_cast<EFillAttachment>(m_attachment); } EFillBox clip() const { return static_cast<EFillBox>(m_clip); } EFillBox origin() const { return static_cast<EFillBox>(m_origin); } EFillRepeat repeat() const { return static_cast<EFillRepeat>(m_repeat); } @@ -65,7 +65,7 @@ public: void setImage(StyleImage* i) { m_image = i; m_imageSet = true; } void setXPosition(const Length& l) { m_xPosition = l; m_xPosSet = true; } void setYPosition(const Length& l) { m_yPosition = l; m_yPosSet = true; } - void setAttachment(bool b) { m_attachment = b; m_attachmentSet = true; } + void setAttachment(EFillAttachment attachment) { m_attachment = attachment; m_attachmentSet = true; } void setClip(EFillBox b) { m_clip = b; m_clipSet = true; } void setOrigin(EFillBox b) { m_origin = b; m_originSet = true; } void setRepeat(EFillRepeat r) { m_repeat = r; m_repeatSet = true; } @@ -104,7 +104,7 @@ public: bool hasFixedImage() const { - if (m_image && !m_attachment) + if (m_image && m_attachment == FixedBackgroundAttachment) return true; return m_next ? m_next->hasFixedImage() : false; } @@ -114,7 +114,7 @@ public: void fillUnsetProperties(); void cullEmptyLayers(); - static bool initialFillAttachment(EFillLayerType) { return true; } + static EFillAttachment initialFillAttachment(EFillLayerType) { return ScrollBackgroundAttachment; } static EFillBox initialFillClip(EFillLayerType) { return BorderFillBox; } static EFillBox initialFillOrigin(EFillLayerType type) { return type == BackgroundFillLayer ? PaddingFillBox : BorderFillBox; } static EFillRepeat initialFillRepeat(EFillLayerType) { return RepeatFill; } @@ -133,7 +133,7 @@ public: Length m_xPosition; Length m_yPosition; - bool m_attachment : 1; + unsigned m_attachment : 2; // EFillAttachment unsigned m_clip : 2; // EFillBox unsigned m_origin : 2; // EFillBox unsigned m_repeat : 2; // EFillRepeat diff --git a/WebCore/rendering/style/RenderStyle.cpp b/WebCore/rendering/style/RenderStyle.cpp index f3a2cd9..0e258c8 100644 --- a/WebCore/rendering/style/RenderStyle.cpp +++ b/WebCore/rendering/style/RenderStyle.cpp @@ -206,7 +206,7 @@ void RenderStyle::setHasPseudoStyle(PseudoId pseudo) noninherited_flags._pseudoBits |= pseudoBit(pseudo); } -RenderStyle* RenderStyle::getCachedPseudoStyle(PseudoId pid) +RenderStyle* RenderStyle::getCachedPseudoStyle(PseudoId pid) const { if (!m_cachedPseudoStyle || styleType() != NOPSEUDO) return 0; @@ -225,7 +225,14 @@ RenderStyle* RenderStyle::addCachedPseudoStyle(PassRefPtr<RenderStyle> pseudo) return m_cachedPseudoStyle.get(); } -bool RenderStyle::inheritedNotEqual(RenderStyle* other) const +void RenderStyle::getPseudoStyleCache(PseudoStyleCache& cache) const +{ + ASSERT(cache.isEmpty()); + for (RenderStyle* pseudoStyle = m_cachedPseudoStyle.get(); pseudoStyle; pseudoStyle = pseudoStyle->m_cachedPseudoStyle.get()) + cache.append(pseudoStyle); +} + +bool RenderStyle::inheritedNotEqual(const RenderStyle* other) const { return inherited_flags != other->inherited_flags || inherited != other->inherited || @@ -688,6 +695,8 @@ void RenderStyle::addBindingURI(StringImpl* uri) void RenderStyle::setTextShadow(ShadowData* val, bool add) { + ASSERT(!val || !val->spread && val->style == Normal); + StyleRareInheritedData* rareData = rareInheritedData.access(); if (!add) { delete rareData->textShadow; @@ -897,4 +906,53 @@ void RenderStyle::setBlendedFontSize(int size) font().update(font().fontSelector()); } +void RenderStyle::getBoxShadowExtent(int &top, int &right, int &bottom, int &left) const +{ + top = 0; + right = 0; + bottom = 0; + left = 0; + + for (ShadowData* boxShadow = this->boxShadow(); boxShadow; boxShadow = boxShadow->next) { + if (boxShadow->style == Inset) + continue; + int blurAndSpread = boxShadow->blur + boxShadow->spread; + + top = min(top, boxShadow->y - blurAndSpread); + right = max(right, boxShadow->x + blurAndSpread); + bottom = max(bottom, boxShadow->y + blurAndSpread); + left = min(left, boxShadow->x - blurAndSpread); + } +} + +void RenderStyle::getBoxShadowHorizontalExtent(int &left, int &right) const +{ + left = 0; + right = 0; + + for (ShadowData* boxShadow = this->boxShadow(); boxShadow; boxShadow = boxShadow->next) { + if (boxShadow->style == Inset) + continue; + int blurAndSpread = boxShadow->blur + boxShadow->spread; + + left = min(left, boxShadow->x - blurAndSpread); + right = max(right, boxShadow->x + blurAndSpread); + } +} + +void RenderStyle::getBoxShadowVerticalExtent(int &top, int &bottom) const +{ + top = 0; + bottom = 0; + + for (ShadowData* boxShadow = this->boxShadow(); boxShadow; boxShadow = boxShadow->next) { + if (boxShadow->style == Inset) + continue; + int blurAndSpread = boxShadow->blur + boxShadow->spread; + + top = min(top, boxShadow->y - blurAndSpread); + bottom = max(bottom, boxShadow->y + blurAndSpread); + } +} + } // namespace WebCore diff --git a/WebCore/rendering/style/RenderStyle.h b/WebCore/rendering/style/RenderStyle.h index 5062596..720bc8d 100644 --- a/WebCore/rendering/style/RenderStyle.h +++ b/WebCore/rendering/style/RenderStyle.h @@ -301,12 +301,15 @@ public: void inheritFrom(const RenderStyle* inheritParent); - PseudoId styleType() { return static_cast<PseudoId>(noninherited_flags._styleType); } + PseudoId styleType() const { return static_cast<PseudoId>(noninherited_flags._styleType); } void setStyleType(PseudoId styleType) { noninherited_flags._styleType = styleType; } - RenderStyle* getCachedPseudoStyle(PseudoId); + RenderStyle* getCachedPseudoStyle(PseudoId) const; RenderStyle* addCachedPseudoStyle(PassRefPtr<RenderStyle>); + typedef Vector<RenderStyle*, 10> PseudoStyleCache; + void getPseudoStyleCache(PseudoStyleCache&) const; + bool affectedByHoverRules() const { return noninherited_flags._affectedByHover; } bool affectedByActiveRules() const { return noninherited_flags._affectedByActive; } bool affectedByDragRules() const { return noninherited_flags._affectedByDrag; } @@ -520,7 +523,7 @@ public: StyleImage* backgroundImage() const { return background->m_background.m_image.get(); } EFillRepeat backgroundRepeat() const { return static_cast<EFillRepeat>(background->m_background.m_repeat); } CompositeOperator backgroundComposite() const { return static_cast<CompositeOperator>(background->m_background.m_composite); } - bool backgroundAttachment() const { return background->m_background.m_attachment; } + EFillAttachment backgroundAttachment() const { return static_cast<EFillAttachment>(background->m_background.m_attachment); } EFillBox backgroundClip() const { return static_cast<EFillBox>(background->m_background.m_clip); } EFillBox backgroundOrigin() const { return static_cast<EFillBox>(background->m_background.m_origin); } Length backgroundXPosition() const { return background->m_background.m_xPosition; } @@ -532,7 +535,7 @@ public: StyleImage* maskImage() const { return rareNonInheritedData->m_mask.m_image.get(); } EFillRepeat maskRepeat() const { return static_cast<EFillRepeat>(rareNonInheritedData->m_mask.m_repeat); } CompositeOperator maskComposite() const { return static_cast<CompositeOperator>(rareNonInheritedData->m_mask.m_composite); } - bool maskAttachment() const { return rareNonInheritedData->m_mask.m_attachment; } + EFillAttachment maskAttachment() const { return static_cast<EFillAttachment>(rareNonInheritedData->m_mask.m_attachment); } EFillBox maskClip() const { return static_cast<EFillBox>(rareNonInheritedData->m_mask.m_clip); } EFillBox maskOrigin() const { return static_cast<EFillBox>(rareNonInheritedData->m_mask.m_origin); } Length maskXPosition() const { return rareNonInheritedData->m_mask.m_xPosition; } @@ -603,7 +606,12 @@ public: unsigned int boxOrdinalGroup() const { return rareNonInheritedData->flexibleBox->ordinal_group; } EBoxOrient boxOrient() const { return static_cast<EBoxOrient>(rareNonInheritedData->flexibleBox->orient); } EBoxAlignment boxPack() const { return static_cast<EBoxAlignment>(rareNonInheritedData->flexibleBox->pack); } + ShadowData* boxShadow() const { return rareNonInheritedData->m_boxShadow.get(); } + void getBoxShadowExtent(int &top, int &right, int &bottom, int &left) const; + void getBoxShadowHorizontalExtent(int &left, int &right) const; + void getBoxShadowVerticalExtent(int &top, int &bottom) const; + StyleReflection* boxReflect() const { return rareNonInheritedData->m_boxReflect.get(); } EBoxSizing boxSizing() const { return static_cast<EBoxSizing>(box->boxSizing); } Length marqueeIncrement() const { return rareNonInheritedData->marquee->increment; } @@ -792,7 +800,7 @@ public: void setOverflowY(EOverflow v) { noninherited_flags._overflowY = v; } void setVisibility(EVisibility v) { inherited_flags._visibility = v; } void setVerticalAlign(EVerticalAlign v) { noninherited_flags._vertical_align = v; } - void setVerticalAlignLength(Length l) { SET_VAR(box, vertical_align, l ) } + void setVerticalAlignLength(Length l) { SET_VAR(box, vertical_align, l) } void setHasClip(bool b = true) { SET_VAR(visual, hasClip, b) } void setClipLeft(Length v) { SET_VAR(visual, clip.m_left, v) } @@ -801,7 +809,7 @@ public: void setClipBottom(Length v) { SET_VAR(visual, clip.m_bottom, v) } void setClip(Length top, Length right, Length bottom, Length left); - void setUnicodeBidi( EUnicodeBidi b ) { noninherited_flags._unicodeBidi = b; } + void setUnicodeBidi(EUnicodeBidi b) { noninherited_flags._unicodeBidi = b; } void setClear(EClear v) { noninherited_flags._clear = v; } void setTableLayout(ETableLayout v) { noninherited_flags._table_layout = v; } @@ -888,7 +896,7 @@ public: void setPaddingLeft(Length v) { SET_VAR(surround, padding.m_left, v) } void setPaddingRight(Length v) { SET_VAR(surround, padding.m_right, v) } - void setCursor( ECursor c ) { inherited_flags._cursor_style = c; } + void setCursor(ECursor c) { inherited_flags._cursor_style = c; } void addCursor(CachedImage*, const IntPoint& = IntPoint()); void setCursorList(PassRefPtr<CursorList>); void clearCursorList(); @@ -1033,7 +1041,7 @@ public: const CounterDirectiveMap* counterDirectives() const; CounterDirectiveMap& accessCounterDirectives(); - bool inheritedNotEqual(RenderStyle*) const; + bool inheritedNotEqual(const RenderStyle*) const; StyleDifference diff(const RenderStyle*, unsigned& changedContextSensitiveProperties) const; diff --git a/WebCore/rendering/style/RenderStyleConstants.h b/WebCore/rendering/style/RenderStyleConstants.h index 405cf7c..c491816 100644 --- a/WebCore/rendering/style/RenderStyleConstants.h +++ b/WebCore/rendering/style/RenderStyleConstants.h @@ -69,7 +69,8 @@ enum PseudoId { 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_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, + MEDIA_CONTROLS_SEEK_FORWARD_BUTTON, MEDIA_CONTROLS_FULLSCREEN_BUTTON, MEDIA_CONTROLS_REWIND_BUTTON, + MEDIA_CONTROLS_RETURN_TO_REALTIME_BUTTON, MEDIA_CONTROLS_STATUS_DISPLAY, SCROLLBAR_THUMB, SCROLLBAR_BUTTON, SCROLLBAR_TRACK, SCROLLBAR_TRACK_PIECE, SCROLLBAR_CORNER, RESIZER, FIRST_INTERNAL_PSEUDOID = FILE_UPLOAD_BUTTON @@ -109,7 +110,7 @@ enum EVerticalAlign { TEXT_BOTTOM, TOP, BOTTOM, BASELINE_MIDDLE, LENGTH }; -enum EClear{ +enum EClear { CNONE = 0, CLEFT = 1, CRIGHT = 2, CBOTH = 3 }; @@ -121,6 +122,10 @@ enum EUnicodeBidi { UBNormal, Embed, Override }; +enum EFillAttachment { + ScrollBackgroundAttachment, LocalBackgroundAttachment, FixedBackgroundAttachment +}; + enum EFillBox { BorderFillBox, PaddingFillBox, ContentFillBox, TextFillBox }; @@ -207,6 +212,11 @@ enum StyleContentType { enum EBorderFit { BorderFitBorder, BorderFitLines }; +enum EAnimPlayState { + AnimPlayStatePlaying = 0x0, + AnimPlayStatePaused = 0x1 +}; + enum ETimingFunctionType { LinearTimingFunction, CubicBezierTimingFunction }; enum EWhiteSpace { diff --git a/WebCore/rendering/style/SVGRenderStyle.cpp b/WebCore/rendering/style/SVGRenderStyle.cpp index c5f0648..1289b06 100644 --- a/WebCore/rendering/style/SVGRenderStyle.cpp +++ b/WebCore/rendering/style/SVGRenderStyle.cpp @@ -32,6 +32,7 @@ #include "CSSPrimitiveValue.h" #include "CSSValueList.h" +#include "NodeRenderStyle.h" #include "RenderObject.h" #include "RenderStyle.h" #include "SVGStyledElement.h" @@ -136,7 +137,7 @@ float SVGRenderStyle::cssPrimitiveToLength(const RenderObject* item, CSSValue* v } } - return primitive->computeLengthFloat(const_cast<RenderStyle*>(item->style())); + return primitive->computeLengthFloat(const_cast<RenderStyle*>(item->style()), item->document()->documentElement()->renderStyle()); } } diff --git a/WebCore/rendering/style/SVGRenderStyleDefs.h b/WebCore/rendering/style/SVGRenderStyleDefs.h index cb504d2..b7bf026 100644 --- a/WebCore/rendering/style/SVGRenderStyleDefs.h +++ b/WebCore/rendering/style/SVGRenderStyleDefs.h @@ -60,13 +60,13 @@ #define SVG_RS_DEFINE_ATTRIBUTE_DATAREF_WITH_INITIAL_REFCOUNTED(Data, Group, Variable, Type, Name, Initial) \ Data* Name() const { return Group->Variable.get(); } \ void set##Type(PassRefPtr<Data> obj) { \ - if(!(Group->Variable == obj)) \ + if (!(Group->Variable == obj)) \ Group.access()->Variable = obj; \ } \ static Data* initial##Type() { return Initial; } #define SVG_RS_SET_VARIABLE(Group, Variable, Value) \ - if(!(Group->Variable == Value)) \ + if (!(Group->Variable == Value)) \ Group.access()->Variable = Value; namespace WebCore { diff --git a/WebCore/rendering/style/ShadowData.cpp b/WebCore/rendering/style/ShadowData.cpp index 75fb9dc..1954224 100644 --- a/WebCore/rendering/style/ShadowData.cpp +++ b/WebCore/rendering/style/ShadowData.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org) - * Copyright (C) 2004, 2005, 2006, 2007, 2008 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 @@ -28,6 +28,8 @@ ShadowData::ShadowData(const ShadowData& o) : x(o.x) , y(o.y) , blur(o.blur) + , spread(o.spread) + , style(o.style) , color(o.color) { next = o.next ? new ShadowData(*o.next) : 0; @@ -39,7 +41,7 @@ bool ShadowData::operator==(const ShadowData& o) const (next && o.next && *next != *o.next)) return false; - return x == o.x && y == o.y && blur == o.blur && color == o.color; + return x == o.x && y == o.y && blur == o.blur && spread == o.spread && style == o.style && color == o.color; } } // namespace WebCore diff --git a/WebCore/rendering/style/ShadowData.h b/WebCore/rendering/style/ShadowData.h index dac2b18..f4061f2 100644 --- a/WebCore/rendering/style/ShadowData.h +++ b/WebCore/rendering/style/ShadowData.h @@ -2,7 +2,7 @@ * 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) 2003, 2005, 2006, 2007, 2008, 2009 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 @@ -29,6 +29,8 @@ namespace WebCore { +enum ShadowStyle { Normal, Inset }; + // This struct holds information about shadows for the text-shadow and box-shadow properties. struct ShadowData { @@ -36,15 +38,19 @@ struct ShadowData { : x(0) , y(0) , blur(0) + , spread(0) + , style(Normal) , next(0) { } - ShadowData(int _x, int _y, int _blur, const Color& _color) - : x(_x) - , y(_y) - , blur(_blur) - , color(_color) + ShadowData(int x, int y, int blur, int spread, ShadowStyle style, const Color& color) + : x(x) + , y(y) + , blur(blur) + , spread(spread) + , style(style) + , color(color) , next(0) { } @@ -62,6 +68,8 @@ struct ShadowData { int x; int y; int blur; + int spread; + ShadowStyle style; Color color; ShadowData* next; }; diff --git a/WebCore/rendering/style/StyleInheritedData.h b/WebCore/rendering/style/StyleInheritedData.h index 5f1077e..548ca72 100644 --- a/WebCore/rendering/style/StyleInheritedData.h +++ b/WebCore/rendering/style/StyleInheritedData.h @@ -44,7 +44,7 @@ public: ~StyleInheritedData(); bool operator==(const StyleInheritedData& o) const; - bool operator!=( const StyleInheritedData& o) const + bool operator!=(const StyleInheritedData& o) const { return !(*this == o); } diff --git a/WebCore/rendering/style/StyleRareInheritedData.cpp b/WebCore/rendering/style/StyleRareInheritedData.cpp index 680fd57..0f3b7e7 100644 --- a/WebCore/rendering/style/StyleRareInheritedData.cpp +++ b/WebCore/rendering/style/StyleRareInheritedData.cpp @@ -89,6 +89,7 @@ bool StyleRareInheritedData::operator==(const StyleRareInheritedData& o) const #ifdef ANDROID_CSS_TAP_HIGHLIGHT_COLOR && tapHighlightColor == o.tapHighlightColor #endif + && resize == o.resize && userSelect == o.userSelect; } |
